Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.x] Add findOrNew, firstOrCreate, createOrUpdate (& related methods) methods to Entry & Term query builders #9815

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
6 changes: 6 additions & 0 deletions src/Contracts/Entries/EntryRepository.php
Expand Up @@ -18,6 +18,12 @@ public function findByUri(string $uri);

public function make();

public function firstOrCreate(array $attributes, array $values = []);

public function createOrFirst(array $attributes, array $values = []);

public function updateOrCreate(array $attributes, array $values = []);

public function query();

public function save($entry);
Expand Down
3 changes: 3 additions & 0 deletions src/Facades/Entry.php
Expand Up @@ -13,6 +13,9 @@
* @method static \Statamic\Contracts\Entries\Entry findOrFail($id)
* @method static null|\Statamic\Contracts\Entries\Entry findByUri(string $uri, string $site)
* @method static \Statamic\Contracts\Entries\Entry make()
* @method static \Statamic\Contracts\Entries\Entry firstOrCreate()
godismyjudge95 marked this conversation as resolved.
Show resolved Hide resolved
* @method static \Statamic\Contracts\Entries\Entry createOrFirst()
* @method static \Statamic\Contracts\Entries\Entry updateOrCreate()
* @method static \Statamic\Contracts\Entries\QueryBuilder query()
* @method static void save($entry)
* @method static void delete($entry)
Expand Down
37 changes: 37 additions & 0 deletions src/Stache/Query/EntryQueryBuilder.php
Expand Up @@ -5,6 +5,7 @@
use Statamic\Contracts\Entries\QueryBuilder;
use Statamic\Entries\EntryCollection;
use Statamic\Facades;
use Statamic\Facades\Entry;
use Statamic\Support\Arr;

class EntryQueryBuilder extends Builder implements QueryBuilder
Expand Down Expand Up @@ -148,4 +149,40 @@ public function prepareForFakeQuery(): array

return $data;
}

public function firstOrCreate(array $attributes = [], array $values = [])
duncanmcclean marked this conversation as resolved.
Show resolved Hide resolved
{
if (!is_null($instance = (clone $this)->where($attributes)->first())) {
return $instance;
}

return $this->createOrFirst($attributes, $values);
}

public function createOrFirst(array $attributes = [], array $values = [])
{
try {
$entry = Entry::make();
if (!isset($attributes['collection']) && empty($this->collections)) {
return null;
}

$entry->collection($attributes['collection'] ?? $this->collections[0] ?? null);

$entry->data($attributes)->merge($values);
$entry->save();
return $entry;
} catch (\Exception $e) {
return $this->where($attributes)->first();
}
}

public function updateOrCreate(array $attributes, array $values = [])
{
return tap($this->firstOrCreate($attributes, $values), function ($instance) use ($values) {
if (!$instance->wasRecentlyCreated) {
$instance->merge($values)->save();
}
});
}
}
15 changes: 15 additions & 0 deletions src/Stache/Repositories/EntryRepository.php
Expand Up @@ -116,6 +116,21 @@ public function make(): Entry
return app(Entry::class);
}

public function firstOrCreate(array $attributes, array $values = [])
{
return $this->query()->firstOrCreate($attributes, $values);
}

public function createOrFirst(array $attributes, array $values = [])
{
return $this->query()->createOrFirst($attributes, $values);
}

public function updateOrCreate(array $attributes, array $values = [])
{
return $this->query()->updateOrCreate($attributes, $values);
}

public function taxonomize($entry)
{
$entry->collection()->taxonomies()->each(function ($taxonomy) use ($entry) {
Expand Down
38 changes: 38 additions & 0 deletions tests/Data/Entries/EntryQueryBuilderTest.php
Expand Up @@ -803,4 +803,42 @@ public function values_can_be_plucked()
'thing-2',
], Entry::query()->where('type', 'b')->pluck('slug')->all());
}

/** @test */
public function entries_can_be_found_or_created_or_updated()
{
$this->createDummyCollectionAndEntries();

// Create new entry
$entry = Entry::query()
->where('collection', 'posts')
->firstOrCreate(
['id' => 'id-1'],
['title' => 'Post 1'],
);
$this->assertEquals('Post 1', $entry->title);

// Get the first entry if it already exists
$entry = Entry::query()
->where('collection', 'posts')
->firstOrCreate(
['id' => 'id-1'],
['title' => 'Post 2'],
);
$this->assertEquals('Post 1', $entry->title);

// Create new entry
$entry = Entry::updateOrCreate(
['id' => 'id-2', 'collection' => 'posts'],
['title' => 'Post 2'],
);
$this->assertEquals('Post 2', $entry->title);

// Only update the entry if it already exists
$entry = Entry::updateOrCreate(
['id' => 'id-1', 'collection' => 'posts'],
['title' => 'Post 1 - Updated'],
);
$this->assertEquals('Post 1 - Updated', $entry->title);
}
}