Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/Doctrine/ConditionalUpdate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

/*
* This file is part of the FOSElasticaBundle package.
*
* (c) FriendsOfSymfony <https://friendsofsymfony.github.com/>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace FOS\ElasticaBundle\Doctrine;

interface ConditionalUpdate
{
/**
* Determines if an entity should be updated in Elasticsearch.
*/
public function shouldBeUpdated(): bool;
}
8 changes: 6 additions & 2 deletions src/Doctrine/Listener.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ public function postPersist(LifecycleEventArgs $eventArgs)
$entity = $eventArgs->getObject();

if ($this->objectPersister->handlesObject($entity) && $this->isObjectIndexable($entity)) {
$this->scheduledForInsertion[] = $entity;
if (!$entity instanceof ConditionalUpdate || $entity->shouldBeUpdated()) {
$this->scheduledForInsertion[] = $entity;
}
}
}

Expand All @@ -109,7 +111,9 @@ public function postUpdate(LifecycleEventArgs $eventArgs)

if ($this->objectPersister->handlesObject($entity)) {
if ($this->isObjectIndexable($entity)) {
$this->scheduledForUpdate[] = $entity;
if (!$entity instanceof ConditionalUpdate || $entity->shouldBeUpdated()) {
$this->scheduledForUpdate[] = $entity;
}
} else {
// Delete if no longer indexable
$this->scheduleForDeletion($entity);
Expand Down
100 changes: 100 additions & 0 deletions tests/Unit/Doctrine/AbstractListenerTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,22 @@ public function getId()
}
}

class ConditionalUpdateEntity extends Entity
{
private $shouldBeUpdated;

public function __construct($id, $shouldBeUpdated)
{
parent::__construct($id);
$this->shouldBeUpdated = $shouldBeUpdated;
}

public function shouldBeUpdated(): bool
{
return $this->shouldBeUpdated;
}
}

