Skip to content

Implement Doctrine discriminator maps for dynamic entity management #321

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

Merged
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
31 changes: 26 additions & 5 deletions src/Services/MeilisearchService.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,7 @@ public function __construct(NormalizerInterface $normalizer, Engine $engine, arr

public function isSearchable($className): bool
{
if (is_object($className)) {
$className = ClassUtils::getClass($className);
}
$className = $this->getBaseClassName($className);

return in_array($className, $this->searchableEntities, true);
}
Expand All @@ -76,6 +74,8 @@ public function getConfiguration(): Collection

public function searchableAs(string $className): string
{
$className = $this->getBaseClassName($className);

$indexes = new Collection($this->getConfiguration()->get('indices'));
$index = $indexes->firstWhere('class', $className);

Expand Down Expand Up @@ -207,7 +207,8 @@ public function count(string $className, string $query = '', array $searchParams

public function shouldBeIndexed(object $entity): bool
{
$className = ClassUtils::getClass($entity);
$className = $this->getBaseClassName($entity);

$propertyPath = $this->indexIfMapping[$className];

if (null !== $propertyPath) {
Expand All @@ -221,6 +222,26 @@ public function shouldBeIndexed(object $entity): bool
return true;
}

/**
* @param object|class-string $objectOrClass
*
* @return class-string
*/
private function getBaseClassName($objectOrClass): string
{
foreach ($this->searchableEntities as $class) {
if (is_a($objectOrClass, $class, true)) {
return $class;
}
}

if (is_object($objectOrClass)) {
return ClassUtils::getClass($objectOrClass);
}

return $objectOrClass;
}

private function setSearchableEntities(): void
{
$searchable = [];
Expand Down Expand Up @@ -313,7 +334,7 @@ private function makeSearchServiceResponseFrom(
foreach (array_chunk($entities, $this->configuration->get('batchSize')) as $chunk) {
$searchableEntitiesChunk = [];
foreach ($chunk as $entity) {
$entityClassName = ClassUtils::getClass($entity);
$entityClassName = $this->getBaseClassName($entity);

$searchableEntitiesChunk[] = new SearchableEntity(
$this->searchableAs($entityClassName),
Expand Down
30 changes: 30 additions & 0 deletions tests/BaseKernelTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
use Meilisearch\Bundle\Collection;
use Meilisearch\Bundle\SearchableEntity;
use Meilisearch\Bundle\SearchService;
use Meilisearch\Bundle\Tests\Entity\Article;
use Meilisearch\Bundle\Tests\Entity\Comment;
use Meilisearch\Bundle\Tests\Entity\Image;
use Meilisearch\Bundle\Tests\Entity\Link;
use Meilisearch\Bundle\Tests\Entity\ObjectId\DummyObjectId;
use Meilisearch\Bundle\Tests\Entity\Page;
use Meilisearch\Bundle\Tests\Entity\Podcast;
use Meilisearch\Bundle\Tests\Entity\Post;
use Meilisearch\Bundle\Tests\Entity\Tag;
use Meilisearch\Client;
Expand Down Expand Up @@ -116,6 +118,34 @@ protected function createImage(?int $id = null): Image
return $image;
}

protected function createArticle(?int $id = null): Article
{
$article = new Article();
$article->setTitle('Test Article');
if (null !== $id) {
$article->setId($id);
}

$this->entityManager->persist($article);
$this->entityManager->flush();

return $article;
}

protected function createPodcast(?int $id = null): Podcast
{
$podcast = new Podcast();
$podcast->setTitle('Test Podcast');
if (null !== $id) {
$podcast->setId($id);
}

$this->entityManager->persist($podcast);
$this->entityManager->flush();

return $podcast;
}

protected function createSearchableImage(): SearchableEntity
{
$image = $this->createImage(random_int(100, 300));
Expand Down
15 changes: 15 additions & 0 deletions tests/Entity/Article.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Meilisearch\Bundle\Tests\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Entity
*/
#[ORM\Entity]
class Article extends ContentItem
{
}
66 changes: 66 additions & 0 deletions tests/Entity/ContentItem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

declare(strict_types=1);

namespace Meilisearch\Bundle\Tests\Entity;

use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Entity
*
* @ORM\InheritanceType("JOINED")
*
* @ORM\DiscriminatorColumn(name="type", type="integer")
*
* @ORM\DiscriminatorMap({1 = Article::class, 2 = Podcast::class})
*/
#[ORM\Entity]
#[ORM\InheritanceType('JOINED')]
#[ORM\DiscriminatorColumn(name: 'type', type: 'integer')]
#[ORM\DiscriminatorMap([1 => Article::class, 2 => Podcast::class])]
abstract class ContentItem
{
/**
* @ORM\Id
*
* @ORM\GeneratedValue
*
* @ORM\Column(type="integer")
*/
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: Types::INTEGER)]
private int $id;

/**
* @ORM\Column(type="string")
*/
#[ORM\Column(type: Types::STRING)]
private string $title = 'Title';

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

public function setId(int $id): self
{
$this->id = $id;

return $this;
}

public function getTitle(): string
{
return $this->title;
}

public function setTitle(string $title): self
{
$this->title = $title;

return $this;
}
}
15 changes: 15 additions & 0 deletions tests/Entity/Podcast.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Meilisearch\Bundle\Tests\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Entity
*/
#[ORM\Entity]
class Podcast extends ContentItem
{
}
29 changes: 29 additions & 0 deletions tests/Integration/CommandsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ public function testSearchImportAndClearAndDeleteWithoutIndices(): void
Indexed a batch of 6 / 6 Meilisearch\Bundle\Tests\Entity\Tag entities into sf_phpunit__tags index (6 indexed since start)
Indexed a batch of 6 / 6 Meilisearch\Bundle\Tests\Entity\Tag entities into sf_phpunit__aggregated index (6 indexed since start)
Importing for index Meilisearch\Bundle\Tests\Entity\Link
Importing for index Meilisearch\Bundle\Tests\Entity\ContentItem
Importing for index Meilisearch\Bundle\Tests\Entity\Page
Indexed a batch of 6 / 6 Meilisearch\Bundle\Tests\Entity\Page entities into sf_phpunit__pages index (6 indexed since start)
Importing for index Meilisearch\Bundle\Tests\Entity\SelfNormalizable
Expand Down Expand Up @@ -111,6 +112,7 @@ public function testSearchImportAndClearAndDeleteWithoutIndices(): void
Cleared sf_phpunit__aggregated index of Meilisearch\Bundle\Tests\Entity\ContentAggregator
Cleared sf_phpunit__tags index of Meilisearch\Bundle\Tests\Entity\Tag
Cleared sf_phpunit__tags index of Meilisearch\Bundle\Tests\Entity\Link
Cleared sf_phpunit__discriminator_map index of Meilisearch\Bundle\Tests\Entity\ContentItem
Cleared sf_phpunit__pages index of Meilisearch\Bundle\Tests\Entity\Page
Cleared sf_phpunit__self_normalizable index of Meilisearch\Bundle\Tests\Entity\SelfNormalizable
Cleared sf_phpunit__dummy_custom_groups index of Meilisearch\Bundle\Tests\Entity\DummyCustomGroups
Expand All @@ -130,6 +132,7 @@ public function testSearchImportAndClearAndDeleteWithoutIndices(): void
Deleted sf_phpunit__comments
Deleted sf_phpunit__aggregated
Deleted sf_phpunit__tags
Deleted sf_phpunit__discriminator_map
Deleted sf_phpunit__pages
Deleted sf_phpunit__self_normalizable
Deleted sf_phpunit__dummy_custom_groups
Expand Down Expand Up @@ -157,6 +160,30 @@ public function testImportWithoutUpdatingSettings(): void
Indexed a batch of 6 / 6 Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__aggregated index (6 indexed since start)
Done!

EOD, $importOutput);
}

public function testImportContentItem(): void
{
for ($i = 0; $i <= 5; ++$i) {
$this->createArticle();
}

for ($i = 0; $i <= 5; ++$i) {
$this->createPodcast();
}

$importCommand = $this->application->find('meilisearch:import');
$importCommandTester = new CommandTester($importCommand);
$importCommandTester->execute(['--indices' => 'discriminator_map', '--no-update-settings' => true]);

$importOutput = $importCommandTester->getDisplay();

$this->assertSame(<<<'EOD'
Importing for index Meilisearch\Bundle\Tests\Entity\ContentItem
Indexed a batch of 12 / 12 Meilisearch\Bundle\Tests\Entity\ContentItem entities into sf_phpunit__discriminator_map index (12 indexed since start)
Done!

EOD, $importOutput);
}

Expand Down Expand Up @@ -359,6 +386,7 @@ public function testSearchCreateWithoutIndices(bool $updateSettings): void
Creating index sf_phpunit__comments for Meilisearch\Bundle\Tests\Entity\Comment
Creating index sf_phpunit__tags for Meilisearch\Bundle\Tests\Entity\Tag
Creating index sf_phpunit__tags for Meilisearch\Bundle\Tests\Entity\Link
Creating index sf_phpunit__discriminator_map for Meilisearch\Bundle\Tests\Entity\ContentItem
Creating index sf_phpunit__pages for Meilisearch\Bundle\Tests\Entity\Page
Creating index sf_phpunit__self_normalizable for Meilisearch\Bundle\Tests\Entity\SelfNormalizable
Creating index sf_phpunit__dummy_custom_groups for Meilisearch\Bundle\Tests\Entity\DummyCustomGroups
Expand All @@ -378,6 +406,7 @@ public function testSearchCreateWithoutIndices(bool $updateSettings): void
Creating index sf_phpunit__comments for Meilisearch\Bundle\Tests\Entity\Comment
Creating index sf_phpunit__tags for Meilisearch\Bundle\Tests\Entity\Tag
Creating index sf_phpunit__tags for Meilisearch\Bundle\Tests\Entity\Link
Creating index sf_phpunit__discriminator_map for Meilisearch\Bundle\Tests\Entity\ContentItem
Creating index sf_phpunit__pages for Meilisearch\Bundle\Tests\Entity\Page
Creating index sf_phpunit__self_normalizable for Meilisearch\Bundle\Tests\Entity\SelfNormalizable
Creating index sf_phpunit__dummy_custom_groups for Meilisearch\Bundle\Tests\Entity\DummyCustomGroups
Expand Down
2 changes: 2 additions & 0 deletions tests/config/meilisearch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ meilisearch:
- name: tags
class: 'Meilisearch\Bundle\Tests\Entity\Link'
index_if: isSponsored
- name: discriminator_map
class: 'Meilisearch\Bundle\Tests\Entity\ContentItem'
- name: pages
class: 'Meilisearch\Bundle\Tests\Entity\Page'
enable_serializer_groups: true
Expand Down