Skip to content

Commit 3b2c82d

Browse files
authored
Store entry origin data alongside localized data (#114)
1 parent a7d3acb commit 3b2c82d

File tree

3 files changed

+182
-4
lines changed

3 files changed

+182
-4
lines changed

src/Entries/Entry.php

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ class Entry extends FileEntry
1414

1515
public static function fromModel(Model $model)
1616
{
17+
$data = isset($model->data['__localized_fields']) ? collect($model->data)->only($model->data['__localized_fields']) : $model->data;
18+
1719
$entry = (new static())
1820
->origin($model->origin_id)
1921
->locale($model->site)
2022
->slug($model->slug)
2123
->collection($model->collection)
22-
->data($model->data)
24+
->data($data)
2325
->blueprint($model->blueprint ?? $model->data['blueprint'] ?? null)
2426
->published($model->published)
2527
->model($model);
@@ -47,16 +49,57 @@ public static function makeModelFromContract(EntryContract $source)
4749
$class = app('statamic.eloquent.entries.model');
4850

4951
$data = $source->data();
52+
$date = $source->hasDate() ? $source->date() : null;
53+
54+
$origin = $source->origin();
55+
56+
if ($source->hasOrigin()) {
57+
if ($blueprint = $source->blueprint()) {
58+
$localizedBlueprintFields = $blueprint
59+
->fields()
60+
->localizable()
61+
->all()
62+
->map
63+
->handle()
64+
->all();
65+
66+
$originData = $origin->data();
67+
68+
// remove any fields in entry data that are marked as localized but value is present, and does not match origin
69+
$localizedFields = [];
70+
foreach ($localizedBlueprintFields as $blueprintField) {
71+
if ($data->has($blueprintField)) {
72+
if ($data->get($blueprintField) === $originData->get($blueprintField)) {
73+
$data->forget($blueprintField);
74+
} else {
75+
$localizedFields[] = $blueprintField;
76+
}
77+
}
78+
}
79+
80+
$data = $originData->merge($data);
81+
82+
$data->put('__localized_fields', $localizedFields);
83+
84+
if (! in_array('date', $localizedFields)) {
85+
$date = $origin->hasDate() ? $origin->date() : null;
86+
}
87+
}
88+
}
89+
90+
if ($parent = $source->parent()) {
91+
$data->put('parent', (string) $parent->id);
92+
}
5093

5194
$attributes = [
52-
'origin_id' => $source->origin()?->id(),
95+
'origin_id' => $origin?->id(),
5396
'site' => $source->locale(),
5497
'slug' => $source->slug(),
5598
'uri' => $source->uri(),
56-
'date' => $source->hasDate() ? $source->date() : null,
99+
'date' => $date,
57100
'collection' => $source->collectionHandle(),
58101
'blueprint' => $source->blueprint ?? $source->blueprint()->handle(),
59-
'data' => $data->except(EntryQueryBuilder::COLUMNS),
102+
'data' => $data->except(EntryQueryBuilder::COLUMNS)->except(['parent']),
60103
'published' => $source->published(),
61104
'status' => $source->status(),
62105
'updated_at' => $source->lastModified(),
@@ -123,4 +166,12 @@ public function origin($origin = null)
123166

124167
return EntryFacade::find($this->model->origin_id);
125168
}
169+
170+
public function makeLocalization($site)
171+
{
172+
$this->localizations = null;
173+
174+
return parent::makeLocalization($site)
175+
->data($this->data());
176+
}
126177
}

src/Entries/EntryRepository.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ public function save($entry)
5858

5959
Blink::put("eloquent-entry-{$entry->id()}", $entry);
6060
Blink::put("eloquent-entry-{$entry->uri()}", $entry);
61+
62+
$entry->descendants()->each->save();
6163
}
6264

6365
public function delete($entry)

tests/Entries/EntryTest.php

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22

33
namespace Tests\Entries;
44

5+
use Facades\Statamic\Fields\BlueprintRepository;
56
use Illuminate\Foundation\Testing\RefreshDatabase;
67
use Statamic\Eloquent\Collections\Collection;
78
use Statamic\Eloquent\Entries\Entry;
89
use Statamic\Eloquent\Entries\EntryModel;
10+
use Statamic\Facades;
911
use Tests\TestCase;
1012

1113
class EntryTest extends TestCase
@@ -56,4 +58,127 @@ public function it_saves_to_entry_model()
5658