/**
* See concrete MongoDB/ORM instances of this abstract test.
*
Expand Down Expand Up @@ -254,6 +270,90 @@ public function testShouldPersistOnKernelTerminateIfDeferIsTrue()
$listener->onTerminate();
}

public function testConditionalUpdateObjectInsertedOnPersistWhenShouldBeUpdatedIsTrue()
{
$entity = new ConditionalUpdateEntity(1, true);
$persister = $this->getMockPersister($entity, 'index');
$eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager());
$indexable = $this->getMockIndexable('index', $entity, true);

$listener = $this->createListener($persister, $indexable, ['indexName' => 'index']);
$listener->postPersist($eventArgs);

$this->assertSame($entity, \current($listener->scheduledForInsertion));

$persister->expects($this->once())
->method('insertMany')
->with($listener->scheduledForInsertion)
;

$listener->postFlush($eventArgs);
}

public function testConditionalUpdateObjectNotInsertedOnPersistWhenShouldBeUpdatedIsFalse()
{
$entity = new ConditionalUpdateEntity(1, false);
$persister = $this->getMockPersister($entity, 'index');
$eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager());
$indexable = $this->getMockIndexable('index', $entity, true);

$listener = $this->createListener($persister, $indexable, ['indexName' => 'index']);
$listener->postPersist($eventArgs);

$this->assertEmpty($listener->scheduledForInsertion);

$persister->expects($this->never())
->method('insertMany')
;

$listener->postFlush($eventArgs);
}

public function testConditionalUpdateObjectReplacedOnUpdateWhenShouldBeUpdatedIsTrue()
{
$entity = new ConditionalUpdateEntity(1, true);
$persister = $this->getMockPersister($entity, 'index');
$eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager());
$indexable = $this->getMockIndexable('index', $entity, true);

$listener = $this->createListener($persister, $indexable, ['indexName' => 'index']);
$listener->postUpdate($eventArgs);

$this->assertSame($entity, \current($listener->scheduledForUpdate));

$persister->expects($this->once())
->method('replaceMany')
->with([$entity])
;
$persister->expects($this->never())
->method('deleteById')
;

$listener->postFlush($eventArgs);
}

public function testConditionalUpdateObjectNotReplacedOnUpdateWhenShouldBeUpdatedIsFalse()
{
$entity = new ConditionalUpdateEntity(1, false);
$persister = $this->getMockPersister($entity, 'index');
$eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager());
$indexable = $this->getMockIndexable('index', $entity, true);

$listener = $this->createListener($persister, $indexable, ['indexName' => 'index']);
$listener->postUpdate($eventArgs);

$this->assertEmpty($listener->scheduledForUpdate);

$persister->expects($this->never())
->method('replaceMany')
;
$persister->expects($this->never())
->method('deleteById')
;

$listener->postFlush($eventArgs);
}

abstract protected function getLifecycleEventArgsClass();

abstract protected function getListenerClass();
Expand Down
42 changes: 42 additions & 0 deletions tests/Unit/Doctrine/ConditionalUpdateEntity.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

/*
* This file is part of the FOSElasticaBundle package.
*
* (c) FriendsOfSymfony <https://friendsofsymfony.github.com/>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace FOS\ElasticaBundle\Tests\Unit\Doctrine;

use FOS\ElasticaBundle\Doctrine\ConditionalUpdate;

class ConditionalUpdateEntity implements ConditionalUpdate
{
public $identifier;
private $id;
private $shouldBeUpdated = true;

public function __construct($id, $shouldBeUpdated = true)
{
$this->id = $id;
$this->shouldBeUpdated = $shouldBeUpdated;
}

public function getId()
{
return $this->id;
}

public function shouldBeUpdated(): bool
{
return $this->shouldBeUpdated;
}

public function setShouldBeUpdated(bool $shouldBeUpdated): void
{
$this->shouldBeUpdated = $shouldBeUpdated;
}
}
183 changes: 183 additions & 0 deletions tests/Unit/Doctrine/ConditionalUpdateListenerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
<?php

/*
* This file is part of the FOSElasticaBundle package.
*
* (c) FriendsOfSymfony <https://friendsofsymfony.github.com/>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace FOS\ElasticaBundle\Tests\Unit\Doctrine;

use Doctrine\Persistence\Event\LifecycleEventArgs;
use FOS\ElasticaBundle\Doctrine\ConditionalUpdate;
use FOS\ElasticaBundle\Doctrine\Listener;
use FOS\ElasticaBundle\Persister\ObjectPersisterInterface;
use FOS\ElasticaBundle\Provider\IndexableInterface;
use PHPUnit\Framework\TestCase;

/**
* @internal
*/
class ConditionalUpdateListenerTest extends TestCase
{
public function testEntityWithConditionalUpdateTrueIsIndexed()
{
$entity = $this->createMock(ConditionalUpdate::class);
$entity->expects($this->once())
->method('shouldBeUpdated')
->willReturn(true)
;

$persister = $this->createMock(ObjectPersisterInterface::class);
$persister->expects($this->once())
->method('handlesObject')
->with($entity)
->willReturn(true)
;

$indexable = $this->createMock(IndexableInterface::class);
$indexable->expects($this->once())
->method('isObjectIndexable')
->with('index_name', $entity)
->willReturn(true)
;

$eventArgs = $this->createMock(LifecycleEventArgs::class);
$eventArgs->expects($this->once())
->method('getObject')
->willReturn($entity)
;

$listener = new Listener($persister, $indexable, ['indexName' => 'index_name']);

$listener->postPersist($eventArgs);

$this->assertContains($entity, $listener->scheduledForInsertion);
}

public function testEntityWithConditionalUpdateFalseIsNotIndexed()
{
// Create a mock entity implementing ConditionalUpdate that returns false
$entity = $this->createMock(ConditionalUpdate::class);
$entity->expects($this->once())
->method('shouldBeUpdated')
->willReturn(false)
;

// Mock dependencies
$persister = $this->createMock(ObjectPersisterInterface::class);
$persister->expects($this->once())
->method('handlesObject')
->with($entity)
->willReturn(true)
;

$indexable = $this->createMock(IndexableInterface::class);
$indexable->expects($this->once())
->method('isObjectIndexable')
->with('index_name', $entity)
->willReturn(true)
;

// Create the event args
$eventArgs = $this->createMock(LifecycleEventArgs::class);
$eventArgs->expects($this->once())
->method('getObject')
->willReturn($entity)
;

// Create listener
$listener = new Listener($persister, $indexable, ['indexName' => 'index_name']);

// Test postPersist
$listener->postPersist($eventArgs);

// Check if entity is NOT in scheduledForInsertion
$this->assertEmpty($listener->scheduledForInsertion);
}

public function testEntityWithConditionalUpdateTrueIsUpdated()
{
// Create a mock entity implementing ConditionalUpdate that returns true
$entity = $this->createMock(ConditionalUpdate::class);
$entity->expects($this->once())
->method('shouldBeUpdated')
->willReturn(true)
;

// Mock dependencies
$persister = $this->createMock(ObjectPersisterInterface::class);
$persister->expects($this->once())
->method('handlesObject')
->with($entity)
->willReturn(true)
;

$indexable = $this->createMock(IndexableInterface::class);
$indexable->expects($this->once())
->method('isObjectIndexable')
->with('index_name', $entity)
->willReturn(true)
;

// Create the event args
$eventArgs = $this->createMock(LifecycleEventArgs::class);
$eventArgs->expects($this->once())
->method('getObject')
->willReturn($entity)
;

// Create listener
$listener = new Listener($persister, $indexable, ['indexName' => 'index_name']);

// Test postUpdate
$listener->postUpdate($eventArgs);

// Check if entity is in scheduledForUpdate
$this->assertContains($entity, $listener->scheduledForUpdate);
}

public function testEntityWithConditionalUpdateFalseIsNotUpdated()
{
// Create a mock entity implementing ConditionalUpdate that returns false
$entity = $this->createMock(ConditionalUpdate::class);
$entity->expects($this->once())
->method('shouldBeUpdated')
->willReturn(false)
;

// Mock dependencies
$persister = $this->createMock(ObjectPersisterInterface::class);
$persister->expects($this->once())
->method('handlesObject')
->with($entity)
->willReturn(true)
;

$indexable = $this->createMock(IndexableInterface::class);
$indexable->expects($this->once())
->method('isObjectIndexable')
->with('index_name', $entity)
->willReturn(true)
;

// Create the event args
$eventArgs = $this->createMock(LifecycleEventArgs::class);
$eventArgs->expects($this->once())
->method('getObject')
->willReturn($entity)
;

// Create listener
$listener = new Listener($persister, $indexable, ['indexName' => 'index_name']);

// Test postUpdate
$listener->postUpdate($eventArgs);

// Check if entity is NOT in scheduledForUpdate
$this->assertEmpty($listener->scheduledForUpdate);
}
}