5759
$this->assertEquals(collect($model->toArray())->except(['updated_at'])->all(), collect($entry->toModel()->toArray())->except('updated_at')->all());
5860
}
61+
62+
/** @test */
63+
public function it_propagates_entry_if_configured()
64+
{
65+
Facades\Site::setConfig([
66+
'default' => 'en',
67+
'sites' => [
68+
'en' => ['name' => 'English', 'locale' => 'en_US', 'url' => 'http://test.com/'],
69+
'fr' => ['name' => 'French', 'locale' => 'fr_FR', 'url' => 'http://fr.test.com/'],
70+
'es' => ['name' => 'Spanish', 'locale' => 'es_ES', 'url' => 'http://test.com/es/'],
71+
'de' => ['name' => 'German', 'locale' => 'de_DE', 'url' => 'http://test.com/de/'],
72+
],
73+
]);
74+
75+
$collection = (new Collection)
76+
->handle('pages')
77+
->propagate(true)
78+
->sites(['en', 'fr', 'de'])
79+
->save();
80+
81+
$entry = (new Entry)
82+
->id(1)
83+
->locale('en')
84+
->collection($collection);
85+
86+
$return = $entry->save();
87+
88+
$this->assertIsObject($fr = $entry->descendants()->get('fr'));
89+
$this->assertIsObject($de = $entry->descendants()->get('de'));
90+
$this->assertNull($entry->descendants()->get('es')); // collection not configured for this site
91+
}
92+
93+
/** @test */
94+
public function it_propagates_updating_origin_data_to_descendent_models()
95+
{
96+
Facades\Site::setConfig([
97+
'default' => 'en',
98+
'sites' => [
99+
'en' => ['name' => 'English', 'locale' => 'en_US', 'url' => 'http://test.com/'],
100+
'fr' => ['name' => 'French', 'locale' => 'fr_FR', 'url' => 'http://fr.test.com/'],
101+
'es' => ['name' => 'Spanish', 'locale' => 'es_ES', 'url' => 'http://test.com/es/'],
102+
'de' => ['name' => 'German', 'locale' => 'de_DE', 'url' => 'http://test.com/de/'],
103+
],
104+
]);
105+
106+
$blueprint = Facades\Blueprint::makeFromFields(['foo' => ['type' => 'test', 'localizable' => true]])->setHandle('test');
107+
$blueprint->save();
108+
109+
BlueprintRepository::shouldReceive('in')->with('collections/pages')->andReturn(collect(['test' => $blueprint]));
110+
111+
$collection = (new Collection)
112+
->handle('pages')
113+
->propagate(true)
114+
->sites(['en', 'fr', 'de'])
115+
->save();
116+
117+
$entry = (new Entry)
118+
->id(1)
119+
->locale('en')
120+
->collection($collection)
121+
->blueprint('test')
122+
->data([
123+
'foo' => 'bar',
124+
'roo' => 'rar',
125+
]);
126+
127+
$return = $entry->save();
128+
129+
$this->assertNull($entry->descendants()->get('fr')->model()->data['too'] ?? null);
130+
$this->assertNull($entry->descendants()->get('de')->model()->data['too'] ?? null);
131+
132+
$blueprint->ensureField('too', ['type' => 'test', 'localizable' => true]);
133+
$entry->merge(['too' => 'tar']);
134+
135+
Facades\Entry::save($entry);
136+
137+
$this->assertNotNull($entry->descendants()->get('fr')->model()->data['too'] ?? null);
138+
$this->assertNotNull($entry->descendants()->get('de')->model()->data['too'] ?? null);
139+
}
140+
141+
/** @test */
142+
public function it_propagates_origin_date_to_descendent_models()
143+
{
144+
Facades\Site::setConfig([
145+
'default' => 'en',
146+
'sites' => [
147+
'en' => ['name' => 'English', 'locale' => 'en_US', 'url' => 'http://test.com/'],
148+
'fr' => ['name' => 'French', 'locale' => 'fr_FR', 'url' => 'http://fr.test.com/'],
149+
'es' => ['name' => 'Spanish', 'locale' => 'es_ES', 'url' => 'http://test.com/es/'],
150+
'de' => ['name' => 'German', 'locale' => 'de_DE', 'url' => 'http://test.com/de/'],
151+
],
152+
]);
153+
154+
$blueprint = Facades\Blueprint::makeFromFields(['foo' => ['type' => 'test', 'localizable' => true]])->setHandle('test');
155+
$blueprint->save();
156+
157+
BlueprintRepository::shouldReceive('in')->with('collections/pages')->andReturn(collect(['test' => $blueprint]));
158+
159+
$collection = (new Collection)
160+
->handle('pages')
161+
->dated(true)
162+
->propagate(true)
163+
->sites(['en', 'fr', 'de'])
164+
->save();
165+
166+
$entry = (new Entry)
167+
->id(1)
168+
->collection($collection)
169+
->date('2023-01-01')
170+
->locale('en')
171+
->blueprint('test');
172+
173+
$return = $entry->save();
174+
175+
$this->assertEquals($entry->descendants()->get('fr')->model()->date, '2023-01-01 00:00:00');
176+
177+
$blueprint->ensureField('too', ['type' => 'test', 'localizable' => true]);
178+
$entry->date('2024-01-01');
179+
180+
Facades\Entry::save($entry);
181+
182+
$this->assertEquals($entry->descendants()->get('fr')->model()->date, '2024-01-01 00:00:00');
183+
}
59184
}

0 commit comments

Comments
 (0)