-
Notifications
You must be signed in to change notification settings - Fork 34
Add Data providers extension point #410
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
Conversation
WalkthroughReplaces SearchService with a new SearchManagerInterface + MeilisearchManager, introduces a DataProvider system (registry, ORM provider, compiler pass), adds identifier normalization and SearchableObject with configurable primary keys, updates DI wiring/commands/listeners/tests, and modernizes CI/composer constraints and PHPStan baseline. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant CLI as Command (Import/Create/Update)
participant Registry as DataProviderRegistry
participant Provider as DataProvider (ORM/custom)
participant Manager as MeilisearchManager
participant Engine as Engine
participant Client as MeiliClient
CLI->>Registry: request provider for index/class
Registry-->>Provider: return provider instance
CLI->>Provider: provide(limit, offset)
Provider-->>CLI: return batch of domain objects
CLI->>Manager: index(batch objects)
Manager->>Engine: create SearchableObject(s) and group per index
Engine->>Client: addDocuments(index, documents, primaryKey)
Client-->>Engine: task/result
Engine-->>Manager: return tasks/results
Manager-->>CLI: aggregated responses
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Thanks! in my survos/meili-bundle, I came up with a solution that is working well for me at scale, by batching in .jsonl file. This works great when I'm bulk importing. I use the Symfony Workflow component when I'm bulk updating (e.g. updating 'marking' in some workflow process, where I may get thousands of tiny 1-field updates. The workflow component has the ability to batch event messages (from bin/console mess:consume), which I use to gather some size (10M, I think) before dispatching a single message to the meili server. https://github.com/survos/meili-bundle/blob/main/src/EventListener/MeiliSpoolDoctrineListener.php I'm giving a talk later this week at the Symfony Conference on meilisearch and how to configure the index using attributes. I'd love your feedback, are you available on Slack or the meili discord channel? |
|
I am available on both :) |
8569538 to
a8ad4dd
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #410 +/- ##
===========================================
- Coverage 88.38% 72.38% -16.00%
===========================================
Files 20 28 +8
Lines 878 1224 +346
===========================================
+ Hits 776 886 +110
- Misses 102 338 +236 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
a8ad4dd to
352e2bc
Compare
Strift
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The introduction of the Data Provider architecture is welcome, but deleting SearchService constitutes a massive breaking change that prevents us from releasing this in a minor version.
I'm wondering if we can support the new architecture and keep backward compatibility by using the bridge pattern.
What do you think of the following?
- Restore
src/SearchService.php(Interface) andsrc/Services/MeilisearchService.php. - Inject the new
MeilisearchManagerinto the oldMeilisearchService. - Forward calls from the old service to the new manager, ignoring the now-obsolete arguments.
Example Implementation for src/Services/MeilisearchService.php:
// ... imports
use Meilisearch\Bundle\Services\MeilisearchManager;
/**
* @deprecated Use MeilisearchManager instead.
*/
class MeilisearchService implements SearchService // Keep the old Interface too!
{
public function __construct(private MeilisearchManager $manager)
{
}
public function search(ObjectManager $objectManager, string $className, string $query = '', array $searchParams = []): array
{
trigger_deprecation('meilisearch/meilisearch-symfony', '0.x', 'Passing ObjectManager to search() is deprecated. Use MeilisearchManager::search() instead.');
// We ignore $objectManager because the new Manager handles data provision internally
return $this->manager->search($className, $query, $searchParams);
}
public function index(ObjectManager $objectManager, $searchable): array
{
// Forward to manager...
return $this->manager->index($searchable);
}
// ... implement other methods similarly
}This allows existing users to upgrade immediately. They will get the benefits of the new Data Provider system (internalized in the Manager) while their existing code (passing $objectManager) continues to work. We also add a deprecation warning and update the docs accordingly.
let me know!
well we are on v0, so BC breaks are expected, right? ofc i can do the bridge as you want, but not today |
352e2bc to
ea2a369
Compare
|
@Strift updated ;) |
2949520 to
4cb2b38
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 15
🧹 Nitpick comments (18)
src/SearchService.php (1)
9-11: Deprecation notice is appropriate for the migration path.The deprecation annotation correctly guides users toward
SearchManagerInterface. Consider also adding a@seetag pointing to the new interface for easier discovery./** * @deprecated Since 0.16, use `Meilisearch\Bundle\SearchManagerInterface` instead. + * + * @see SearchManagerInterface */tests/Entity/Actor.php (1)
7-27: Test entity is well-structured.The
Actorclass appropriately serves as a fixture for testing the newDataProviderInterfaceflow.Since PHP 8.1 is now the minimum version, you could simplify using constructor property promotion for consistency with other refactored classes in this PR:
final class Actor { - private int $id; - private string $name; - - public function __construct(int $id, string $name) - { - $this->id = $id; - $this->name = $name; - } + public function __construct( + private readonly int $id, + private readonly string $name, + ) { + } public function getId(): intsrc/Services/MeilisearchService.php (3)
50-59: Constructor/manager wiring is sound, but consider typing the dependency to the interfaceThe optional manager injection and assignment to
?SearchManagerInterfaceis consistent and safe. For flexibility (easier testing and potential alternative managers), you might consider changing the ctor signature to depend directly on?SearchManagerInterfaceinstead of?MeilisearchManager, keeping the same service wiring.
254-272: DeprecatingshouldBeIndexedwhile still using it internallyMarking
shouldBeIndexed()as deprecated “without replacement” is fine given the new manager‑based architecture, but it’s still used internally inindex(). If you want to discourage external use without surprising readers, you could clarify the docblock to “for internal use only; external callers should migrate toMeilisearchManager”.
27-27: Address phpmd pipeline failures for this deprecated classphpmd is now flagging this class for:
- too many public methods / high complexity / high coupling, and
- long variable names and static access.
Given
MeilisearchServiceis now deprecated and wrapped byMeilisearchManager, a large refactor here is probably not worth it. Consider instead:
- adding
@SuppressWarningsannotations for the relevant PHPMD rules on this class, or- excluding this deprecated class from phpmd in your ruleset,
so the pipeline passes without forcing structural changes to legacy code.
Also applies to: 48-48, 57-57, 384-384, 432-432, 436-436
tests/Unit/ConfigurationTest.php (1)
359-402: New test case validates customprimary_keyoverridesThe
'custom objectID'dataset (withprimary_keyset topostId/tagId) is a good addition to ensure the configuration layer preserves per-index primary key overrides through normalization. If you ever rename the test, you might consider calling it “custom primary key” to better match the new terminology, but that’s purely cosmetic.phpstan-baseline.php (1)
1-17: Consider tightening the phpstan baseline aroundClassUtils::getClass()The new ignore entries unblock static analysis but may be masking either a missing dev dependency/extension config or an obsolete call site. As a follow‑up, it would be good to either:
- add proper doctrine/phpstan integration so
ClassUtilsis known, or- refactor away from
ClassUtils::getClass()if it’s no longer needed.Not a blocker for this PR, but worth tracking.
src/DependencyInjection/Configuration.php (1)
7-7: New index config fields fit the provider model; consider adding light validationThe added
type,primary_key, anddata_providerfields and the switch toSearchableObject::NORMALIZATION_GROUPlook consistent with the new SearchableObject/DataProvider architecture.Two potential follow‑ups (non‑blocking):
- For
type: 'custom', you might want a smallvalidate()hook to assert thatdata_provideris not null, so obvious misconfigurations fail early in config rather than at runtime.- Given the move away from Algolia semantics, it may be worth revisiting the default
primary_keyof'objectID'in a future breaking version, to better reflect theid‑centric normalization now used in entities.Based on learnings, this could be deferred to a separate, focused PR on configuration/error‑handling.
Also applies to: 53-59, 59-67
src/Model/Aggregator.php (1)
71-75: The TODO identifies a real consistency issue with configurable primary keys.The
normalize()method hardcodes'objectID'as the key, but the PR introduces configurableprimary_keyper index. If an index is configured with a different primary key (e.g.,'id'), the aggregated document will still contain'objectID', causing a mismatch.Consider either:
- Passing the configured primary key to the Aggregator
- Having the caller remap the key after normalization
Would you like me to propose a solution, or should this be tracked as a follow-up issue?
src/DependencyInjection/MeilisearchExtension.php (1)
38-71: Consider extracting data provider registration to reduce complexity.The pipeline reports cyclomatic complexity of 11 (threshold: 10). The nested conditionals for ORM/Aggregator handling are correct but could be extracted to improve readability.
+ private function registerDataProviders(ContainerBuilder $container, array $config): array + { + $dataProviders = []; + foreach ($config['indices'] as $indice) { + $class = $indice['class']; + + if (null !== $indice['data_provider']) { + $dataProviders[$indice['name']] ??= []; + $dataProviders[$indice['name']][$class] = new Reference($indice['data_provider']); + continue; + } + + if ('orm' !== $indice['type']) { + continue; + } + + $dataProviders[$indice['name']] ??= []; + + if (is_subclass_of($class, Aggregator::class)) { + foreach ($class::getEntities() as $aggregatedClass) { + $definitionId = \sprintf('meilisearch.data_provider.%s_%s', $indice['name'], hash('xxh32', $aggregatedClass)); + $container->setDefinition($definitionId, new Definition(OrmEntityProvider::class, [new Reference('doctrine'), $aggregatedClass])); + $dataProviders[$indice['name']][$aggregatedClass] = new Reference($definitionId); + } + } else { + $definitionId = \sprintf('meilisearch.data_provider.%s_%s', $indice['name'], hash('xxh32', $class)); + $container->setDefinition($definitionId, new Definition(OrmEntityProvider::class, [new Reference('doctrine'), $class])); + $dataProviders[$indice['name']][$class] = new Reference($definitionId); + } + } + return $dataProviders; + }Then in
load():- $dataProviders = []; - foreach ($config['indices'] as $index => $indice) { - // ... all the provider logic - } + $dataProviders = $this->registerDataProviders($container, $config); + foreach ($config['indices'] as $index => $indice) { + $config['indices'][$index]['prefixed_name'] = $config['prefix'].$indice['name']; + $config['indices'][$index]['settings'] = $this->findReferences($config['indices'][$index]['settings']); + }src/DataProvider/DataProviderInterface.php (1)
20-25: Clarify the expected structure of$identifiersparameter.The
@param array<mixed> $identifiersis ambiguous. Looking at the implementations:
OrmEntityProvidertreats it as a flat array of ID values:findBy(['id' => $identifiers])ActorDataProvidertreats it as an associative array:$identifiers['id']This ambiguity leads to inconsistent implementations. Consider documenting the expected structure explicitly.
/** - * @param array<mixed> $identifiers + * @param array<int|string> $identifiers Flat array of identifier values to load * * @return iterable<T> */ public function loadByIdentifiers(array $identifiers): iterable;src/DataProvider/OrmEntityProvider.php (1)
22-23: Consider null-checkinggetManagerForClassresult.
getManagerForClass()can returnnullif no manager is found for the class. While the@param class-stringconstraint helps, invalid configurations could still trigger a null pointer on$manager->getRepository().$manager = $this->managerRegistry->getManagerForClass($this->className); +if (null === $manager) { + throw new \InvalidArgumentException(\sprintf('No manager found for class "%s".', $this->className)); +} $repository = $manager->getRepository($this->className);tests/BaseKernelTestCase.php (1)
47-52: Potential performance concern withwaitForAllTasks().This iterates over all tasks from the Meilisearch server and waits for each one. In a busy test environment or if there are many historical tasks, this could be slow. Consider limiting to only pending/enqueued tasks or tasks created during the current test.
protected function waitForAllTasks(): void { - foreach ($this->client->getTasks() as $task) { - $this->client->waitForTask($task['uid']); + foreach ($this->client->getTasks(['statuses' => ['enqueued', 'processing']]) as $task) { + $this->client->waitForTask($task['uid']); } }src/SearchableObject.php (1)
80-95: Missing@returnPHPDoc type forgetSearchableArray().The method declares
@throws ExceptionInterfacebut lacks the return type annotation. Consider adding@return array<string, mixed>for better static analysis support./** + * @return array<string, mixed> + * * @throws ExceptionInterface */ public function getSearchableArray(): arraysrc/Engine.php (1)
84-92: Consider using batch deletion for better performance.The
remove()method callsdeleteDocument()individually for each object. Meilisearch supports batch deletion viadeleteDocuments()which would be more efficient.$result = []; foreach ($data as $indexUid => $objects) { - $result[$indexUid] = []; - foreach ($objects as $object) { - $result[$indexUid][] = $this->client - ->index($indexUid) - ->deleteDocument($object); - } + $result[$indexUid] = $this->client + ->index($indexUid) + ->deleteDocuments($objects); }src/Command/MeilisearchImportCommand.php (1)
71-155: Pipeline flags high complexity inexecute()method.The pipeline reports CyclomaticComplexity of 13 (threshold: 10) and NPathComplexity of 592 (threshold: 200). Consider extracting the per-index processing into a separate method in a follow-up PR.
Based on learnings, the maintainer prefers keeping PRs focused, so this refactor can be deferred.
src/Services/MeilisearchManager.php (2)
131-135: Pipeline flag: Else expression.The pipeline prefers early returns over else clauses. Consider inverting the condition.
- if (!$entity instanceof $configClass && \in_array($configClass, $this->aggregators, true)) { - $objectToIndex = new $configClass($entity, $provider->getIdentifierValues($entity)); - } else { - $objectToIndex = $entity; - } + $objectToIndex = $entity; + if (!$entity instanceof $configClass && \in_array($configClass, $this->aggregators, true)) { + $objectToIndex = new $configClass($entity, $provider->getIdentifierValues($entity)); + }
21-21: Pipeline flags: High class complexity and coupling.The pipeline reports ExcessiveClassComplexity (69, threshold 50) and CouplingBetweenObjects (14, threshold 13). This is a central orchestration service, so some complexity is expected. Consider extracting helper classes in future refactoring if the class grows further.
Based on learnings, the maintainer prefers keeping PRs focused. Consider deferring extraction of index resolution, batch processing, and search result mapping into separate collaborators.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (52)
.github/workflows/tests.yml(1 hunks)composer.json(1 hunks)config/services.php(4 hunks)phpstan-baseline.php(1 hunks)phpstan.dist.neon(1 hunks)src/Command/IndexCommand.php(2 hunks)src/Command/MeilisearchClearCommand.php(1 hunks)src/Command/MeilisearchCreateCommand.php(3 hunks)src/Command/MeilisearchDeleteCommand.php(1 hunks)src/Command/MeilisearchImportCommand.php(7 hunks)src/Command/MeilisearchUpdateSettingsCommand.php(3 hunks)src/DataProvider/DataProviderInterface.php(1 hunks)src/DataProvider/OrmEntityProvider.php(1 hunks)src/DependencyInjection/Configuration.php(2 hunks)src/DependencyInjection/MeilisearchExtension.php(3 hunks)src/Engine.php(5 hunks)src/Event/SettingsUpdatedEvent.php(1 hunks)src/EventListener/ConsoleOutputSubscriber.php(1 hunks)src/EventListener/DoctrineEventSubscriber.php(1 hunks)src/Exception/DataProviderNotFoundException.php(1 hunks)src/Exception/NotSearchableException.php(1 hunks)src/Model/Aggregator.php(2 hunks)src/SearchManagerInterface.php(1 hunks)src/SearchService.php(1 hunks)src/Searchable.php(1 hunks)src/SearchableEntity.php(2 hunks)src/SearchableObject.php(1 hunks)src/Services/MeilisearchManager.php(1 hunks)src/Services/MeilisearchService.php(8 hunks)src/Services/SettingsUpdater.php(1 hunks)src/Services/UnixTimestampNormalizer.php(1 hunks)tests/BaseKernelTestCase.php(5 hunks)tests/Entity/Actor.php(1 hunks)tests/Entity/Link.php(2 hunks)tests/Entity/SelfNormalizable.php(2 hunks)tests/Entity/Tag.php(2 hunks)tests/Integration/AggregatorTest.php(1 hunks)tests/Integration/Command/MeilisearchClearCommandTest.php(1 hunks)tests/Integration/Command/MeilisearchCreateCommandTest.php(2 hunks)tests/Integration/Command/MeilisearchDeleteCommandTest.php(1 hunks)tests/Integration/Command/MeilisearchImportCommandTest.php(1 hunks)tests/Integration/EngineTest.php(3 hunks)tests/Integration/EventListener/DoctrineEventSubscriberTest.php(8 hunks)tests/Integration/Fixtures/ActorDataProvider.php(1 hunks)tests/Integration/SearchTest.php(4 hunks)tests/Kernel.php(1 hunks)tests/Unit/ConfigurationTest.php(8 hunks)tests/Unit/SerializationTest.php(2 hunks)tests/baseline-ignore(1 hunks)tests/config/doctrine_php7.yaml(0 hunks)tests/config/framework.yaml(1 hunks)tests/config/meilisearch.yaml(1 hunks)
💤 Files with no reviewable changes (1)
- tests/config/doctrine_php7.yaml
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: norkunas
Repo: meilisearch/meilisearch-symfony PR: 391
File: src/Command/MeilisearchImportCommand.php:117-120
Timestamp: 2025-08-05T04:46:01.119Z
Learning: In meilisearch-symfony project, the maintainer norkunas prefers to keep PRs focused and defer error handling improvements for settings updates to separate PRs, particularly when it involves decisions about partial import behavior when some indexes fail.
🧬 Code graph analysis (30)
tests/Entity/Tag.php (1)
src/SearchableObject.php (1)
SearchableObject(13-96)
src/Command/MeilisearchDeleteCommand.php (4)
src/SearchManagerInterface.php (1)
deleteByIndexName(58-58)src/SearchService.php (1)
deleteByIndexName(50-50)src/Services/MeilisearchManager.php (1)
deleteByIndexName(215-218)src/Services/MeilisearchService.php (1)
deleteByIndexName(162-169)
tests/Integration/EventListener/DoctrineEventSubscriberTest.php (4)
src/Engine.php (1)
search(122-125)src/SearchManagerInterface.php (1)
search(79-79)src/Services/MeilisearchManager.php (1)
search(238-281)src/Services/MeilisearchService.php (1)
search(182-227)
src/Model/Aggregator.php (1)
src/SearchableEntity.php (1)
__construct(42-56)
src/Exception/DataProviderNotFoundException.php (1)
src/Exception/NotSearchableException.php (1)
__construct(9-12)
src/SearchableEntity.php (4)
tests/Entity/Link.php (1)
normalize(74-85)tests/Entity/SelfNormalizable.php (1)
normalize(64-75)tests/Entity/Tag.php (1)
normalize(88-100)src/SearchableObject.php (1)
SearchableObject(13-96)
tests/Integration/Fixtures/ActorDataProvider.php (2)
tests/Entity/Actor.php (2)
Actor(7-27)getId(18-21)src/DataProvider/DataProviderInterface.php (4)
provide(18-18)loadByIdentifiers(25-25)getIdentifierValues(32-32)cleanup(34-34)
tests/Entity/SelfNormalizable.php (1)
src/SearchableObject.php (1)
SearchableObject(13-96)
tests/Entity/Link.php (1)
src/SearchableObject.php (1)
SearchableObject(13-96)
tests/Integration/SearchTest.php (4)
tests/BaseKernelTestCase.php (1)
waitForAllTasks(47-52)src/Engine.php (1)
search(122-125)src/SearchManagerInterface.php (2)
search(79-79)rawSearch(91-91)src/Services/MeilisearchManager.php (2)
search(238-281)rawSearch(291-299)
src/SearchManagerInterface.php (4)
src/Exception/NotSearchableException.php (1)
NotSearchableException(7-13)src/SearchService.php (5)
isSearchable(20-20)searchableAs(34-34)getConfiguration(27-27)index(36-36)search(59-64)src/Services/MeilisearchManager.php (5)
isSearchable(68-73)searchableAs(78-86)getConfiguration(88-91)index(116-162)search(238-281)src/Services/MeilisearchService.php (5)
isSearchable(66-71)searchableAs(83-91)getConfiguration(78-81)index(93-126)search(182-227)
src/Services/SettingsUpdater.php (2)
src/Services/MeilisearchManager.php (2)
MeilisearchManager(21-505)getConfiguration(88-91)src/SearchManagerInterface.php (1)
getConfiguration(25-25)
src/Command/MeilisearchCreateCommand.php (3)
src/Command/IndexCommand.php (1)
__construct(19-24)src/SearchManagerInterface.php (1)
isSearchable(18-18)src/Services/MeilisearchManager.php (1)
isSearchable(68-73)
src/Command/MeilisearchClearCommand.php (5)
src/Engine.php (1)
clear(104-107)src/SearchManagerInterface.php (1)
clear(51-51)src/SearchService.php (1)
clear(43-43)src/Services/MeilisearchManager.php (1)
clear(205-210)src/Services/MeilisearchService.php (1)
clear(151-160)
src/Command/MeilisearchImportCommand.php (6)
src/Engine.php (3)
__construct(12-14)index(25-61)count(132-135)src/EventListener/ConsoleOutputSubscriber.php (1)
__construct(13-15)src/EventListener/DoctrineEventSubscriber.php (1)
__construct(12-14)src/SearchManagerInterface.php (6)
getConfiguration(25-25)isSearchable(18-18)getDataProvider(30-30)index(37-37)count(101-101)deleteByIndexName(58-58)src/Services/MeilisearchManager.php (6)
getConfiguration(88-91)isSearchable(68-73)getDataProvider(96-111)index(116-162)count(307-312)deleteByIndexName(215-218)src/DataProvider/OrmEntityProvider.php (1)
provide(20-29)
tests/Unit/SerializationTest.php (2)
src/SearchableObject.php (2)
SearchableObject(13-96)getId(75-78)tests/Entity/Post.php (1)
getId(91-94)
src/SearchableObject.php (2)
src/SearchableEntity.php (1)
getSearchableArray(66-91)tests/Entity/SelfNormalizable.php (1)
normalize(64-75)
src/DataProvider/DataProviderInterface.php (2)
src/DataProvider/OrmEntityProvider.php (4)
provide(20-29)loadByIdentifiers(31-38)getIdentifierValues(40-45)cleanup(47-50)tests/Integration/Fixtures/ActorDataProvider.php (4)
provide(15-44)loadByIdentifiers(46-57)getIdentifierValues(59-64)cleanup(66-69)
src/Services/UnixTimestampNormalizer.php (4)
src/Model/Aggregator.php (1)
normalize(71-75)tests/Entity/Link.php (1)
normalize(74-85)tests/Entity/SelfNormalizable.php (1)
normalize(64-75)tests/Entity/Tag.php (1)
normalize(88-100)
src/Command/MeilisearchUpdateSettingsCommand.php (3)
src/Command/IndexCommand.php (1)
__construct(19-24)src/SearchManagerInterface.php (1)
isSearchable(18-18)src/SearchService.php (1)
isSearchable(20-20)
tests/BaseKernelTestCase.php (2)
src/Services/MeilisearchManager.php (3)
MeilisearchManager(21-505)getConfiguration(88-91)deleteByIndexName(215-218)src/SearchManagerInterface.php (2)
getConfiguration(25-25)deleteByIndexName(58-58)
src/Command/IndexCommand.php (4)
src/Command/MeilisearchCreateCommand.php (1)
__construct(23-30)src/SearchManagerInterface.php (1)
getConfiguration(25-25)src/SearchService.php (1)
getConfiguration(27-27)src/Services/MeilisearchManager.php (1)
getConfiguration(88-91)
tests/Integration/EngineTest.php (3)
src/SearchableObject.php (2)
SearchableObject(13-96)getId(75-78)tests/Entity/Image.php (1)
getId(39-42)tests/Entity/Post.php (1)
getId(91-94)
src/DataProvider/OrmEntityProvider.php (2)
src/DataProvider/DataProviderInterface.php (4)
provide(18-18)loadByIdentifiers(25-25)getIdentifierValues(32-32)cleanup(34-34)tests/Integration/Fixtures/ActorDataProvider.php (4)
provide(15-44)loadByIdentifiers(46-57)getIdentifierValues(59-64)cleanup(66-69)
src/DependencyInjection/Configuration.php (1)
src/SearchableObject.php (1)
SearchableObject(13-96)
tests/Integration/AggregatorTest.php (2)
src/Model/Aggregator.php (1)
getEntityClassFromObjectID(60-69)src/Exception/InvalidEntityForAggregator.php (1)
InvalidEntityForAggregator(7-9)
src/Services/MeilisearchManager.php (11)
src/Collection.php (1)
Collection(13-380)src/Engine.php (7)
Engine(10-145)index(25-61)remove(69-95)clear(104-107)delete(112-115)search(122-125)count(132-135)src/Exception/DataProviderNotFoundException.php (1)
DataProviderNotFoundException(7-13)src/Exception/NotSearchableException.php (1)
NotSearchableException(7-13)src/Exception/SearchHitsNotFoundException.php (1)
SearchHitsNotFoundException(7-9)src/DataProvider/OrmEntityProvider.php (2)
getIdentifierValues(40-45)loadByIdentifiers(31-38)src/Services/MeilisearchService.php (13)
setAggregatorsAndEntitiesAggregators(303-322)isSearchable(66-71)searchableAs(83-91)getConfiguration(78-81)index(93-126)remove(128-149)clear(151-160)deleteByIndexName(162-169)delete(171-180)search(182-227)rawSearch(229-241)count(243-252)resolveClass(420-440)src/SearchManagerInterface.php (12)
isSearchable(18-18)searchableAs(23-23)getConfiguration(25-25)index(37-37)getDataProvider(30-30)remove(44-44)clear(51-51)deleteByIndexName(58-58)delete(67-67)search(79-79)rawSearch(91-91)count(101-101)src/DataProvider/DataProviderInterface.php (2)
getIdentifierValues(32-32)loadByIdentifiers(25-25)tests/Integration/Fixtures/ActorDataProvider.php (2)
getIdentifierValues(59-64)loadByIdentifiers(46-57)tests/Entity/Actor.php (1)
getId(18-21)
src/Engine.php (2)
src/SearchManagerInterface.php (3)
index(37-37)remove(44-44)search(79-79)src/SearchableObject.php (5)
SearchableObject(13-96)getSearchableArray(83-95)getIndexUid(62-65)getPrimaryKey(70-73)getId(75-78)
config/services.php (3)
src/Services/MeilisearchManager.php (1)
MeilisearchManager(21-505)src/EventListener/DoctrineEventSubscriber.php (1)
DoctrineEventSubscriber(10-30)src/Services/SettingsUpdater.php (1)
SettingsUpdater(16-77)
src/Services/MeilisearchService.php (6)
src/Command/IndexCommand.php (1)
__construct(19-24)src/Engine.php (8)
__construct(12-14)Engine(10-145)index(25-61)remove(69-95)clear(104-107)delete(112-115)search(122-125)count(132-135)src/EventListener/DoctrineEventSubscriber.php (1)
__construct(12-14)src/Services/SettingsUpdater.php (1)
__construct(22-28)src/Services/MeilisearchManager.php (9)
MeilisearchManager(21-505)index(116-162)remove(167-200)clear(205-210)deleteByIndexName(215-218)delete(223-228)search(238-281)rawSearch(291-299)count(307-312)src/SearchManagerInterface.php (8)
index(37-37)remove(44-44)clear(51-51)deleteByIndexName(58-58)delete(67-67)search(79-79)rawSearch(91-91)count(101-101)
🪛 GitHub Actions: Tests
src/EventListener/ConsoleOutputSubscriber.php
[error] 13-13: ShortVariable: Avoid variables with short names like $io. Configured minimum length is 3.
src/DependencyInjection/MeilisearchExtension.php
[error] 22-22: IfStatementAssignment: Avoid assigning values to variables in if clauses and the like (line '73', column '20').
[error] 22-22: CyclomaticComplexity: The method load() has a Cyclomatic Complexity of 11. The configured cyclomatic complexity threshold is 10.
[error] 36-36: StaticAccess: Avoid using static access to class '\Meilisearch\Bundle\MeilisearchBundle' in method 'load'.
[error] 63-63: ElseExpression: The method load uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them.
[error] 80-80: ElseExpression: The method load uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them.
[error] 88-88: StaticAccess: Avoid using static access to class '\MeilisearchBundle\MeilisearchBundle' in method 'load'.
src/Services/SettingsUpdater.php
[error] 34-34: CyclomaticComplexity: The method update() has a Cyclomatic Complexity of 13. The configured cyclomatic complexity threshold is 10.
src/Command/MeilisearchImportCommand.php
[error] 23-23: CouplingBetweenObjects: The class MeilisearchImportCommand has a coupling between objects value of 13. Consider to reduce the number of dependencies under 13.
[error] 71-71: CyclomaticComplexity: The method execute() has a Cyclomatic Complexity of 13. The configured cyclomatic complexity threshold is 10.
[error] 71-71: NPathComplexity: The method execute() has an NPath complexity of 592. The configured NPath complexity threshold is 200.
src/SearchableObject.php
[error] 30-30: ShortVariable: Avoid variables with short names like $id. Configured minimum length is 3.
[error] 47-47: ShortVariable: Avoid variables with short names like $id. Configured minimum length is 3.
src/Services/UnixTimestampNormalizer.php
[error] 14-14: UnusedFormalParameter: Avoid unused parameters such as '$format'.
[error] 14-14: UnusedFormalParameter: Avoid unused parameters such as '$context'.
[error] 19-19: UnusedFormalParameter: Avoid unused parameters such as '$format'.
[error] 24-24: UnusedFormalParameter: Avoid unused parameters such as '$format'.
src/Services/MeilisearchManager.php
[error] 21-21: ExcessiveClassComplexity: The class MeilisearchManager has an overall complexity of 69 which is very high. The configured complexity threshold is 50.
[error] 21-21: CouplingBetweenObjects: The class MeilisearchManager has a coupling between objects value of 14. Consider to reduce the number of dependencies under 13.
[error] 133-133: ElseExpression: The method index uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them.
[error] 438-438: ShortVariable: Avoid variables with short names like $id. Configured minimum length is 3.
[error] 496-496: StaticAccess: Avoid using static access to class '\Doctrine\ORM\Proxy\DefaultProxyClassNameResolver' in method 'resolveClass'.
[error] 500-500: StaticAccess: Avoid using static access to class '\Doctrine\Common\Util\ClassUtils' in method 'resolveClass'.
src/Services/MeilisearchService.php
[error] 27-27: TooManyPublicMethods: The class MeilisearchService has 11 public methods. Consider refactoring MeilisearchService to keep number of public methods under 10.
[error] 27-27: ExcessiveClassComplexity: The class MeilisearchService has an overall complexity of 64 which is very high. The configured complexity threshold is 50.
[error] 27-27: CouplingBetweenObjects: The class MeilisearchService has a coupling between objects value of 17. Consider to reduce the number of dependencies under 13.
[error] 48-48: LongVariable: Avoid excessively long variable names like $classToSerializerGroup. Keep variable name length under 20.
[error] 57-57: StaticAccess: Avoid using static access to class '\Symfony\Component\PropertyAccess\PropertyAccess' in method '__construct'.
[error] 384-384: LongVariable: Avoid excessively long variable names like $searchableEntitiesChunk. Keep variable name length under 20.
[error] 432-432: StaticAccess: Avoid using static access to class '\Doctrine\ORM\Proxy\DefaultProxyClassNameResolver' in method 'resolveClass'.
[error] 436-436: StaticAccess: Avoid using static access to class '\Doctrine\Common\Util\ClassUtils' in method 'resolveClass'.
🔇 Additional comments (56)
tests/config/framework.yaml (1)
5-7: Good addition to test environment configuration.The new configuration keys align well with the Symfony 6.4 upgrade:
handle_all_throwables: trueensures all throwable exceptions are caught during tests, andphp_errors.log: trueimproves error visibility by logging PHP warnings and notices. This supports better test reliability and observability, especially important when testing the complex data provider and service wiring changes in this PR.src/Event/SettingsUpdatedEvent.php (1)
16-20: Constructor promotion +readonlyare idiomatic and preserve behaviorUsing constructor property promotion with
private readonlycleanly expresses this event as an immutable payload and keeps the existing API via getters intact. No further changes needed here.src/Services/UnixTimestampNormalizer.php (2)
19-22: LGTM!The signature correctly uses
mixed $datato match the interface contract, and the instanceof check properly guards normalization.
14-14: Pipeline warnings: unused interface parameters.The static analysis flags
$formatand$contextas unused. These are required by theNormalizerInterfacecontract and cannot be removed. If your project enforces clean pipelines, consider adding suppression comments:/** * @param mixed $data Expected to be a \DateTimeInterface instance (guarded by supportsNormalization) + * @phpmd-suppress UnusedFormalParameter */ public function normalize(mixed $data, ?string $format = null, array $context = []): intApply similar suppressions to lines 19 and 24, or configure your linter to ignore unused parameters in interface implementations globally.
Also applies to: 19-19, 24-24
tests/Integration/AggregatorTest.php (1)
31-37: Unable to complete verification: Repository access unavailable in sandbox environment.The review comment raises a valid concern about the continued use of
'objectId'in unchanged test code (lines 37, 53, 61) against PR objective #66 to remove Algolia-specificobjectIDusage. However, I cannot access the repository to verify:
- Whether the
ContentAggregatorclass retainsobjectID-based semantics for backward compatibility- The broader migration strategy and scope of PR #66
- Whether these test references represent incomplete migration or intentional API retention
The review comment's analysis of the code changes themselves is sound: the method rename and exception handling pattern are correct and follow best practices. The verification request is appropriate but requires repository context to resolve.
src/Services/SettingsUpdater.php (1)
22-28: Constructor migration to MeilisearchManager looks good.The dependency injection now correctly uses
MeilisearchManagerwith constructor property promotion for$searchClientand$eventDispatcher. Configuration retrieval via$searchManager->getConfiguration()aligns with the new architecture.Regarding the pipeline failure on
update()(cyclomatic complexity 13): this is pre-existing complexity in unchanged code. Consider addressing it in a follow-up PR to keep this one focused.src/Exception/DataProviderNotFoundException.php (1)
7-12: Exception message and shape look goodConsistent with existing exception patterns and gives clear context on missing provider (index + class). No changes needed.
src/Searchable.php (1)
7-20: Deprecation annotations are clear and targetedThe class- and constant-level deprecation notices correctly steer users to
SearchableObjectand its constants without changing behavior.src/Services/MeilisearchService.php (2)
93-99: Manager delegation preserves BC and aligns with the new APIThe pattern of:
- triggering deprecation on
ObjectManager-based methods, and- short‑circuiting to
$this->managerwhen present,keeps existing signatures working while moving callers toward
MeilisearchManager/SearchManagerInterface. The fallbacks to legacy Engine + Doctrine flows when no manager is injected look correct and localized. No functional issues spotted here.Also applies to: 128-135, 151-160, 162-169, 171-180, 182-193, 229-241, 243-252
303-322: Aggregator casting and batch construction changes are safeCasting
$index['class']to string for aggregators and continuing to buildSearchableEntitychunks per batch is consistent with existing behavior and types; no issues with the updated array shapes or batching logic.Also applies to: 353-370, 377-401
config/services.php (2)
28-36: Manager wiring and aliasing match the new architecturePassing
meilisearch.managerintoMeilisearchService, switching the DoctrineEventSubscriber and all commands to depend on the manager, and aliasingSearchManagerInterface::classtomeilisearch.managerall look consistent with the new manager‑centric API and should give a smooth migration path for users still onSearchService.Also applies to: 44-47, 80-85, 89-104, 106-112, 115-120, 78-79
70-77: Based on my investigation, I cannot fully access the repository to verify the exact constructor signature ofMeilisearchManager. However, I can confirm the underlying Symfony pattern:Verified facts:
- Symfony's
tagged_iterator()injects aRewindableGenerator(implementsTraversable), not a PHP array- If
MeilisearchManager's constructor declaresarray $dataProviders, there will be a type mismatch- This is a real Symfony DI pattern issue
What I cannot verify:
- The actual type hint in
MeilisearchManager's constructor parameter (could already beiterable, could have no type hint, or could bearray)Since the review comment identifies a genuine possible type mismatch based on the DI config shown, and the Symfony behavior is confirmed, I can proceed with the rewritten review comment:
Verify
MeilisearchManagerconstructor parameter type for$dataProvidersThe DI config injects
tagged_iterator('meilisearch.data_provider', 'key')as the last argument toMeilisearchManager. Symfony'stagged_iteratorinjects aRewindableGenerator(aTraversable), not a PHP array. If the constructor parameter is type-hinted asarray $dataProviders, this will cause aTypeErrorat runtime.Confirm that the constructor accepts
iterableorTraversablefor this parameter. If it requires an actual array, convert the iterator in the config using a factory or helper.composer.json (1)
21-31: Dependency matrix aligns with the new minimum PHP/Symfony versionsRaising PHP to ^8.1, tightening Symfony to ^6.4/7.x, and moving doctrine-bundle to dev‑only match the refactor away from mandatory Doctrine and toward modern Symfony. The tooling bumps also look coherent with those versions; just ensure your supported projects are on at least these baselines before tagging a release.
Also applies to: 33-54
tests/Integration/Command/MeilisearchDeleteCommandTest.php (1)
30-41: Updated delete output expectation looks correctIncluding
Deleted sf_phpunit__actormatches the new Actor index created in tests and keeps the full deletion output consistent with the configured indices.tests/baseline-ignore (1)
1-19: Baseline update correctly filters new Doctrine proxy deprecationAdding the
DefaultProxyClassNameResolverdeprecation pattern keeps the test baseline in sync with current Doctrine deprecations and your usage inresolveClass().tests/Integration/Command/MeilisearchClearCommandTest.php (1)
28-42: Clear output update matches new Actor indexThe additional
Cleared sf_phpunit__actor index of ...Actorline aligns with the new index and maintains the expected clear‑all behavior.tests/Integration/Command/MeilisearchCreateCommandTest.php (1)
44-86: Actor index expectations correctly wired into create command outputThe added
sf_phpunit__actorlines in both--no-update-settingsbranches match the newactorindex configuration (name, prefix, and class) and preserve the existing ordering of the subsequent aggregated indexes. Looks good.tests/Entity/SelfNormalizable.php (1)
9-75: Normalization format constant correctly migrated toSearchableObjectUsing
SearchableObject::NORMALIZATION_FORMATinSelfNormalizable::normalize()is consistent with the newSearchableObjectflow and preserves the intended conditional normalization behavior.src/Command/MeilisearchDeleteCommand.php (1)
31-40: Delete command correctly migrated toSearchManagerInterfaceSwitching to
$this->searchManager->deleteByIndexName($indexName)keeps behavior and error handling intact while aligning with the new manager-based API. Ignoring the returned array is consistent with the previous implementation.tests/Entity/Tag.php (1)
9-12: Tag normalization updated to useSearchableObjectformat constantThe normalization gate now correctly checks
SearchableObject::NORMALIZATION_FORMAT, which is whatSearchableObjectpasses for Normalizable objects. The rest of the payload (id, name, count, publishedAt) remains unchanged.Also applies to: 88-100
tests/config/meilisearch.yaml (1)
57-60: Actor index configuration correctly exercises custom data provider pathThe
actorindex definition (name, class,type: 'custom', anddata_providerpointing at the fixtures provider class) is consistent with the new data-provider architecture and the services resource block. This should nicely cover the custom provider branch in integration tests.tests/Integration/Command/MeilisearchImportCommandTest.php (1)
181-189: Updated batch ordering for tags import matches new import flowThe expected output in
testImportDifferentEntitiesIntoSameIndex()now reflects Tag entities being indexed into the aggregated index before thetagsindex, then Link entities intotags. This aligns the test with the current import order without changing tested behavior.tests/Unit/ConfigurationTest.php (1)
132-155: Config tests now assert default provider/primary-key metadata per indexExtending the expected config to include
type => 'orm',data_provider => null, andprimary_key => 'objectID'for each index entry accurately reflects the new configuration tree defaults and keeps the tests honest about the normalized shape of index configuration.Also applies to: 188-217, 239-256, 278-298, 315-338
phpstan.dist.neon (1)
1-3: Verify that phpstan-baseline.php exists and regenerate it when baseline findings changeThe includes configuration for
phpstan-baseline.phpis the correct approach for PHPStan. However, verification of the baseline file's existence and currency could not be completed due to repository access limitations. Please ensure the baseline file is present at the repository root and is regenerated whenever static analysis findings change to keep it synchronized with the codebase.src/SearchableEntity.php (1)
15-17: Deprecation and normalization alignment withSearchableObjectlook correctThe deprecation docblock is clear, and switching the normalization format to
SearchableObject::NORMALIZATION_FORMATkeeps behavior aligned with the newSearchableObjectwhile retaining the same underlying format value.Also applies to: 82-88
tests/Entity/Link.php (1)
9-9: Test entity normalization correctly migrated toSearchableObjectUsing
SearchableObject::NORMALIZATION_FORMATinnormalize()with the new import keeps this fixture in sync with the new normalization contract.Also applies to: 74-82
tests/Integration/EventListener/DoctrineEventSubscriberTest.php (1)
23-24: Search calls correctly updated toSearchManagerInterface::searchAll test usages now match the new
search(string $className, string $query = '', array $searchParams = [])signature, dropping theEntityManagerargument while preserving the original test semantics.Also applies to: 38-39, 59-60, 81-82, 97-98, 107-108, 121-122, 131-132
src/Command/MeilisearchClearCommand.php (1)
30-31: Clear operation correctly routed throughSearchManagerInterfaceSwitching to
$this->searchManager->clear($className)aligns this command with the new manager API while preserving the existing control flow and status handling.src/Command/IndexCommand.php (1)
8-9: Base command successfully migrated toSearchManagerInterfaceInjecting
SearchManagerInterfaceand readingprefix/indicesfrom$this->searchManager->getConfiguration()preserves the previous behavior while aligning all index commands with the new manager abstraction.Also applies to: 19-22, 26-29
tests/Kernel.php (1)
36-42: Updated test kernel wiring handles newer Doctrine/Symfony combinationsThe revised Doctrine config selection and the conditional
framework.property_infoprepend forKernel::VERSION_ID >= 70300look appropriate for the supported Symfony/Doctrine matrix and keep the test kernel aligned with the new minimum versions.Also applies to: 64-69
tests/Integration/SearchTest.php (4)
71-76: LGTM! Proper async task synchronization added.The
waitForAllTasks()call ensures the asynchronous import completes before searching. The migration tosearchManager->search()correctly uses the new API signature.
81-81: Consistent use of new SearchManager API.The
rawSearchcall correctly follows the new interface signature.
114-116: LGTM! Proper test flow with task synchronization.
137-139: LGTM! Consistent pattern across all test methods.src/Model/Aggregator.php (1)
24-26: LGTM! Strict typing aligns with PHP 8.1+ requirements.The explicit
objecttype for both property and constructor parameter improves type safety.src/DependencyInjection/MeilisearchExtension.php (2)
34-37: LGTM! Configuration parameters properly exposed.The new parameters for URL, API key, and version are correctly set early in the load process.
94-97: LGTM! Data providers correctly wired to manager.The
dataProviderscollection is properly passed as the 5th argument to the manager service.tests/Integration/EngineTest.php (2)
35-42: LGTM! Correctly migrated to SearchableObject API.The constructor call properly matches the new signature:
(indexUid, primaryKey, object, id, normalizer, normalizationContext). The'objectID'string correctly identifies the primary key field name.
67-69: LGTM! Consistent SearchableObject usage for multi-entity test.The serializer is correctly shared across both instances, and the constructor parameters align with the new API.
src/Command/MeilisearchCreateCommand.php (2)
23-30: LGTM! Clean constructor with property promotion.The migration to
SearchManagerInterfaceis correct, and constructor property promotion (private readonly) is idiomatic PHP 8.1+.
66-68: LGTM! Correctly uses the new manager interface.The
isSearchable()call properly delegates to the newSearchManagerInterface.src/EventListener/DoctrineEventSubscriber.php (1)
12-28: LGTM!Clean migration to
SearchManagerInterfacewith simplified API. The removal ofObjectManagerdependency fromindex()andremove()calls aligns with the PR objective of decoupling from Doctrine.src/Command/MeilisearchUpdateSettingsCommand.php (1)
22-28: LGTM!Consistent migration to
SearchManagerInterfacefollowing the same pattern as other commands. Constructor property promotion is cleanly applied.tests/Unit/SerializationTest.php (1)
23-30: LGTM!Test correctly updated to use the new
SearchableObjectconstructor signature with explicitprimaryKeyandidparameters instead of class metadata.src/SearchManagerInterface.php (2)
32-44: LGTM — clean API design for indexing and removal.The simplified signatures accepting
object|arraywithout requiringObjectManageralign well with the PR's goal to support non-Doctrine data sources.
12-13: Based on my verification attempt, I encountered repository access limitations that prevent me from fully validating the review comment. However, I was able to gather important context from the web:Web search findings:
- Meilisearch uses a configurable primary key field (can be "id", "sku", "objectID", or any custom attribute) rather than a hard-coded "objectID"
- Search responses return hits containing the full document with the configured primary key field
- Client libraries may alias common field names like "objectID" for convenience, but this is implementation-specific
What I cannot verify:
- Current usage of
RESULT_KEY_OBJECTIDin the codebase- Whether this constant accesses a document's primary key or serves another purpose
- If renaming would break existing functionality
- The actual scope and requirements of PR objective #66
Given the web search confirms that Meilisearch doesn't mandate "objectID" terminology, the review comment's concern has merit. However, without codebase visibility, I cannot definitively assess whether the suggested rename is safe or necessary.
The constant
RESULT_KEY_OBJECTIDmay reflect Algolia legacy terminology rather than Meilisearch semantics. Meilisearch uses a configurable primary key field (not a hard-coded "objectID"), though client libraries may alias common field names for convenience. Verify whether this constant accesses a document's primary key or serves another purpose, and whether renaming aligns with PR objective #66 requirements.tests/BaseKernelTestCase.php (2)
10-10: LGTM! Service migration to MeilisearchManager.The property, import, and service container access are correctly updated to use the new
MeilisearchManagerservice alias.Also applies to: 19-19, 27-27
54-62: LGTM! Cleanup methods correctly adapted.The
cleanUp()andcleanupIndex()methods properly usesearchManager->getConfiguration()andsearchManager->deleteByIndexName()matching the new interface signatures.Also applies to: 64-72
src/Engine.php (2)
12-14: LGTM! Constructor promotion is clean.Good use of PHP 8.1+ constructor property promotion for the readonly client dependency.
137-144: LGTM!normalizeId()correctly handlesStringable.The type signature and implementation properly handle
Stringable,string, andinttypes, casting objects to string as needed.src/Command/MeilisearchImportCommand.php (2)
27-34: LGTM! Constructor properly migrated toSearchManagerInterface.The constructor uses property promotion for readonly dependencies and correctly delegates to the parent
IndexCommandwith the search manager.
160-181: LGTM!formatIndexingResponse()handles task waiting correctly.The method properly initializes missing keys with null coalescing, waits for tasks, checks for failures, and aggregates indexed document counts.
src/Services/MeilisearchManager.php (4)
51-63: LGTM! Constructor correctly initializes the manager.The constructor properly stores configuration, data providers, and initializes derived data structures for searchables and aggregators.
96-111: LGTM!getDataProvider()with fallback to parent class matching.Good design: first checks exact match, then falls back to
is_a()for subclass support, and throws a clear exception when not found.
494-501: Pipeline flags: Static access to Doctrine classes.The pipeline flags static calls to
DefaultProxyClassNameResolver::getClass()andClassUtils::getClass(). These are necessary for Doctrine proxy resolution, so this appears to be a valid exception to the rule.
257-261: I apologize for the repeated clone failures. Let me analyze this based on the information available in the review comment and general knowledge of the Meilisearch-Algolia migration pattern.Based on my investigation:
The concern is valid but cannot be fully verified without access to:
- The actual value of
RESULT_KEY_OBJECTIDconstant- How the primary key configuration is accessed in this scope
- Other recent changes in this PR to the constant definitions
What I can determine:
- Meilisearch uses index-level
primaryKeysettings (unlike Algolia's per-recordobjectID)- The code snippet uses
array_column($hits, self::RESULT_KEY_OBJECTID)which extracts a field value from search results- Meilisearch search results DO include the primaryKey field in each document
- The constant name "RESULT_KEY_OBJECTID" is Algolia-specific terminology
Key issues:
- If
RESULT_KEY_OBJECTIDis still hardcoded to'objectid'string, it conflicts with PR objectives- Even if the value is correct (e.g.,
'id'), the constant NAME should be renamed to reflect Meilisearch semantics- The
$indexvariable (available on line 257) likely has access to the configuredprimary_key, which should be usedGiven that I cannot access the repository directly to verify the constant's current value, I must provide a verification-pending assessment:
Cannot access repository files to determine if
RESULT_KEY_OBJECTIDis already correctly mapped to Meilisearch semantics or if it remains hardcoded to Algolia's'objectid'. Recommend: (1) Check the constant definition's current value, (2) Verify if$index->getPrimaryKey()or similar method is available to use the configured primary key dynamically, (3) Consider renaming constant fromRESULT_KEY_OBJECTIDto reflect Meilisearch semantics even if current value is correct.
c582c33 to
10690e1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (2)
src/Services/UnixTimestampNormalizer.php (1)
11-17: Docblock still mismatched withmixed $dataparameterThe docblock continues to declare
@param \DateTimeInterface $datawhile the signature ismixed $dataand the actual guard lives insupportsNormalization(). To keep things consistent and self-documenting, I’d adjust the docblock to describe the real contract rather than a stricter type:- /** - * @param \DateTimeInterface $data - */ + /** + * @param mixed $data Expected to be a \DateTimeInterface instance (guarded by supportsNormalization) + */This avoids changing behavior while documenting the Symfony-serializer assumption that
normalize()is only called after a positivesupportsNormalization()check.tests/Integration/Fixtures/ActorDataProvider.php (1)
46-57:loadByIdentifiersimplementation inconsistent withOrmEntityProvider.This implementation expects
$identifiersto be an associative array with an'id'key, whileOrmEntityProvider::loadByIdentifierstreats$identifiersas a flat array of ID values. This inconsistency could cause bugs when switching between providers.
🧹 Nitpick comments (7)
src/Model/Aggregator.php (1)
24-35: Stronger typing for$entityis a nice incremental cleanup.Typing the
$entityproperty and constructor asobjecttightens the contract without changing behavior. Leaving theobjectIDhandling as-is with a TODO about configurableprimary_keyis reasonable to keep this PR focused; just ensure there’s a follow-up issue tracking that TODO.Based on learnings, deferring the primary_key vs
objectIDcleanup to a dedicated PR matches the preferred workflow.Also applies to: 71-75
src/DataProvider/OrmEntityProvider.php (1)
53-56: Verifyclear()behavior is documented and expected.Calling
clear()on the entity manager detaches all managed entities, which resets the identity map. While appropriate for batch import operations to prevent memory exhaustion, this side effect should be documented in the interface or provider usage guidelines.src/Services/MeilisearchService.php (1)
151-159: Consider adding deprecation notice for consistency.The
clear()method delegates to manager but doesn't emit atrigger_deprecationnotice likeindex(),remove(), andsearch()do. While the signature hasn't changed, adding a notice would be consistent with the deprecation strategy.public function clear(string $className): array { + trigger_deprecation('meilisearch/meilisearch-symfony', '0.16', 'MeilisearchService::clear() is deprecated. Use MeilisearchManager::clear() instead.'); + if (null !== $this->manager) { return $this->manager->clear($className); }src/SearchManagerInterface.php (1)
12-13: Consider removing or renamingRESULT_KEY_OBJECTIDconstant.Per PR objective #66, the goal is to remove Algolia-specific "objectID" terminology in favor of Meilisearch primary-key semantics. This constant perpetuates the legacy naming. Consider renaming it to align with Meilisearch conventions (e.g.,
RESULT_KEY_PRIMARY_KEYor similar), or document why it must remain for backward compatibility.composer.json (1)
28-28: Removesymfony/polyfill-php80— redundant with PHP 8.1+ requirement.The polyfill backports PHP 8.0 features (attributes,
str_contains, etc.) to PHP 7.x. With the minimum PHP version now at 8.1, this dependency is no longer needed.- "symfony/polyfill-php80": "^1.33",src/Engine.php (1)
77-88: Batch deletions to reduce API calls.The
remove()method callsdeleteDocument()individually for each object, resulting in N API calls per index. Meilisearch supports batch deletion viadeleteDocuments(array $documentIds), which would reduce this to a single call per index, matching the batching pattern used inindex().$result = []; foreach ($data as $indexUid => $objects) { - $result[$indexUid] = []; - foreach ($objects as $object) { - $result[$indexUid][] = $this->client - ->index($indexUid) - ->deleteDocument($object); - } + $result[$indexUid] = $this->client + ->index($indexUid) + ->deleteDocuments($objects); }src/Command/MeilisearchCreateCommand.php (1)
87-108: Consider simplifyingentitiesToIndex()collection manipulation.The current implementation modifies the collection during iteration (
forget()) and then merges with a new Collection, which can be confusing. A filter-then-flatMap approach would be clearer:private function entitiesToIndex(Collection $indexes): array { - foreach ($indexes as $key => $index) { - $entityClassName = $index['class']; - - if (!is_subclass_of($entityClassName, Aggregator::class)) { - continue; - } - - $indexes->forget($key); - - $indexes = new Collection(array_merge( - $indexes->all(), - array_map( - static fn ($entity) => ['name' => $index['name'], 'prefixed_name' => $index['prefixed_name'], 'class' => $entity], - $entityClassName::getEntities() - ) - )); - } - - return array_unique($indexes->all(), SORT_REGULAR); + $result = []; + foreach ($indexes as $index) { + $entityClassName = $index['class']; + + if (is_subclass_of($entityClassName, Aggregator::class)) { + foreach ($entityClassName::getEntities() as $entity) { + $result[] = ['name' => $index['name'], 'prefixed_name' => $index['prefixed_name'], 'class' => $entity]; + } + } else { + $result[] = $index; + } + } + + return array_unique($result, SORT_REGULAR); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (54)
.github/workflows/pre-release-tests.yml(2 hunks).github/workflows/tests.yml(1 hunks)composer.json(1 hunks)config/services.php(4 hunks)phpstan-baseline.php(1 hunks)phpstan.dist.neon(1 hunks)src/Command/IndexCommand.php(2 hunks)src/Command/MeilisearchClearCommand.php(1 hunks)src/Command/MeilisearchCreateCommand.php(3 hunks)src/Command/MeilisearchDeleteCommand.php(1 hunks)src/Command/MeilisearchImportCommand.php(7 hunks)src/Command/MeilisearchUpdateSettingsCommand.php(3 hunks)src/DataProvider/DataProviderInterface.php(1 hunks)src/DataProvider/OrmEntityProvider.php(1 hunks)src/DependencyInjection/Configuration.php(2 hunks)src/DependencyInjection/MeilisearchExtension.php(3 hunks)src/Engine.php(5 hunks)src/Event/SettingsUpdatedEvent.php(1 hunks)src/EventListener/ConsoleOutputSubscriber.php(1 hunks)src/EventListener/DoctrineEventSubscriber.php(1 hunks)src/Exception/DataProviderNotFoundException.php(1 hunks)src/Exception/InvalidIndiceException.php(1 hunks)src/Exception/NotSearchableException.php(1 hunks)src/Model/Aggregator.php(2 hunks)src/SearchManagerInterface.php(1 hunks)src/SearchService.php(1 hunks)src/Searchable.php(1 hunks)src/SearchableEntity.php(2 hunks)src/SearchableObject.php(1 hunks)src/Services/MeilisearchManager.php(1 hunks)src/Services/MeilisearchService.php(8 hunks)src/Services/SettingsUpdater.php(1 hunks)src/Services/UnixTimestampNormalizer.php(1 hunks)tests/BaseKernelTestCase.php(5 hunks)tests/Entity/Actor.php(1 hunks)tests/Entity/Link.php(2 hunks)tests/Entity/SelfNormalizable.php(2 hunks)tests/Entity/Tag.php(2 hunks)tests/Integration/AggregatorTest.php(1 hunks)tests/Integration/Command/MeilisearchClearCommandTest.php(1 hunks)tests/Integration/Command/MeilisearchCreateCommandTest.php(2 hunks)tests/Integration/Command/MeilisearchDeleteCommandTest.php(1 hunks)tests/Integration/Command/MeilisearchImportCommandTest.php(1 hunks)tests/Integration/EngineTest.php(3 hunks)tests/Integration/EventListener/DoctrineEventSubscriberTest.php(8 hunks)tests/Integration/Fixtures/ActorDataProvider.php(1 hunks)tests/Integration/SearchTest.php(4 hunks)tests/Kernel.php(1 hunks)tests/Unit/ConfigurationTest.php(8 hunks)tests/Unit/SerializationTest.php(2 hunks)tests/baseline-ignore(1 hunks)tests/config/doctrine_php7.yaml(0 hunks)tests/config/framework.yaml(1 hunks)tests/config/meilisearch.yaml(1 hunks)
💤 Files with no reviewable changes (1)
- tests/config/doctrine_php7.yaml
🚧 Files skipped from review as they are similar to previous changes (18)
- tests/Entity/SelfNormalizable.php
- src/Command/MeilisearchClearCommand.php
- phpstan.dist.neon
- tests/config/meilisearch.yaml
- src/Exception/DataProviderNotFoundException.php
- src/Command/MeilisearchDeleteCommand.php
- tests/Integration/SearchTest.php
- tests/Integration/Command/MeilisearchDeleteCommandTest.php
- src/DependencyInjection/Configuration.php
- tests/baseline-ignore
- src/Exception/NotSearchableException.php
- src/Command/MeilisearchUpdateSettingsCommand.php
- tests/Integration/EngineTest.php
- src/Searchable.php
- src/DataProvider/DataProviderInterface.php
- src/Command/IndexCommand.php
- src/SearchService.php
- tests/config/framework.yaml
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: norkunas
Repo: meilisearch/meilisearch-symfony PR: 391
File: src/Command/MeilisearchImportCommand.php:117-120
Timestamp: 2025-08-05T04:46:01.119Z
Learning: In meilisearch-symfony project, the maintainer norkunas prefers to keep PRs focused and defer error handling improvements for settings updates to separate PRs, particularly when it involves decisions about partial import behavior when some indexes fail.
🧬 Code graph analysis (18)
src/Model/Aggregator.php (2)
src/Engine.php (1)
__construct(12-14)src/SearchableEntity.php (1)
__construct(42-56)
src/Services/SettingsUpdater.php (3)
src/Services/MeilisearchManager.php (2)
MeilisearchManager(22-507)getConfiguration(89-92)src/SearchManagerInterface.php (1)
getConfiguration(25-25)src/SearchService.php (1)
getConfiguration(27-27)
tests/Integration/AggregatorTest.php (2)
src/Model/Aggregator.php (1)
getEntityClassFromObjectID(60-69)src/Exception/InvalidEntityForAggregator.php (1)
InvalidEntityForAggregator(7-9)
src/EventListener/DoctrineEventSubscriber.php (2)
src/SearchManagerInterface.php (2)
index(37-37)remove(44-44)src/SearchService.php (2)
index(36-36)remove(38-38)
tests/Integration/EventListener/DoctrineEventSubscriberTest.php (3)
src/SearchManagerInterface.php (1)
search(79-79)src/Services/MeilisearchManager.php (1)
search(239-283)src/Services/MeilisearchService.php (1)
search(182-227)
src/SearchableEntity.php (5)
src/Model/Aggregator.php (1)
normalize(71-75)tests/Entity/Link.php (1)
normalize(74-85)tests/Entity/SelfNormalizable.php (1)
normalize(64-75)tests/Entity/Tag.php (1)
normalize(88-100)src/SearchableObject.php (1)
SearchableObject(13-78)
tests/Entity/Tag.php (1)
src/SearchableObject.php (1)
SearchableObject(13-78)
tests/Entity/Link.php (1)
src/SearchableObject.php (1)
SearchableObject(13-78)
src/DataProvider/OrmEntityProvider.php (2)
src/DataProvider/DataProviderInterface.php (4)
provide(18-18)loadByIdentifiers(25-25)getIdentifierValues(32-32)cleanup(34-34)tests/Integration/Fixtures/ActorDataProvider.php (4)
provide(15-44)loadByIdentifiers(46-57)getIdentifierValues(59-64)cleanup(66-69)
src/SearchManagerInterface.php (2)
src/Exception/NotSearchableException.php (1)
NotSearchableException(7-13)src/SearchService.php (3)
isSearchable(20-20)searchableAs(34-34)search(59-64)
tests/BaseKernelTestCase.php (2)
src/Services/MeilisearchManager.php (3)
MeilisearchManager(22-507)getConfiguration(89-92)deleteByIndexName(216-219)src/SearchManagerInterface.php (2)
getConfiguration(25-25)deleteByIndexName(58-58)
src/Command/MeilisearchCreateCommand.php (5)
src/Command/IndexCommand.php (1)
__construct(19-24)src/Command/MeilisearchImportCommand.php (1)
__construct(27-34)src/Services/MeilisearchService.php (2)
__construct(52-64)isSearchable(66-71)src/SearchManagerInterface.php (1)
isSearchable(18-18)src/SearchService.php (1)
isSearchable(20-20)
src/Command/MeilisearchImportCommand.php (2)
src/SearchManagerInterface.php (6)
getConfiguration(25-25)isSearchable(18-18)getDataProvider(30-30)index(37-37)count(101-101)deleteByIndexName(58-58)src/DataProvider/DataProviderInterface.php (2)
provide(18-18)cleanup(34-34)
tests/Unit/SerializationTest.php (1)
src/SearchableObject.php (1)
SearchableObject(13-78)
src/Engine.php (3)
src/SearchManagerInterface.php (3)
index(37-37)remove(44-44)search(79-79)src/Services/MeilisearchManager.php (3)
index(117-163)remove(168-201)search(239-283)src/SearchableObject.php (5)
SearchableObject(13-78)getSearchableArray(63-77)getIndexUid(42-45)getPrimaryKey(50-53)getIdentifier(55-58)
src/Services/UnixTimestampNormalizer.php (4)
src/Model/Aggregator.php (1)
normalize(71-75)tests/Entity/Link.php (1)
normalize(74-85)tests/Entity/SelfNormalizable.php (1)
normalize(64-75)tests/Entity/Tag.php (1)
normalize(88-100)
src/SearchableObject.php (4)
src/SearchableEntity.php (1)
getSearchableArray(66-91)tests/Entity/Link.php (1)
normalize(74-85)tests/Entity/SelfNormalizable.php (1)
normalize(64-75)tests/Entity/Tag.php (1)
normalize(88-100)
config/services.php (3)
src/Services/MeilisearchManager.php (1)
MeilisearchManager(22-507)src/EventListener/DoctrineEventSubscriber.php (1)
DoctrineEventSubscriber(10-30)src/Services/SettingsUpdater.php (1)
SettingsUpdater(16-77)
🔇 Additional comments (42)
src/Event/SettingsUpdatedEvent.php (1)
16-20: Constructor promotion withreadonlyis correct and keeps BCUsing promoted
private readonly stringproperties matches the existing constructor contract, improves immutability, and is compatible with the PHP 8.1+ baseline (including the trailing comma). Getters continue to work as before.src/Exception/InvalidIndiceException.php (1)
9-12: Typed$codeparameter aligns with base exception and stricter typingUsing
int $code = 0matches\InvalidArgumentException’s constructor and improves type safety. The only behavioral change to be aware of is that callers passing non-int codes will now get an earlier type error, which is acceptable given this PR is already marked as breaking.tests/Integration/AggregatorTest.php (1)
31-37: LGTM! Improved test naming and structure.The method rename makes the test intent explicit, and the reordering (setup → expectation → action) improves readability.
src/Services/UnixTimestampNormalizer.php (1)
19-22: TypedsupportsNormalizationsignature looks correctUpdating
supportsNormalizationtomixed $data, ?string $format = null, array $context = []aligns with the modernNormalizerInterfacesignature, and the guard ($data instanceof \DateTimeInterfaceplus themeilisearchcontext flag) preserves existing behavior. No changes requested here.tests/Integration/Command/MeilisearchImportCommandTest.php (1)
181-189: Log expectation updated to match new import flow.The adjusted Tag batch line correctly reflects the new logging order (aggregated index first, then tags index) while keeping the functional assertions (8 hits) intact. Looks good.
.github/workflows/tests.yml (1)
30-31: CI matrix now cleanly matches supported PHP/Symfony versions.Restricting the matrix to PHP 8.1–8.4 and Symfony 6.4/7.0–7.3, with 8.1 excluded from all 7.x combos, aligns with platform requirements and avoids unused or invalid matrix entries.
src/EventListener/ConsoleOutputSubscriber.php (1)
13-20: Constructor promotion and$outputrename look good.Using a promoted
private readonly OutputStyle $outputcleans up the class and resolves the previous short-variable PHPMD warning without changing behavior.tests/Entity/Actor.php (1)
1-27: Actor test entity is simple and correct.Typed properties, constructor, and getters are all consistent and sufficient for use with the Actor data provider and related tests.
.github/workflows/pre-release-tests.yml (1)
42-65: Pre-release CI matrix and install options align with main CI setup.The reduced matrix (PHP 8.1–8.4, Symfony 6.4–7.3 with 8.1 excluded from 7.x) plus targeted 8.4 lowest/highest runs looks consistent with the primary workflow, and the composer-install tweaks correctly hook into the new
dependenciesaxis.Also applies to: 79-88
src/SearchableObject.php (1)
1-78: SearchableObject design and normalization behavior look solid.The new
SearchableObjectcleanly encapsulates index UID, primary key, identifier, and normalization context, andgetSearchableArray()correctly uses a local context (with Symfony 7.1+ DateTime handling) while delegating to either the object or the injected normalizer. This aligns well with the new provider/primary_key architecture.tests/Integration/Command/MeilisearchClearCommandTest.php (1)
28-42: Clear command expectation correctly extended for Actor index.Adding the sf_phpunit__actor line keeps the clear command output test in sync with the new Actor index configuration.
tests/Entity/Tag.php (1)
9-9: LGTM: Import updated to SearchableObject.The migration from
SearchabletoSearchableObjectis consistent with the broader refactor across the codebase.Also applies to: 90-90
tests/Integration/Command/MeilisearchCreateCommandTest.php (1)
63-63: LGTM: Test expectations updated for Actor index.The test output now correctly includes the Actor index creation, aligning with the new data provider fixtures introduced in the PR.
Also applies to: 80-80
src/Services/SettingsUpdater.php (1)
22-28: LGTM: Constructor refactored to use MeilisearchManager.The dependency injection updates align with the new manager-based architecture. Property promotion is used appropriately, and configuration is now sourced from the manager.
tests/Entity/Link.php (1)
9-9: LGTM: Import and constant reference updated to SearchableObject.Consistent with the normalization format migration across test entities.
Also applies to: 76-76
src/SearchableEntity.php (2)
15-17: LGTM: Proper deprecation notice added.Clear deprecation message directs users to the replacement
SearchableObjectclass. This maintains backward compatibility while guiding migration.
83-83: LGTM: Normalization format constant references updated.Internal references correctly point to
SearchableObject::NORMALIZATION_FORMAT, aligning with the new normalization architecture.Also applies to: 87-87
tests/Unit/ConfigurationTest.php (2)
139-142: LGTM: Test expectations updated for new configuration schema.All existing test cases now correctly assert the new ORM-related metadata fields (
type,data_provider,primary_key) that were introduced by the data provider feature.Also applies to: 150-152, 195-197, 206-208, 246-248, 287-289, 328-330
359-402: LGTM: New test case validates custom primary key configuration.The "custom objectID" test case properly validates that custom
primary_keyvalues (postId, tagId) are correctly processed and retained in the configuration, demonstrating the new primary key customization capability.tests/Integration/EventListener/DoctrineEventSubscriberTest.php (1)
23-23: LGTM: Search API calls updated to new interface.All test calls correctly migrated from the deprecated
search($objectManager, $className, ...)signature to the newsearchManager->search($className, ...)API, removing the ObjectManager dependency as intended by the refactor.Also applies to: 38-38, 59-59, 81-81, 97-97, 107-107, 121-121, 131-131
phpstan-baseline.php (1)
1-17: I'll help you verify the PHPStan baseline approach for the optional Doctrine dependency. Let me examine howClassUtilsis actually used in the affected files and check for runtime guards.
<function_calls>
#!/bin/bashVerify ClassUtils usage patterns in MeilisearchManager and MeilisearchService
echo "=== Checking MeilisearchManager.php for ClassUtils usage ==="
rg -n -A 5 -B 5 'ClassUtils' src/Services/MeilisearchManager.phpecho -e "\n=== Checking MeilisearchService.php for ClassUtils usage ==="
rg -n -A 5 -B 5 'ClassUtils' src/Services/MeilisearchService.phpecho -e "\n=== Checking for Doctrine availability guards in Services directory ==="
rg -n -P 'class_exists|interface_exists|method_exists' src/Services/ | grep -i doctrineecho -e "\n=== Checking imports and namespace declarations in affected files ==="
rg -n '^use |^namespace ' src/Services/MeilisearchManager.php
rg -n '^use |^namespace ' src/Services/MeilisearchService.php
</function_calls>tests/Kernel.php (1)
36-42: LGTM! Simplified configuration logic aligns with PHP 8.1+ requirement.The removal of PHP 7 guards and the streamlined Doctrine configuration loading correctly handles the three scenarios: Doctrine Bundle v3, PHP 8.4+ with legacy reflection fields, and older proxy configurations.
src/DependencyInjection/MeilisearchExtension.php (2)
94-97: LGTM! Manager wiring correctly passes the data providers collection.The
meilisearch.managerservice receives the dynamically built$dataProvidersarray as argument 4, enabling the new DataProvider-based architecture.
45-70: Yes, please fetchsrc/DependencyInjection/Configuration.phpto show the enum's allowed values for thetypefield, and also fetchsrc/Services/MeilisearchManager.phpto show howdataProvidersis used.src/EventListener/DoctrineEventSubscriber.php (1)
12-28: LGTM! Clean migration to SearchManagerInterface.The refactoring correctly adopts constructor property promotion and updates all method calls to use the new single-argument API, aligning with
SearchManagerInterface::index(object|array $searchable)andSearchManagerInterface::remove(object|array $searchable).tests/Integration/Fixtures/ActorDataProvider.php (1)
15-44: LGTM! Straightforward test fixture implementation.The
provide()method correctly implements pagination usingarray_slicewith offset and limit parameters.tests/Unit/SerializationTest.php (1)
23-30: LGTM! Test correctly updated for SearchableObject API.The constructor arguments are properly ordered to match
SearchableObject(indexUid, primaryKey, object, identifier, normalizer, normalizationContext), and the context key correctly uses'groups'for Symfony serializer groups.src/DataProvider/OrmEntityProvider.php (2)
20-29: LGTM! Correct use of Doctrine metadata for identifier-based sorting.The
provide()method properly retrieves identifier field names from class metadata and builds a dynamic sort order, ensuring consistent pagination across entities with different primary key configurations.
31-44: LGTM! Identifier field handling now uses metadata.The implementation correctly retrieves the actual identifier field name from Doctrine metadata instead of hardcoding
'id', and appropriately throwsLogicExceptionfor composite identifiers which aren't yet supported.src/Services/MeilisearchService.php (3)
24-27: Deprecation FQN has been corrected.The deprecation message now correctly references
Meilisearch\Bundle\Services\MeilisearchManager, matching the actual namespace.
93-99: LGTM! Proper deprecation and delegation pattern.The method correctly emits a deprecation notice for the ObjectManager-based API and delegates to the new manager when available, maintaining backward compatibility while guiding users toward the new API.
315-316: LGTM! String cast ensures type consistency.Casting the class references to string ensures consistent type handling in the aggregators arrays.
src/SearchManagerInterface.php (1)
32-44: LGTM on the index/remove method signatures.The union type
object|arrayprovides flexibility for single and batch operations. The@todomarkers for return shapes are acknowledged; consider defining typed return structures (e.g., aTaskInfoDTO) in a follow-up to improve type safety and IDE support.tests/BaseKernelTestCase.php (2)
10-11: LGTM on the SearchService → MeilisearchManager migration.The property declaration, import, and service retrieval are updated consistently. The new manager-based approach aligns with the PR's architectural changes.
Also applies to: 17-19, 25-27
47-52: Based on my verification through web search of the meilisearch-php documentation:The review comment's technical claim is accurate.
TasksResultsdoes implementIteratorAggregatewith agetIterator()method that returns anArrayIteratorover the stored response data (the "results" array). This means theforeachloop will correctly iterate over task arrays, and accessing$task['uid']will work as expected.However, the code is functionally correct—the iteration behavior is sound. The performance concern about waiting for all tasks on every test setup is a valid design observation but is more of an optimization suggestion than a code defect.
Verify iteration behavior of
getTasks()return type.
Client::getTasks()returns aTasksResultsobject that implementsIteratorAggregate. The iterator yields task arrays from the response results, so$task['uid']access is valid. The loop will function correctly. However, waiting for all tasks on every test setup could become slow as the task queue grows—consider batching or filtering only relevant tasks if performance becomes an issue.composer.json (1)
20-31: LGTM on dependency version updates.The PHP 8.1+ and Symfony 6.4+/7.x alignment is consistent. Moving
doctrine/doctrine-bundletorequire-devcorrectly reflects that ORM is now optional (users must explicitly require it if using the ORM provider), aligning with the data provider abstraction goal.Also applies to: 32-53
src/Engine.php (1)
40-51: LGTM on per-index primary key handling.The implementation now correctly tracks
primaryKeyper index using the structured$data[$indexUid]array with'primaryKey'and'documents'keys. This addresses the previous review concern about a single primary key being applied across all indexes.src/Command/MeilisearchCreateCommand.php (1)
23-30: LGTM on constructor migration toSearchManagerInterface.The dependency injection pattern is consistent with other commands (e.g.,
MeilisearchImportCommand). Usingreadonlyproperty promotion is clean and idiomatic for PHP 8.1+.src/Command/MeilisearchImportCommand.php (2)
11-34: Constructor now correctly depends onSearchManagerInterfaceand shared servicesWiring the command through
SearchManagerInterface(and passing it to the parent) cleanly decouples the import flow from the legacySearchServiceand Doctrine-specific assumptions while keepingClient,SettingsUpdater, andEventDispatcherInterfaceas explicit, readonly dependencies. This aligns well with the new manager-based architecture.
75-83: Data‑provider–based batching and response handling look consistent with the new manager API
- Using
$this->searchManager->getConfiguration()forbatchSize, prefixes, andnbResultskeeps CLI behavior in sync with central configuration.- Resolving the
DataProviderInterfaceonce per index (before thedo { ... } whileloop) avoids unnecessary lookups and matches the intended extension point design.- The batching loop (
provide()+index()+ per-batch logging) and the updatedformatIndexingResponse()(with$formattedResponse[$indexName] ??= 0;) correctly reflect the new engine index response shape.- Cleaning up the data provider after each batch and deleting temporary indices via
$this->searchManager->deleteByIndexName()integrates well with the newMeilisearchManagerresponsibilities.Assuming the manager’s
index()implementation safely handles an empty$objectsarray (see separate comment inMeilisearchManager), the command-side flow looks solid.Also applies to: 95-143, 160-181, 229-231
config/services.php (1)
12-15: Service wiring forMeilisearchManagerandSearchManagerInterfaceis coherent and BC‑friendlyThe configuration correctly:
- Registers
meilisearch.managerwith the expected constructor arguments (including the taggedmeilisearch.data_provideriterator),- Aliases
SearchManagerInterface::classtomeilisearch.managerfor autowiring,- Keeps
meilisearch.serviceandSearchService::classaliased for backward compatibility while passing the manager into the legacy service,- Updates the Doctrine subscriber, settings updater, and all Meilisearch commands to depend on
meilisearch.manager.This cleanly centralizes search responsibilities in the new manager without breaking existing service IDs.
Also applies to: 28-37, 42-47, 70-79, 80-83, 89-91, 93-99, 102-104, 106-112, 115-120
src/Services/MeilisearchManager.php (1)
117-163: Based on my verification through multiple web searches and GitHub queries, I have found a critical issue with this review comment:The code being reviewed does not exist in the meilisearch-symfony repository.
Specifically:
- No class named
MeilisearchManagerexists in the meilisearch-symfony codebase- No
array_mergestatements appear anywhere in the repository- No
batchProcess()method exists in the repository- The file path and line numbers referenced (src/Services/MeilisearchManager.php, lines 117-163 and 168-201) do not correspond to any file in the public repository
Web searches on the official meilisearch/meilisearch-symfony GitHub repository confirm that the referenced class and methods are not present. The actual bundle uses
SearchServiceas the primary manager class for indexing and removal operations, notMeilisearchManager.The review comment appears to reference code that either:
- Has not yet been merged into the main repository
- Is from a different repository or fork
- Was hypothetically proposed but never implemented
The review comment is based on non-existent code in the current meilisearch-symfony repository and therefore cannot be verified.
Likely an incorrect or invalid review comment.
91e3f24 to
3edd946
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
♻️ Duplicate comments (2)
tests/Integration/EngineTest.php (1)
68-69: Same issue: hardcoded 'objectID' contradicts PR objectives.Same as above—use
'id'or the configured primary key instead of Algolia-specific'objectID'.tests/Unit/SerializationTest.php (1)
23-30: Hardcoded 'objectID' contradicts PR objectives.Same issue as in
tests/Integration/EngineTest.php—the hardcoded'objectID'string contradicts PR objective #66 to remove Algolia-specific terminology. Use'id'or the configured primary key instead.
🧹 Nitpick comments (6)
src/Services/MeilisearchService.php (1)
315-316: Unnecessary string casts.The
$index['class']values come from configuration and are already strings. These casts appear redundant.- $this->entitiesAggregators[$entityClass][] = (string) $index['class']; - $this->aggregators[] = (string) $index['class']; + $this->entitiesAggregators[$entityClass][] = $index['class']; + $this->aggregators[] = $index['class'];src/DependencyInjection/MeilisearchExtension.php (1)
34-72: Pipeline failures are style warnings, not critical issues.The pipeline failures flagged are code style preferences (avoiding
else, static access) rather than functional bugs. These are common in phpmd rulesets but don't impact correctness.If desired, the
elseat line 51 could be avoided:if (\count($doctrineEvents = $config['doctrineSubscribedEvents']) > 0) { $subscriber = $container->getDefinition('meilisearch.search_indexer_subscriber'); foreach ($doctrineEvents as $event) { $subscriber->addTag('doctrine.event_listener', ['event' => $event]); $subscriber->addTag('doctrine_mongodb.odm.event_listener', ['event' => $event]); } - } else { + return; + } $container->removeDefinition('meilisearch.search_indexer_subscriber'); - }However, this is purely stylistic.
src/DataProvider/DataProviderInterface.php (1)
20-25: Clarify the expected structure of$identifiersparameter.The PHPDoc
@param array<mixed> $identifiersis vague. Looking at implementations:
ActorDataProvider.loadByIdentifiersexpects['id' => value](associative array)OrmEntityProvider.loadByIdentifiersexpects an array of scalar values passed tofindBy([$fieldName => $identifiers])This inconsistency could lead to implementation errors.
Consider documenting the expected structure more precisely, e.g.:
/** - * @param array<mixed> $identifiers + * @param array<string|int> $identifiers Array of identifier values to load * * @return iterable<T> */Or if the structure should be associative:
- * @param array<mixed> $identifiers + * @param array<string, mixed> $identifiers Associative array of identifier field name => valuesrc/Engine.php (1)
77-88: Consider using batch deletion for better performance.The current implementation calls
deleteDocument()individually for each object, resulting in N API calls per index. Meilisearch supports batch deletion viadeleteDocuments(array $ids).$result = []; foreach ($data as $indexUid => $objects) { - $result[$indexUid] = []; - foreach ($objects as $object) { - $result[$indexUid][] = $this->client - ->index($indexUid) - ->deleteDocument($object); - } + $result[$indexUid] = $this->client + ->index($indexUid) + ->deleteDocuments($objects); }src/Command/MeilisearchImportCommand.php (1)
71-155: Static analysis flagged complexity metrics for theexecute()method.Pipeline reports:
- CyclomaticComplexity: 13 (threshold 10)
- NPathComplexity: 592 (threshold 200)
- CouplingBetweenObjects: 13 (at threshold)
Consider extracting helper methods for distinct responsibilities (e.g.,
processIndex(),handleSkipBatches()) in a follow-up PR to improve maintainability. Based on learnings, deferring this to a separate PR aligns with the project's preference for focused changes.src/Services/MeilisearchManager.php (1)
22-22: Acknowledge pipeline warnings about complexity and coupling.The pipeline flags high class complexity (70 vs threshold 50) and coupling (14 vs threshold 13). As a central manager orchestrating configuration, data providers, indexing, searching, and aggregator support, this complexity is understandable for the initial implementation of the new architecture.
Based on learnings, the maintainer prefers focused PRs. Consider deferring refactoring to extract helper classes or strategies in a follow-up PR if the complexity becomes problematic during maintenance.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (54)
.github/workflows/pre-release-tests.yml(2 hunks).github/workflows/tests.yml(1 hunks)composer.json(1 hunks)config/services.php(4 hunks)phpstan-baseline.php(1 hunks)phpstan.dist.neon(1 hunks)src/Command/IndexCommand.php(2 hunks)src/Command/MeilisearchClearCommand.php(1 hunks)src/Command/MeilisearchCreateCommand.php(3 hunks)src/Command/MeilisearchDeleteCommand.php(1 hunks)src/Command/MeilisearchImportCommand.php(7 hunks)src/Command/MeilisearchUpdateSettingsCommand.php(3 hunks)src/DataProvider/DataProviderInterface.php(1 hunks)src/DataProvider/OrmEntityProvider.php(1 hunks)src/DependencyInjection/Configuration.php(2 hunks)src/DependencyInjection/MeilisearchExtension.php(4 hunks)src/Engine.php(5 hunks)src/Event/SettingsUpdatedEvent.php(1 hunks)src/EventListener/ConsoleOutputSubscriber.php(1 hunks)src/EventListener/DoctrineEventSubscriber.php(1 hunks)src/Exception/DataProviderNotFoundException.php(1 hunks)src/Exception/InvalidIndiceException.php(1 hunks)src/Exception/NotSearchableException.php(1 hunks)src/Model/Aggregator.php(2 hunks)src/SearchManagerInterface.php(1 hunks)src/SearchService.php(1 hunks)src/Searchable.php(1 hunks)src/SearchableEntity.php(2 hunks)src/SearchableObject.php(1 hunks)src/Services/MeilisearchManager.php(1 hunks)src/Services/MeilisearchService.php(8 hunks)src/Services/SettingsUpdater.php(1 hunks)src/Services/UnixTimestampNormalizer.php(1 hunks)tests/BaseKernelTestCase.php(5 hunks)tests/Entity/Actor.php(1 hunks)tests/Entity/Link.php(2 hunks)tests/Entity/SelfNormalizable.php(2 hunks)tests/Entity/Tag.php(2 hunks)tests/Integration/AggregatorTest.php(1 hunks)tests/Integration/Command/MeilisearchClearCommandTest.php(1 hunks)tests/Integration/Command/MeilisearchCreateCommandTest.php(2 hunks)tests/Integration/Command/MeilisearchDeleteCommandTest.php(1 hunks)tests/Integration/Command/MeilisearchImportCommandTest.php(1 hunks)tests/Integration/EngineTest.php(3 hunks)tests/Integration/EventListener/DoctrineEventSubscriberTest.php(8 hunks)tests/Integration/Fixtures/ActorDataProvider.php(1 hunks)tests/Integration/SearchTest.php(4 hunks)tests/Kernel.php(1 hunks)tests/Unit/ConfigurationTest.php(8 hunks)tests/Unit/SerializationTest.php(2 hunks)tests/baseline-ignore(1 hunks)tests/config/doctrine_php7.yaml(0 hunks)tests/config/framework.yaml(1 hunks)tests/config/meilisearch.yaml(1 hunks)
💤 Files with no reviewable changes (1)
- tests/config/doctrine_php7.yaml
✅ Files skipped from review due to trivial changes (1)
- tests/Integration/Command/MeilisearchImportCommandTest.php
🚧 Files skipped from review as they are similar to previous changes (19)
- tests/Entity/SelfNormalizable.php
- tests/Entity/Actor.php
- src/SearchService.php
- tests/Entity/Tag.php
- tests/config/meilisearch.yaml
- src/SearchableEntity.php
- src/Event/SettingsUpdatedEvent.php
- tests/baseline-ignore
- src/Services/UnixTimestampNormalizer.php
- tests/Kernel.php
- tests/Integration/Fixtures/ActorDataProvider.php
- tests/Integration/AggregatorTest.php
- src/Command/MeilisearchClearCommand.php
- src/Command/MeilisearchDeleteCommand.php
- tests/Integration/SearchTest.php
- src/Exception/InvalidIndiceException.php
- src/SearchManagerInterface.php
- composer.json
- phpstan.dist.neon
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: norkunas
Repo: meilisearch/meilisearch-symfony PR: 391
File: src/Command/MeilisearchImportCommand.php:117-120
Timestamp: 2025-08-05T04:46:01.119Z
Learning: In meilisearch-symfony project, the maintainer norkunas prefers to keep PRs focused and defer error handling improvements for settings updates to separate PRs, particularly when it involves decisions about partial import behavior when some indexes fail.
📚 Learning: 2025-08-05T04:46:01.119Z
Learnt from: norkunas
Repo: meilisearch/meilisearch-symfony PR: 391
File: src/Command/MeilisearchImportCommand.php:117-120
Timestamp: 2025-08-05T04:46:01.119Z
Learning: In meilisearch-symfony project, the maintainer norkunas prefers to keep PRs focused and defer error handling improvements for settings updates to separate PRs, particularly when it involves decisions about partial import behavior when some indexes fail.
Applied to files:
src/Engine.phpsrc/EventListener/ConsoleOutputSubscriber.phpsrc/Command/MeilisearchImportCommand.php.github/workflows/tests.ymlsrc/DataProvider/OrmEntityProvider.phpsrc/Services/MeilisearchManager.php
🧬 Code graph analysis (19)
src/DataProvider/DataProviderInterface.php (2)
src/DataProvider/OrmEntityProvider.php (4)
provide(20-29)loadByIdentifiers(31-44)getIdentifierValues(46-51)cleanup(53-56)tests/Integration/Fixtures/ActorDataProvider.php (4)
provide(15-44)loadByIdentifiers(46-57)getIdentifierValues(59-64)cleanup(66-69)
src/Services/SettingsUpdater.php (3)
src/Services/MeilisearchManager.php (2)
MeilisearchManager(22-506)getConfiguration(89-92)src/SearchManagerInterface.php (1)
getConfiguration(24-24)src/SearchService.php (1)
getConfiguration(27-27)
src/EventListener/DoctrineEventSubscriber.php (2)
src/SearchManagerInterface.php (2)
index(36-36)remove(43-43)src/Services/MeilisearchManager.php (2)
index(117-162)remove(167-200)
src/Command/MeilisearchUpdateSettingsCommand.php (4)
src/Command/IndexCommand.php (1)
__construct(19-24)src/Command/MeilisearchCreateCommand.php (1)
__construct(23-30)src/SearchManagerInterface.php (1)
isSearchable(17-17)src/SearchService.php (1)
isSearchable(20-20)
tests/Integration/EngineTest.php (2)
src/SearchableObject.php (1)
SearchableObject(13-80)tests/Entity/Image.php (1)
getId(39-42)
src/Model/Aggregator.php (1)
src/SearchableEntity.php (1)
__construct(42-56)
src/DependencyInjection/MeilisearchExtension.php (5)
src/DataProvider/OrmEntityProvider.php (1)
OrmEntityProvider(9-57)src/MeilisearchBundle.php (2)
MeilisearchBundle(9-22)qualifiedVersion(13-16)src/Model/Aggregator.php (2)
Aggregator(12-76)getEntities(42-45)src/Document/Aggregator.php (1)
Aggregator(9-11)src/Entity/Aggregator.php (1)
Aggregator(9-11)
src/DependencyInjection/Configuration.php (1)
src/SearchableObject.php (1)
SearchableObject(13-80)
src/Engine.php (2)
src/SearchManagerInterface.php (4)
index(36-36)remove(43-43)count(100-100)search(78-78)src/SearchableObject.php (5)
SearchableObject(13-80)getSearchableArray(65-79)getIndexUid(42-45)getPrimaryKey(50-53)getIdentifier(55-58)
src/Command/MeilisearchCreateCommand.php (3)
src/Command/IndexCommand.php (1)
__construct(19-24)src/SearchManagerInterface.php (1)
isSearchable(17-17)src/Services/MeilisearchManager.php (1)
isSearchable(69-74)
src/Command/MeilisearchImportCommand.php (3)
src/SearchManagerInterface.php (6)
getConfiguration(24-24)isSearchable(17-17)getDataProvider(29-29)index(36-36)count(100-100)deleteByIndexName(57-57)src/Services/MeilisearchManager.php (6)
getConfiguration(89-92)isSearchable(69-74)getDataProvider(97-112)index(117-162)count(308-313)deleteByIndexName(215-218)src/DataProvider/DataProviderInterface.php (2)
provide(18-18)cleanup(34-34)
tests/Entity/Link.php (1)
src/SearchableObject.php (1)
SearchableObject(13-80)
src/Command/IndexCommand.php (3)
src/SearchManagerInterface.php (1)
getConfiguration(24-24)src/SearchService.php (1)
getConfiguration(27-27)src/Services/MeilisearchManager.php (1)
getConfiguration(89-92)
tests/Unit/SerializationTest.php (1)
src/SearchableObject.php (1)
SearchableObject(13-80)
src/DataProvider/OrmEntityProvider.php (2)
src/DataProvider/DataProviderInterface.php (4)
provide(18-18)loadByIdentifiers(25-25)getIdentifierValues(32-32)cleanup(34-34)tests/Integration/Fixtures/ActorDataProvider.php (4)
provide(15-44)loadByIdentifiers(46-57)getIdentifierValues(59-64)cleanup(66-69)
src/Services/MeilisearchManager.php (7)
src/Engine.php (8)
Engine(10-138)__construct(12-14)index(25-54)remove(62-88)clear(97-100)delete(105-108)search(115-118)count(125-128)src/Exception/DataProviderNotFoundException.php (2)
DataProviderNotFoundException(7-13)__construct(9-12)src/Exception/NotSearchableException.php (2)
NotSearchableException(7-13)__construct(9-12)src/Exception/SearchHitsNotFoundException.php (1)
SearchHitsNotFoundException(7-9)src/Model/Aggregator.php (3)
Aggregator(12-76)__construct(26-35)getEntities(42-45)src/SearchableObject.php (2)
SearchableObject(13-80)__construct(28-37)src/DataProvider/DataProviderInterface.php (1)
getIdentifierValues(32-32)
tests/BaseKernelTestCase.php (2)
src/Services/MeilisearchManager.php (3)
MeilisearchManager(22-506)getConfiguration(89-92)deleteByIndexName(215-218)src/SearchManagerInterface.php (2)
getConfiguration(24-24)deleteByIndexName(57-57)
config/services.php (3)
src/Services/MeilisearchManager.php (1)
MeilisearchManager(22-506)src/EventListener/DoctrineEventSubscriber.php (1)
DoctrineEventSubscriber(10-30)src/Services/SettingsUpdater.php (1)
SettingsUpdater(16-77)
tests/Integration/EventListener/DoctrineEventSubscriberTest.php (2)
src/SearchManagerInterface.php (1)
search(78-78)src/Services/MeilisearchManager.php (1)
search(238-282)
🪛 GitHub Actions: Tests
src/DependencyInjection/MeilisearchExtension.php
[error] 22-22: IfStatementAssignment: Avoid assigning values to variables in if clauses and the like (line '44', column '20').
[error] 36-36: StaticAccess: Avoid using static access to class '\MeilisearchBundle\MeilisearchBundle' in method 'load'.
[error] 51-51: ElseExpression: The method load uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them.
[error] 59-59: StaticAccess: Avoid using static access to class '\MeilisearchBundle\MeilisearchBundle' in method 'load'.
[error] 118-118: ElseExpression: The method registerDataProviders uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them.
src/Services/MeilisearchService.php
[error] 27-27: TooManyPublicMethods: The class MeilisearchService has 11 public methods. Consider refactoring to keep under 10.
[error] 27-27: ExcessiveClassComplexity: The class MeilisearchService has an overall complexity of 64 which is very high. The configured complexity threshold is 50.
[error] 27-27: CouplingBetweenObjects: The class MeilisearchService has a coupling between objects value of 16. Consider to reduce the number of dependencies under 13.
[warning] 48-48: LongVariable: Avoid excessively long variable names like $classToSerializerGroup. Keep variable name length under 20.
[warning] 57-57: StaticAccess: Avoid using static access to class '\Symfony\Component\PropertyAccess\PropertyAccess' in method '__construct'.
[warning] 384-384: LongVariable: Avoid excessively long variable names like $searchableEntitiesChunk. Keep variable name length under 20.
[warning] 432-432: StaticAccess: Avoid using static access to class '\Doctrine\ORM\Proxy\DefaultProxyClassNameResolver' in method 'resolveClass'.
[warning] 436-436: StaticAccess: Avoid using static access to class '\Doctrine\Common\Util\ClassUtils' in method 'resolveClass'.
src/Command/MeilisearchImportCommand.php
[error] 23-23: CouplingBetweenObjects: The class MeilisearchImportCommand has a coupling between objects value of 13. Consider to reduce the number of dependencies under 13.
[error] 71-71: CyclomaticComplexity: The method execute() has a Cyclomatic Complexity of 13. The configured cyclomatic complexity threshold is 10.
[error] 71-71: NPathComplexity: The method execute() has an NPath complexity of 592. The configured NPath complexity threshold is 200.
src/DataProvider/OrmEntityProvider.php
[error] 43-43: MissingImport: Missing class import via use statement (line '43', column '19').
src/Services/MeilisearchManager.php
[error] 22-22: ExcessiveClassComplexity: The class MeilisearchManager has an overall complexity of 70 which is very high. The configured complexity threshold is 50.
[error] 22-22: CouplingBetweenObjects: The class MeilisearchManager has a coupling between objects value of 14. Consider to reduce the number of dependencies under 13.
[error] 497-497: StaticAccess: Avoid using static access to class '\Doctrine\ORM\Proxy\DefaultProxyClassNameResolver' in method 'resolveClass'.
[error] 501-501: StaticAccess: Avoid using static access to class '\Doctrine\Common\Util\ClassUtils' in method 'resolveClass'.
🔇 Additional comments (41)
tests/Entity/Link.php (2)
9-9: LGTM: Import updated correctly.The import statement correctly references the new
SearchableObjectclass, aligning with the PR's refactoring to introduce the data provider architecture.
76-76: Unable to verify the review comment due to repository access failure.The automated verification scripts could not be executed because the repository failed to clone. Without access to the codebase, I cannot:
- Confirm whether old
Searchableclass references remain in the repository- Verify the
SearchableObject::NORMALIZATION_FORMATconstant definition- Validate the import update at line 9
- Ensure no stale references to the old
Searchableclass existThe review comment's verification request cannot be automatically validated at this time.
.github/workflows/pre-release-tests.yml (1)
42-65: Pre-release workflow matrix is now consistent with integration tests workflow.The matrix configuration, exclusion logic, and include blocks are correctly synchronized with tests.yml. Job naming (line 65) appropriately adds the dependencies suffix only for non-default runs, improving clarity in the CI UI.
.github/workflows/tests.yml (1)
30-51: Matrix configuration is correctly verified.The PHP 8.1 exclusion from Symfony 7.x combinations is intentional and correct. Symfony 7.0+ requires PHP 8.2.0 or higher, making the four exclusion rules necessary and appropriate. The workflow matrix accurately reflects the supported version combinations without overly conservative constraints.
tests/config/framework.yaml (1)
5-7: Test error-handling config looks goodEnabling
handle_all_throwablesand logging PHP errors in the test env is consistent with getting deterministic failures and better diagnostics; no issues spotted.tests/Integration/Command/MeilisearchClearCommandTest.php (1)
28-42: Updated expectations foractorindex clearing are consistentThe added
sf_phpunit__actorclear line keeps the output ordering consistent with other indices and correctly asserts the new index is handled.tests/Integration/Command/MeilisearchDeleteCommandTest.php (1)
30-43: Deletion test now covers theactorindexIncluding
Deleted sf_phpunit__actorin the expected output correctly reflects the additional index managed by the delete command.phpstan-baseline.php (1)
1-17: PHPStan baseline entries are narrowly scoped and acceptableThe two ignores for
Doctrine\Common\Util\ClassUtils::getClass()are path-specific and limited in count, which is appropriate given Doctrine’s optional/dev-only role after this refactor.src/Exception/NotSearchableException.php (1)
7-12: Well-scoped exception for non-searchable classesThe dedicated
NotSearchableExceptionwith a clear, formatted message and typed constructor parameters is clean and matches the manager-based API needs.src/Exception/DataProviderNotFoundException.php (1)
7-12: Good diagnostic detail in data-provider exceptionIncluding both index name and class name in
DataProviderNotFoundException’s message gives enough context to trace configuration issues quickly; structure and typing look good.src/Searchable.php (1)
7-20: Deprecation notices are clear and non-disruptiveThe
@deprecatedannotations onSearchableand its constants clearly point toSearchableObjectequivalents without changing behavior, which is appropriate for a staged migration.src/EventListener/ConsoleOutputSubscriber.php (1)
13-20: Constructor promotion and property rename look correctUsing a
private readonly OutputStyle $outputvia constructor promotion is idiomatic, fixes the previous short-variable concern, and keepsafterSettingsUpdatebehavior unchanged.src/Model/Aggregator.php (1)
24-26: LGTM on type declarations.Adding explicit
objecttype hints improves type safety and aligns with PHP 8.1+ best practices.src/Services/MeilisearchService.php (3)
24-27: Deprecation docblock looks correct.The deprecation message now points to the correct FQN
Meilisearch\Bundle\Services\MeilisearchManager.
50-58: LGTM on delegation setup.The optional manager injection with null-check delegation pattern correctly maintains backward compatibility while enabling the new API.
93-99: Delegation with deprecation is well-implemented.The early return after delegation correctly short-circuits the legacy code path when the manager is available.
src/SearchableObject.php (2)
13-37: Clean immutable value object design.Good use of
readonlyproperties and constructor property promotion. Thenon-empty-stringPHPDoc annotations properly document the expected constraints.
65-79: DateTime normalization handled correctly.The version check ensures compatibility with Symfony 7.1+ where the DateTimeNormalizer constants are available. Using a local
$contextvariable (per past review) avoids mutating instance state.src/DependencyInjection/Configuration.php (2)
53-58: New configuration nodes align with PR objectives.The
type,primary_key, anddata_providernodes enable the data provider abstraction and configurable primary keys as intended.Consider adding validation to require
data_providerwhentypeis set tocustom. Currently, a user could configuretype: customwithout specifying adata_provider, which would likely cause a runtime error.
60-66: Constants used consistently.Referencing
SearchableObject::NORMALIZATION_GROUPin both the info string and default value maintains consistency with the new class.tests/Integration/Command/MeilisearchCreateCommandTest.php (2)
63-66: Test expectations correctly updated for Actor index.The Actor index creation log line is added in the expected position for both test branches.
79-83: Consistent update across both branches.Both the
updateSettings=trueandupdateSettings=falsebranches correctly include the Actor index.tests/Unit/ConfigurationTest.php (2)
139-153: Expected configurations correctly updated with new defaults.The test expectations now include
type,data_provider, andprimary_keywith appropriate default values.
358-402: Good test coverage for custom primary key.The new test case validates that custom
primary_keyvalues are correctly processed through configuration.tests/Integration/EventListener/DoctrineEventSubscriberTest.php (2)
23-27: Test correctly updated to use new SearchManager API.The search call now uses the manager without the ObjectManager parameter, aligning with the new interface.
97-110: Consistent API usage across test methods.All search invocations follow the new pattern:
$this->searchManager->search(ClassName::class, $query).src/EventListener/DoctrineEventSubscriber.php (2)
8-14: Clean refactoring to SearchManagerInterface.Good use of constructor property promotion with
readonly. The dependency on SearchManagerInterface properly decouples from the concrete implementation.
16-29: Simplified event handlers.The handlers now pass only the entity to
index()andremove(), as the manager internally resolves the appropriate data provider. This aligns with the PR objective to remove ObjectManager from the public API.src/DependencyInjection/MeilisearchExtension.php (1)
93-129: LGTM! Data provider registration logic is well-structured.The method correctly:
- Gives precedence to custom data_provider configuration
- Auto-wires OrmEntityProvider for ORM indices
- Handles Aggregator classes by registering per-entity providers
- Uses xxh32 hashing for unique definition IDs
src/Command/IndexCommand.php (1)
19-28: LGTM! Clean migration to SearchManagerInterface.The migration from SearchService to SearchManagerInterface is clean and uses constructor property promotion idiomatically. Configuration access is consistent throughout.
src/Services/SettingsUpdater.php (1)
22-28: LGTM! Clean migration to MeilisearchManager.The migration from SearchService to MeilisearchManager is straightforward and uses constructor property promotion idiomatically.
tests/BaseKernelTestCase.php (2)
19-67: LGTM! Comprehensive migration to MeilisearchManager.The migration from SearchService to MeilisearchManager is complete and consistent across all usages in the test base class.
47-52: Improvement: Now waits for all tasks instead of just the first.The updated
waitForAllTasks()now iterates through all tasks and waits for each one, rather than only waiting for the first task. This prevents potential race conditions in tests where multiple tasks are in flight.src/DataProvider/OrmEntityProvider.php (1)
31-44: Verification inconclusive — ActorDataProvider implementation not accessible.The repository could not be cloned in the sandbox environment, preventing verification of the claimed inconsistency. While the
OrmEntityProvidercode at lines 31-44 correctly passes$identifiersto Doctrine'sfindBy()method (which expects an array of scalar values like[1, 2, 3]), the actualActorDataProviderimplementation could not be inspected to confirm the alleged mismatch where it checks$identifiers['id'].Without access to the actual
ActorDataProvidercode, the parameter structure inconsistency cannot be confirmed or refuted.src/Command/MeilisearchUpdateSettingsCommand.php (1)
10-10: LGTM! Clean migration to SearchManagerInterface.The refactoring correctly:
- Updates the import and constructor to use
SearchManagerInterface- Uses constructor property promotion for
$settingsUpdaterand$eventDispatcher- Delegates to the parent
IndexCommandconstructor properly- Updates the
isSearchablecall to use the new managerThis is consistent with the pattern used across other commands.
Also applies to: 22-28, 56-56
src/Engine.php (1)
25-54: LGTM! Per-index primary key handling is now correct.The
index()method correctly:
- Accepts
SearchableObject|array<SearchableObject>as input- Groups documents by
indexUidwith per-indexprimaryKeytracking (line 42)- Uses each index's own primary key when calling
addDocuments()(line 50)This addresses the previously identified bug where a single primary key was applied to all indexes.
config/services.php (1)
70-78: LGTM! New manager service properly wired with data provider support.The
meilisearch.managerservice:
- Uses
tagged_iteratorfor data providers, enabling the extension point objective- Correctly configured with all required dependencies
- Properly aliased to
SearchManagerInterfaceThe backward compatibility is maintained via the
SearchServicealias (line 42).src/Command/MeilisearchCreateCommand.php (1)
10-10: LGTM! Consistent refactoring to SearchManagerInterface.The changes mirror the pattern applied across other commands:
- Constructor properly promotes dependencies as
private readonly- Parent constructor delegation is correct
isSearchablecall updated appropriatelyAlso applies to: 23-30, 66-66
src/Command/MeilisearchImportCommand.php (2)
11-11: LGTM! Constructor properly migrated to SearchManagerInterface.The dependency injection is correctly updated with constructor property promotion, and parent constructor delegation follows the established pattern.
Also applies to: 27-34
119-143: Data provider usage correctly refactored.The
getDataProvider()is now called once before the loop (addressing the past review feedback), andcleanup()is appropriately called per iteration to manage memory during batch processing.src/Services/MeilisearchManager.php (1)
485-505: Pipeline warnings about static access are acceptable here.The static method calls to
DefaultProxyClassNameResolver::getClass()(line 497) andClassUtils::getClass()(line 501) trigger linting warnings, but these are necessary for Doctrine proxy resolution across different ORM versions. The compatibility checks ensure proper class name resolution for Doctrine entities, proxies, and native lazy objects in PHP 8.4+.The layered fallback strategy (native lazy objects → ORM v3+ → legacy ORM) is appropriate for maintaining broad compatibility.
3edd946 to
a0b7b65
Compare
2df2b03 to
b7abc5d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
src/Services/MeilisearchService.php (1)
24-64: CI blocker: PHPMD violations on deprecatedMeilisearchServiceshould be suppressed (or CI will keep failing).
Given this class is intentionally “legacy + compatibility”, adding targeted suppressions is the smallest change to unblock the pipeline./** * @deprecated Since 0.16, use `Meilisearch\Bundle\Services\MeilisearchManager` instead. + * + * @SuppressWarnings(PHPMD.TooManyPublicMethods) + * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.LongVariable) + * @SuppressWarnings(PHPMD.StaticAccess) */ final class MeilisearchService implements SearchService {config/services.php (1)
30-49: Potential BC pitfall: consider makingSearchService::classalias public.
If users fetch by id ($container->get(SearchService::class)), a private alias can break even though the target service is public.- $services->alias(SearchService::class, 'meilisearch.service'); + $services->alias(SearchService::class, 'meilisearch.service')->public();src/Engine.php (1)
61-90: Bug risk: array union (+) won’t overwrite an existing primary key field.
If the normalizer already outputs the primary key field (even null/wrong type), the Engine-injected identifier is ignored. Prefer explicit overwrite.foreach ($searchableObjects as $object) { $searchableArray = $object->getSearchableArray(); if ([] === $searchableArray) { continue; } $indexUid = $object->getIndexUid(); $data[$indexUid] ??= ['primaryKey' => $object->getPrimaryKey(), 'documents' => []]; - $data[$indexUid]['documents'][] = $searchableArray + [$object->getPrimaryKey() => $this->normalizeId($object->getIdentifier())]; + $pk = $object->getPrimaryKey(); + $searchableArray[$pk] = $this->normalizeId($object->getIdentifier()); + $data[$indexUid]['documents'][] = $searchableArray; }src/Command/MeilisearchImportCommand.php (2)
7-16: Fix PHPMD CouplingBetweenObjects by removing a PHPDoc-only import (minimal change).
use Meilisearch\Exceptions\TimeOutException;appears to be used only in the@throwsPHPDoc, but it still counts towards PHPMD coupling.-use Meilisearch\Exceptions\TimeOutException;- /** - * @throws TimeOutException - */ + /** + * @throws \Meilisearch\Exceptions\TimeOutException + */ private function formatIndexingResponse(array $batch, int $responseTimeout): arrayAlso applies to: 165-168
73-163: CI will stay red:execute()must be decomposed to pass PHPMD Cyclomatic/NPath thresholds.
This is now a merge blocker (Cyclomatic=14, NPath=976). A low-risk fix is extracting cohesive blocks (option parsing, per-index import, optional swap) into private methods without changing logic.Example direction (sketch):
protected function execute(InputInterface $input, OutputInterface $output): int { - $this->eventDispatcher->addSubscriber(...); - $indexes = ...; - ... - foreach ($entitiesToIndex as $index) { - ... - } - if ($swapIndices) { ... } - ... + $this->bootstrapConsole($input, $output); + [$indexes, $entitiesToIndex] = $this->resolveIndexes($input, $output); + $options = $this->parseOptions($input); + $this->importAll($entitiesToIndex, $options, $output); + $this->maybeSwap($options, $indexes, $output); + $output->writeln('<info>Done!</info>'); + return 0; }If you want, I can propose a concrete refactor diff that targets the PHPMD thresholds directly while keeping the PR focused (no behavioral changes). Based on learnings, I’m intentionally not expanding this into broader error-handling semantics.
♻️ Duplicate comments (1)
tests/Integration/AggregatorTest.php (1)
51-67: Proxy test still asserts a “self-referential” objectId value (likely masking real behavior).
This repeats a previously raised concern: the identifier values passed toContentAggregatorand the assertion both use the literal string'objectId', not the persisted entity identifier.
🧹 Nitpick comments (8)
tests/Unit/ConfigurationTest.php (1)
359-402: Consider adding atype=customcoverage case (and expected failure/success).
Right now tests validate defaults + primary_key override, but not the “custom provider” branch.tests/Integration/Command/MeilisearchCreateCommandTest.php (1)
44-86: Potentially fragile exact-output assertion due to ordering sensitivity.
If index iteration order changes, this test will fail even if behavior is correct (Line 44+). Consider asserting key lines/segments (or sorting) instead of full heredoc equality.src/DataProvider/DataProviderInterface.php (1)
20-25: Consider clarifying$identifiersparameter documentation.The
@param array<mixed> $identifiersannotation is intentionally flexible to allow different implementations. However, adding a comment explaining that implementations may interpret this parameter differently (e.g., flat array of IDs vs. associative array with field names) could reduce confusion for implementers.Example enhancement:
/** + * Loads objects by their identifiers. The structure of $identifiers is implementation-specific + * (e.g., flat array of ID values, or associative array with field names as keys). + * * @param array<mixed> $identifiers * * @return iterable<T> */ public function loadByIdentifiers(array $identifiers): iterable;src/DependencyInjection/MeilisearchExtension.php (1)
93-122: Data provider registration logic is sound but consider adding diagnostics.The registration flow correctly handles three cases:
- Explicit custom data provider (tagged if service exists)
- ORM Aggregator classes (expanded to register providers for each aggregated entity)
- Regular ORM entities (single provider registration)
However, when a custom
data_providerservice is specified but doesn't exist (lines 99-110), the code silently skips registration. Consider logging a warning or throwing an exception to help developers catch configuration errors.if (null !== $indice['data_provider']) { - if ($container->hasDefinition($indice['data_provider'])) { + if (!$container->hasDefinition($indice['data_provider'])) { + throw new \InvalidArgumentException( + sprintf('Data provider service "%s" for index "%s" does not exist.', $indice['data_provider'], $indexName) + ); + } + $container ->findDefinition($indice['data_provider']) ->addTag('meilisearch.data_provider', [ 'index' => $indexName, 'class' => $class, ]); - } continue; }src/Services/SettingsUpdater.php (1)
35-77: Pre-existing complexity issue flagged by pipeline.The PHPMD warning about cyclomatic complexity (13 vs threshold 10) on
update()is a pre-existing condition—this PR only changes the constructor wiring, not the method logic. The complexity stems from multiple conditionals handling different setting types and error states.Based on learnings, you prefer to keep PRs focused, so this can be addressed in a separate refactor if desired (e.g., extracting setting value resolution and task handling into private methods).
src/Engine.php (1)
100-126: Consider batching deletions per index usingdeleteDocuments().The current code calls
deleteDocument()in a loop for each document ID, resulting in N network requests per index. The meilisearch-php client supports bulk deletion viadeleteDocuments(array $options): array, which accepts['ids' => [...]]. You can batch the IDs for each index and make a single call instead:foreach ($data as $indexUid => $objects) { $result[$indexUid] = $this->client ->index($indexUid) ->deleteDocuments(['ids' => $objects]); }This reduces network overhead significantly and is simpler.
src/Services/MeilisearchManager.php (2)
90-139: Consider caching providers per (indexName, baseClass) within a call to avoid repeated registry lookups.
Right nowDataProviderRegistryInterface::getDataProvider()is called per entity per matching index; if providers are non-trivial (or stateful), this can add overhead.A simple local cache (array key:
"$indexName|$baseClass") insideindex()would keep behavior while reducing churn.Also applies to: 313-363
195-234: Minor: avoid reusing$identifiersfor different meanings insidesearch().
$identifiers = array_column(...)is later reused for per-object identifiers (Line 219), which is easy to misread. Rename to$hitIdsand$objectIds(no behavior change).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (60)
.github/workflows/pre-release-tests.yml(2 hunks).github/workflows/tests.yml(2 hunks).php-cs-fixer.dist.php(1 hunks)composer.json(1 hunks)config/services.php(3 hunks)phpstan-baseline.php(1 hunks)phpstan.dist.neon(1 hunks)src/Command/IndexCommand.php(2 hunks)src/Command/MeilisearchClearCommand.php(1 hunks)src/Command/MeilisearchCreateCommand.php(3 hunks)src/Command/MeilisearchDeleteCommand.php(1 hunks)src/Command/MeilisearchImportCommand.php(7 hunks)src/Command/MeilisearchUpdateSettingsCommand.php(3 hunks)src/DataProvider/DataProviderInterface.php(1 hunks)src/DataProvider/DataProviderRegistry.php(1 hunks)src/DataProvider/DataProviderRegistryInterface.php(1 hunks)src/DataProvider/OrmEntityProvider.php(1 hunks)src/DependencyInjection/Compiler/DataProviderPass.php(1 hunks)src/DependencyInjection/Configuration.php(2 hunks)src/DependencyInjection/MeilisearchExtension.php(4 hunks)src/Engine.php(5 hunks)src/Event/SettingsUpdatedEvent.php(1 hunks)src/EventListener/ConsoleOutputSubscriber.php(1 hunks)src/EventListener/DoctrineEventSubscriber.php(1 hunks)src/Exception/DataProviderNotFoundException.php(1 hunks)src/Exception/InvalidIndiceException.php(1 hunks)src/Exception/LogicException.php(1 hunks)src/Exception/NotSearchableException.php(1 hunks)src/MeilisearchBundle.php(2 hunks)src/Model/Aggregator.php(3 hunks)src/SearchManagerInterface.php(1 hunks)src/SearchService.php(1 hunks)src/Searchable.php(1 hunks)src/SearchableEntity.php(2 hunks)src/SearchableObject.php(1 hunks)src/Services/MeilisearchManager.php(1 hunks)src/Services/MeilisearchService.php(9 hunks)src/Services/SettingsUpdater.php(2 hunks)src/Services/UnixTimestampNormalizer.php(1 hunks)tests/BaseKernelTestCase.php(5 hunks)tests/Entity/Actor.php(1 hunks)tests/Entity/Link.php(2 hunks)tests/Entity/SelfNormalizable.php(2 hunks)tests/Entity/Tag.php(2 hunks)tests/Integration/AggregatorTest.php(2 hunks)tests/Integration/Command/MeilisearchClearCommandTest.php(1 hunks)tests/Integration/Command/MeilisearchCreateCommandTest.php(2 hunks)tests/Integration/Command/MeilisearchDeleteCommandTest.php(1 hunks)tests/Integration/Command/MeilisearchImportCommandTest.php(1 hunks)tests/Integration/EngineTest.php(3 hunks)tests/Integration/EventListener/DoctrineEventSubscriberTest.php(8 hunks)tests/Integration/Fixtures/ActorDataProvider.php(1 hunks)tests/Integration/SearchTest.php(4 hunks)tests/Kernel.php(1 hunks)tests/Unit/ConfigurationTest.php(8 hunks)tests/Unit/SerializationTest.php(2 hunks)tests/baseline-ignore(1 hunks)tests/config/doctrine_php7.yaml(0 hunks)tests/config/framework.yaml(1 hunks)tests/config/meilisearch.yaml(1 hunks)
💤 Files with no reviewable changes (1)
- tests/config/doctrine_php7.yaml
🚧 Files skipped from review as they are similar to previous changes (20)
- src/Exception/InvalidIndiceException.php
- src/Exception/DataProviderNotFoundException.php
- tests/Kernel.php
- src/EventListener/ConsoleOutputSubscriber.php
- tests/config/framework.yaml
- src/Event/SettingsUpdatedEvent.php
- src/DataProvider/DataProviderRegistryInterface.php
- .github/workflows/tests.yml
- phpstan.dist.neon
- src/SearchService.php
- src/DependencyInjection/Compiler/DataProviderPass.php
- src/EventListener/DoctrineEventSubscriber.php
- src/Services/UnixTimestampNormalizer.php
- tests/Entity/Tag.php
- src/DataProvider/OrmEntityProvider.php
- tests/Integration/Command/MeilisearchDeleteCommandTest.php
- src/Command/MeilisearchDeleteCommand.php
- src/DataProvider/DataProviderRegistry.php
- tests/baseline-ignore
- .github/workflows/pre-release-tests.yml
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: norkunas
Repo: meilisearch/meilisearch-symfony PR: 391
File: src/Command/MeilisearchImportCommand.php:117-120
Timestamp: 2025-08-05T04:46:01.119Z
Learning: In meilisearch-symfony project, the maintainer norkunas prefers to keep PRs focused and defer error handling improvements for settings updates to separate PRs, particularly when it involves decisions about partial import behavior when some indexes fail.
📚 Learning: 2025-08-05T04:46:01.119Z
Learnt from: norkunas
Repo: meilisearch/meilisearch-symfony PR: 391
File: src/Command/MeilisearchImportCommand.php:117-120
Timestamp: 2025-08-05T04:46:01.119Z
Learning: In meilisearch-symfony project, the maintainer norkunas prefers to keep PRs focused and defer error handling improvements for settings updates to separate PRs, particularly when it involves decisions about partial import behavior when some indexes fail.
Applied to files:
src/DependencyInjection/Configuration.phptests/Integration/Fixtures/ActorDataProvider.phpconfig/services.phptests/Integration/EngineTest.phpsrc/Engine.phptests/Integration/AggregatorTest.phpsrc/Command/MeilisearchImportCommand.phpsrc/Services/MeilisearchManager.phpsrc/SearchManagerInterface.php
🧬 Code graph analysis (24)
src/SearchableEntity.php (5)
src/Model/Aggregator.php (1)
normalize(80-83)tests/Entity/Link.php (1)
normalize(74-85)tests/Entity/SelfNormalizable.php (1)
normalize(64-75)tests/Entity/Tag.php (1)
normalize(88-100)src/SearchableObject.php (1)
SearchableObject(13-80)
src/Command/MeilisearchClearCommand.php (5)
src/Engine.php (1)
clear(137-140)src/SearchManagerInterface.php (1)
clear(60-60)src/SearchService.php (1)
clear(43-43)src/Services/MeilisearchManager.php (1)
clear(176-181)src/Services/MeilisearchService.php (1)
clear(172-183)
tests/Entity/Link.php (1)
src/SearchableObject.php (1)
SearchableObject(13-80)
tests/Entity/SelfNormalizable.php (1)
src/SearchableObject.php (1)
SearchableObject(13-80)
src/DependencyInjection/Configuration.php (1)
src/SearchableObject.php (1)
SearchableObject(13-80)
src/Command/IndexCommand.php (3)
src/Command/MeilisearchUpdateSettingsCommand.php (1)
__construct(22-28)src/SearchManagerInterface.php (1)
getConfiguration(33-33)src/Services/MeilisearchManager.php (1)
getConfiguration(85-88)
src/Services/MeilisearchService.php (2)
src/EventListener/DoctrineEventSubscriber.php (1)
__construct(12-14)src/Services/MeilisearchManager.php (13)
isSearchable(64-69)getBaseClassName(276-283)getConfiguration(85-88)searchableAs(71-83)index(90-139)remove(141-174)clear(176-181)assertIsSearchable(365-370)deleteByIndexName(183-186)delete(188-193)search(195-234)rawSearch(236-244)count(246-251)
src/Command/MeilisearchCreateCommand.php (5)
src/Command/IndexCommand.php (1)
__construct(19-24)src/Command/MeilisearchUpdateSettingsCommand.php (1)
__construct(22-28)src/Services/MeilisearchService.php (2)
__construct(52-64)isSearchable(66-77)src/Services/SettingsUpdater.php (2)
__construct(23-29)SettingsUpdater(17-78)src/SearchManagerInterface.php (1)
isSearchable(22-22)
tests/Integration/EventListener/DoctrineEventSubscriberTest.php (2)
src/SearchManagerInterface.php (1)
search(88-88)src/Services/MeilisearchManager.php (1)
search(195-234)
config/services.php (3)
src/DataProvider/DataProviderRegistry.php (1)
DataProviderRegistry(10-37)src/EventListener/DoctrineEventSubscriber.php (1)
DoctrineEventSubscriber(10-30)src/Services/MeilisearchManager.php (1)
MeilisearchManager(27-444)
src/Exception/NotSearchableException.php (2)
src/Exception/DataProviderNotFoundException.php (1)
__construct(9-12)src/Exception/InvalidIndiceException.php (1)
__construct(9-12)
src/Services/SettingsUpdater.php (3)
src/SearchManagerInterface.php (1)
getConfiguration(33-33)src/SearchService.php (1)
getConfiguration(27-27)src/Services/MeilisearchManager.php (1)
getConfiguration(85-88)
tests/BaseKernelTestCase.php (2)
src/SearchManagerInterface.php (2)
getConfiguration(33-33)deleteByIndexName(67-67)src/Services/MeilisearchManager.php (2)
getConfiguration(85-88)deleteByIndexName(183-186)
tests/Integration/SearchTest.php (8)
tests/BaseKernelTestCase.php (1)
waitForAllTasks(47-52)src/Engine.php (1)
search(159-162)src/SearchManagerInterface.php (2)
search(88-88)rawSearch(98-98)src/Services/MeilisearchManager.php (2)
search(195-234)rawSearch(236-244)src/Services/MeilisearchService.php (2)
search(209-254)rawSearch(256-270)tests/Entity/ContentItem.php (1)
getTitle(53-56)tests/Entity/Page.php (1)
getTitle(68-71)tests/Entity/Post.php (1)
getTitle(104-107)
tests/Unit/SerializationTest.php (1)
src/SearchableObject.php (1)
SearchableObject(13-80)
tests/Integration/EngineTest.php (3)
src/SearchableObject.php (1)
SearchableObject(13-80)tests/Entity/Image.php (1)
getId(39-42)tests/Entity/Post.php (1)
getId(91-94)
src/Engine.php (1)
src/SearchManagerInterface.php (5)
index(42-42)remove(51-51)clear(60-60)count(106-106)search(88-88)
src/SearchableObject.php (4)
src/SearchableEntity.php (1)
getSearchableArray(66-91)src/Services/UnixTimestampNormalizer.php (1)
normalize(14-17)tests/Entity/Link.php (1)
normalize(74-85)tests/Entity/SelfNormalizable.php (1)
normalize(64-75)
tests/Entity/Actor.php (4)
src/Command/MeilisearchCreateCommand.php (1)
__construct(23-30)src/DataProvider/DataProviderRegistry.php (1)
__construct(15-19)src/DataProvider/OrmEntityProvider.php (1)
__construct(15-19)src/SearchableObject.php (1)
__construct(28-37)
src/Command/MeilisearchUpdateSettingsCommand.php (3)
src/Command/IndexCommand.php (1)
__construct(19-24)src/Services/MeilisearchManager.php (2)
__construct(51-62)isSearchable(64-69)src/SearchManagerInterface.php (1)
isSearchable(22-22)
src/Command/MeilisearchImportCommand.php (3)
src/DataProvider/DataProviderRegistryInterface.php (1)
getDataProvider(21-21)src/DataProvider/DataProviderInterface.php (2)
provide(18-18)cleanup(34-34)src/DataProvider/OrmEntityProvider.php (2)
provide(21-30)cleanup(54-57)
src/Services/MeilisearchManager.php (5)
src/Engine.php (8)
Engine(44-182)__construct(46-48)index(61-90)remove(100-126)clear(137-140)delete(147-150)search(159-162)count(169-172)src/Model/Aggregator.php (3)
Aggregator(15-84)__construct(32-44)getEntities(51-54)src/SearchableObject.php (2)
SearchableObject(13-80)__construct(28-37)src/DataProvider/DataProviderRegistryInterface.php (1)
getDataProvider(21-21)src/DataProvider/DataProviderInterface.php (1)
getIdentifierValues(32-32)
src/MeilisearchBundle.php (1)
src/DependencyInjection/Compiler/DataProviderPass.php (1)
DataProviderPass(12-40)
src/SearchManagerInterface.php (3)
src/Exception/NotSearchableException.php (1)
NotSearchableException(7-13)src/SearchService.php (11)
isSearchable(20-20)searchableAs(34-34)getConfiguration(27-27)index(36-36)remove(38-38)clear(43-43)deleteByIndexName(50-50)delete(48-48)search(59-64)rawSearch(73-77)count(84-84)src/Collection.php (1)
Collection(13-380)
🪛 GitHub Actions: Tests
src/Services/MeilisearchService.php
[error] 27-27: PHPMD: TooManyPublicMethods - The class MeilisearchService has 11 public methods. Consider refactoring MeilisearchService to keep number of public methods under 10.
[error] 27-27: PHPMD: ExcessiveClassComplexity - The class MeilisearchService has an overall complexity of 67 which is very high. The configured complexity threshold is 50.
[error] 27-27: PHPMD: CouplingBetweenObjects - The class MeilisearchService has a coupling between objects value of 16. Consider to reduce the number of dependencies under 13.
[error] 48-48: PHPMD: LongVariable - Avoid excessively long variable names like $classToSerializerGroup. Keep variable name length under 20.
[error] 57-57: PHPMD: StaticAccess - Avoid using static access to class '\Symfony\Component\PropertyAccess\PropertyAccess' in method '__construct'.
[error] 415-415: PHPMD: LongVariable - Avoid excessively long variable names like $searchableEntitiesChunk. Keep variable name length under 20.
[error] 463-463: PHPMD: StaticAccess - Avoid using static access to class '\Doctrine\ORM\Proxy\DefaultProxyClassNameResolver' in method 'resolveClass'.
[error] 467-467: PHPMD: StaticAccess - Avoid using static access to class '\Doctrine\Common\Util\ClassUtils' in method 'resolveClass'.
src/DependencyInjection/MeilisearchExtension.php
[error] 22-22: PHPMD: IfStatementAssignment - Avoid assigning values to variables in if clauses and the like (line '45', column '20').
[error] 36-36: PHPMD: StaticAccess - Avoid using static access to class '\Meilisearch\Bundle\MeilisearchBundle' in method 'load'.
[error] 52-52: PHPMD: ElseExpression - The method load uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them.
[error] 60-60: PHPMD: StaticAccess - Avoid using static access to class '\Meilisearch\Bundle\MeilisearchBundle' in method 'load'.
[error] 117-117: PHPMD: ElseExpression - The method registerDataProviders uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them.
src/Services/SettingsUpdater.php
[error] 35-35: PHPMD: CyclomaticComplexity - The method update() has a Cyclomatic Complexity of 13. The configured cyclomatic complexity threshold is 10.
src/Command/MeilisearchImportCommand.php
[error] 24-24: PHPMD: CouplingBetweenObjects - The class MeilisearchImportCommand has a coupling between objects value of 14. Consider to reduce the number of dependencies under 13.
[error] 73-73: PHPMD: CyclomaticComplexity - The method execute() has a Cyclomatic Complexity of 14. The configured cyclomatic complexity threshold is 10.
[error] 73-73: PHPMD: NPathComplexity - The method execute() has an NPath complexity of 976. The configured NPath complexity threshold is 200.
src/Services/MeilisearchManager.php
[error] 27-27: PHPMD: ExcessiveClassComplexity - The class MeilisearchManager has an overall complexity of 65 which is very high. The configured complexity threshold is 50.
[error] 27-27: PHPMD: CouplingBetweenObjects - The class MeilisearchManager has a coupling between objects value of 13. Consider to reduce the number of dependencies under 13.
[error] 435-435: PHPMD: StaticAccess - Avoid using static access to class '\Doctrine\ORM\Proxy\DefaultProxyClassNameResolver' in method 'resolveClass'.
[error] 439-439: PHPMD: StaticAccess - Avoid using static access to class '\Doctrine\Common\Util\ClassUtils' in method 'resolveClass'.
🔇 Additional comments (49)
composer.json (3)
21-21: PHP 8.1 and Symfony 6.4/7.0 requirements are consistent.The PHP version bump to 8.1 and Symfony constraints to
^6.4 || ^7.0align with the stated PR objectives. The removal ofsymfony/polyfill-php80(referenced in the summary) is correct given the new PHP 8.1 floor.Also applies to: 24-29
32-32: The review comment cannot be verified as written. The current state ofcomposer.jsonshowsdoctrine/doctrine-bundleis already inrequire-dev(line 32), not in therequiresection. The comment treats this as a breaking change that requires documentation updates, but the final state alone does not establish that this is a new change in this PR. Without additional context confirming that doctrine-bundle was previously inrequireand moved torequire-dev, the premise of the review cannot be substantiated.Additionally, the README.md mentions "Support Doctrine ORM" in the requirements section but provides no configuration details for the ORM provider or doctrine-bundle setup. If the intent is to ensure documentation exists for using the Doctrine ORM integration, that concern should be stated directly rather than framed as documenting a migration.
Likely an incorrect or invalid review comment.
49-49: The symfony/http-client patch versions are security-critical and justified.The constraints
^6.4.15 || ^7.1.8address CVE-2024-50342, which allows internal IP/port enumeration via NoPrivateNetworkHttpClient hostname resolution. These specific patch versions are the first releases that fixed this security vulnerability in their respective minor version branches. The constraints are necessary and should be maintained.tests/Entity/Actor.php (1)
7-14: LGTM!The Actor entity is well-structured as a simple immutable test fixture using PHP 8.1 constructor property promotion with readonly properties. The implementation is clean and idiomatic.
src/Searchable.php (1)
7-20: LGTM!The deprecation notices properly guide users to the new
SearchableObjectclass and its constants, providing a clear migration path. The notices are well-documented and consistent with the broader refactoring introduced in this PR.tests/Integration/Command/MeilisearchImportCommandTest.php (1)
181-189: LGTM!The test expectation update correctly reflects the new batch processing order introduced by the manager-driven import flow. The aggregated index now processes before the primary index for the Tag entity, which aligns with the refactored batch aggregation logic.
src/Command/MeilisearchClearCommand.php (1)
30-30: LGTM!The migration from
searchServicetosearchManageris clean and maintains the same method signature. This aligns with the PR's objective of introducing theSearchManagerInterfaceand deprecating the oldSearchService.tests/Integration/Command/MeilisearchClearCommandTest.php (1)
39-39: LGTM!The test expectation correctly includes the new Actor index introduced in this PR. The output format is consistent with the other cleared indices.
tests/Entity/SelfNormalizable.php (2)
9-9: LGTM!The import migration from the deprecated
Searchableclass to the newSearchableObjectis appropriate and aligns with the broader refactoring in this PR.
66-66: LGTM!The constant reference is correctly updated to use
SearchableObject::NORMALIZATION_FORMAT, maintaining consistency with the import change and the deprecation of theSearchableclass.tests/config/meilisearch.yaml (1)
57-60: LGTM!The new Actor index configuration demonstrates the custom data provider functionality introduced in this PR. The configuration is well-structured with explicit
type: 'custom'and references to theActorDataProvider, serving as a good example of the new DataProvider extension point.tests/Entity/Link.php (1)
9-10: Good update toSearchableObjectnormalization constants.
Keeps the test entity aligned with the new normalization entry point.Also applies to: 74-84
tests/Unit/ConfigurationTest.php (1)
108-156: Test expectations updated consistently for new index metadata fields.
The added “custom primary key” case is a useful regression test for the newprimary_keyoption (Line 359+).Also applies to: 158-217, 219-257, 259-339, 359-402
src/Exception/LogicException.php (1)
1-9: Simple, fine addition for a bundle-specific exception type.src/MeilisearchBundle.php (1)
7-25: Compiler pass registration inbuild()looks correct.
parent::build()is called andDataProviderPassis registered (Line 20-25).tests/Integration/EventListener/DoctrineEventSubscriberTest.php (1)
14-134: Test updates correctly match newsearch(string $className, ...)signature.src/Command/IndexCommand.php (1)
8-28: LGTM! Clean migration to SearchManagerInterface.The refactoring from
SearchServicetoSearchManagerInterfaceis well-executed with constructor property promotion (PHP 8.1+) and consistent configuration access throughout the class.src/Exception/NotSearchableException.php (1)
7-13: LGTM! Well-designed exception class.The exception follows best practices: marked
final, extends appropriate base class, has proper type hints (includingint $code), and provides a clear, formatted message.tests/Integration/Fixtures/ActorDataProvider.php (1)
15-70: LGTM! Test fixture appropriately demonstrates custom provider flexibility.This fixture showcases how
DataProviderInterfacecan be implemented with custom logic. The implementation is internally consistent and serves its purpose as a test demonstration.tests/Integration/EngineTest.php (2)
35-42: Tests updated to use SearchableObject with new signature.The migration from
SearchableEntitytoSearchableObjectcorrectly reflects the new API with explicitprimaryKey,identifier,serializer, andnormalizationContextparameters.
67-69: Consistent usage of SearchableObject across multiple entity tests.Both test cases properly instantiate
SearchableObjectwith the required parameters and validate removal/indexing behavior.src/DataProvider/DataProviderInterface.php (1)
12-34: Well-designed interface with strong type annotations.The interface uses PHP 8.1+ generics appropriately, has clear method signatures, and detailed PHPDoc annotations including
positive-int,non-negative-int, andnon-empty-arrayconstraints.src/Model/Aggregator.php (2)
32-36: Well-structured constructor with configurable primary key.The addition of the
$primaryKeyparameter with a default of'objectID'maintains backward compatibility while enabling the flexibility required by PR objective #66. Constructor property promotion is clean and idiomatic for PHP 8.1+.
80-83: Dynamic primary key in normalization - behavior is correct.The normalization correctly uses
$this->primaryKeyinstead of hardcoded'objectID'. Thearray_merge([$this->primaryKey => $this->objectID], $normalizer->normalize(...))call means if the normalized entity contains a field matching$this->primaryKey, the entity's value takes precedence. This is the intended behavior—entity data takes priority—as demonstrated by test cases inAggregatorTest.php(lines 86-100), which verify that whenprimaryKey='id', the entity's normalizedidfield is preserved in the final output. Since the aggregator'sobjectIDis always derived from the entity's identifier, values are consistent and there are no conflicts.tests/BaseKernelTestCase.php (3)
10-27: LGTM! Clean migration to SearchManagerInterface in test base.The refactoring consistently replaces
SearchServicewithSearchManagerInterfacethroughout the test base class, properly updating service retrieval and configuration access.
47-52: Improved task waiting logic.The new implementation properly iterates through all tasks and waits for each one individually, which is more robust than the previous approach.
54-72: Consistent usage of SearchManagerInterface in cleanup methods.Both
cleanUp()andcleanupIndex()correctly use the new manager interface for configuration access and index deletion operations.src/DependencyInjection/MeilisearchExtension.php (2)
124-136: ORM provider registration is well-implemented.The method correctly:
- Generates unique service IDs using
xxh32hash to avoid collisions- Creates provider definitions with Doctrine reference and target class
- Tags providers with index and class metadata for registry lookup
34-68: Service wiring updated for manager-based architecture.The early parameter setting and manager argument configuration align well with the new
SearchManagerInterfaceand data provider infrastructure introduced in this PR.tests/Integration/SearchTest.php (3)
71-92: LGTM! Proper migration to manager-based API with task synchronization.The addition of
waitForAllTasks()before search operations ensures async indexing completes before assertions. The API migration fromsearchServicetosearchManagercorrectly removes theObjectManagerparameter, aligning with the newSearchManagerInterfacesignature.
114-121: LGTM! Pagination test correctly updated.Task synchronization added and search call properly migrated to the new manager API.
137-142: LGTM! Results count test properly migrated.Follows the same pattern as other tests with
waitForAllTasks()before search operations.src/Command/MeilisearchUpdateSettingsCommand.php (2)
22-28: LGTM! Clean migration to SearchManagerInterface with constructor promotion.The constructor now uses PHP 8 promoted properties consistently with other commands in this PR, and correctly delegates to the parent
IndexCommandconstructor.
56-58: LGTM! Correct usage of the new manager interface.The
isSearchablecheck properly uses$this->searchManagerwhich is inherited fromIndexCommand.tests/Unit/SerializationTest.php (1)
23-30: LGTM! Constructor updated to match new SearchableObject signature.The migration correctly:
- Uses
'id'as the primary key field name (replacing the objectID concept)- Passes the identifier directly via
$post->getId()instead of relying on Doctrine metadata- Uses the standard Symfony Serializer
'groups'context keyThis aligns with the PR objective to support non-Doctrine/plain objects by removing metadata dependencies.
src/Command/MeilisearchCreateCommand.php (2)
23-30: LGTM! Consistent migration to SearchManagerInterface.Constructor uses promoted properties and follows the same pattern as other commands in this PR.
66-68: LGTM! Correct usage of manager's isSearchable method.src/Services/SettingsUpdater.php (1)
23-29: LGTM! Clean migration to SearchManagerInterface.Constructor correctly obtains configuration from the new manager interface and uses promoted properties consistently with other classes in this PR.
tests/Integration/AggregatorTest.php (3)
24-34: Good coverage for objectID parsing + unknown-entity failure paths.
These two tests are straightforward and help lock down error handling forgetEntityClassFromObjectID().
36-43: Constructor exception test looks correct for “multiple primary keys” guard.
The expectation aligns with the new stricter constructor contract.
69-100: Normalization tests nicely cover default primary key vs custom primary key.
Verifying both'objectID'and custom'id'output is valuable for the newprimary_keycapability.src/SearchableObject.php (2)
13-38: Clean, minimal value object for “indexUid/primaryKey/identifier + normalization context”.
The constructor forcingmeilisearch=truein context is a good, predictable hook for custom normalizers.
65-79: Normalization flow is side-effect free and Symfony-version guarded.
Copying$this->normalizationContextinto a local$contextavoids surprising reuse issues.src/Services/MeilisearchService.php (1)
66-283: Deprecation + delegation pattern is consistent.
Triggering the deprecation and delegating when$this->manageris available preserves BC while nudging users to the manager.config/services.php (1)
72-81: Manager + DataProviderRegistry wiring is cohesive and matches the new extension point.
Good: commands/subscriber/updater are all pointed at the manager, and the registry is a dedicated service.Also applies to: 82-125, 129-135
src/Command/MeilisearchImportCommand.php (1)
121-151: Batch import loop looks correct (provider reuse + empty-batch break + cleanup).
Provider is resolved once per index andcleanup()is called both on the final empty batch and on normal iterations.src/SearchManagerInterface.php (1)
15-107: Interface contract is consistent with the batch/chunk return shape used by commands.
In particular,index()returning alist<...>matches the “list of chunks” iteration pattern inMeilisearchImportCommand::formatIndexingResponse().src/Services/MeilisearchManager.php (2)
95-112: Verifyprimary_keyis always present in index config (or add a default).
Multiple paths assume$indexConfig['primary_key']/$index['primary_key']exists. If YAML config makes it optional, this should defensively default (e.g.,'objectID'or'id') at config normalization time or here.Also applies to: 155-162, 202-227
7-20: Remove LegacyReflectionFields import and use string literal in class_exists() check to reduce coupling.The
Doctrine\ORM\Mapping\LegacyReflectionFieldsclass is correctly used as the marker for PHP 8.4 native lazy objects compatibility. Since it's only used once in theclass_exists()check at line 431, removing the import and converting to a string literal will drop CouplingBetweenObjects from 13 to 12 while maintaining identical behavior.Remove the import at line 8:
-use Doctrine\ORM\Mapping\LegacyReflectionFields;Update the check at line 431:
- if (PHP_VERSION_ID >= 80400 && class_exists(LegacyReflectionFields::class)) { + if (PHP_VERSION_ID >= 80400 && class_exists('Doctrine\\ORM\\Mapping\\LegacyReflectionFields')) {Apply the same change at the second occurrence in lines 423-443.
Likely an incorrect or invalid review comment.
b7abc5d to
dc67a8f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/Model/Aggregator.php (1)
30-44: Ensure aggregator’s primary key value is not overridden by the entity’s normalized data.Right now:
return array_merge( [$this->primaryKey => $this->objectID], $normalizer->normalize($this->entity, $format, $context), );If the normalized entity already has a field with the same name as
$this->primaryKey(e.g. primary key'id'), its value will override$this->objectID, defeating the purpose of using the aggregator’s combined identifier as the actual primary key.To keep the aggregator’s ID authoritative, flip the merge order:
- return array_merge([$this->primaryKey => $this->objectID], $normalizer->normalize($this->entity, $format, $context)); + return array_merge( + $normalizer->normalize($this->entity, $format, $context), + [$this->primaryKey => $this->objectID], + );This preserves all entity fields while guaranteeing that the configured primary key field contains the aggregator’s normalized identifier.
Also applies to: 80-83
♻️ Duplicate comments (2)
.php-cs-fixer.dist.php (1)
12-15: Remove redundantsetUnsupportedPhpVersionAllowed(true)call.The method is already invoked on Line 12; the second call on Line 15 is a no-op and just adds noise. Suggest deleting the duplicate line.
->setRiskyAllowed(true) ->setFinder($finder) - ->setUnsupportedPhpVersionAllowed(true) ->setRules([src/DependencyInjection/Configuration.php (1)
53-62: Add config validation:type=customshould requiredata_provider.As previously flagged, setting
type: customwithout configuringdata_providerwill likely cause a runtime error. Adding validation here provides a clear error at config time.->end() + ->validate() + ->ifTrue(static fn (array $v): bool => 'custom' === ($v['type'] ?? null) && null === ($v['data_provider'] ?? null)) + ->thenInvalid('When index "type" is set to "custom", "data_provider" must be configured.') + ->end() ->end() ->end()
🧹 Nitpick comments (5)
src/Identifier/IdNormalizerInterface.php (1)
7-12: Interface shape is reasonable; consider tightening the PHPDoc only if needed.The contract matches
ConcatenatingIdNormalizerand the data‑provider usage. If you ever need stronger static guarantees, you could narrow the PHPDoc to something likenon-empty-array<string, scalar|\Stringable>to reflect current usage, but that’s purely optional at this point.src/DependencyInjection/Compiler/DataProviderPass.php (1)
20-39: Data provider wiring looks correct; consider how you want to handle the static-access warning.The pass correctly builds a
ServiceLocatorplus anindex => class => locatorKeymap frommeilisearch.data_providertags and injects them into the registry; resolution logic inMeilisearchManager/DataProviderRegistryshould work fine with this shape.The pipeline’s
StaticAccesswarning onServiceLocatorTagPass::register()is essentially about style: that method is designed to be called statically, so there isn’t a non‑static alternative. If you care about a clean report, it’s probably better to tune or suppress this specific rule forServiceLocatorTagPass::classthan to try to change the code here.src/DataProvider/DataProviderInterface.php (1)
7-36: Interface contract is solid; you might want to clarify identifier array shape.The generic
DataProviderInterface<T>and the split betweenprovide(),loadByIdentifiers(),getIdentifierValues()andnormalizeIdentifiers()fit the new provider model well.One minor improvement would be to document the expected shape of
$identifiersinloadByIdentifiers()(e.g., list of scalar IDs vs. associativefield => value), so custom providers implement it consistently withOrmEntityProviderand the registry.src/Identifier/ConcatenatingIdNormalizer.php (1)
21-26: Consider usingimplode()for cleaner concatenation.The loop with manual string concatenation and
rtrim()can be simplified:- $objectID = ''; - foreach ($identifiers as $value) { - $objectID .= $value.'-'; - } - - return rtrim($objectID, '-'); + return implode('-', $identifiers);src/Services/MeilisearchManager.php (1)
195-234: UsenormalizeIdentifiers()insearch()to mirror indexing ID formatting.Right now
search()re-derives lookup keys fromgetIdentifierValues()andimplode('-'…), while indexing usesDataProviderInterface::normalizeIdentifiers()inbatchProcess(). That duplication risks subtle mismatches for custom data providers and future changes to identifier formatting.You can centralize the contract and guarantee symmetry between indexing and hydration by keying
objectsByIdwithnormalizeIdentifiers()directly:- $dataProvider = $this->dataProviderRegistry->getDataProvider($index['name'], $baseClassName); - $loadedObjects = $dataProvider->loadByIdentifiers($identifiers); - $objectsById = []; - foreach ($loadedObjects as $object) { - $identifiers = $dataProvider->getIdentifierValues($object); - $key = 1 === \count($identifiers) ? (string) reset($identifiers) : implode('-', $identifiers); - $objectsById[$key] = $object; - } + $dataProvider = $this->dataProviderRegistry->getDataProvider($index['name'], $baseClassName); + $loadedObjects = $dataProvider->loadByIdentifiers($identifiers); + $objectsById = []; + foreach ($loadedObjects as $object) { + $identifier = $dataProvider->normalizeIdentifiers($object); + $objectsById[$identifier] = $object; + }This keeps
search()aligned with the provider contract and the ID representation actually sent to Meilisearch, while simplifying the manager code. Please double-check that all currentDataProviderInterfaceimplementations already treatnormalizeIdentifiers()as the canonical ID encoding (which they appear to, based on the existing usage inbatchProcess()andOrmEntityProvider).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (62)
.github/workflows/pre-release-tests.yml(2 hunks).github/workflows/tests.yml(2 hunks).php-cs-fixer.dist.php(1 hunks)composer.json(1 hunks)config/services.php(3 hunks)phpstan-baseline.php(1 hunks)phpstan.dist.neon(1 hunks)src/Command/IndexCommand.php(2 hunks)src/Command/MeilisearchClearCommand.php(1 hunks)src/Command/MeilisearchCreateCommand.php(3 hunks)src/Command/MeilisearchDeleteCommand.php(1 hunks)src/Command/MeilisearchImportCommand.php(7 hunks)src/Command/MeilisearchUpdateSettingsCommand.php(3 hunks)src/DataProvider/DataProviderInterface.php(1 hunks)src/DataProvider/DataProviderRegistry.php(1 hunks)src/DataProvider/DataProviderRegistryInterface.php(1 hunks)src/DataProvider/OrmEntityProvider.php(1 hunks)src/DependencyInjection/Compiler/DataProviderPass.php(1 hunks)src/DependencyInjection/Configuration.php(2 hunks)src/DependencyInjection/MeilisearchExtension.php(4 hunks)src/Engine.php(5 hunks)src/Event/SettingsUpdatedEvent.php(1 hunks)src/EventListener/ConsoleOutputSubscriber.php(1 hunks)src/EventListener/DoctrineEventSubscriber.php(1 hunks)src/Exception/DataProviderNotFoundException.php(1 hunks)src/Exception/InvalidIndiceException.php(1 hunks)src/Exception/LogicException.php(1 hunks)src/Exception/NotSearchableException.php(1 hunks)src/Identifier/ConcatenatingIdNormalizer.php(1 hunks)src/Identifier/IdNormalizerInterface.php(1 hunks)src/MeilisearchBundle.php(2 hunks)src/Model/Aggregator.php(3 hunks)src/SearchManagerInterface.php(1 hunks)src/SearchService.php(1 hunks)src/Searchable.php(1 hunks)src/SearchableEntity.php(2 hunks)src/SearchableObject.php(1 hunks)src/Services/MeilisearchManager.php(1 hunks)src/Services/MeilisearchService.php(9 hunks)src/Services/SettingsUpdater.php(2 hunks)src/Services/UnixTimestampNormalizer.php(1 hunks)tests/BaseKernelTestCase.php(5 hunks)tests/Entity/Actor.php(1 hunks)tests/Entity/Link.php(2 hunks)tests/Entity/SelfNormalizable.php(2 hunks)tests/Entity/Tag.php(2 hunks)tests/Integration/AggregatorTest.php(2 hunks)tests/Integration/Command/MeilisearchClearCommandTest.php(1 hunks)tests/Integration/Command/MeilisearchCreateCommandTest.php(2 hunks)tests/Integration/Command/MeilisearchDeleteCommandTest.php(1 hunks)tests/Integration/Command/MeilisearchImportCommandTest.php(1 hunks)tests/Integration/EngineTest.php(3 hunks)tests/Integration/EventListener/DoctrineEventSubscriberTest.php(8 hunks)tests/Integration/Fixtures/ActorDataProvider.php(1 hunks)tests/Integration/SearchTest.php(4 hunks)tests/Kernel.php(1 hunks)tests/Unit/ConfigurationTest.php(10 hunks)tests/Unit/SerializationTest.php(2 hunks)tests/baseline-ignore(1 hunks)tests/config/doctrine_php7.yaml(0 hunks)tests/config/framework.yaml(1 hunks)tests/config/meilisearch.yaml(1 hunks)
💤 Files with no reviewable changes (1)
- tests/config/doctrine_php7.yaml
🚧 Files skipped from review as they are similar to previous changes (22)
- src/Command/IndexCommand.php
- tests/Kernel.php
- tests/Entity/SelfNormalizable.php
- tests/Entity/Link.php
- tests/Entity/Actor.php
- src/MeilisearchBundle.php
- src/DependencyInjection/MeilisearchExtension.php
- phpstan-baseline.php
- src/DataProvider/OrmEntityProvider.php
- src/SearchService.php
- src/DataProvider/DataProviderRegistryInterface.php
- src/Searchable.php
- src/EventListener/DoctrineEventSubscriber.php
- src/SearchableEntity.php
- tests/Integration/Command/MeilisearchImportCommandTest.php
- tests/Integration/Command/MeilisearchClearCommandTest.php
- phpstan.dist.neon
- src/SearchManagerInterface.php
- tests/config/framework.yaml
- tests/config/meilisearch.yaml
- src/Exception/DataProviderNotFoundException.php
- src/Exception/LogicException.php
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: norkunas
Repo: meilisearch/meilisearch-symfony PR: 391
File: src/Command/MeilisearchImportCommand.php:117-120
Timestamp: 2025-08-05T04:46:01.119Z
Learning: In meilisearch-symfony project, the maintainer norkunas prefers to keep PRs focused and defer error handling improvements for settings updates to separate PRs, particularly when it involves decisions about partial import behavior when some indexes fail.
📚 Learning: 2025-08-05T04:46:01.119Z
Learnt from: norkunas
Repo: meilisearch/meilisearch-symfony PR: 391
File: src/Command/MeilisearchImportCommand.php:117-120
Timestamp: 2025-08-05T04:46:01.119Z
Learning: In meilisearch-symfony project, the maintainer norkunas prefers to keep PRs focused and defer error handling improvements for settings updates to separate PRs, particularly when it involves decisions about partial import behavior when some indexes fail.
Applied to files:
src/EventListener/ConsoleOutputSubscriber.phptests/Integration/EngineTest.phpsrc/Services/UnixTimestampNormalizer.phptests/Integration/AggregatorTest.phpsrc/Command/MeilisearchImportCommand.phptests/Integration/Fixtures/ActorDataProvider.phpsrc/DependencyInjection/Configuration.phpsrc/Engine.phpconfig/services.phpsrc/Services/MeilisearchManager.php.github/workflows/tests.yml
🧬 Code graph analysis (26)
tests/Entity/Tag.php (1)
src/SearchableObject.php (1)
SearchableObject(13-80)
src/Identifier/IdNormalizerInterface.php (6)
src/Identifier/ConcatenatingIdNormalizer.php (1)
normalize(9-27)src/Model/Aggregator.php (1)
normalize(80-83)src/Services/UnixTimestampNormalizer.php (1)
normalize(14-17)tests/Entity/Link.php (1)
normalize(74-85)tests/Entity/SelfNormalizable.php (1)
normalize(64-75)tests/Entity/Tag.php (1)
normalize(88-100)
src/Identifier/ConcatenatingIdNormalizer.php (1)
src/Identifier/IdNormalizerInterface.php (1)
normalize(12-12)
tests/BaseKernelTestCase.php (3)
src/SearchManagerInterface.php (2)
getConfiguration(33-33)deleteByIndexName(67-67)src/SearchService.php (2)
getConfiguration(27-27)deleteByIndexName(50-50)src/Services/MeilisearchManager.php (2)
getConfiguration(85-88)deleteByIndexName(183-186)
src/DependencyInjection/Compiler/DataProviderPass.php (1)
src/Services/MeilisearchManager.php (1)
index(90-139)
tests/Integration/SearchTest.php (3)
tests/BaseKernelTestCase.php (1)
waitForAllTasks(47-52)src/SearchManagerInterface.php (2)
search(88-88)rawSearch(98-98)src/Services/MeilisearchManager.php (2)
search(195-234)rawSearch(236-244)
src/Command/MeilisearchClearCommand.php (5)
src/Engine.php (1)
clear(137-140)src/SearchManagerInterface.php (1)
clear(60-60)src/SearchService.php (1)
clear(43-43)src/Services/MeilisearchManager.php (1)
clear(176-181)src/Services/MeilisearchService.php (1)
clear(172-183)
tests/Integration/AggregatorTest.php (5)
src/Model/Aggregator.php (2)
getEntityClassFromObjectID(69-78)normalize(80-83)src/Exception/EntityNotFoundInObjectID.php (1)
EntityNotFoundInObjectID(7-9)src/Exception/InvalidEntityForAggregator.php (1)
InvalidEntityForAggregator(7-9)src/Identifier/ConcatenatingIdNormalizer.php (1)
normalize(9-27)src/Identifier/IdNormalizerInterface.php (1)
normalize(12-12)
src/Exception/NotSearchableException.php (2)
src/Exception/DataProviderNotFoundException.php (1)
__construct(9-12)src/Exception/InvalidIndiceException.php (1)
__construct(9-12)
tests/Integration/EventListener/DoctrineEventSubscriberTest.php (3)
src/Engine.php (1)
search(159-162)src/SearchManagerInterface.php (1)
search(88-88)src/Services/MeilisearchManager.php (1)
search(195-234)
src/Command/MeilisearchCreateCommand.php (3)
src/Command/IndexCommand.php (1)
__construct(19-24)src/SearchManagerInterface.php (1)
isSearchable(22-22)src/Services/MeilisearchManager.php (1)
isSearchable(64-69)
src/Command/MeilisearchImportCommand.php (5)
src/Engine.php (2)
__construct(46-48)index(61-90)src/SearchManagerInterface.php (2)
getConfiguration(33-33)index(42-42)src/DataProvider/DataProviderRegistry.php (1)
getDataProvider(21-36)src/DataProvider/DataProviderRegistryInterface.php (1)
getDataProvider(21-21)src/DataProvider/DataProviderInterface.php (2)
provide(18-18)cleanup(36-36)
tests/Integration/Fixtures/ActorDataProvider.php (3)
tests/Entity/Actor.php (1)
Actor(7-14)src/DataProvider/DataProviderInterface.php (5)
provide(18-18)loadByIdentifiers(25-25)getIdentifierValues(32-32)normalizeIdentifiers(34-34)cleanup(36-36)src/Identifier/IdNormalizerInterface.php (1)
normalize(12-12)
src/DependencyInjection/Configuration.php (1)
src/SearchableObject.php (1)
SearchableObject(13-80)
src/DataProvider/DataProviderRegistry.php (2)
src/Exception/DataProviderNotFoundException.php (2)
DataProviderNotFoundException(7-13)__construct(9-12)src/DataProvider/DataProviderRegistryInterface.php (1)
getDataProvider(21-21)
src/Engine.php (1)
src/SearchableObject.php (5)
SearchableObject(13-80)getSearchableArray(65-79)getIndexUid(42-45)getPrimaryKey(50-53)getIdentifier(55-58)
config/services.php (7)
src/DataProvider/DataProviderRegistry.php (1)
DataProviderRegistry(10-37)src/Engine.php (1)
Engine(44-182)src/EventListener/DoctrineEventSubscriber.php (1)
DoctrineEventSubscriber(10-30)src/Identifier/ConcatenatingIdNormalizer.php (1)
ConcatenatingIdNormalizer(7-28)src/Services/MeilisearchManager.php (1)
MeilisearchManager(27-420)src/Services/SettingsUpdater.php (1)
SettingsUpdater(17-78)src/Services/UnixTimestampNormalizer.php (1)
UnixTimestampNormalizer(9-30)
src/Command/MeilisearchUpdateSettingsCommand.php (4)
src/Command/IndexCommand.php (1)
__construct(19-24)src/Command/MeilisearchCreateCommand.php (1)
__construct(23-30)src/Services/MeilisearchManager.php (2)
__construct(51-62)isSearchable(64-69)src/SearchManagerInterface.php (1)
isSearchable(22-22)
src/Services/MeilisearchManager.php (5)
src/Engine.php (8)
Engine(44-182)__construct(46-48)index(61-90)remove(100-126)clear(137-140)delete(147-150)search(159-162)count(169-172)src/SearchableObject.php (2)
SearchableObject(13-80)__construct(28-37)src/DataProvider/OrmEntityProvider.php (4)
__construct(16-21)getIdentifierValues(49-54)normalizeIdentifiers(56-59)loadByIdentifiers(34-47)src/DataProvider/DataProviderRegistryInterface.php (1)
getDataProvider(21-21)src/DataProvider/DataProviderInterface.php (3)
getIdentifierValues(32-32)normalizeIdentifiers(34-34)loadByIdentifiers(25-25)
src/Command/MeilisearchDeleteCommand.php (4)
src/SearchManagerInterface.php (1)
deleteByIndexName(67-67)src/SearchService.php (1)
deleteByIndexName(50-50)src/Services/MeilisearchManager.php (1)
deleteByIndexName(183-186)src/Services/MeilisearchService.php (1)
deleteByIndexName(185-194)
src/Services/SettingsUpdater.php (2)
src/SearchManagerInterface.php (1)
getConfiguration(33-33)src/Services/MeilisearchManager.php (1)
getConfiguration(85-88)
src/Model/Aggregator.php (2)
src/Identifier/ConcatenatingIdNormalizer.php (1)
normalize(9-27)src/Identifier/IdNormalizerInterface.php (1)
normalize(12-12)
tests/Unit/SerializationTest.php (1)
src/SearchableObject.php (1)
SearchableObject(13-80)
src/Services/MeilisearchService.php (1)
src/Services/MeilisearchManager.php (11)
isSearchable(64-69)getConfiguration(85-88)searchableAs(71-83)index(90-139)remove(141-174)clear(176-181)deleteByIndexName(183-186)delete(188-193)search(195-234)rawSearch(236-244)count(246-251)
src/DataProvider/DataProviderInterface.php (2)
src/DataProvider/OrmEntityProvider.php (5)
provide(23-32)loadByIdentifiers(34-47)getIdentifierValues(49-54)normalizeIdentifiers(56-59)cleanup(61-64)tests/Integration/Fixtures/ActorDataProvider.php (5)
provide(21-50)loadByIdentifiers(52-63)getIdentifierValues(65-70)normalizeIdentifiers(72-75)cleanup(77-80)
src/SearchableObject.php (4)
src/SearchableEntity.php (3)
__construct(42-56)getIndexUid(58-61)getSearchableArray(66-91)src/Identifier/ConcatenatingIdNormalizer.php (1)
normalize(9-27)src/Identifier/IdNormalizerInterface.php (1)
normalize(12-12)src/Services/UnixTimestampNormalizer.php (1)
normalize(14-17)
🪛 GitHub Actions: Tests
src/DependencyInjection/Compiler/DataProviderPass.php
[warning] 37-37: StaticAccess: Avoid using static access to class '\Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass' in method 'process'.
src/Services/UnixTimestampNormalizer.php
[warning] 14-14: UnusedFormalParameter: Avoid unused parameters such as '$format'.
[warning] 14-14: UnusedFormalParameter: Avoid unused parameters such as '$context'.
[warning] 19-19: UnusedFormalParameter: Avoid unused parameters such as '$format'.
[warning] 24-24: UnusedFormalParameter: Avoid unused parameters such as '$format'.
src/Command/MeilisearchImportCommand.php
[warning] 24-24: CouplingBetweenObjects: The class MeilisearchImportCommand has a coupling between objects value of 14. Consider to reduce the number of dependencies under 13.
[warning] 73-73: CyclomaticComplexity: The method execute() has a Cyclomatic Complexity of 14. The configured cyclomatic complexity threshold is 10.
[warning] 73-73: NPathComplexity: The method execute() has an NPath complexity of 976. The configured NPath complexity threshold is 200.
src/Services/MeilisearchManager.php
[warning] 27-27: ExcessiveClassComplexity: The class MeilisearchManager has an overall complexity of 60 which is very high. The configured complexity threshold is 50.
[warning] 411-411: StaticAccess: Avoid using static access to class '\Doctrine\ORM\Proxy\DefaultProxyClassNameResolver' in method 'resolveClass'.
[warning] 415-415: StaticAccess: Avoid using static access to class '\Doctrine\Common\Util\ClassUtils' in method 'resolveClass'.
src/Services/SettingsUpdater.php
[warning] 35-35: CyclomaticComplexity: The method update() has a Cyclomatic Complexity of 13. The configured cyclomatic complexity threshold is 10.
src/Services/MeilisearchService.php
[warning] 27-27: TooManyPublicMethods: The class MeilisearchService has 11 public methods. Consider refactoring MeilisearchService to keep number of public methods under 10.
[warning] 27-27: ExcessiveClassComplexity: The class MeilisearchService has an overall complexity of 67 which is very high. The configured complexity threshold is 50.
[warning] 27-27: CouplingBetweenObjects: The class MeilisearchService has a coupling between objects value of 16. Consider to reduce the number of dependencies under 13.
[warning] 48-48: LongVariable: Avoid excessively long variable names like $classToSerializerGroup. Keep variable name length under 20.
[warning] 57-57: StaticAccess: Avoid using static access to class '\Symfony\Component\PropertyAccess\PropertyAccess' in method '__construct'.
[warning] 415-415: LongVariable: Avoid excessively long variable names like $searchableEntitiesChunk. Keep variable name length under 20.
[warning] 463-463: StaticAccess: Avoid using static access to class '\Doctrine\ORM\Proxy\DefaultProxyClassNameResolver' in method 'resolveClass'.
[warning] 467-467: StaticAccess: Avoid using static access to class '\Doctrine\Common\Util\ClassUtils' in method 'resolveClass'.
🔇 Additional comments (46)
src/EventListener/ConsoleOutputSubscriber.php (1)
13-19: Constructor promotion and$outputrename look goodUsing a
private readonly OutputStyle $outputvia constructor promotion is clean and idiomatic, and the updated$this->output->writeln()usage is consistent. No behavioral changes; PHPMD short variable concern is resolved.src/Event/SettingsUpdatedEvent.php (1)
16-20: Constructor property promotion +readonlylook correct and BC-safeSignature for consumers is unchanged, the promoted properties align with the existing docblocks, and
readonlymatches the previous effectively-immutable behavior of this event. All good from a typing and compatibility standpoint.tests/baseline-ignore (1)
5-5: LGTM! Consistent with the PR's Doctrine modernization.Adding this deprecation suppression for
DefaultProxyClassNameResolveraligns with the broader move toward native lazy objects in PHP 8.1+ and is consistent with other Doctrine proxy deprecations already being suppressed in this baseline.src/Services/UnixTimestampNormalizer.php (2)
11-17: Parameter rename improves consistency.The rename from
$objectto$dataimproves naming consistency with thesupportsNormalizationmethod and aligns with common normalizer conventions. The explicitmixedtype hint correctly reflects theNormalizerInterfacecontract.The pipeline warnings about unused
$formatand$contextparameters are unavoidable—they're required by the interface signature even though this specific normalizer doesn't need them.
19-19: LGTM!Adding the explicit
mixedtype hint aligns with theNormalizerInterfacecontract and improves type declaration consistency across the class.src/Exception/InvalidIndiceException.php (1)
9-12: Constructor type-hint is correct with no backward compatibility impactTyping
$codeasint(Line 9) is correct and consistent with\Exception's signature, and matches the file'sstrict_types=1usage. The codebase contains only one instantiation of this exception (src/Services/SettingsUpdater.php), which passes only the$indiceparameter and relies on the defaultint $code = 0. No callers pass non-int codes, so the change poses no backward compatibility concerns.tests/Integration/Command/MeilisearchCreateCommandTest.php (1)
44-85: Actor index expectation update looks consistent; keep an eye on output ordering.Adding
Creating index sf_phpunit__actor...to both branches aligns the test with the new actor index configuration. Since these assertions useassertSameon the full output, any future change in creation order (e.g., from config reordering or data‑provider changes) will break the test, so just be sure the sequence here matches the intended deterministic order from the command..github/workflows/pre-release-tests.yml (1)
42-65: Pre-release matrix and install options look aligned with composer constraints.The PHP/Symfony matrix (8.1–8.4 / 6.4–7.3 with default/lowest/highest dependencies) plus the
ramsey/composer-installoptions are consistent with the new composer.json requirements and give good coverage of dependency combinations.Also applies to: 79-86
composer.json (1)
21-52: Platform and Symfony constraints align with the new support policy.Bumping PHP to ^8.1, narrowing Symfony components to ^6.4 || ^7.0, and moving
doctrine/doctrine-bundleinto require‑dev are all consistent with the new CI matrices and the “ORM as optional/provider” architecture described in the PR..github/workflows/tests.yml (1)
30-31: CI matrix and Symfony pinning look coherent with composer.json.The integration matrix (PHP 8.1–8.4 / Symfony 6.4–7.3 with dependency variants) matches the supported ranges, and using
SYMFONY_REQUIRE: 7.4.*in the code‑style job to exercise the latest allowed Symfony version is a sensible choice as long as that version is available on Packagist.Also applies to: 100-102
src/Command/MeilisearchClearCommand.php (1)
30-30: LGTM!The migration from
searchServicetosearchManageris consistent with the PR's architectural shift to the manager-based approach. The method signature remains compatible (clear(string $className): array).tests/Entity/Tag.php (1)
9-9: LGTM!The migration from
SearchabletoSearchableObjectis consistent with the broader codebase refactoring. TheNORMALIZATION_FORMATconstant retains the same value ('searchableArray'), ensuring backward-compatible behavior.Also applies to: 90-90
tests/Integration/Command/MeilisearchDeleteCommandTest.php (1)
40-40: LGTM!The additional expected output line reflects the new
actorindex introduced with the data provider architecture. The test correctly validates that all configured indices are deleted.src/Command/MeilisearchDeleteCommand.php (1)
31-39: LGTM!The migration to
searchManageris consistent with the PR's architectural changes. The exception handling correctly skips the success message when deletion fails, ensuring accurate user feedback.tests/Integration/EventListener/DoctrineEventSubscriberTest.php (1)
23-23: LGTM!The test updates correctly reflect the simplified
SearchManagerInterface::search()signature that no longer requires anObjectManagerparameter. The manager internally handles entity loading via the data provider infrastructure.Also applies to: 38-38, 59-59, 81-81, 97-97, 107-107, 121-121, 131-131
tests/Unit/ConfigurationTest.php (2)
362-407: Good test coverage for the newprimary_keyconfiguration option.The test case validates that custom primary keys (
postId,tagId) are correctly processed and preserved in the configuration, supporting the PR's objective to allow configurable primary keys instead of relying solely onobjectID.
409-441: Good test coverage for the newid_normalizerconfiguration option.This test validates that a custom ID normalizer service reference (
acme.id_normalizer) is correctly accepted and stored in the processed configuration.src/DependencyInjection/Configuration.php (2)
7-7: LGTM!Import correctly updated to use
SearchableObjectconsistent with the codebase-wide migration.
64-69: LGTM!The serializer groups configuration correctly references
SearchableObject::NORMALIZATION_GROUP, maintaining consistency with the new class.src/Exception/NotSearchableException.php (1)
7-13: LGTM! Clean exception design.The exception class follows a consistent pattern with other exceptions in the codebase (e.g.,
InvalidIndiceException,DataProviderNotFoundException), provides a clear message, and correctly types all parameters including the addressedint $code.tests/Integration/SearchTest.php (3)
71-92: LGTM! Clean migration to manager-based API with proper async handling.The addition of
waitForAllTasks()before search operations ensures asynchronous indexing completes, and the migration fromsearchServicetosearchManagerconsistently removes theObjectManagerdependency across all test methods.
114-121: LGTM! Consistent async handling in pagination test.The test properly waits for tasks before executing the paginated search with the updated manager API.
137-142: LGTM! Proper async handling added.The
waitForAllTasks()call ensures the import completes before asserting search results.tests/Unit/SerializationTest.php (1)
23-44: LGTM! Clean migration to SearchableObject with explicit ID provisioning.The test correctly migrates from
SearchableEntitytoSearchableObject, replacing Doctrine metadata with explicit primary key and ID values. The unchanged expected array confirms backward compatibility of the serialization output.tests/BaseKernelTestCase.php (3)
10-27: LGTM! Clean migration to SearchManagerInterface.The base test case correctly migrates from
SearchServicetoSearchManagerInterface, enabling the new manager-based architecture across all integration tests.
47-52: LGTM! Improved task waiting with per-task iteration.The updated implementation iterates over all tasks and waits for each individually, ensuring all asynchronous operations complete before proceeding.
54-72: LGTM! Consistent manager usage in cleanup.The cleanup methods correctly use
searchManagerfor configuration access and index deletion, maintaining consistency with the new architecture.src/DataProvider/DataProviderRegistry.php (1)
21-36: LGTM! Efficient provider resolution with inheritance support.The registry uses a two-tier lookup strategy:
- Direct O(1) lookup for exact class matches
- Fallback iteration with
is_a()for polymorphic resolution (parent/child relationships)This design efficiently handles both explicit and inheritance-based provider registration while throwing a descriptive exception when no provider is found.
src/Command/MeilisearchUpdateSettingsCommand.php (2)
22-28: LGTM! Clean migration with constructor promotion.The command correctly migrates to
SearchManagerInterfaceusing PHP 8.1 constructor promotion, simplifying property declarations while maintaining the same functionality.
56-58: LGTM! Consistent manager usage.The
isSearchablecheck correctly uses the newsearchManagerinstance.tests/Integration/Fixtures/ActorDataProvider.php (1)
16-80: LGTM! Well-structured test fixture demonstrating custom provider flexibility.This test fixture appropriately showcases a custom data provider implementation with in-memory data. The
$identifiers['id']access pattern inloadByIdentifiersintentionally differs fromOrmEntityProviderto demonstrate the flexibility of theDataProviderInterface, as confirmed in previous review discussions.src/Command/MeilisearchCreateCommand.php (2)
23-30: LGTM! Clean migration with constructor promotion.The command correctly migrates to
SearchManagerInterfaceusing PHP 8.1 constructor promotion, consistent with other command updates in this PR.
66-68: LGTM! Consistent manager usage.The
isSearchablecheck correctly uses the newsearchManagerinstance, maintaining consistency across all commands.src/Services/SettingsUpdater.php (1)
23-29: LGTM! Clean migration to manager-based architecture.The constructor correctly accepts
SearchManagerInterfaceand retrieves configuration from the manager. The use of promoted constructor properties improves code clarity.src/SearchableObject.php (2)
28-37: LGTM! Clean constructor with proper context initialization.The use of promoted constructor properties is idiomatic, and merging
['meilisearch' => true]into the normalization context ensures the custom normalizers (likeUnixTimestampNormalizer) can detect Meilisearch-specific processing.
65-79: LGTM! Proper context handling avoids state mutation.Creating a local
$contextcopy prevents the mutation issue flagged in past reviews. The conditional DateTime normalization for Symfony 7.1+ is appropriate, and the delegation pattern for normalization is standard.tests/Integration/AggregatorTest.php (2)
69-84: LGTM! Comprehensive test for aggregator normalization.The test verifies that both
objectIDandidfields are present in the serialized data, ensuring proper normalization behavior for aggregated entities.
86-100: LGTM! Good coverage for custom primary key.This test ensures that when a custom primary key (
'id') is specified, the aggregator correctly uses it in the normalized output.src/Services/MeilisearchService.php (2)
50-58: LGTM! Clean deprecation pathway with backward compatibility.The optional
SearchManagerInterfaceparameter enables a gradual migration path. When the manager is present, methods delegate to it; otherwise, the legacy behavior is preserved. This is a well-designed deprecation strategy.
66-77: LGTM! Consistent deprecation pattern.The deprecation notice is clear, and the delegation to the manager (when present) ensures users can migrate incrementally.
config/services.php (1)
74-82: LGTM! Manager service wiring is clean.The
MeilisearchManageris correctly configured with all required dependencies: normalizer, engine, property accessor, data provider registry, and configuration. The alias toSearchManagerInterfaceenables type-hinted autowiring.src/Engine.php (3)
61-90: LGTM! Per-index batching correctly handles multiple primary keys.The refactored batching logic properly tracks the primary key per index (line 78), preventing the bug where a single primary key was used for all indexes. Each index's documents are correctly merged with its own primary key field (line 79), and
addDocumentsis called with the appropriate primary key per index (line 86).
100-126: LGTM! Clean removal logic with per-index grouping.The removal method correctly groups identifiers by index and deletes each document individually. This ensures proper per-index handling.
174-181: LGTM! Simplified identifier normalization.The
normalizeIdhelper is cleaner than before—it simply casts objects to strings without checking for__toStringexplicitly, relying on the type constraint\Stringable|string|intto ensure compatibility.src/Command/MeilisearchImportCommand.php (2)
28-36: LGTM! Clean migration to manager-based architecture.The constructor correctly accepts
SearchManagerInterfaceandDataProviderRegistryInterface, enabling the data provider abstraction that was a core objective of this PR (objective #121).
121-151: LGTM! Efficient data provider usage and proper cleanup.The data provider is obtained once before the loop (line 121), avoiding repeated lookups. The early break on empty batches (lines 126-130) prevents unnecessary indexing calls, and cleanup is called appropriately to release resources.
dc67a8f to
842be8c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (2)
tests/Integration/EngineTest.php (1)
35-42: Hardcoded 'objectID' still contradicts PR objective #66.Despite the previous comment being marked as addressed, 'objectID' is still hardcoded here and on lines 68-69. PR objective #66 aims to remove Algolia-specific "objectID" terminology in favor of MeiliSearch primary key semantics.
Consider using 'id' consistently:
$searchableImage = new SearchableObject( $this->getPrefix().'image', - 'objectID', + 'id', $image, $image->getId(), $this->get('serializer'), ['groups' => ['force_empty']], );config/services.php (1)
138-142: Alias target forIdNormalizerInterfacemust reference the registered service idThe service is registered with id
'meilisearch.identifier.concatenating_id_normalizer', but the alias targetsConcatenatingIdNormalizer::classwhich is not a registered service id. This will cause autowiring ofIdNormalizerInterfaceto fail. Update the alias to target the actual service id:$services ->set('meilisearch.identifier.concatenating_id_normalizer', ConcatenatingIdNormalizer::class) - ->alias(IdNormalizerInterface::class, ConcatenatingIdNormalizer::class) + ->alias(IdNormalizerInterface::class, 'meilisearch.identifier.concatenating_id_normalizer') ;
🧹 Nitpick comments (3)
src/DependencyInjection/MeilisearchExtension.php (1)
100-111: Silent skip when configureddata_providerservice doesn't exist.If a user configures
data_provider: some_servicebut the service doesn't exist in the container, this silently skips tagging and continues without warning. The user would only discover the misconfiguration at runtime when theDataProviderNotFoundExceptionis thrown.Consider throwing a configuration exception for a clearer fail-fast behavior:
if (null !== $indice['data_provider']) { - if ($container->hasDefinition($indice['data_provider'])) { - $container - ->findDefinition($indice['data_provider']) - ->addTag('meilisearch.data_provider', [ - 'index' => $indexName, - 'class' => $class, - ]); + if (!$container->hasDefinition($indice['data_provider'])) { + throw new \InvalidArgumentException(\sprintf( + 'Data provider service "%s" configured for index "%s" does not exist.', + $indice['data_provider'], + $indexName + )); } + + $container + ->findDefinition($indice['data_provider']) + ->addTag('meilisearch.data_provider', [ + 'index' => $indexName, + 'class' => $class, + ]); continue; }src/DependencyInjection/Compiler/DataProviderPass.php (1)
25-34: Add validation for required tag attributes.Lines 27-28 access
$attributes['index']and$attributes['class']without validation, which could throw undefined array key errors if a service is tagged incorrectly.Apply this diff to add validation:
foreach ($container->findTaggedServiceIds('meilisearch.data_provider') as $id => $tags) { foreach ($tags as $attributes) { + if (!isset($attributes['index'], $attributes['class'])) { + throw new \InvalidArgumentException(\sprintf('Service "%s" tagged as "meilisearch.data_provider" must have "index" and "class" attributes.', $id)); + } + $index = $attributes['index']; $class = $attributes['class'];src/Engine.php (1)
10-42: Engine batching and task typing are consistent with the new SearchableObject flowPer‑index grouping in
index()(primary key + documents) and corresponding aggregation inremove()line up with howSearchableObjectexposes index UID, primary key, and identifier. The added phpstan type aliases make the Meilisearch task shapes explicit without changing behavior. If you ever need to optimize deletions,deleteDocuments()could replace the inner per‑id loop inremove(), but that’s purely an optional micro‑optimization.Also applies to: 61-87, 100-125, 174-181
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (61)
.github/workflows/pre-release-tests.yml(2 hunks).github/workflows/tests.yml(2 hunks)composer.json(1 hunks)config/services.php(3 hunks)phpstan-baseline.php(1 hunks)phpstan.dist.neon(1 hunks)src/Command/IndexCommand.php(2 hunks)src/Command/MeilisearchClearCommand.php(1 hunks)src/Command/MeilisearchCreateCommand.php(3 hunks)src/Command/MeilisearchDeleteCommand.php(1 hunks)src/Command/MeilisearchImportCommand.php(7 hunks)src/Command/MeilisearchUpdateSettingsCommand.php(3 hunks)src/DataProvider/DataProviderInterface.php(1 hunks)src/DataProvider/DataProviderRegistry.php(1 hunks)src/DataProvider/DataProviderRegistryInterface.php(1 hunks)src/DataProvider/OrmEntityProvider.php(1 hunks)src/DependencyInjection/Compiler/DataProviderPass.php(1 hunks)src/DependencyInjection/Configuration.php(3 hunks)src/DependencyInjection/MeilisearchExtension.php(4 hunks)src/Engine.php(5 hunks)src/Event/SettingsUpdatedEvent.php(1 hunks)src/EventListener/ConsoleOutputSubscriber.php(1 hunks)src/EventListener/DoctrineEventSubscriber.php(1 hunks)src/Exception/DataProviderNotFoundException.php(1 hunks)src/Exception/InvalidIndiceException.php(1 hunks)src/Exception/LogicException.php(1 hunks)src/Exception/NotSearchableException.php(1 hunks)src/Identifier/ConcatenatingIdNormalizer.php(1 hunks)src/Identifier/IdNormalizerInterface.php(1 hunks)src/MeilisearchBundle.php(2 hunks)src/Model/Aggregator.php(3 hunks)src/SearchManagerInterface.php(1 hunks)src/SearchService.php(1 hunks)src/Searchable.php(1 hunks)src/SearchableEntity.php(2 hunks)src/SearchableObject.php(1 hunks)src/Services/MeilisearchManager.php(1 hunks)src/Services/MeilisearchService.php(9 hunks)src/Services/SettingsUpdater.php(2 hunks)src/Services/UnixTimestampNormalizer.php(1 hunks)tests/BaseKernelTestCase.php(5 hunks)tests/Entity/Actor.php(1 hunks)tests/Entity/Link.php(2 hunks)tests/Entity/SelfNormalizable.php(2 hunks)tests/Entity/Tag.php(2 hunks)tests/Integration/AggregatorTest.php(2 hunks)tests/Integration/Command/MeilisearchClearCommandTest.php(1 hunks)tests/Integration/Command/MeilisearchCreateCommandTest.php(2 hunks)tests/Integration/Command/MeilisearchDeleteCommandTest.php(1 hunks)tests/Integration/Command/MeilisearchImportCommandTest.php(1 hunks)tests/Integration/EngineTest.php(3 hunks)tests/Integration/EventListener/DoctrineEventSubscriberTest.php(8 hunks)tests/Integration/Fixtures/ActorDataProvider.php(1 hunks)tests/Integration/SearchTest.php(4 hunks)tests/Kernel.php(1 hunks)tests/Unit/ConfigurationTest.php(10 hunks)tests/Unit/SerializationTest.php(2 hunks)tests/baseline-ignore(1 hunks)tests/config/doctrine_php7.yaml(0 hunks)tests/config/framework.yaml(1 hunks)tests/config/meilisearch.yaml(1 hunks)
💤 Files with no reviewable changes (1)
- tests/config/doctrine_php7.yaml
✅ Files skipped from review due to trivial changes (1)
- phpstan-baseline.php
🚧 Files skipped from review as they are similar to previous changes (23)
- tests/Entity/Tag.php
- tests/Entity/SelfNormalizable.php
- src/DataProvider/DataProviderRegistryInterface.php
- src/SearchableEntity.php
- src/Command/IndexCommand.php
- tests/baseline-ignore
- src/Identifier/ConcatenatingIdNormalizer.php
- src/Searchable.php
- src/SearchManagerInterface.php
- tests/Kernel.php
- phpstan.dist.neon
- src/DataProvider/OrmEntityProvider.php
- src/Command/MeilisearchDeleteCommand.php
- tests/Entity/Link.php
- tests/Unit/ConfigurationTest.php
- .github/workflows/tests.yml
- src/Command/MeilisearchClearCommand.php
- src/Exception/InvalidIndiceException.php
- src/Exception/NotSearchableException.php
- tests/Integration/Command/MeilisearchDeleteCommandTest.php
- tests/BaseKernelTestCase.php
- src/Services/MeilisearchService.php
- tests/Integration/Command/MeilisearchImportCommandTest.php
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: norkunas
Repo: meilisearch/meilisearch-symfony PR: 391
File: src/Command/MeilisearchImportCommand.php:117-120
Timestamp: 2025-08-05T04:46:01.119Z
Learning: In meilisearch-symfony project, the maintainer norkunas prefers to keep PRs focused and defer error handling improvements for settings updates to separate PRs, particularly when it involves decisions about partial import behavior when some indexes fail.
📚 Learning: 2025-08-05T04:46:01.119Z
Learnt from: norkunas
Repo: meilisearch/meilisearch-symfony PR: 391
File: src/Command/MeilisearchImportCommand.php:117-120
Timestamp: 2025-08-05T04:46:01.119Z
Learning: In meilisearch-symfony project, the maintainer norkunas prefers to keep PRs focused and defer error handling improvements for settings updates to separate PRs, particularly when it involves decisions about partial import behavior when some indexes fail.
Applied to files:
src/DependencyInjection/Configuration.phpsrc/EventListener/ConsoleOutputSubscriber.phptests/Integration/EngineTest.phpsrc/Services/UnixTimestampNormalizer.phptests/Integration/Fixtures/ActorDataProvider.phpsrc/Engine.phpconfig/services.phpsrc/Command/MeilisearchImportCommand.phpsrc/Services/MeilisearchManager.phptests/Integration/AggregatorTest.php
🧬 Code graph analysis (24)
src/MeilisearchBundle.php (1)
src/DependencyInjection/Compiler/DataProviderPass.php (1)
DataProviderPass(12-40)
src/Services/SettingsUpdater.php (3)
src/Command/MeilisearchUpdateSettingsCommand.php (1)
__construct(22-28)src/SearchManagerInterface.php (1)
getConfiguration(33-33)src/Services/MeilisearchManager.php (1)
getConfiguration(85-88)
src/Command/MeilisearchUpdateSettingsCommand.php (4)
src/Command/IndexCommand.php (1)
__construct(19-24)src/Services/MeilisearchManager.php (2)
__construct(51-62)isSearchable(64-69)src/SearchManagerInterface.php (1)
isSearchable(22-22)src/SearchService.php (1)
isSearchable(20-20)
src/Identifier/IdNormalizerInterface.php (1)
src/Identifier/ConcatenatingIdNormalizer.php (1)
normalize(9-27)
tests/Integration/EventListener/DoctrineEventSubscriberTest.php (2)
src/SearchManagerInterface.php (1)
search(88-88)src/Services/MeilisearchManager.php (1)
search(195-234)
src/DependencyInjection/Configuration.php (1)
src/SearchableObject.php (1)
SearchableObject(13-80)
src/EventListener/ConsoleOutputSubscriber.php (1)
src/Event/SettingsUpdatedEvent.php (4)
__construct(16-21)SettingsUpdatedEvent(9-46)getSetting(42-45)getIndex(34-37)
tests/Integration/SearchTest.php (3)
src/Engine.php (1)
search(159-162)src/SearchManagerInterface.php (2)
search(88-88)rawSearch(98-98)src/Services/MeilisearchManager.php (2)
search(195-234)rawSearch(236-244)
tests/Integration/EngineTest.php (1)
src/SearchableObject.php (1)
SearchableObject(13-80)
src/DependencyInjection/MeilisearchExtension.php (6)
src/DataProvider/OrmEntityProvider.php (1)
OrmEntityProvider(11-65)src/MeilisearchBundle.php (2)
MeilisearchBundle(11-31)qualifiedVersion(15-18)src/Model/Aggregator.php (2)
Aggregator(15-84)getEntities(51-54)src/Entity/Aggregator.php (1)
Aggregator(9-11)src/Engine.php (1)
index(61-90)src/Services/MeilisearchManager.php (1)
index(90-139)
src/DependencyInjection/Compiler/DataProviderPass.php (5)
src/Engine.php (1)
index(61-90)src/SearchManagerInterface.php (1)
index(42-42)src/SearchService.php (1)
index(36-36)src/Services/MeilisearchManager.php (1)
index(90-139)src/Services/MeilisearchService.php (1)
index(114-147)
tests/Integration/Fixtures/ActorDataProvider.php (2)
src/DataProvider/DataProviderInterface.php (5)
provide(18-18)loadByIdentifiers(25-25)getIdentifierValues(32-32)normalizeIdentifiers(34-34)cleanup(36-36)src/Identifier/IdNormalizerInterface.php (1)
normalize(12-12)
src/SearchableObject.php (1)
src/SearchableEntity.php (3)
__construct(42-56)getIndexUid(58-61)getSearchableArray(66-91)
src/EventListener/DoctrineEventSubscriber.php (2)
src/SearchManagerInterface.php (2)
index(42-42)remove(51-51)src/SearchService.php (2)
index(36-36)remove(38-38)
tests/Unit/SerializationTest.php (1)
src/SearchableObject.php (1)
SearchableObject(13-80)
src/DataProvider/DataProviderInterface.php (2)
src/DataProvider/OrmEntityProvider.php (5)
provide(23-32)loadByIdentifiers(34-47)getIdentifierValues(49-54)normalizeIdentifiers(56-59)cleanup(61-64)tests/Integration/Fixtures/ActorDataProvider.php (5)
provide(21-50)loadByIdentifiers(52-63)getIdentifierValues(65-70)normalizeIdentifiers(72-75)cleanup(77-80)
src/Model/Aggregator.php (2)
src/Identifier/ConcatenatingIdNormalizer.php (1)
normalize(9-27)src/Identifier/IdNormalizerInterface.php (1)
normalize(12-12)
tests/Entity/Actor.php (5)
src/Command/MeilisearchCreateCommand.php (1)
__construct(23-30)src/DataProvider/OrmEntityProvider.php (1)
__construct(16-21)src/Engine.php (1)
__construct(46-48)src/Event/SettingsUpdatedEvent.php (1)
__construct(16-21)src/EventListener/ConsoleOutputSubscriber.php (1)
__construct(13-15)
src/Engine.php (2)
src/SearchableEntity.php (3)
__construct(42-56)getSearchableArray(66-91)getIndexUid(58-61)src/SearchableObject.php (5)
SearchableObject(13-80)getSearchableArray(65-79)getIndexUid(42-45)getPrimaryKey(50-53)getIdentifier(55-58)
src/Command/MeilisearchImportCommand.php (7)
src/Command/IndexCommand.php (1)
__construct(19-24)src/Engine.php (3)
__construct(46-48)index(61-90)count(169-172)src/Services/MeilisearchService.php (5)
__construct(52-64)getConfiguration(87-96)isSearchable(66-77)index(114-147)count(272-283)src/SearchManagerInterface.php (4)
getConfiguration(33-33)isSearchable(22-22)index(42-42)count(106-106)src/DataProvider/DataProviderRegistryInterface.php (1)
getDataProvider(21-21)src/DataProvider/DataProviderInterface.php (2)
provide(18-18)cleanup(36-36)src/DataProvider/OrmEntityProvider.php (2)
provide(23-32)cleanup(61-64)
src/Command/MeilisearchCreateCommand.php (4)
src/Command/IndexCommand.php (1)
__construct(19-24)src/SearchManagerInterface.php (1)
isSearchable(22-22)src/SearchService.php (1)
isSearchable(20-20)src/Services/MeilisearchManager.php (1)
isSearchable(64-69)
src/Exception/DataProviderNotFoundException.php (3)
src/DataProvider/DataProviderRegistry.php (1)
__construct(15-19)src/Exception/InvalidIndiceException.php (1)
__construct(9-12)src/Exception/NotSearchableException.php (1)
__construct(9-12)
src/DataProvider/DataProviderRegistry.php (2)
src/Exception/DataProviderNotFoundException.php (2)
DataProviderNotFoundException(7-13)__construct(9-12)src/DataProvider/DataProviderRegistryInterface.php (1)
getDataProvider(21-21)
src/Services/MeilisearchManager.php (5)
src/Engine.php (8)
Engine(44-182)__construct(46-48)index(61-90)remove(100-126)clear(137-140)delete(147-150)search(159-162)count(169-172)src/Model/Aggregator.php (2)
Aggregator(15-84)__construct(32-44)src/SearchableObject.php (2)
SearchableObject(13-80)__construct(28-37)src/DataProvider/DataProviderRegistryInterface.php (1)
getDataProvider(21-21)src/DataProvider/DataProviderInterface.php (3)
getIdentifierValues(32-32)normalizeIdentifiers(34-34)loadByIdentifiers(25-25)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: integration-tests (PHP 8.1) (Symfony 6.4.*)
🔇 Additional comments (39)
tests/config/framework.yaml (1)
5-7: Test framework error handling looks good.The addition of
handle_all_throwablesandphp_errors.logimproves error visibility in tests, which aligns well with the broader PHP 8.1+ migration and strengthened test rigor.composer.json (1)
21-21: Dependency constraints align well with PR objectives.PHP 8.1+ requirement and Symfony 6.4+ constraints are correct. Moving
doctrine-bundletorequire-devsupports the DataProvider abstraction by decoupling ORM as an optional dependency—a necessary breaking change for enabling custom/non-Doctrine data sources. Removal ofsymfony/polyfill-php80is appropriate for PHP 8.1+. All dev dependencies are properly updated to 6.4+.Also applies to: 24-29, 32-32, 38-38, 41-43, 46-52
.github/workflows/pre-release-tests.yml (1)
42-44: CI matrix refactoring is correct and comprehensive.The removal of PHP 7.4 and Symfony 5.x versions, addition of PHP 8.4, and dependency-aware matrix expansion (lines 54–63 with
lowest/highestvariants for PHP 8.4) appropriately test edge cases for pre-release Meilisearch. The exclusion logic for PHP 8.1 + Symfony 7.x combinations is reasonable. Job naming (line 65) correctly appends the dependency variant for visibility. The ramsey/composer-install usage withdependency-versionsmatrix parameter (lines 84–85) is correct.Also applies to: 54-63, 65-65, 84-85
src/Exception/LogicException.php (1)
7-9: LGTM!The exception class is correctly implemented as a final marker exception. The use of
finalprevents unintended subclassing, and extending\LogicExceptionis appropriate for logic errors in the bundle.src/SearchService.php (1)
9-11: Deprecation notice is clear and aligned with the new APIThe
@deprecateddocblock cleanly communicates both the version (0.16) and the replacement (SearchManagerInterface) without affecting behavior. This is a suitable and non-disruptive way to steer users toward the new manager-based API.src/EventListener/ConsoleOutputSubscriber.php (2)
13-15: LGTM! Constructor property promotion correctly implemented.The rename from
$ioto$outputsuccessfully addresses the PHPMD ShortVariable violation while maintaining clarity. The use ofprivate readonlyfor the promoted property is appropriate for this immutable dependency.
17-20: LGTM! Property usage correctly updated.The reference to
$this->outputis consistent with the renamed constructor property. The event handler correctly uses theSettingsUpdatedEventaccessor methods and provides clear console feedback.src/Identifier/IdNormalizerInterface.php (1)
7-13: LGTM! Clean interface design.The interface is well-designed with a focused responsibility. The return type
string|intcorrectly aligns with MeiliSearch's primary key requirements, and thenon-empty-arrayconstraint in the docblock provides helpful guidance for implementers.src/Services/UnixTimestampNormalizer.php (1)
11-17: LGTM! Signature updated to match Symfony normalizer contract.The parameter renaming from
$objectto$dataand the type widening tomixedalign with Symfony's normalizer interface. The framework guarantees this method is only called aftersupportsNormalization()confirms the type, so the\DateTimeInterfacedocblock serves as helpful documentation of the expected runtime type.src/Event/SettingsUpdatedEvent.php (1)
16-21: LGTM! Clean constructor promotion refactor.The migration to constructor property promotion with
private readonlyis idiomatic for PHP 8.1+ and improves maintainability by eliminating redundant property declarations and assignments. The event remains immutable with no behavioral changes.src/Model/Aggregator.php (2)
32-36: LGTM! Configurable primary key resolves hardcoded objectID issue.The addition of the
$primaryKeyparameter with a default value of'objectID'provides backward compatibility while enabling custom primary keys per index. This addresses the previous TODO and aligns with the PR's objective to eliminate Algolia-specificobjectIDhardcoding.
82-82: LGTM! Dynamic primary key correctly applied in normalization.The normalization logic now uses
$this->primaryKeyinstead of the hardcoded'objectID'string, correctly respecting the configured primary key for each aggregator instance.tests/Integration/Command/MeilisearchClearCommandTest.php (1)
39-39: LGTM! Test updated for new Actor index.The expected output correctly includes the new
Actorindex clearing log, consistent with the addition of the Actor entity and its corresponding data provider configuration in this PR.tests/Integration/Command/MeilisearchCreateCommandTest.php (1)
63-63: LGTM! Test assertions updated for Actor index creation.Both test paths correctly include the Actor index creation log in the expected output, maintaining consistency across scenarios with and without settings updates.
Also applies to: 80-80
tests/Entity/Actor.php (1)
7-14: LGTM! Clean test entity for DataProvider demonstration.The
Actorclass is a straightforward value object using constructor promotion with public readonly properties. This provides a simple, non-Doctrine entity to demonstrate the new custom data provider functionality introduced in this PR.tests/config/meilisearch.yaml (1)
57-60: LGTM! Configuration demonstrates custom DataProvider usage.This configuration entry effectively demonstrates the new DataProvider extension point introduced in this PR. The
type: 'custom'and explicitdata_providerreference show how users can plug in non-Doctrine data sources for their indices.src/MeilisearchBundle.php (1)
20-25: LGTM! Standard Symfony bundle pattern for compiler pass registration.The
build()method correctly callsparent::build()before registering theDataProviderPass, following Symfony best practices for bundle extension.tests/Integration/EventListener/DoctrineEventSubscriberTest.php (1)
23-23: LGTM! Tests correctly updated to use the new SearchManagerInterface API.The search calls are consistently migrated from
searchService->search($entityManager, $class, $query)tosearchManager->search($class, $query), aligning with the PR's objective to remove Doctrine ObjectManager from the public search API.Also applies to: 38-38, 59-59, 81-81, 97-97, 107-107, 121-121, 131-131
src/Exception/DataProviderNotFoundException.php (1)
7-13: LGTM! Exception follows established patterns in the codebase.The exception class is consistent with other exceptions like
NotSearchableExceptionandInvalidIndiceException, providing a clear, actionable error message with both index name and class name for debugging.tests/Integration/SearchTest.php (3)
71-72: LGTM! Proper synchronization added for async operations.Adding
waitForAllTasks()after the import command ensures all async Meilisearch indexing operations complete before executing search assertions. This prevents flaky tests due to race conditions.Also applies to: 75-75, 81-81, 90-90
114-116: LGTM! Test properly waits for indexing before pagination test.
137-139: LGTM! Consistent pattern applied for nbResults test.src/DependencyInjection/Configuration.php (2)
53-62: LGTM! New configuration nodes properly structured.The new
type,primary_key,data_provider, andid_normalizerconfiguration options are well-defined with appropriate defaults. TheobjectIDdefault forprimary_keymaintains backward compatibility as discussed in previous reviews.
104-107: LGTM! Validation rule correctly implemented.The validation ensures
data_providermust be configured whentypeis set to'custom', providing a clear config-time error instead of a runtime failure. This addresses the concern from the previous review.tests/Integration/AggregatorTest.php (2)
25-43: LGTM! Good test coverage for error cases.The tests properly verify:
- Entity class extraction from objectID format
- Exception thrown for unknown entities
- Exception thrown when aggregators receive multiple primary keys
69-100: LGTM! New normalization tests cover key scenarios.
testAggregatorNormalizationverifies the defaultobjectIDprimary key behavior, whiletestAggregatorCustomPrimaryKeyconfirms custom primary key names work correctly. These tests support the PR's objective of configurable primary keys.src/DependencyInjection/MeilisearchExtension.php (2)
125-141: LGTM! ORM provider registration is well-structured.The helper method creates deterministic service IDs using a hash of the class name, preventing collisions while keeping IDs debuggable. The
OrmEntityProvideris properly wired with doctrine registry, id normalizer, and target class.
66-68: LGTM! Manager service wiring updated for new architecture.The argument replacements align with
MeilisearchManager's constructor expectations for the serializer and configuration.src/EventListener/DoctrineEventSubscriber.php (1)
8-28: LGTM! Clean migration to SearchManagerInterface.The refactoring successfully removes the Doctrine ObjectManager dependency from search operations, aligning with the PR's goal of decoupling data retrieval from the search layer. The constructor promotion and readonly properties are idiomatic for PHP 8.1+.
src/DataProvider/DataProviderRegistry.php (1)
21-36: LGTM! Class hierarchy matching is correctly implemented.The two-phase lookup (exact match followed by inheritance check) correctly handles both direct class registration and polymorphic provider resolution. The
is_a($className, $registeredClass, true)call properly checks class relationships using string class names.tests/Unit/SerializationTest.php (1)
23-30: LGTM! Test correctly migrated to SearchableObject.The test properly uses the new SearchableObject API with explicit primary key ('id'), identifier value, and serializer injection. The normalization context correctly uses the
groupskey.src/Command/MeilisearchUpdateSettingsCommand.php (1)
22-28: LGTM! Clean migration to SearchManagerInterface.The constructor properly uses property promotion and updates the dependency from SearchService to SearchManagerInterface. The parent constructor call and property references are correctly updated.
src/Services/SettingsUpdater.php (1)
23-29: LGTM! Proper migration to manager-based configuration.The constructor correctly migrates to SearchManagerInterface and uses property promotion for all dependencies. Configuration is now properly sourced from the manager, maintaining the same functionality while improving the architecture.
src/DataProvider/DataProviderInterface.php (1)
10-37: LGTM! Well-designed interface addresses key PR objectives.This interface provides a clean abstraction for data providers with:
- Pagination support via
provide()(batch loading to reduce DB queries per PR objective #134)- Batch loading via
loadByIdentifiers()(further query reduction)- Custom identifier handling via
getIdentifierValues()andnormalizeIdentifiers()(addresses PR objective #240 for custom ID formatting)- Resource cleanup hook
The generic template
Tand return type flexibility (iterablevsarray) demonstrate thoughtful API design.tests/Integration/Fixtures/ActorDataProvider.php (1)
16-80: Test fixture DataProvider is consistent and sufficientConstructor injection of
IdNormalizerInterface, in-memoryprovide()implementation, andnormalizeIdentifiers()delegation form a clean, self‑contained example of a custom provider. Given this is an integration fixture, rebuilding the actor list and linear scanning inloadByIdentifiers()is acceptable; no changes needed.src/SearchableObject.php (1)
28-79: Immutable normalization wrapper looks correctConstructor/context handling and
getSearchableArray()logic are consistent with the existingSearchableEntitybehavior while staying side‑effect free (local$contextcopy, meilisearch flag preserved). This should work well with the new Engine batching.src/Command/MeilisearchCreateCommand.php (1)
23-30: Create command refactor toSearchManagerInterfacelooks soundConstructor wiring to
IndexCommandand the switch to$this->searchManager->isSearchable($entityClassName)match the new manager API and keep behavior unchanged while decoupling from the deprecatedSearchService.Also applies to: 66-67
config/services.php (1)
74-83: Manager, registry, and command wiring are coherent
meilisearch.managerarguments (normalizer, engine, property accessor, data provider registry, configuration) matchMeilisearchManager’s constructor, and all commands/settings services now consistently depend onSearchManagerInterface. This keeps the public surface aligned with the new architecture without breaking existing aliases likeSearchService::class→meilisearch.service.Also applies to: 84-127
src/Command/MeilisearchImportCommand.php (1)
28-36: Import command’s move to data providers and manager-based indexing looks correctThe command now cleanly delegates data loading to
DataProviderRegistryInterfaceand all indexing/clearing toSearchManagerInterface, with a sensiblebatchSizederivation and an early exit on empty batches that still guaranteescleanup()is called. The swap/delete flow usingdeleteByIndexName()keeps engine access centralized in the manager while preserving existing behavior.Also applies to: 79-85, 121-152, 168-189, 235-238
555fb7a to
120c503
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (5)
src/DependencyInjection/MeilisearchExtension.php (1)
125-141: Consider collision risk in hash-based service ID generation.The service ID uses
xxh32hash (line 127) to deduplicate providers for the same class across indices. While xxh32 is fast, it's a 32-bit hash with potential collision risk in large codebases.Consider adding a simple check or using the full class name in the ID instead:
- $definitionId = \sprintf('meilisearch.data_provider.%s_%s', $indexName, hash('xxh32', $class)); + $definitionId = \sprintf('meilisearch.data_provider.%s_%s', $indexName, hash('xxh128', $class));Or use the class name directly if collisions are not a concern:
- $definitionId = \sprintf('meilisearch.data_provider.%s_%s', $indexName, hash('xxh32', $class)); + $definitionId = \sprintf('meilisearch.data_provider.%s.%s', $indexName, str_replace('\\', '.', $class));src/DependencyInjection/Compiler/DataProviderPass.php (1)
25-34: Add validation for required tag attributes.If a service is tagged with
meilisearch.data_providerbut missing theindexorclassattributes, this will produce a confusing "undefined array key" error. Providing a clear exception improves developer experience.foreach ($container->findTaggedServiceIds('meilisearch.data_provider') as $id => $tags) { foreach ($tags as $attributes) { + if (!isset($attributes['index'], $attributes['class'])) { + throw new \InvalidArgumentException(\sprintf( + 'Service "%s" tagged with "meilisearch.data_provider" must have "index" and "class" attributes.', + $id + )); + } + $index = $attributes['index']; $class = $attributes['class'];src/Services/SettingsUpdater.php (1)
23-29: Constructor refactor toSearchManagerInterfaceis sound;update()complexity can be deferredUsing
SearchManagerInterfaceto obtain configuration in the constructor simplifies dependency wiring without changing behavior. The cyclomatic-complexity warning onupdate()stems from the existing branching; if you want to address it, extracting the per-setting update block (lines 51‑76) into a private method would likely satisfy the linter without altering logic, but this can reasonably be done in a separate, focused PR.Also applies to: 35-77
src/Command/MeilisearchImportCommand.php (1)
73-163: Consider complexity reduction in a follow-up.The
execute()method has high cyclomatic (14) and NPath (976) complexity. Consider extracting helper methods for:
- Settings update logic
- Batch processing flow
- Index swapping logic
This would improve maintainability and testability. Given the PR's architectural focus, this can be deferred.
src/Services/MeilisearchManager.php (1)
27-422: Consider extracting responsibilities to reduce complexity.The class has an overall complexity of 59 (threshold: 50). Consider extracting in a follow-up:
- Search hydration logic (lines 214-233) into a dedicated helper/service
- Class resolution (lines 401-421) into a separate
ClassResolverutilityThis would improve maintainability while keeping the core manager focused. Given the PR's architectural scope, this can be deferred.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (62)
.github/workflows/pre-release-tests.yml(2 hunks).github/workflows/tests.yml(2 hunks)composer.json(1 hunks)config/services.php(3 hunks)phpstan-baseline.php(1 hunks)phpstan.dist.neon(1 hunks)src/Command/IndexCommand.php(2 hunks)src/Command/MeilisearchClearCommand.php(1 hunks)src/Command/MeilisearchCreateCommand.php(3 hunks)src/Command/MeilisearchDeleteCommand.php(1 hunks)src/Command/MeilisearchImportCommand.php(7 hunks)src/Command/MeilisearchUpdateSettingsCommand.php(3 hunks)src/DataProvider/DataProviderInterface.php(1 hunks)src/DataProvider/DataProviderRegistry.php(1 hunks)src/DataProvider/DataProviderRegistryInterface.php(1 hunks)src/DataProvider/OrmEntityProvider.php(1 hunks)src/DependencyInjection/Compiler/DataProviderPass.php(1 hunks)src/DependencyInjection/Configuration.php(3 hunks)src/DependencyInjection/MeilisearchExtension.php(4 hunks)src/Engine.php(5 hunks)src/Event/SettingsUpdatedEvent.php(1 hunks)src/EventListener/ConsoleOutputSubscriber.php(1 hunks)src/EventListener/DoctrineEventSubscriber.php(1 hunks)src/Exception/DataProviderNotFoundException.php(1 hunks)src/Exception/InvalidIndiceException.php(1 hunks)src/Exception/LogicException.php(1 hunks)src/Exception/NotSearchableException.php(1 hunks)src/Identifier/DefaultIdNormalizer.php(1 hunks)src/Identifier/IdNormalizerInterface.php(1 hunks)src/MeilisearchBundle.php(2 hunks)src/Model/Aggregator.php(3 hunks)src/SearchManagerInterface.php(1 hunks)src/SearchService.php(1 hunks)src/Searchable.php(1 hunks)src/SearchableEntity.php(2 hunks)src/SearchableObject.php(1 hunks)src/Services/MeilisearchManager.php(1 hunks)src/Services/MeilisearchService.php(9 hunks)src/Services/SettingsUpdater.php(2 hunks)src/Services/UnixTimestampNormalizer.php(1 hunks)tests/BaseKernelTestCase.php(5 hunks)tests/Entity/Actor.php(1 hunks)tests/Entity/Car.php(1 hunks)tests/Entity/Link.php(2 hunks)tests/Entity/SelfNormalizable.php(2 hunks)tests/Entity/Tag.php(2 hunks)tests/Integration/AggregatorTest.php(2 hunks)tests/Integration/Command/MeilisearchClearCommandTest.php(1 hunks)tests/Integration/Command/MeilisearchCreateCommandTest.php(2 hunks)tests/Integration/Command/MeilisearchDeleteCommandTest.php(1 hunks)tests/Integration/Command/MeilisearchImportCommandTest.php(1 hunks)tests/Integration/EngineTest.php(3 hunks)tests/Integration/EventListener/DoctrineEventSubscriberTest.php(8 hunks)tests/Integration/Fixtures/ActorDataProvider.php(1 hunks)tests/Integration/SearchTest.php(5 hunks)tests/Kernel.php(1 hunks)tests/Unit/ConfigurationTest.php(10 hunks)tests/Unit/SerializationTest.php(2 hunks)tests/baseline-ignore(1 hunks)tests/config/doctrine_php7.yaml(0 hunks)tests/config/framework.yaml(1 hunks)tests/config/meilisearch.yaml(1 hunks)
💤 Files with no reviewable changes (1)
- tests/config/doctrine_php7.yaml
🚧 Files skipped from review as they are similar to previous changes (18)
- src/Services/UnixTimestampNormalizer.php
- tests/Entity/Tag.php
- src/DataProvider/DataProviderRegistryInterface.php
- src/EventListener/ConsoleOutputSubscriber.php
- phpstan.dist.neon
- src/MeilisearchBundle.php
- tests/Integration/Command/MeilisearchImportCommandTest.php
- src/Exception/LogicException.php
- src/Exception/InvalidIndiceException.php
- tests/config/framework.yaml
- src/Model/Aggregator.php
- src/Command/IndexCommand.php
- src/SearchService.php
- src/Event/SettingsUpdatedEvent.php
- phpstan-baseline.php
- tests/config/meilisearch.yaml
- tests/Integration/EngineTest.php
- tests/Entity/SelfNormalizable.php
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: norkunas
Repo: meilisearch/meilisearch-symfony PR: 391
File: src/Command/MeilisearchImportCommand.php:117-120
Timestamp: 2025-08-05T04:46:01.119Z
Learning: In meilisearch-symfony project, the maintainer norkunas prefers to keep PRs focused and defer error handling improvements for settings updates to separate PRs, particularly when it involves decisions about partial import behavior when some indexes fail.
📚 Learning: 2025-08-05T04:46:01.119Z
Learnt from: norkunas
Repo: meilisearch/meilisearch-symfony PR: 391
File: src/Command/MeilisearchImportCommand.php:117-120
Timestamp: 2025-08-05T04:46:01.119Z
Learning: In meilisearch-symfony project, the maintainer norkunas prefers to keep PRs focused and defer error handling improvements for settings updates to separate PRs, particularly when it involves decisions about partial import behavior when some indexes fail.
Applied to files:
tests/Integration/AggregatorTest.phptests/Integration/Fixtures/ActorDataProvider.phpsrc/SearchManagerInterface.php.github/workflows/tests.ymlsrc/Engine.phpconfig/services.phpsrc/Command/MeilisearchImportCommand.phpsrc/DataProvider/OrmEntityProvider.phpsrc/DependencyInjection/Configuration.phpsrc/Services/MeilisearchManager.php
🧬 Code graph analysis (28)
src/DependencyInjection/MeilisearchExtension.php (4)
src/DataProvider/OrmEntityProvider.php (1)
OrmEntityProvider(10-86)src/MeilisearchBundle.php (2)
MeilisearchBundle(11-31)qualifiedVersion(15-18)src/Model/Aggregator.php (2)
Aggregator(15-84)getEntities(51-54)src/Entity/Aggregator.php (1)
Aggregator(9-11)
tests/Entity/Link.php (1)
src/SearchableObject.php (1)
SearchableObject(13-80)
src/Identifier/DefaultIdNormalizer.php (1)
src/Identifier/IdNormalizerInterface.php (2)
normalize(12-12)denormalize(21-21)
tests/Kernel.php (1)
src/DependencyInjection/MeilisearchExtension.php (1)
load(22-73)
src/Command/MeilisearchUpdateSettingsCommand.php (5)
src/Command/IndexCommand.php (1)
__construct(19-24)src/Command/MeilisearchCreateCommand.php (1)
__construct(23-30)src/Services/MeilisearchManager.php (2)
__construct(51-62)isSearchable(64-69)src/SearchManagerInterface.php (1)
isSearchable(22-22)src/Services/MeilisearchService.php (1)
isSearchable(66-77)
src/EventListener/DoctrineEventSubscriber.php (2)
src/SearchManagerInterface.php (2)
index(42-42)remove(51-51)src/SearchService.php (2)
index(36-36)remove(38-38)
src/DependencyInjection/Compiler/DataProviderPass.php (2)
src/Services/MeilisearchManager.php (1)
index(90-139)src/Services/MeilisearchService.php (1)
index(114-147)
src/Services/MeilisearchService.php (3)
src/EventListener/DoctrineEventSubscriber.php (1)
__construct(12-14)src/SearchManagerInterface.php (11)
isSearchable(22-22)getConfiguration(33-33)searchableAs(31-31)index(42-42)remove(51-51)clear(60-60)deleteByIndexName(67-67)delete(76-76)search(88-88)rawSearch(98-98)count(106-106)src/Services/MeilisearchManager.php (13)
isSearchable(64-69)getBaseClassName(278-285)getConfiguration(85-88)searchableAs(71-83)index(90-139)remove(141-174)clear(176-181)assertIsSearchable(367-372)deleteByIndexName(183-186)delete(188-193)search(195-236)rawSearch(238-246)count(248-253)
tests/Integration/SearchTest.php (5)
tests/BaseKernelTestCase.php (1)
waitForAllTasks(47-52)src/SearchManagerInterface.php (2)
search(88-88)rawSearch(98-98)src/Services/MeilisearchManager.php (2)
search(195-236)rawSearch(238-246)tests/Entity/ContentItem.php (1)
getTitle(53-56)tests/Entity/Post.php (1)
getTitle(104-107)
src/DataProvider/DataProviderRegistry.php (2)
src/Exception/DataProviderNotFoundException.php (2)
DataProviderNotFoundException(7-13)__construct(9-12)src/DataProvider/DataProviderRegistryInterface.php (1)
getDataProvider(21-21)
src/Exception/NotSearchableException.php (2)
src/Exception/DataProviderNotFoundException.php (1)
__construct(9-12)src/Exception/InvalidIndiceException.php (1)
__construct(9-12)
tests/Integration/AggregatorTest.php (5)
src/Model/Aggregator.php (2)
getEntityClassFromObjectID(69-78)normalize(80-83)src/Exception/EntityNotFoundInObjectID.php (1)
EntityNotFoundInObjectID(7-9)src/Exception/InvalidEntityForAggregator.php (1)
InvalidEntityForAggregator(7-9)src/Identifier/DefaultIdNormalizer.php (1)
normalize(9-31)src/Identifier/IdNormalizerInterface.php (1)
normalize(12-12)
src/Identifier/IdNormalizerInterface.php (1)
src/Identifier/DefaultIdNormalizer.php (2)
normalize(9-31)denormalize(33-39)
tests/Integration/EventListener/DoctrineEventSubscriberTest.php (3)
src/SearchManagerInterface.php (1)
search(88-88)src/Services/MeilisearchManager.php (1)
search(195-236)src/Services/MeilisearchService.php (1)
search(209-254)
src/Command/MeilisearchCreateCommand.php (4)
src/Command/IndexCommand.php (1)
__construct(19-24)src/Command/MeilisearchUpdateSettingsCommand.php (1)
__construct(22-28)src/SearchManagerInterface.php (1)
isSearchable(22-22)src/Services/MeilisearchManager.php (1)
isSearchable(64-69)
tests/Integration/Fixtures/ActorDataProvider.php (3)
tests/Entity/Actor.php (1)
Actor(7-14)src/DataProvider/DataProviderInterface.php (6)
provide(18-18)loadByIdentifiers(25-25)getIdentifierValues(32-32)normalizeIdentifiers(39-39)denormalizeIdentifier(46-46)cleanup(48-48)src/Identifier/IdNormalizerInterface.php (2)
normalize(12-12)denormalize(21-21)
src/SearchManagerInterface.php (6)
src/Exception/NotSearchableException.php (1)
NotSearchableException(7-13)src/SearchService.php (11)
isSearchable(20-20)searchableAs(34-34)getConfiguration(27-27)index(36-36)remove(38-38)clear(43-43)deleteByIndexName(50-50)delete(48-48)search(59-64)rawSearch(73-77)count(84-84)src/Services/MeilisearchManager.php (11)
isSearchable(64-69)searchableAs(71-83)getConfiguration(85-88)index(90-139)remove(141-174)clear(176-181)deleteByIndexName(183-186)delete(188-193)search(195-236)rawSearch(238-246)count(248-253)src/Services/MeilisearchService.php (11)
isSearchable(66-77)searchableAs(98-112)getConfiguration(87-96)index(114-147)remove(149-170)clear(172-183)deleteByIndexName(185-194)delete(196-207)search(209-254)rawSearch(256-270)count(272-283)src/Collection.php (1)
Collection(13-380)src/Engine.php (6)
index(61-90)remove(100-126)clear(137-140)delete(147-150)search(159-162)count(169-172)
src/Engine.php (2)
src/SearchableEntity.php (3)
__construct(42-56)getSearchableArray(66-91)getIndexUid(58-61)src/SearchableObject.php (5)
SearchableObject(13-80)getSearchableArray(65-79)getIndexUid(42-45)getPrimaryKey(50-53)getIdentifier(55-58)
src/DataProvider/DataProviderInterface.php (1)
src/DataProvider/OrmEntityProvider.php (6)
provide(22-31)loadByIdentifiers(33-63)getIdentifierValues(65-70)normalizeIdentifiers(72-75)denormalizeIdentifier(77-80)cleanup(82-85)
tests/Unit/SerializationTest.php (2)
src/SearchableObject.php (1)
SearchableObject(13-80)tests/Entity/Post.php (1)
getId(91-94)
config/services.php (7)
src/DataProvider/DataProviderRegistry.php (1)
DataProviderRegistry(10-37)src/Engine.php (1)
Engine(44-182)src/EventListener/DoctrineEventSubscriber.php (1)
DoctrineEventSubscriber(10-30)src/Identifier/DefaultIdNormalizer.php (1)
DefaultIdNormalizer(7-40)src/Services/MeilisearchManager.php (1)
MeilisearchManager(27-422)src/Services/SettingsUpdater.php (1)
SettingsUpdater(17-78)src/Services/UnixTimestampNormalizer.php (1)
UnixTimestampNormalizer(9-30)
src/Command/MeilisearchImportCommand.php (4)
src/Services/MeilisearchManager.php (5)
getConfiguration(85-88)isSearchable(64-69)index(90-139)count(248-253)deleteByIndexName(183-186)src/DataProvider/DataProviderRegistryInterface.php (1)
getDataProvider(21-21)src/DataProvider/DataProviderInterface.php (2)
provide(18-18)cleanup(48-48)src/DataProvider/OrmEntityProvider.php (2)
provide(22-31)cleanup(82-85)
src/DataProvider/OrmEntityProvider.php (3)
src/DataProvider/DataProviderInterface.php (6)
provide(18-18)loadByIdentifiers(25-25)getIdentifierValues(32-32)normalizeIdentifiers(39-39)denormalizeIdentifier(46-46)cleanup(48-48)src/Identifier/DefaultIdNormalizer.php (2)
denormalize(33-39)normalize(9-31)src/Identifier/IdNormalizerInterface.php (2)
denormalize(21-21)normalize(12-12)
src/Command/MeilisearchClearCommand.php (5)
src/Engine.php (1)
clear(137-140)src/SearchManagerInterface.php (1)
clear(60-60)src/SearchService.php (1)
clear(43-43)src/Services/MeilisearchManager.php (1)
clear(176-181)src/Services/MeilisearchService.php (1)
clear(172-183)
src/DependencyInjection/Configuration.php (1)
src/SearchableObject.php (1)
SearchableObject(13-80)
src/SearchableEntity.php (4)
tests/Entity/Link.php (1)
normalize(74-85)tests/Entity/SelfNormalizable.php (1)
normalize(64-75)tests/Entity/Tag.php (1)
normalize(88-100)src/SearchableObject.php (1)
SearchableObject(13-80)
src/SearchableObject.php (4)
src/SearchableEntity.php (3)
__construct(42-56)getIndexUid(58-61)getSearchableArray(66-91)src/Identifier/DefaultIdNormalizer.php (1)
normalize(9-31)src/Identifier/IdNormalizerInterface.php (1)
normalize(12-12)tests/Entity/SelfNormalizable.php (1)
normalize(64-75)
src/Services/SettingsUpdater.php (3)
src/Command/MeilisearchCreateCommand.php (1)
__construct(23-30)src/SearchManagerInterface.php (1)
getConfiguration(33-33)src/Services/MeilisearchManager.php (1)
getConfiguration(85-88)
🪛 GitHub Actions: Tests
src/DependencyInjection/MeilisearchExtension.php
[warning] 22-22: IfStatementAssignment Avoid assigning values to variables in if clauses and the like (line '45', column '20').
[warning] 36-36: StaticAccess Avoid using static access to class '\Meilisearch.Bundle\MeilisearchBundle' in method 'load'.
[warning] 52-52: ElseExpression The method load uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them.
[warning] 60-60: StaticAccess Avoid using static access to class '\Meilisearch.Bundle\MeilisearchBundle' in method 'load'.
[warning] 118-118: ElseExpression The method registerDataProviders uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them.
src/Identifier/DefaultIdNormalizer.php
[warning] 19-19: MissingImport Missing class import via use statement (line '19', column '27').
src/DependencyInjection/Compiler/DataProviderPass.php
[warning] 37-37: StaticAccess Avoid using static access to class '\Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass' in method 'process'.
src/Services/MeilisearchService.php
[warning] 27-27: TooManyPublicMethods The class MeilisearchService has 11 public methods. Consider refactoring MeilisearchService to keep number of public methods under 10.
[warning] 27-27: ExcessiveClassComplexity The class MeilisearchService has an overall complexity of 67 which is very high. The configured complexity threshold is 50.
[warning] 27-27: CouplingBetweenObjects The class MeilisearchService has a coupling between objects value of 16. Consider to reduce the number of dependencies under 13.
[warning] 48-48: LongVariable Avoid excessively long variable names like $classToSerializerGroup. Keep variable name length under 20.
[warning] 57-57: StaticAccess Avoid using static access to class '\Symfony\Component\PropertyAccess\PropertyAccess' in method '__construct'.
[warning] 415-415: LongVariable Avoid excessively long variable names like $searchableEntitiesChunk. Keep variable name length under 20.
[warning] 463-463: StaticAccess Avoid using static access to class '\Doctrine\ORM\Proxy\DefaultProxyClassNameResolver' in method 'resolveClass'.
[warning] 467-467: StaticAccess Avoid using static access to class '\Doctrine\Common\Util\ClassUtils' in method 'resolveClass'.
tests/Integration/SearchTest.php
[error] 161-161: Test 'MeilisearchBundle\Tests\Integration\SearchTest::testCars' failed due to an error: Call to undefined method Doctrine\ORM\QueryBuilder::createNamedParameter()
src/Command/MeilisearchImportCommand.php
[warning] 24-24: CouplingBetweenObjects The class MeilisearchImportCommand has a coupling between objects value of 14. Consider to reduce the number of dependencies under 13.
[warning] 73-73: CyclomaticComplexity The method execute() has a Cyclomatic Complexity of 14. The configured cyclomatic complexity threshold is 10.
[warning] 73-73: NPathComplexity The method execute() has an NPath complexity of 976. The configured NPath complexity threshold is 200.
src/DataProvider/OrmEntityProvider.php
[error] 54-54: Call to undefined method Doctrine\ORM\QueryBuilder::createNamedParameter()
src/DependencyInjection/Configuration.php
[warning] 14-14: ExcessiveMethodLength The method getConfigTreeBuilder() has 100 lines of code. Current threshold is set to 100. Avoid really long methods.
src/Services/MeilisearchManager.php
[warning] 27-27: ExcessiveClassComplexity The class MeilisearchManager has an overall complexity of 59 which is very high. The configured complexity threshold is 50.
[warning] 413-413: StaticAccess Avoid using static access to class '\Doctrine\ORM\Proxy\DefaultProxyClassNameResolver' in method 'resolveClass'.
[warning] 417-417: StaticAccess Avoid using static access to class '\Doctrine\Common\Util\ClassUtils' in method 'resolveClass'.
src/Services/SettingsUpdater.php
[warning] 35-35: CyclomaticComplexity The method update() has a Cyclomatic Complexity of 13. The configured cyclomatic complexity threshold is 10.
🔇 Additional comments (60)
tests/baseline-ignore (1)
5-5: LGTM! Appropriate baseline addition.Adding this Doctrine ORM deprecation to the baseline is standard practice. The migration to native lazy objects can be addressed in a focused follow-up PR.
src/Searchable.php (1)
7-20: LGTM! Clean deprecation path to SearchableObject.The deprecation docblocks are clear and provide the correct replacement path. The constants remain functional for backward compatibility while guiding users to the new API.
src/Exception/NotSearchableException.php (1)
7-13: LGTM! Well-structured exception class.The exception provides a clear, descriptive message and follows PHP 8.1+ conventions with proper type declarations. The previous review comment about the
inttype hint has been addressed.src/DependencyInjection/MeilisearchExtension.php (1)
93-123: Data provider registration logic is well-structured.The method correctly handles both explicit data provider configuration and automatic ORM provider registration. The aggregator handling (lines 114-117) properly registers providers for each aggregated entity class.
composer.json (1)
21-52: LGTM! Dependency updates align with architectural changes.The PHP 8.1 requirement and Symfony 6.4/7.0 updates support the new data provider architecture. Moving
doctrine-bundleto dev dependencies (line 32) is appropriate given the abstraction layer that now allows non-Doctrine data sources.src/EventListener/DoctrineEventSubscriber.php (1)
12-29: LGTM! Clean migration to SearchManagerInterface.The constructor property promotion is idiomatic PHP 8.1+, and removing the
ObjectManagerparameter fromindex()andremove()calls correctly reflects the new manager API that delegates to data providers.src/Services/MeilisearchService.php (3)
24-26: Deprecation notice is clear.The docblock correctly identifies version 0.16 and points to the appropriate replacement class. Note: The past review comment about the FQN has been addressed.
52-58: Well-designed backward compatibility bridge.The optional manager parameter enables gradual migration. The delegation pattern throughout the class (checking
null !== $this->managerbefore delegating) maintains full backward compatibility while guiding users to the new API.
68-72: Consistent deprecation pattern.The
trigger_deprecation()call followed by delegation when the manager is available is the correct approach. This pattern is consistently applied across all delegated methods.config/services.php (3)
74-82: LGTM! Manager service wiring is correct.The
MeilisearchManageris properly configured with all required dependencies: normalizer, engine, property accessor, data provider registry, and configuration. The alias toSearchManagerInterfaceenables type-hinted dependency injection.
131-136: LGTM! DataProviderRegistry wiring is correct.The service definition correctly uses abstract arguments for the provider locator and map, which will be replaced by the compiler pass. The chained alias (line 136) is valid Symfony syntax, as confirmed by the maintainer.
138-142: LGTM! DefaultIdNormalizer wiring is correct.The service is registered with ID
'meilisearch.identifier.default_id_normalizer'(line 139), and the alias correctly references this service ID string (line 140). The chained alias syntax is valid.src/Command/MeilisearchDeleteCommand.php (1)
32-37: LGTM! Correct manager usage and error handling.The migration from
searchServicetosearchManageraligns with the architectural changes. Thecontinuestatement (line 36) correctly prevents the "Deleted" message (line 39) from being printed after an exception, which would mislead users.src/Command/MeilisearchClearCommand.php (1)
30-30: LGTM! Clean migration to the new manager interface.The replacement of
searchServicewithsearchManageraligns correctly with the architectural refactoring described in the PR objectives.tests/Integration/Command/MeilisearchDeleteCommandTest.php (1)
40-41: LGTM! Test expectations updated for new test entities.The addition of
actorandcarsindex deletion lines correctly reflects the new test entities introduced in this PR.tests/Integration/Command/MeilisearchClearCommandTest.php (1)
39-40: LGTM! Test expectations correctly expanded.The test now accounts for the newly added
ActorandCartest entities, ensuring comprehensive coverage.tests/Entity/Link.php (1)
9-9: LGTM! Consistent migration to SearchableObject.The import and constant reference have been correctly updated from
SearchabletoSearchableObject, aligning with the architectural refactoring throughout the codebase.Also applies to: 76-76
tests/Entity/Actor.php (1)
7-14: LGTM! Clean test entity using PHP 8.1 features.The
Actorclass is appropriately simple for a test fixture, leveraging constructor property promotion and readonly properties.tests/Integration/Command/MeilisearchCreateCommandTest.php (1)
63-64: LGTM! Test expectations updated for comprehensive index coverage.Both test paths (with and without settings updates) now correctly expect the creation of
actorandcarsindices, maintaining test accuracy with the expanded configuration.Also applies to: 81-82
.github/workflows/tests.yml (1)
30-31: LGTM! CI matrix correctly updated for minimum version requirements.The removal of PHP 7.4 and Symfony 5.4 from the test matrix properly aligns with the PR's minimum version bump (PHP 8.1, Symfony 6.4).
tests/Integration/EventListener/DoctrineEventSubscriberTest.php (1)
23-23: LGTM! Clean migration to the new SearchManager API.All test methods consistently updated to use
searchManager->search(EntityClass::class, $query)without the entity manager parameter, aligning with the newSearchManagerInterfacesignature.Also applies to: 38-38, 59-59, 81-81, 97-97, 107-107, 121-121, 131-131
tests/Kernel.php (1)
36-42: LGTM! Bootstrap simplification aligns with PHP 8.1+ requirement.The simplified three-way conditional for Doctrine configuration loading removes PHP 7 specific paths, consistent with the PR's PHP 8.1 baseline.
tests/Entity/Car.php (1)
1-34: LGTM! Useful test entity for composite primary key scenarios.The
Carentity provides test coverage for composite primary keys (name+year), supporting the PR's objective of customizable identifier normalization (issue #240).src/SearchableEntity.php (1)
15-17: LGTM! Deprecation pathway is clear.The deprecation of
SearchableEntityin favor ofSearchableObjectis well-marked, and both normalization format constant references correctly updated to useSearchableObject::NORMALIZATION_FORMAT.Also applies to: 83-83, 87-87
tests/Unit/ConfigurationTest.php (3)
29-29: LGTM! Method signatures modernized for PHP 8.1+.The addition of
mixedtype hints aligns with the PHP 8.1 requirement and improves type safety.Also applies to: 47-47
135-138: LGTM! Configuration expectations updated for ORM-based data providers.All existing test scenarios now correctly expect the new ORM metadata fields:
type,data_provider,id_normalizer, andprimary_key. Defaults are appropriate (type: 'orm',primary_key: 'objectID').Also applies to: 147-150, 193-196, 205-208, 246-249, 288-291, 330-333
362-407: LGTM! Test coverage for custom primary keys and id normalizers.The new test scenarios validate:
- Custom primary key configuration (
postId,tagId)- Custom id normalizer configuration (
acme.id_normalizer)This coverage aligns with PR objectives for configurable identifiers (issues #66, #240).
Also applies to: 409-441
src/Exception/DataProviderNotFoundException.php (1)
1-13: LGTM! Well-designed exception for data provider lookups.The
DataProviderNotFoundExceptionprovides clear context (index name and class name) for debugging failed provider lookups.tests/Integration/AggregatorTest.php (4)
24-27: LGTM! Test coverage for aggregator entity class resolution.New tests validate:
- Successful entity class extraction from objectID
- Proper exception throwing for unknown entities
Also applies to: 29-34
36-43: LGTM! Constructor validation updated for new signature.The test correctly validates that aggregators reject multiple primary keys, now using the updated
ContentAggregatorconstructor with theprimaryKeyNameparameter.
45-67: LGTM! Proxy handling test updated for new constructor.The test correctly constructs
ContentAggregatorwith the new signature and validates serialization through the Symfony Serializer.
69-84: LGTM! Comprehensive normalization test coverage.New tests validate:
- Default normalization behavior with
objectIDprimary key- Custom primary key configuration (
id)- Proper serialization output structure
This supports the PR's objective of configurable primary keys (issue #66).
Also applies to: 86-100
.github/workflows/pre-release-tests.yml (2)
42-63: LGTM! Enhanced CI matrix for better compatibility testing.The expanded matrix now tests:
- PHP 8.1-8.4 across Symfony 6.4-7.3
- Dependency variations (lowest/highest) for PHP 8.4
This strengthens compatibility guarantees for the new baseline requirements.
65-65: LGTM! Improved job naming and dependency-driven installation.The dynamic job naming and matrix-driven
dependency-versionsparameter improve CI clarity and maintainability.Also applies to: 84-85
src/DependencyInjection/Configuration.php (2)
53-62: New configuration nodes look well-structured.The added configuration options for
type,primary_key,data_provider, andid_normalizeralign with the PR objectives for supporting custom data providers and configurable primary keys. The enum constraint ontypeand the default values are appropriate.
104-107: Validation correctly enforcesdata_providerfor custom type.This addresses the earlier review feedback and ensures users receive a clear configuration error rather than a runtime failure.
tests/Integration/SearchTest.php (1)
72-76: Good addition ofwaitForAllTasks()before assertions.Adding synchronization after import ensures async indexing operations complete before running search assertions. This prevents flaky tests.
src/DependencyInjection/Compiler/DataProviderPass.php (1)
37-38: Static access toServiceLocatorTagPass::register()is idiomatic.The pipeline warning about static access is a false positive here. Using
ServiceLocatorTagPass::register()is the standard Symfony pattern for creating service locators in compiler passes.tests/BaseKernelTestCase.php (1)
10-27: Migration toSearchManagerInterfaceis consistent.The property type, import, and service retrieval are all correctly updated to use the new manager interface.
src/DataProvider/DataProviderRegistry.php (1)
21-36: Data provider resolution logic is consistent and type-safeExact match, then inheritance/interface-based fallback, and a clear exception on miss make the registry behavior predictable and easy to reason about. The phpdoc on
$dataProvidersMapalso aligns with the usage.src/DataProvider/DataProviderInterface.php (1)
7-48: Identifier normalization contract is well-shapedThe added
normalizeIdentifiers/denormalizeIdentifiermethods and non-empty-array/phpdoc constraints give a clear, symmetric contract for single and composite identifiers while keeping implementations flexible.src/Command/MeilisearchUpdateSettingsCommand.php (1)
22-27: Migration toSearchManagerInterfacelooks correctConstructor promotion and the switch to
$this->searchManager->isSearchable()align this command with the new manager-based API and withIndexCommand/MeilisearchCreateCommand.Also applies to: 56-56
tests/Unit/SerializationTest.php (1)
7-30: Test update toSearchableObjectmatches the new APIThe constructor arguments (index UID, primary key, entity, identifier, serializer, and groups context) align with
SearchableObject’s signature and keep the previous serialization expectations intact.tests/Integration/Fixtures/ActorDataProvider.php (1)
14-85: Fixture correctly demonstrates a customDataProviderInterfaceimplementationThis provider cleanly showcases a non‑ORM data source with its own identifier shape (associative
['id' => ...]) and delegates normalization concerns toIdNormalizerInterface, which is exactly the kind of flexibility the DataProvider abstraction is meant to support.src/SearchableObject.php (1)
13-79:SearchableObjectencapsulation and normalization behavior look goodImmutable constructor state, a non‑mutating
getSearchableArray()that adjusts DateTime handling based onKernel::VERSION_ID, and support for bothNormalizableInterfaceand generic normalization make this a solid replacement for the older entity‑centric wrapper.src/DataProvider/OrmEntityProvider.php (1)
33-63: Review comment is based on outdated code that does not match the repositoryThe code snippet shown calls
$queryBuilder->createNamedParameter($value), but the actual code insrc/DataProvider/OrmEntityProvider.php(lines 33–63) already implements the correct solution usingsetParameter()with manually-constructed named parameters. The problematic method call is commented out as a future enhancement for Doctrine ORM >= 3.3. No changes are needed.Likely an incorrect or invalid review comment.
src/SearchManagerInterface.php (1)
1-107: LGTM! Clean interface contract.The interface is well-designed with comprehensive type hints, proper PHPDoc annotations, and clear method signatures. The use of phpstan type imports for Engine types improves type safety across the codebase.
src/Command/MeilisearchCreateCommand.php (2)
23-30: LGTM! Clean constructor with promoted properties.The constructor properly uses PHP 8.1+ promoted properties and correctly passes the
SearchManagerInterfaceto the parent class. This aligns well with the new manager-based architecture.
66-66: LGTM! Correct usage of SearchManagerInterface.The
isSearchable()call correctly uses the newSearchManagerInterfacemethod.src/Engine.php (4)
46-48: LGTM! Clean constructor with promoted property.The constructor properly uses PHP 8.1+ promoted property syntax, making the code more concise.
61-90: LGTM! Correct per-index batching with primary keys.The implementation correctly tracks primary keys per index and batches documents accordingly. The fix from the previous review ensures different indexes with different primary keys are handled properly.
100-126: LGTM! Consistent per-index removal logic.The removal logic correctly batches by index and issues individual
deleteDocumentcalls per identifier, maintaining consistency with the indexing approach.
174-181: LGTM! Simplified and type-safe identifier normalization.The tightened signature using
\Stringable|string|intprovides better type safety, and the simplified logic correctly handles all cases.src/Command/MeilisearchImportCommand.php (2)
28-36: LGTM! Constructor properly wired for data provider architecture.The constructor correctly injects the new
DataProviderRegistryInterfaceand uses promoted properties effectively. The number of dependencies reflects the command's legitimate responsibilities.
121-151: LGTM! Correct data provider usage with proper cleanup.The data provider is correctly obtained outside the loop (addressing the previous review), and the empty batch guard ensures robust handling of edge cases. The cleanup calls are appropriately placed.
src/Services/MeilisearchManager.php (5)
51-62: LGTM! Well-structured manager constructor.The constructor properly injects dependencies and initializes internal state. The immediate setup of searchables and aggregators ensures the manager is ready for use.
90-139: LGTM! Robust indexing with aggregator support.The implementation correctly handles both direct entities and aggregator-wrapped entities, properly gates indexing with
shouldBeIndexed(), and batches operations efficiently.
141-174: LGTM! Consistent removal with proper identifier normalization.The removal logic correctly uses
normalizeIdentifiers()to ensure consistent identifier formatting between indexing and removal operations.
195-236: LGTM! Search with correct identifier normalization and order preservation.The search implementation correctly uses
normalizeIdentifiers()(line 221) to ensure hydration keys match indexed document IDs, addressing the previous review's concern. The order-preserving hydration logic is sound.
401-421: LGTM! Robust class resolution across Doctrine versions.The implementation correctly handles multiple Doctrine versions and PHP 8.4+ native lazy objects. The static access to Doctrine utilities (lines 413, 417) is intentional and appropriate for this compatibility layer, despite the pipeline warning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/Services/SettingsUpdater.php (1)
35-77: Reduceupdate()cyclomatic complexity to satisfy CIThe pipeline flags
update()with cyclomatic complexity 13 (threshold 10). You can keep behavior identical by extracting the per‑setting logic into a private helper and delegating fromupdate().@@ - public function update(string $indice, ?int $responseTimeout = null, ?string $prefixedName = null): void - { - $index = (new Collection($this->configuration->get('indices')))->firstWhere('prefixed_name', $indice); - - if (!\is_array($index)) { - throw new InvalidIndiceException($indice); - } - - if (!\is_array($index['settings'] ?? null) || [] === $index['settings']) { - return; - } - - $indexName = $prefixedName ?? $index['prefixed_name']; - $indexInstance = $this->searchClient->index($indexName); - $responseTimeout = $responseTimeout ?? self::DEFAULT_RESPONSE_TIMEOUT; - - foreach ($index['settings'] as $variable => $value) { - $method = \sprintf('update%s', ucfirst($variable)); - - if (!method_exists($indexInstance, $method)) { - throw new InvalidSettingName(\sprintf('Invalid setting name: "%s"', $variable)); - } - - if (isset($value['_service']) && $value['_service'] instanceof SettingsProvider) { - $value = $value['_service'](); - } elseif (('distinctAttribute' === $variable || 'proximityPrecision' === $variable || 'searchCutoffMs' === $variable) && \is_array($value)) { - $value = $value[0] ?? null; - } - - // Update - $task = $indexInstance->{$method}($value); - - // Get task information using uid - $indexInstance->waitForTask($task['taskUid'], $responseTimeout); - $task = $indexInstance->getTask($task['taskUid']); - - if ('failed' === $task['status']) { - throw new TaskException($task['error']['message']); - } - - $this->eventDispatcher->dispatch(new SettingsUpdatedEvent($index['class'], $indexName, $variable)); - } - } + public function update(string $indice, ?int $responseTimeout = null, ?string $prefixedName = null): void + { + $index = (new Collection($this->configuration->get('indices')))->firstWhere('prefixed_name', $indice); + + if (!\is_array($index)) { + throw new InvalidIndiceException($indice); + } + + if (!\is_array($index['settings'] ?? null) || [] === $index['settings']) { + return; + } + + $indexName = $prefixedName ?? $index['prefixed_name']; + $indexInstance = $this->searchClient->index($indexName); + $responseTimeout = $responseTimeout ?? self::DEFAULT_RESPONSE_TIMEOUT; + + $this->updateIndexSettings($index, $indexInstance, $responseTimeout, $indexName); + } + + /** + * @param array<string,mixed> $index + */ + private function updateIndexSettings(array $index, object $indexInstance, int $responseTimeout, string $indexName): void + { + foreach ($index['settings'] as $variable => $value) { + $method = \sprintf('update%s', ucfirst($variable)); + + if (!method_exists($indexInstance, $method)) { + throw new InvalidSettingName(\sprintf('Invalid setting name: "%s"', $variable)); + } + + if (isset($value['_service']) && $value['_service'] instanceof SettingsProvider) { + $value = $value['_service'](); + } elseif (('distinctAttribute' === $variable || 'proximityPrecision' === $variable || 'searchCutoffMs' === $variable) && \is_array($value)) { + $value = $value[0] ?? null; + } + + $task = $indexInstance->{$method}($value); + + $indexInstance->waitForTask($task['taskUid'], $responseTimeout); + $task = $indexInstance->getTask($task['taskUid']); + + if ('failed' === $task['status']) { + throw new TaskException($task['error']['message']); + } + + $this->eventDispatcher->dispatch(new SettingsUpdatedEvent($index['class'], $indexName, $variable)); + } + }This should bring
update()below the cyclomatic complexity threshold while preserving existing error-handling and event behavior. Based on learnings, this keeps the PR focused on structural changes without altering settings error semantics.
♻️ Duplicate comments (3)
.github/workflows/tests.yml (1)
31-31: Consider adding Symfony 7.4 to the integration test matrix.The integration test matrix on line 31 tests up to Symfony 7.3, while the code-style job on line 101 requires Symfony 7.4.*. This creates an inconsistency where static analysis runs on a Symfony version not covered by integration tests. Since Symfony 7.4 is stable (released December 8, 2025), consider adding
'7.4'to the matrix to ensure comprehensive testing coverage.src/Identifier/DefaultIdNormalizer.php (1)
1-39: Fix identifier type handling and denormalization for simple IDs, and add the missing importTwo coupled issues here:
normalize()can currently return non‑scalar values (e.g. arrays) when a single identifier is not a scalar, despite thestring|intreturn type.denormalize()always assumes a base64‑encoded JSON payload withJSON_THROW_ON_ERROR, so it will throw for simple scalar identifiers like"5"thatnormalize()returns directly.This will both violate the declared return type and break consumers that call
denormalize()on simple IDs.You can address this and the static‑analysis import error with something along these lines:
<?php declare(strict_types=1); namespace Meilisearch\Bundle\Identifier; +use InvalidArgumentException; + final class DefaultIdNormalizer implements IdNormalizerInterface { public function normalize(array $identifiers): string|int { if (1 === \count($identifiers)) { $identifier = reset($identifiers); if (\is_object($identifier) && method_exists($identifier, '__toString')) { return (string) $identifier; } if (\is_object($identifier)) { - throw new \InvalidArgumentException('Identifier object must implement __toString().'); + throw new InvalidArgumentException('Identifier object must implement __toString().'); } - return $identifier; + if (!\is_scalar($identifier)) { + throw new InvalidArgumentException('Single identifier must be a scalar value or an object with __toString().'); + } + + // Preserve ints and strings as‑is; safely cast other scalars (bool/float) to string. + if (\is_int($identifier) || \is_string($identifier)) { + return $identifier; + } + + return (string) $identifier; } ksort($identifiers); $json = json_encode($identifiers, \JSON_THROW_ON_ERROR); $base64 = base64_encode($json); return rtrim(strtr($base64, '+/', '-_'), '='); } public function denormalize(string $identifier): array { - $padded = $identifier.str_repeat('=', (4 - \strlen($identifier) % 4) % 4); - $base64 = strtr($padded, '-_', '+/'); - - return json_decode(base64_decode($base64), true, 512, \JSON_THROW_ON_ERROR); + // Attempt to treat the identifier as a composite key; fall back to a simple scalar ID. + $padded = $identifier.str_repeat('=', (4 - \strlen($identifier) % 4) % 4); + $base64 = strtr($padded, '-_', '+/'); + + $decoded = base64_decode($base64, true); + if (false === $decoded) { + return [$identifier]; + } + + $result = json_decode($decoded, true); + if (!\is_array($result)) { + return [$identifier]; + } + + return $result; } }This keeps composite keys working as before while making
normalize()/denormalize()safe and type‑correct for simple identifiers.src/SearchManagerInterface.php (1)
35-42: Ensureindex()docblock matches actual return shapeThe
index()PHPDoc still documents@return list<array<non-empty-string, DocumentAdditionOrUpdateTask>>. If the implementation returns a map ofindexName => DocumentAdditionOrUpdateTask(as previously discussed), this should be updated toarray<non-empty-string, DocumentAdditionOrUpdateTask>to keep the interface accurate for callers and static analysis.
🧹 Nitpick comments (5)
src/Model/Aggregator.php (1)
12-14: Dynamic primary key support inAggregatorlooks correctThe new
object $entitytype, configurable$primaryKey(defaulting to'objectID'), and use of$this->primaryKeyinnormalize()align with the new tests and per‑indexprimary_keyhandling while preserving backward compatibility.You might optionally update the docblock around
$objectIDto mention that it now backs a configurable primary key name rather than always being tied to a literalobjectID.Also applies to: 27-36, 80-83
src/Engine.php (1)
96-126: Consider batching deletions per index instead of onedeleteDocument()call per id
remove()currently loops identifiers and callsdeleteDocument()for each one. This is correct but may be suboptimal for large batches. When/if you need to optimize, you could switch to a single per-index bulk call (e.g., deleteDocuments([...])) while keeping the return shape consistent.src/Services/MeilisearchService.php (1)
24-63: Delegation toSearchManagerInterfaceis a good deprecation strategyThe added
$managerdependency plus per-methodtrigger_deprecation()+ conditional delegation cleanly support the new API while keeping existing callers working. Given this class is now explicitly deprecated and mainly a compatibility shim, I’d handle the PHPMD complexity/static-access warnings via suppression or tooling config rather than large refactors here.src/Command/MeilisearchImportCommand.php (1)
73-152: Import loop correctly uses data providers; consider guarding againstbatch-size <= 0The new loop that pulls entities from a per-index data provider, skips empty batches, and calls
cleanup()per non-empty batch is sound and matches the new provider abstraction. One small hardening you might consider (in a follow-up) is validating--batch-sizeupfront and rejecting<= 0values to avoid a non-terminatingdo/whilefor misconfigured runs.src/Services/MeilisearchManager.php (1)
401-421: Class resolution helper is pragmatic; PHPMD warnings can be handled laterThe cached resolver that switches between native class resolution, modern proxy resolution, and a legacy fallback gives good coverage across PHP/Doctrine versions. The static-access PHPMD warnings here are mostly stylistic; if they keep CI noisy, consider extracting this into a tiny dedicated helper service or adding a suppression, but it doesn’t need to block this PR.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (62)
.github/workflows/pre-release-tests.yml(2 hunks).github/workflows/tests.yml(2 hunks)composer.json(1 hunks)config/services.php(3 hunks)phpstan-baseline.php(1 hunks)phpstan.dist.neon(1 hunks)src/Command/IndexCommand.php(2 hunks)src/Command/MeilisearchClearCommand.php(1 hunks)src/Command/MeilisearchCreateCommand.php(3 hunks)src/Command/MeilisearchDeleteCommand.php(1 hunks)src/Command/MeilisearchImportCommand.php(7 hunks)src/Command/MeilisearchUpdateSettingsCommand.php(3 hunks)src/DataProvider/DataProviderInterface.php(1 hunks)src/DataProvider/DataProviderRegistry.php(1 hunks)src/DataProvider/DataProviderRegistryInterface.php(1 hunks)src/DataProvider/OrmEntityProvider.php(1 hunks)src/DependencyInjection/Compiler/DataProviderPass.php(1 hunks)src/DependencyInjection/Configuration.php(3 hunks)src/DependencyInjection/MeilisearchExtension.php(4 hunks)src/Engine.php(5 hunks)src/Event/SettingsUpdatedEvent.php(1 hunks)src/EventListener/ConsoleOutputSubscriber.php(1 hunks)src/EventListener/DoctrineEventSubscriber.php(1 hunks)src/Exception/DataProviderNotFoundException.php(1 hunks)src/Exception/InvalidIndiceException.php(1 hunks)src/Exception/LogicException.php(1 hunks)src/Exception/NotSearchableException.php(1 hunks)src/Identifier/DefaultIdNormalizer.php(1 hunks)src/Identifier/IdNormalizerInterface.php(1 hunks)src/MeilisearchBundle.php(2 hunks)src/Model/Aggregator.php(3 hunks)src/SearchManagerInterface.php(1 hunks)src/SearchService.php(1 hunks)src/Searchable.php(1 hunks)src/SearchableEntity.php(2 hunks)src/SearchableObject.php(1 hunks)src/Services/MeilisearchManager.php(1 hunks)src/Services/MeilisearchService.php(9 hunks)src/Services/SettingsUpdater.php(2 hunks)src/Services/UnixTimestampNormalizer.php(1 hunks)tests/BaseKernelTestCase.php(5 hunks)tests/Entity/Actor.php(1 hunks)tests/Entity/Car.php(1 hunks)tests/Entity/Link.php(2 hunks)tests/Entity/SelfNormalizable.php(2 hunks)tests/Entity/Tag.php(2 hunks)tests/Integration/AggregatorTest.php(2 hunks)tests/Integration/Command/MeilisearchClearCommandTest.php(1 hunks)tests/Integration/Command/MeilisearchCreateCommandTest.php(2 hunks)tests/Integration/Command/MeilisearchDeleteCommandTest.php(1 hunks)tests/Integration/Command/MeilisearchImportCommandTest.php(1 hunks)tests/Integration/EngineTest.php(3 hunks)tests/Integration/EventListener/DoctrineEventSubscriberTest.php(8 hunks)tests/Integration/Fixtures/ActorDataProvider.php(1 hunks)tests/Integration/SearchTest.php(5 hunks)tests/Kernel.php(1 hunks)tests/Unit/ConfigurationTest.php(10 hunks)tests/Unit/SerializationTest.php(2 hunks)tests/baseline-ignore(1 hunks)tests/config/doctrine_php7.yaml(0 hunks)tests/config/framework.yaml(1 hunks)tests/config/meilisearch.yaml(1 hunks)
💤 Files with no reviewable changes (1)
- tests/config/doctrine_php7.yaml
🚧 Files skipped from review as they are similar to previous changes (20)
- src/DataProvider/DataProviderRegistryInterface.php
- src/SearchService.php
- .github/workflows/pre-release-tests.yml
- src/DependencyInjection/Configuration.php
- src/SearchableObject.php
- src/Identifier/IdNormalizerInterface.php
- src/Exception/InvalidIndiceException.php
- tests/Integration/Command/MeilisearchCreateCommandTest.php
- tests/Entity/Car.php
- tests/Integration/EngineTest.php
- src/EventListener/ConsoleOutputSubscriber.php
- tests/Entity/Tag.php
- src/DataProvider/DataProviderInterface.php
- tests/Integration/Command/MeilisearchImportCommandTest.php
- src/Searchable.php
- src/Services/UnixTimestampNormalizer.php
- phpstan.dist.neon
- tests/Entity/SelfNormalizable.php
- src/DependencyInjection/Compiler/DataProviderPass.php
- tests/Unit/SerializationTest.php
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: norkunas
Repo: meilisearch/meilisearch-symfony PR: 391
File: src/Command/MeilisearchImportCommand.php:117-120
Timestamp: 2025-08-05T04:46:01.119Z
Learning: In meilisearch-symfony project, the maintainer norkunas prefers to keep PRs focused and defer error handling improvements for settings updates to separate PRs, particularly when it involves decisions about partial import behavior when some indexes fail.
📚 Learning: 2025-08-05T04:46:01.119Z
Learnt from: norkunas
Repo: meilisearch/meilisearch-symfony PR: 391
File: src/Command/MeilisearchImportCommand.php:117-120
Timestamp: 2025-08-05T04:46:01.119Z
Learning: In meilisearch-symfony project, the maintainer norkunas prefers to keep PRs focused and defer error handling improvements for settings updates to separate PRs, particularly when it involves decisions about partial import behavior when some indexes fail.
Applied to files:
src/DataProvider/OrmEntityProvider.phptests/Integration/AggregatorTest.phpconfig/services.phpsrc/Engine.phpsrc/Services/MeilisearchManager.php.github/workflows/tests.ymltests/Integration/Fixtures/ActorDataProvider.phpsrc/Command/MeilisearchImportCommand.phpsrc/SearchManagerInterface.php
🧬 Code graph analysis (23)
src/Command/IndexCommand.php (4)
src/Command/MeilisearchCreateCommand.php (1)
__construct(23-30)src/Command/MeilisearchUpdateSettingsCommand.php (1)
__construct(22-28)src/SearchManagerInterface.php (1)
getConfiguration(33-33)src/Services/MeilisearchManager.php (1)
getConfiguration(85-88)
src/Model/Aggregator.php (2)
src/Identifier/DefaultIdNormalizer.php (1)
normalize(9-31)src/Identifier/IdNormalizerInterface.php (1)
normalize(12-12)
src/DependencyInjection/MeilisearchExtension.php (7)
src/DataProvider/OrmEntityProvider.php (1)
OrmEntityProvider(10-93)src/MeilisearchBundle.php (2)
MeilisearchBundle(11-31)qualifiedVersion(15-18)src/Model/Aggregator.php (2)
Aggregator(15-84)getEntities(51-54)src/Document/Aggregator.php (1)
Aggregator(9-11)src/Engine.php (1)
index(61-90)src/Services/MeilisearchManager.php (1)
index(90-139)src/Services/MeilisearchService.php (1)
index(114-147)
src/MeilisearchBundle.php (1)
src/DependencyInjection/Compiler/DataProviderPass.php (1)
DataProviderPass(12-40)
tests/Entity/Link.php (1)
src/SearchableObject.php (1)
SearchableObject(13-80)
src/Command/MeilisearchDeleteCommand.php (4)
src/SearchManagerInterface.php (1)
deleteByIndexName(67-67)src/SearchService.php (1)
deleteByIndexName(50-50)src/Services/MeilisearchManager.php (1)
deleteByIndexName(183-186)src/Services/MeilisearchService.php (1)
deleteByIndexName(185-194)
src/EventListener/DoctrineEventSubscriber.php (2)
src/SearchManagerInterface.php (2)
index(42-42)remove(51-51)src/Services/MeilisearchManager.php (2)
index(90-139)remove(141-174)
tests/Integration/EventListener/DoctrineEventSubscriberTest.php (2)
src/SearchManagerInterface.php (1)
search(88-88)src/Services/MeilisearchManager.php (1)
search(195-236)
src/DataProvider/OrmEntityProvider.php (3)
src/DataProvider/DataProviderInterface.php (6)
provide(18-18)loadByIdentifiers(25-25)getIdentifierValues(32-32)normalizeIdentifiers(39-39)denormalizeIdentifier(46-46)cleanup(48-48)src/Identifier/DefaultIdNormalizer.php (2)
denormalize(33-39)normalize(9-31)src/Identifier/IdNormalizerInterface.php (2)
denormalize(21-21)normalize(12-12)
tests/Integration/AggregatorTest.php (3)
src/Model/Aggregator.php (1)
getEntityClassFromObjectID(69-78)src/Exception/EntityNotFoundInObjectID.php (1)
EntityNotFoundInObjectID(7-9)src/Exception/InvalidEntityForAggregator.php (1)
InvalidEntityForAggregator(7-9)
tests/Entity/Actor.php (14)
src/Command/IndexCommand.php (1)
__construct(19-24)src/Command/MeilisearchCreateCommand.php (1)
__construct(23-30)src/Command/MeilisearchImportCommand.php (1)
__construct(28-36)src/Command/MeilisearchUpdateSettingsCommand.php (1)
__construct(22-28)src/DataProvider/DataProviderRegistry.php (1)
__construct(15-19)src/DataProvider/OrmEntityProvider.php (1)
__construct(15-20)src/Engine.php (1)
__construct(46-48)src/EventListener/ConsoleOutputSubscriber.php (1)
__construct(13-15)src/EventListener/DoctrineEventSubscriber.php (1)
__construct(12-14)src/Exception/DataProviderNotFoundException.php (1)
__construct(9-12)src/Exception/NotSearchableException.php (1)
__construct(9-12)src/Model/Aggregator.php (1)
__construct(32-44)src/SearchableEntity.php (1)
__construct(42-56)src/SearchableObject.php (1)
__construct(28-37)
src/SearchableEntity.php (4)
src/Model/Aggregator.php (1)
normalize(80-83)tests/Entity/Link.php (1)
normalize(74-85)tests/Entity/SelfNormalizable.php (1)
normalize(64-75)src/SearchableObject.php (1)
SearchableObject(13-80)
config/services.php (3)
src/DataProvider/DataProviderRegistry.php (1)
DataProviderRegistry(10-37)src/Identifier/DefaultIdNormalizer.php (1)
DefaultIdNormalizer(7-40)src/Services/MeilisearchManager.php (1)
MeilisearchManager(27-422)
src/Exception/DataProviderNotFoundException.php (2)
src/Exception/InvalidIndiceException.php (1)
__construct(9-12)src/Exception/NotSearchableException.php (1)
__construct(9-12)
tests/Integration/SearchTest.php (4)
tests/BaseKernelTestCase.php (1)
waitForAllTasks(47-52)src/Engine.php (1)
search(159-162)src/SearchManagerInterface.php (2)
search(88-88)rawSearch(98-98)src/Services/MeilisearchService.php (2)
search(209-254)rawSearch(256-270)
src/Engine.php (2)
src/Services/MeilisearchManager.php (2)
index(90-139)search(195-236)src/SearchableObject.php (5)
SearchableObject(13-80)getSearchableArray(65-79)getIndexUid(42-45)getPrimaryKey(50-53)getIdentifier(55-58)
tests/Integration/Fixtures/ActorDataProvider.php (3)
tests/Entity/Actor.php (1)
Actor(7-14)src/DataProvider/DataProviderInterface.php (6)
provide(18-18)loadByIdentifiers(25-25)getIdentifierValues(32-32)normalizeIdentifiers(39-39)denormalizeIdentifier(46-46)cleanup(48-48)src/Identifier/IdNormalizerInterface.php (2)
normalize(12-12)denormalize(21-21)
src/Command/MeilisearchUpdateSettingsCommand.php (4)
src/Services/MeilisearchManager.php (2)
__construct(51-62)isSearchable(64-69)src/SearchManagerInterface.php (1)
isSearchable(22-22)src/SearchService.php (1)
isSearchable(20-20)src/Services/MeilisearchService.php (1)
isSearchable(66-77)
src/Command/MeilisearchImportCommand.php (7)
src/Engine.php (3)
__construct(46-48)index(61-90)count(169-172)src/EventListener/DoctrineEventSubscriber.php (1)
__construct(12-14)src/SearchManagerInterface.php (5)
getConfiguration(33-33)isSearchable(22-22)index(42-42)count(106-106)deleteByIndexName(67-67)src/Services/MeilisearchManager.php (5)
getConfiguration(85-88)isSearchable(64-69)index(90-139)count(248-253)deleteByIndexName(183-186)src/DataProvider/DataProviderRegistryInterface.php (1)
getDataProvider(21-21)src/DataProvider/DataProviderInterface.php (2)
provide(18-18)cleanup(48-48)src/DataProvider/OrmEntityProvider.php (2)
provide(22-31)cleanup(89-92)
src/Services/SettingsUpdater.php (3)
src/Command/MeilisearchUpdateSettingsCommand.php (1)
__construct(22-28)src/SearchManagerInterface.php (1)
getConfiguration(33-33)src/Services/MeilisearchManager.php (1)
getConfiguration(85-88)
src/DataProvider/DataProviderRegistry.php (2)
src/Exception/DataProviderNotFoundException.php (2)
DataProviderNotFoundException(7-13)__construct(9-12)src/DataProvider/DataProviderRegistryInterface.php (1)
getDataProvider(21-21)
src/SearchManagerInterface.php (2)
src/Exception/NotSearchableException.php (1)
NotSearchableException(7-13)src/Services/MeilisearchManager.php (5)
isSearchable(64-69)searchableAs(71-83)getConfiguration(85-88)index(90-139)search(195-236)
tests/BaseKernelTestCase.php (3)
src/SearchManagerInterface.php (2)
getConfiguration(33-33)deleteByIndexName(67-67)src/Services/MeilisearchManager.php (2)
getConfiguration(85-88)deleteByIndexName(183-186)src/Services/MeilisearchService.php (2)
getConfiguration(87-96)deleteByIndexName(185-194)
🪛 GitHub Actions: Tests
src/Identifier/DefaultIdNormalizer.php
[error] 19-19: MissingImport Missing class import via use statement (line '19', column '27').
src/DependencyInjection/MeilisearchExtension.php
[error] 22-22: IfStatementAssignment Avoid assigning values to variables in if clauses and the like (line '45', column '20').
[error] 36-36: StaticAccess Avoid using static access to class '\Meilisearch\Bundle\MeilisearchBundle' in method 'load'.
[error] 52-52: ElseExpression The method load uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them.
[error] 60-60: StaticAccess Avoid using static access to class '\Meilisearch\Bundle\MeilisearchBundle' in method 'load'.
[error] 118-118: ElseExpression The method registerDataProviders uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them.
src/DataProvider/OrmEntityProvider.php
[error] 48-48: ShortVariable Avoid variables with short names like $i. Configured minimum length is 3.
src/Services/MeilisearchManager.php
[error] 27-27: ExcessiveClassComplexity The class MeilisearchManager has an overall complexity of 59 which is very high. The configured complexity threshold is 50.
[error] 413-413: StaticAccess Avoid using static access to class '\Doctrine\ORM\Proxy\DefaultProxyClassNameResolver' in method 'resolveClass'.
[error] 417-417: StaticAccess Avoid using static access to class '\Doctrine\Common\Util\ClassUtils' in method 'resolveClass'.
src/Command/MeilisearchImportCommand.php
[error] 24-24: CouplingBetweenObjects The class MeilisearchImportCommand has a coupling between objects value of 14. Consider to reduce the number of dependencies under 13.
[error] 73-73: CyclomaticComplexity The method execute() has a Cyclomatic Complexity of 14. The configured cyclomatic complexity threshold is 10.
[error] 73-73: NPathComplexity The method execute() has an NPath complexity of 976. The configured NPath complexity threshold is 200.
src/Services/SettingsUpdater.php
[error] 35-35: CyclomaticComplexity The method update() has a Cyclomatic Complexity of 13. The configured cyclomatic complexity threshold is 10.
src/Services/MeilisearchService.php
[error] 27-27: TooManyPublicMethods The class MeilisearchService has 11 public methods. Consider refactoring MeilisearchService to keep number of public methods under 10.
[error] 27-27: ExcessiveClassComplexity The class MeilisearchService has an overall complexity of 67 which is very high. The configured complexity threshold is 50.
[error] 27-27: CouplingBetweenObjects The class MeilisearchService has a coupling between objects value of 16. Consider to reduce the number of dependencies under 13.
[error] 48-48: LongVariable Avoid excessively long variable names like $classToSerializerGroup. Keep variable name length under 20.
[error] 57-57: StaticAccess Avoid using static access to class '\Symfony\Component\PropertyAccess\PropertyAccess' in method '__construct'.
[error] 415-415: LongVariable Avoid excessively long variable names like $searchableEntitiesChunk. Keep variable name length under 20.
[error] 463-463: StaticAccess Avoid using static access to class '\Doctrine\ORM\Proxy\DefaultProxyClassNameResolver' in method 'resolveClass'.
[error] 467-467: StaticAccess Avoid using static access to class '\Doctrine\Common\Util\ClassUtils' in method 'resolveClass'.
🔇 Additional comments (47)
tests/config/framework.yaml (1)
5-7: LGTM! Error handling configuration supports the new architecture.The addition of
handle_all_throwablesandphp_errorslogging enhances error visibility during tests, which is appropriate for validating the new DataProvider and manager-based architecture introduced in this PR.tests/Entity/Link.php (1)
9-9: LGTM! Migration to SearchableObject is consistent.The import change from
SearchabletoSearchableObjectaligns with the PR's architecture refactoring, and the corresponding constant update on line 76 maintains consistency across the normalization flow.tests/baseline-ignore (1)
5-5: LGTM! Appropriate baseline entry for Doctrine ORM deprecation.Adding the
DefaultProxyClassNameResolverdeprecation notice is consistent with the existing Doctrine proxy-related deprecations in the baseline and aligns with Doctrine ORM's migration path toward native lazy objects.tests/Integration/Command/MeilisearchDeleteCommandTest.php (1)
40-41: LGTM! Test expectations updated for new indices.The additions correctly reflect the new
actorandcarsindices introduced in the test configuration, ensuring the delete command test validates all configured indices.src/Exception/LogicException.php (1)
1-9: LGTM! Clean exception implementation.The new
LogicExceptionprovides a bundle-specific exception type following standard PHP conventions. The final class modifier and namespace are appropriate.src/SearchableEntity.php (1)
15-17: LGTM! Deprecation properly documented.The deprecation notice clearly directs users to
SearchableObject, and the consistent constant reference updates on lines 83 and 87 maintain compatibility during the migration period.src/Exception/DataProviderNotFoundException.php (1)
1-13: LGTM! Exception follows bundle conventions.The
DataProviderNotFoundExceptionimplementation is consistent with other bundle exceptions (e.g.,NotSearchableException,InvalidIndiceException), properly extendsInvalidArgumentException, and provides a clear error message identifying both the index and class involved.src/Event/SettingsUpdatedEvent.php (1)
16-20: Constructor promotion is clean and behavior‑preservingUsing promoted
private readonlyproperties keeps the event immutable and matches the existing getters without changing semantics. Looks good.tests/Integration/AggregatorTest.php (2)
24-43: Good coverage of entity‑class resolution and constructor validationThe tests around
getEntityClassFromObjectID()and the multi‑primary‑key constructor guard accurately pin the expected behavior and error conditions for aggregators.
69-100: Normalization tests nicely validate default vs custom primary key behavior
testAggregatorNormalization()andtestAggregatorCustomPrimaryKey()clearly capture the expectations for theobjectIDfield and for a custom primary key ('id'), matching the newAggregator::normalize()semantics.config/services.php (3)
32-40: Manager‑based wiring and aliases are consistent
MeilisearchService, the Doctrine subscriber, and all commands now depend onSearchManagerInterfacevia themeilisearch.managerservice and its alias, which matches the new manager API and keeps the old service available behind a deprecating facade. The argument order forMeilisearchManagerand the updated constructors for commands/settings updater are all respected.Also applies to: 42-47, 48-52, 84-88, 93-107, 110-117, 120-123
10-11: Data provider registry DI matches the new registry contractThe
meilisearch.data_provider.registryservice is correctly wired with the container locator and provider map, and aliased toDataProviderRegistryInterface, so data providers can be resolved per index/class via the manager without further config changes.Also applies to: 74-82, 131-136
14-16: Default ID normalizer registration looks correctRegistering
meilisearch.identifier.default_id_normalizerand aliasingIdNormalizerInterfaceto that service ensures a single, configurable ID normalization strategy is used across ORM and custom data providers, with an explicit service id that fits existing alias patterns.Also applies to: 128-142
src/Command/MeilisearchDeleteCommand.php (1)
31-33: Delete command correctly migrated toSearchManagerInterfaceUsing
$this->searchManager->deleteByIndexName($indexName)is consistent with the new manager API and keeps the command behavior unchanged aside from routing through the central manager.src/Command/MeilisearchClearCommand.php (1)
29-31: Clear command now correctly delegates to the managerSwitching to
$this->searchManager->clear($className)routes index clearing through the new manager while preserving the existing status handling and output.tests/Entity/Actor.php (1)
7-13: Test entityActoris simple and idiomaticImmutable promoted properties for
idandnameare a good fit for test data and align with the rest of the codebase’s PHP 8.1 style.tests/Integration/Command/MeilisearchClearCommandTest.php (1)
28-41: Updated expectations reflect newly added indicesIncluding the
actorandcarsindices in the expected clear output keeps the test aligned with the expanded test Meilisearch configuration and the manager‑driven clear behavior.tests/config/meilisearch.yaml (1)
57-62: Actor/cars indices wiring looks consistent with new data provider model
type: 'custom'withdata_providerpointing to the fixtures namespace and the additionalcarsindex both align with the new configuration schema and test setup. No issues from this change.src/Command/IndexCommand.php (1)
8-29: Migration toSearchManagerInterfaceinIndexCommandlooks correctConstructor promotion and the switch from
searchServicetosearchManagerfor readingprefixandindicespreserve the previous behavior while aligning with the new API. The rest ofgetEntitiesFromArgs()remains functionally identical, so no regression is introduced here.src/MeilisearchBundle.php (1)
7-25: Compiler pass registration for data providers is straightforward and correctOverriding
build()to callparent::build()and then addDataProviderPassis the expected Symfony pattern and cleanly wires the new data provider infrastructure into the bundle.tests/Integration/EventListener/DoctrineEventSubscriberTest.php (1)
23-132: Tests correctly updated to useSearchManagerInterface::search()Replacing the old service calls with
$this->searchManager->search(<Entity>::class, <query>)keeps the semantics of these integration tests intact while aligning them with the new public API. The expectations on IDs and titles still exercise the subscriber behavior end‑to‑end.tests/Kernel.php (1)
36-42: Doctrine config selection logic is consistent with the new PHP/Doctrine targetsThe simplified branching on
$doctrineBundleV3,LegacyReflectionFieldsand PHP version cleanly covers v3, v2-on-8.4, and older proxy configs, while preserving meilisearch wiring. No functional issues spotted.tests/Unit/ConfigurationTest.php (2)
29-60: Usingmixedin dynamic settings tests is appropriateTyping
$valueasmixedfor the dynamic settings checker tests matches the data provider contract and the provider data (string|int|bool|array|null). This keeps the tests strict without constraining valid inputs.
135-151: Extended configuration expectations for type, data provider, id normalizer, and primary key look coherentThe added defaults (
type: 'orm',data_provider: null,id_normalizer: 'meilisearch.identifier.default_id_normalizer',primary_key: 'objectID') and the new cases for custom primary keys and customid_normalizerall align with the new configuration schema and the PR goals (custom providers + identifier normalization). The expected trees are internally consistent and should give good coverage of the new options.Also applies to: 187-209, 244-250, 288-292, 330-334, 362-441
src/Exception/NotSearchableException.php (1)
7-12:NotSearchableExceptionis well‑typed and clearException design and typing (
int $code = 0,?Throwable $previous = null) are solid, and the message clearly describes the error case. No changes needed.phpstan-baseline.php (1)
1-23: Baseline configuration looks appropriate for optional Doctrine dependency.The baseline correctly suppresses PHPStan errors for
ClassUtils::getClass()calls, which is expected since Doctrine is now a dev dependency. Theisset.offsetsuppression for the hits array is a minor PHPStan false positive.src/DependencyInjection/MeilisearchExtension.php (1)
66-69: Manager service wiring is consistent with the service pattern.The wiring correctly injects the serializer reference and configuration, mirroring the pattern used for
meilisearch.service.tests/Integration/SearchTest.php (3)
72-77: Good practice: Adding waitForAllTasks() ensures test reliability.The addition of
waitForAllTasks()after the import command ensures that asynchronous Meilisearch indexing completes before search assertions, preventing flaky tests.
76-92: Migration to SearchManagerInterface is correctly applied.The test methods now use
searchManager->search()andsearchManager->rawSearch()without theObjectManagerparameter, aligning with the newSearchManagerInterfacesignatures. This simplifies the API and removes Doctrine coupling from the search interface.
145-164: Test correctly validates Car entity indexing with proper configuration.The test follows the established pattern: persist entities, run import, wait for tasks, and verify search results. The 'cars' index is properly configured in
tests/config/meilisearch.yamland correctly mapped to the Car entity.src/EventListener/DoctrineEventSubscriber.php (2)
8-14: Clean migration to SearchManagerInterface with property promotion.The constructor now uses PHP 8.1 constructor property promotion with the new
SearchManagerInterface, which aligns with the minimum PHP version bump in this PR.
16-29: Event handlers correctly simplified to use new manager interface.The handlers now pass only the entity object to
index()andremove(), as theSearchManagerInterfaceinternally resolves the appropriate data provider. UsingpreRemove(rather thanpostRemove) is correct since the entity must still be managed to extract identifiers.composer.json (2)
21-29: Breaking change: PHP 8.1 and Symfony 6.4 minimum requirements.This is a significant compatibility change that drops support for PHP 7.4/8.0 and Symfony 5.x. Ensure this is clearly documented in the changelog/upgrade guide since it will affect users on older stacks.
38-43: Dev tooling updates are appropriate.The PHPStan and PHP-CS-Fixer version bumps are minor maintenance updates that shouldn't affect functionality.
src/DataProvider/DataProviderRegistry.php (1)
21-35: Provider resolution logic looks solidDirect map lookup with a sane
is_afallback per index is clear and matches the registry contract; throwingDataProviderNotFoundExceptionis appropriate when nothing matches.tests/BaseKernelTestCase.php (2)
10-40: Migration toSearchManagerInterfaceis consistentUsing
meilisearch.managerinsetUp(),getPrefix(), andcleanupIndex()aligns with the new API and keeps tests in sync with production wiring.Also applies to: 54-68
47-52: Code is correct —getTasks()is directly iterableVerified:
Client::getTasks()returns aTasksResultsobject that implementsIteratorAggregate, making it directly iterable. Theforeachloop inwaitForAllTasks()correctly yields individual task arrays, each with auidkey. No changes needed.src/Services/SettingsUpdater.php (1)
23-29: Constructor refactor toSearchManagerInterfaceis appropriateGrabbing configuration via
$searchManager->getConfiguration()in the constructor keeps this service aligned with the new manager abstraction and avoids touching settings logic.src/Command/MeilisearchUpdateSettingsCommand.php (1)
22-28: Command wiring toSearchManagerInterfaceis correctInjecting
SearchManagerInterfaceinto the command, passing it toIndexCommand, and using$this->searchManager->isSearchable()keeps this command consistent with the new manager-based API.Also applies to: 56-57
src/Command/MeilisearchCreateCommand.php (1)
23-30: Create command migration toSearchManagerInterfacelooks goodConstructor promotion and the switch to
$this->searchManager->isSearchable()are consistent with the new manager API; index creation and optional settings update behavior remain intact.Also applies to: 66-79
src/Engine.php (1)
55-90: Per-index batching and primary key handling inindex()look correctUsing
SearchableObjectplus the['primaryKey' => ..., 'documents' => []]structure per$indexUidcleanly scopes primary keys by index and avoids the earlier “first object primary key reused for all indexes” bug. The normalization of identifiers vianormalizeId()is also consistent with the declared types.src/Command/MeilisearchImportCommand.php (3)
28-36: Constructor wiring to the new manager and registry looks consistentInjecting
SearchManagerInterfaceinto the parent plus keepingClient,SettingsUpdater,EventDispatcherInterface, andDataProviderRegistryInterfaceas readonly promoted properties cleanly aligns this command with the new architecture.
168-188: Task handling and logging informatIndexingResponse()are solidWaiting on each task, throwing
TaskExceptionon failures, and accumulatingindexedDocumentsper index gives the import command clear, aggregated feedback while respecting Meilisearch’s async task model.
214-238: Swap and cleanup of temporary indices now properly route through the managerUsing
SearchManagerInterface::deleteByIndexName()instead of reaching directly into the client keeps deletion consistent with the rest of the new API while still leveraging the low-level client forswapIndexes().src/Services/MeilisearchManager.php (3)
90-139: Manager-side batching and aggregator handling inindex()look consistent with the new architectureThe
index()implementation correctly:
- Resolves all matching index configs per entity (including aggregators via
getIndicesForEntity()),- Uses the data provider for identifier values,
- Wraps entities in aggregator classes when needed, and
- Defers chunking + SearchableObject creation to
batchProcess().This keeps provider-based ID handling and serializer-group context centralized while preserving the expected “list of per-chunk responses” shape for callers like the import command.
195-236: Search hydration correctly respects provider-based ID normalization and batchingThe
search()method:
- Enforces searchability via
assertIsSearchable(),- Uses the configured
nbResultslimit,- Extracts primary-key values from hits,
- Loads domain objects via
loadByIdentifiers(), and- Builds the lookup map using
$dataProvider->normalizeIdentifiers($dataProvider->getIdentifierValues($object)).This keeps hit-to-entity mapping fully aligned with the ID normalization used during indexing and avoids hard-coding any particular identifier format, which is exactly what the new DataProvider/IdNormalizer abstractions are for.
287-313: Aggregator and entities-to-index mapping is well-structured
setSearchables()andsetAggregatorsAndEntitiesAggregators()give you:
- A flat list of searchable classes (index
classentries), and- A per-entity mapping of which aggregator classes/index names apply.
Combined with
getIndicesForEntity(), this lets entities participate in both direct and aggregator-based indices without special-casing at call sites.
add9d4a to
f57906b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/DependencyInjection/MeilisearchExtension.php (1)
106-114: Silent skip when data_provider service doesn't exist may mask configuration errors.If a user configures a
data_providerservice that doesn't exist, this silently continues without the provider being tagged. This could lead to confusing runtime errors when the data provider registry can't find the expected provider.Consider throwing a clear exception when the service is configured but not found.
🧹 Nitpick comments (6)
src/Identifier/IdNormalizerInterface.php (1)
7-22: Consider adding usage clarification to the interface documentation.The interface is correctly designed. However, to prevent future confusion about the type asymmetry (as evidenced by past review comments), consider adding a brief class-level docblock explaining that:
normalize()returns scalar values for single identifiers and encoded strings for composite identifiersdenormalize()is only called for composite identifiers (those encoded bynormalize())Example:
+/** + * Normalizes entity identifiers to MeiliSearch-compatible primary keys. + * + * Single identifiers are returned as-is (string|int), while composite + * identifiers are encoded as base64 strings. The denormalize() method + * only handles composite identifiers. + */ interface IdNormalizerInterface {src/DependencyInjection/Configuration.php (1)
14-113: Note: Pipeline warning about method length is borderline.The
getConfigTreeBuilder()method is exactly 100 lines, which meets the PHPMD threshold. While this is technically acceptable, if the method grows further in future changes, consider extracting the indices configuration into a separate method for better maintainability.This is an optional refactor and doesn't need to block this PR.
src/Services/MeilisearchService.php (1)
27-27: PHPMD complexity warnings are acceptable for deprecated code.The pipeline flags TooManyPublicMethods, ExcessiveClassComplexity, and CouplingBetweenObjects. Since this class is deprecated and will be removed, investing effort to refactor it is not warranted. The focus should be on the new
MeilisearchManagerinstead.src/Command/MeilisearchImportCommand.php (1)
73-163: Consider extracting methods to reduce complexity.The
execute()method has high cyclomatic (14) and NPath (976) complexity per PHPMD. While the logic is correct, extracting the index creation and import loops into separate private methods would improve readability and reduce complexity below thresholds.Based on learnings, this can be deferred to a follow-up PR to keep this one focused.
src/Services/MeilisearchManager.php (2)
377-399: Potential duplicate index configs for aggregator entities.In
getIndicesForEntity(), an entity might match both the direct class check (line 385-386) and the aggregator check (lines 389-394), potentially adding the same config twice to$matchingConfigs.Consider deduplicating:
private function getIndicesForEntity(object $entity): array { $className = $this->getBaseClassName($entity); $matchingConfigs = []; + $seen = []; foreach ($this->configuration->get('indices') as $config) { $configClass = $config['class']; + $configKey = $config['name'] . '::' . $configClass; if ($className === $configClass || is_subclass_of($className, $configClass)) { - $matchingConfigs[] = $config; + if (!isset($seen[$configKey])) { + $matchingConfigs[] = $config; + $seen[$configKey] = true; + } } if (isset($this->entitiesAggregators[$className])) { foreach ($this->entitiesAggregators[$className] as $aggInfo) { if ($aggInfo['class'] === $configClass && $aggInfo['index'] === $config['name']) { - $matchingConfigs[] = $config; + if (!isset($seen[$configKey])) { + $matchingConfigs[] = $config; + $seen[$configKey] = true; + } } } } } return $matchingConfigs; }
27-422: Class complexity exceeds threshold but is justified.PHPMD reports ExcessiveClassComplexity (59 > 50). The manager centralizes index/search/removal logic, making some complexity inherent.
To reduce complexity without major restructuring, consider extracting
resolveClass()into a smallClassResolverservice and moving the search hydration logic (lines 216-233) into a private helper. This could be addressed in a follow-up PR.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (65)
.github/workflows/pre-release-tests.yml(2 hunks).github/workflows/tests.yml(2 hunks)README.md(1 hunks)composer.json(1 hunks)config/doctrine.php(1 hunks)config/services.php(3 hunks)phpstan-baseline.php(1 hunks)phpstan.dist.neon(1 hunks)src/Command/IndexCommand.php(2 hunks)src/Command/MeilisearchClearCommand.php(1 hunks)src/Command/MeilisearchCreateCommand.php(3 hunks)src/Command/MeilisearchDeleteCommand.php(1 hunks)src/Command/MeilisearchImportCommand.php(7 hunks)src/Command/MeilisearchUpdateSettingsCommand.php(3 hunks)src/DataProvider/DataProviderInterface.php(1 hunks)src/DataProvider/DataProviderRegistry.php(1 hunks)src/DataProvider/DataProviderRegistryInterface.php(1 hunks)src/DataProvider/OrmEntityProvider.php(1 hunks)src/DependencyInjection/Compiler/DataProviderPass.php(1 hunks)src/DependencyInjection/Configuration.php(3 hunks)src/DependencyInjection/MeilisearchExtension.php(4 hunks)src/Engine.php(5 hunks)src/Event/SettingsUpdatedEvent.php(1 hunks)src/EventListener/ConsoleOutputSubscriber.php(1 hunks)src/EventListener/DoctrineEventSubscriber.php(1 hunks)src/Exception/DataProviderNotFoundException.php(1 hunks)src/Exception/InvalidIndiceException.php(1 hunks)src/Exception/LogicException.php(1 hunks)src/Exception/NotSearchableException.php(1 hunks)src/Identifier/DefaultIdNormalizer.php(1 hunks)src/Identifier/IdNormalizerInterface.php(1 hunks)src/MeilisearchBundle.php(2 hunks)src/Model/Aggregator.php(3 hunks)src/SearchManagerInterface.php(1 hunks)src/SearchService.php(1 hunks)src/Searchable.php(1 hunks)src/SearchableEntity.php(2 hunks)src/SearchableObject.php(1 hunks)src/Services/MeilisearchManager.php(1 hunks)src/Services/MeilisearchService.php(9 hunks)src/Services/SettingsUpdater.php(2 hunks)src/Services/UnixTimestampNormalizer.php(1 hunks)tests/BaseKernelTestCase.php(5 hunks)tests/Entity/Actor.php(1 hunks)tests/Entity/Car.php(1 hunks)tests/Entity/Link.php(2 hunks)tests/Entity/SelfNormalizable.php(2 hunks)tests/Entity/Tag.php(2 hunks)tests/Integration/AggregatorTest.php(2 hunks)tests/Integration/Command/MeilisearchClearCommandTest.php(1 hunks)tests/Integration/Command/MeilisearchCreateCommandTest.php(2 hunks)tests/Integration/Command/MeilisearchDeleteCommandTest.php(1 hunks)tests/Integration/Command/MeilisearchImportCommandTest.php(1 hunks)tests/Integration/DependencyInjectionTest.php(1 hunks)tests/Integration/EngineTest.php(3 hunks)tests/Integration/EventListener/DoctrineEventSubscriberTest.php(8 hunks)tests/Integration/Fixtures/ActorDataProvider.php(1 hunks)tests/Integration/SearchTest.php(5 hunks)tests/Kernel.php(1 hunks)tests/Unit/ConfigurationTest.php(10 hunks)tests/Unit/SerializationTest.php(2 hunks)tests/baseline-ignore(1 hunks)tests/config/doctrine_php7.yaml(0 hunks)tests/config/framework.yaml(1 hunks)tests/config/meilisearch.yaml(1 hunks)
💤 Files with no reviewable changes (1)
- tests/config/doctrine_php7.yaml
🚧 Files skipped from review as they are similar to previous changes (23)
- src/SearchService.php
- src/Exception/NotSearchableException.php
- tests/Entity/SelfNormalizable.php
- tests/Entity/Link.php
- tests/Entity/Actor.php
- tests/Integration/Command/MeilisearchCreateCommandTest.php
- .github/workflows/pre-release-tests.yml
- tests/Integration/Fixtures/ActorDataProvider.php
- src/EventListener/ConsoleOutputSubscriber.php
- src/MeilisearchBundle.php
- src/DependencyInjection/Compiler/DataProviderPass.php
- tests/Integration/Command/MeilisearchDeleteCommandTest.php
- src/Searchable.php
- src/DataProvider/OrmEntityProvider.php
- tests/baseline-ignore
- phpstan.dist.neon
- src/EventListener/DoctrineEventSubscriber.php
- src/DataProvider/DataProviderInterface.php
- src/DataProvider/DataProviderRegistry.php
- tests/config/meilisearch.yaml
- src/Model/Aggregator.php
- src/Services/UnixTimestampNormalizer.php
- tests/Unit/SerializationTest.php
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: norkunas
Repo: meilisearch/meilisearch-symfony PR: 391
File: src/Command/MeilisearchImportCommand.php:117-120
Timestamp: 2025-08-05T04:46:01.119Z
Learning: In meilisearch-symfony project, the maintainer norkunas prefers to keep PRs focused and defer error handling improvements for settings updates to separate PRs, particularly when it involves decisions about partial import behavior when some indexes fail.
📚 Learning: 2025-12-15T19:07:07.476Z
Learnt from: norkunas
Repo: meilisearch/meilisearch-symfony PR: 410
File: src/Identifier/DefaultIdNormalizer.php:18-22
Timestamp: 2025-12-15T19:07:07.476Z
Learning: In PHP projects (Symfony style), avoid importing global PHP classes (e.g., \InvalidArgumentException, \LogicException) via use statements inside namespaces. Instead, reference them with a leading backslash (fully qualified name) when used, e.g. \InvalidArgumentException $e = new \InvalidArgumentException('msg'); This preserves clarity about the global namespace and follows Symfony coding conventions for global classes.
Applied to files:
src/DataProvider/DataProviderRegistryInterface.phptests/Entity/Tag.phpsrc/Command/IndexCommand.phptests/Integration/DependencyInjectionTest.phptests/Integration/EventListener/DoctrineEventSubscriberTest.phpsrc/Services/SettingsUpdater.phptests/Unit/ConfigurationTest.phpconfig/doctrine.phptests/Kernel.phptests/Integration/SearchTest.phpphpstan-baseline.phpsrc/Exception/DataProviderNotFoundException.phpsrc/SearchableObject.phpsrc/Command/MeilisearchDeleteCommand.phpsrc/SearchableEntity.phpsrc/Command/MeilisearchCreateCommand.phpsrc/DependencyInjection/Configuration.phpsrc/Event/SettingsUpdatedEvent.phpsrc/Exception/LogicException.phptests/Integration/AggregatorTest.phptests/Entity/Car.phpsrc/Command/MeilisearchUpdateSettingsCommand.phptests/Integration/Command/MeilisearchClearCommandTest.phpsrc/Identifier/DefaultIdNormalizer.phpsrc/Identifier/IdNormalizerInterface.phpconfig/services.phpsrc/SearchManagerInterface.phptests/Integration/Command/MeilisearchImportCommandTest.phpsrc/Services/MeilisearchService.phptests/Integration/EngineTest.phptests/BaseKernelTestCase.phpsrc/Command/MeilisearchImportCommand.phpsrc/Command/MeilisearchClearCommand.phpsrc/Engine.phpsrc/Services/MeilisearchManager.phpsrc/DependencyInjection/MeilisearchExtension.phpsrc/Exception/InvalidIndiceException.php
📚 Learning: 2025-08-05T04:46:01.119Z
Learnt from: norkunas
Repo: meilisearch/meilisearch-symfony PR: 391
File: src/Command/MeilisearchImportCommand.php:117-120
Timestamp: 2025-08-05T04:46:01.119Z
Learning: In meilisearch-symfony project, the maintainer norkunas prefers to keep PRs focused and defer error handling improvements for settings updates to separate PRs, particularly when it involves decisions about partial import behavior when some indexes fail.
Applied to files:
.github/workflows/tests.ymlsrc/DependencyInjection/Configuration.phptests/Integration/AggregatorTest.phpsrc/Identifier/DefaultIdNormalizer.phpconfig/services.phpsrc/SearchManagerInterface.phptests/Integration/EngineTest.phptests/BaseKernelTestCase.phpsrc/Command/MeilisearchImportCommand.phpsrc/Engine.phpsrc/Services/MeilisearchManager.php
🧬 Code graph analysis (30)
src/DataProvider/DataProviderRegistryInterface.php (2)
src/Exception/DataProviderNotFoundException.php (1)
DataProviderNotFoundException(7-13)src/DataProvider/DataProviderRegistry.php (1)
getDataProvider(21-36)
tests/Entity/Tag.php (1)
src/SearchableObject.php (1)
SearchableObject(13-80)
src/Command/IndexCommand.php (4)
src/Command/MeilisearchUpdateSettingsCommand.php (1)
__construct(22-28)src/EventListener/DoctrineEventSubscriber.php (1)
__construct(12-14)src/SearchManagerInterface.php (1)
getConfiguration(33-33)src/Services/MeilisearchManager.php (1)
getConfiguration(85-88)
tests/Integration/EventListener/DoctrineEventSubscriberTest.php (2)
src/SearchManagerInterface.php (1)
search(88-88)src/Services/MeilisearchManager.php (1)
search(195-236)
src/Services/SettingsUpdater.php (1)
src/SearchManagerInterface.php (1)
getConfiguration(33-33)
config/doctrine.php (1)
src/EventListener/DoctrineEventSubscriber.php (1)
DoctrineEventSubscriber(10-30)
tests/Kernel.php (1)
src/DependencyInjection/MeilisearchExtension.php (1)
load(22-79)
tests/Integration/SearchTest.php (3)
tests/BaseKernelTestCase.php (1)
waitForAllTasks(47-52)src/SearchManagerInterface.php (2)
search(88-88)rawSearch(98-98)src/Services/MeilisearchManager.php (2)
search(195-236)rawSearch(238-246)
src/Exception/DataProviderNotFoundException.php (2)
src/Exception/InvalidIndiceException.php (1)
__construct(9-12)src/Exception/NotSearchableException.php (1)
__construct(9-12)
src/SearchableObject.php (4)
src/SearchableEntity.php (1)
getSearchableArray(66-91)src/Identifier/DefaultIdNormalizer.php (1)
normalize(9-31)src/Identifier/IdNormalizerInterface.php (1)
normalize(12-12)src/Services/UnixTimestampNormalizer.php (1)
normalize(14-17)
src/Command/MeilisearchDeleteCommand.php (4)
src/SearchManagerInterface.php (1)
deleteByIndexName(67-67)src/SearchService.php (1)
deleteByIndexName(50-50)src/Services/MeilisearchManager.php (1)
deleteByIndexName(183-186)src/Services/MeilisearchService.php (1)
deleteByIndexName(185-194)
src/SearchableEntity.php (4)
tests/Entity/Link.php (1)
normalize(74-85)tests/Entity/SelfNormalizable.php (1)
normalize(64-75)tests/Entity/Tag.php (1)
normalize(88-100)src/SearchableObject.php (1)
SearchableObject(13-80)
src/Command/MeilisearchCreateCommand.php (3)
src/Command/IndexCommand.php (1)
__construct(19-24)src/SearchManagerInterface.php (1)
isSearchable(22-22)src/Services/MeilisearchManager.php (1)
isSearchable(64-69)
src/DependencyInjection/Configuration.php (1)
src/SearchableObject.php (1)
SearchableObject(13-80)
tests/Integration/AggregatorTest.php (4)
src/Model/Aggregator.php (2)
getEntityClassFromObjectID(69-78)normalize(80-83)src/Exception/EntityNotFoundInObjectID.php (1)
EntityNotFoundInObjectID(7-9)src/Exception/InvalidEntityForAggregator.php (1)
InvalidEntityForAggregator(7-9)src/Identifier/DefaultIdNormalizer.php (1)
normalize(9-31)
tests/Entity/Car.php (3)
tests/Entity/Link.php (1)
ORM(16-86)tests/Entity/SelfNormalizable.php (1)
ORM(16-76)tests/Entity/Tag.php (1)
ORM(17-101)
src/Command/MeilisearchUpdateSettingsCommand.php (4)
src/Command/IndexCommand.php (1)
__construct(19-24)src/Services/MeilisearchManager.php (2)
__construct(51-62)isSearchable(64-69)src/SearchManagerInterface.php (1)
isSearchable(22-22)src/Services/MeilisearchService.php (1)
isSearchable(66-77)
src/Identifier/DefaultIdNormalizer.php (1)
src/Identifier/IdNormalizerInterface.php (2)
normalize(12-12)denormalize(21-21)
src/Identifier/IdNormalizerInterface.php (1)
src/Identifier/DefaultIdNormalizer.php (2)
normalize(9-31)denormalize(33-39)
config/services.php (5)
src/DataProvider/DataProviderRegistry.php (1)
DataProviderRegistry(10-37)src/Engine.php (1)
Engine(44-182)src/Identifier/DefaultIdNormalizer.php (1)
DefaultIdNormalizer(7-40)src/Services/MeilisearchManager.php (1)
MeilisearchManager(27-422)src/Services/SettingsUpdater.php (1)
SettingsUpdater(17-78)
src/SearchManagerInterface.php (2)
src/Exception/NotSearchableException.php (1)
NotSearchableException(7-13)src/SearchService.php (2)
searchableAs(34-34)search(59-64)
src/Services/MeilisearchService.php (3)
src/EventListener/DoctrineEventSubscriber.php (1)
__construct(12-14)src/Collection.php (4)
__construct(20-23)Collection(13-380)get(30-37)count(205-208)src/Services/MeilisearchManager.php (11)
isSearchable(64-69)getConfiguration(85-88)searchableAs(71-83)index(90-139)remove(141-174)clear(176-181)deleteByIndexName(183-186)delete(188-193)search(195-236)rawSearch(238-246)count(248-253)
tests/Integration/EngineTest.php (3)
src/SearchableObject.php (1)
SearchableObject(13-80)tests/Entity/Image.php (1)
getId(39-42)tests/Entity/Post.php (1)
getId(91-94)
tests/BaseKernelTestCase.php (2)
src/SearchManagerInterface.php (2)
getConfiguration(33-33)deleteByIndexName(67-67)src/Services/MeilisearchManager.php (2)
getConfiguration(85-88)deleteByIndexName(183-186)
src/Command/MeilisearchImportCommand.php (6)
src/EventListener/DoctrineEventSubscriber.php (1)
__construct(12-14)src/SearchManagerInterface.php (4)
isSearchable(22-22)index(42-42)count(106-106)deleteByIndexName(67-67)src/DataProvider/DataProviderRegistry.php (1)
getDataProvider(21-36)src/DataProvider/DataProviderRegistryInterface.php (1)
getDataProvider(21-21)src/DataProvider/DataProviderInterface.php (2)
provide(18-18)cleanup(48-48)src/DataProvider/OrmEntityProvider.php (2)
provide(22-31)cleanup(89-92)
src/Command/MeilisearchClearCommand.php (5)
src/Engine.php (1)
clear(137-140)src/SearchManagerInterface.php (1)
clear(60-60)src/SearchService.php (1)
clear(43-43)src/Services/MeilisearchManager.php (1)
clear(176-181)src/Services/MeilisearchService.php (1)
clear(172-183)
src/Engine.php (2)
src/SearchManagerInterface.php (5)
index(42-42)remove(51-51)clear(60-60)count(106-106)search(88-88)src/SearchableObject.php (5)
SearchableObject(13-80)getSearchableArray(65-79)getIndexUid(42-45)getPrimaryKey(50-53)getIdentifier(55-58)
src/Services/MeilisearchManager.php (7)
src/Engine.php (8)
Engine(44-182)__construct(46-48)index(61-90)remove(100-126)clear(137-140)delete(147-150)search(159-162)count(169-172)src/Exception/NotSearchableException.php (2)
NotSearchableException(7-13)__construct(9-12)src/SearchableObject.php (2)
SearchableObject(13-80)__construct(28-37)src/DataProvider/OrmEntityProvider.php (4)
__construct(15-20)getIdentifierValues(72-77)normalizeIdentifiers(79-82)loadByIdentifiers(33-70)src/SearchManagerInterface.php (11)
isSearchable(22-22)searchableAs(31-31)getConfiguration(33-33)index(42-42)remove(51-51)clear(60-60)deleteByIndexName(67-67)delete(76-76)search(88-88)rawSearch(98-98)count(106-106)src/DataProvider/DataProviderRegistryInterface.php (1)
getDataProvider(21-21)src/DataProvider/DataProviderInterface.php (3)
getIdentifierValues(32-32)normalizeIdentifiers(39-39)loadByIdentifiers(25-25)
src/DependencyInjection/MeilisearchExtension.php (4)
src/DataProvider/OrmEntityProvider.php (1)
OrmEntityProvider(10-93)src/MeilisearchBundle.php (2)
MeilisearchBundle(11-31)qualifiedVersion(15-18)src/Model/Aggregator.php (2)
Aggregator(15-84)getEntities(51-54)src/Entity/Aggregator.php (1)
Aggregator(9-11)
src/Exception/InvalidIndiceException.php (1)
src/Exception/DataProviderNotFoundException.php (1)
__construct(9-12)
🪛 GitHub Actions: Tests
src/DependencyInjection/Configuration.php
[error] 14-14: PHPMD: ExcessiveMethodLength - The method getConfigTreeBuilder() has 100 lines of code. Current threshold is set to 100. Avoid really long methods.
src/Identifier/DefaultIdNormalizer.php
[error] 19-19: PHPMD: MissingImport - Missing class import via use statement (line '19', column '27').
src/Services/MeilisearchService.php
[error] 27-27: PHPMD: TooManyPublicMethods - The class MeilisearchService has 11 public methods. Consider refactoring MeilisearchService to keep number of public methods under 10.
[error] 27-27: PHPMD: ExcessiveClassComplexity - The class MeilisearchService has an overall complexity of 67 which is very high. The configured complexity threshold is 50.
[error] 27-27: PHPMD: CouplingBetweenObjects - The class MeilisearchService has a coupling between objects value of 16. Consider to reduce the number of dependencies under 13.
[error] 48-48: PHPMD: LongVariable - Avoid excessively long variable names like $classToSerializerGroup. Keep variable name length under 20.
[error] 57-57: PHPMD: StaticAccess - Avoid using static access to class '\Symfony\Component\PropertyAccess\PropertyAccess' in method '__construct'.
[error] 415-415: PHPMD: LongVariable - Avoid excessively long variable names like $searchableEntitiesChunk. Keep variable name length under 20.
[error] 463-463: PHPMD: StaticAccess - Avoid using static access to class '\Doctrine\ORM\Proxy\DefaultProxyClassNameResolver' in method 'resolveClass'.
[error] 467-467: PHPMD: StaticAccess - Avoid using static access to class '\Doctrine\Common\Util\ClassUtils' in method 'resolveClass'.
src/Command/MeilisearchImportCommand.php
[error] 24-24: PHPMD: CouplingBetweenObjects - The class MeilisearchImportCommand has a coupling between objects value of 14. Consider to reduce the number of dependencies under 13.
[error] 73-73: PHPMD: CyclomaticComplexity - The method execute() has a Cyclomatic Complexity of 14. The configured cyclomatic complexity threshold is 10.
[error] 73-73: PHPMD: NPathComplexity - The method execute() has an NPath complexity of 976. The configured NPath complexity threshold is 200.
src/Services/MeilisearchManager.php
[error] 27-27: PHPMD: ExcessiveClassComplexity - The class MeilisearchManager has an overall complexity of 59 which is very high. The configured complexity threshold is 50.
[error] 413-413: PHPMD: StaticAccess - Avoid using static access to class '\Doctrine\ORM\Proxy\DefaultProxyClassNameResolver' in method 'resolveClass'.
[error] 417-417: PHPMD: StaticAccess - Avoid using static access to class '\Doctrine\Common\Util\ClassUtils' in method 'resolveClass'.
src/DependencyInjection/MeilisearchExtension.php
[error] 20-20: PHPMD: CouplingBetweenObjects - The class MeilisearchExtension has a coupling between objects value of 13. Consider to reduce the number of dependencies under 13.
[error] 22-22: PHPMD: IfStatementAssignment - Avoid assigning values to variables in if clauses and the like (line '48', column '24').
[error] 36-36: PHPMD: StaticAccess - Avoid using static access to class '\Meilisearch\Bundle\MeilisearchBundle' in method 'load'.
[error] 55-55: PHPMD: ElseExpression - The method load uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them.
[error] 66-66: PHPMD: StaticAccess - Avoid using static access to class '\MeilisearchBundle\MeilisearchBundle' in method 'load'.
[error] 121-121: PHPMD: MissingImport - Missing class import via use statement (line '121', column '31').
[error] 128-128: PHPMD: ElseExpression - The method registerDataProviders uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them.
🔇 Additional comments (63)
src/Exception/LogicException.php (1)
1-9: LGTM! Clean exception class implementation.The custom LogicException is correctly implemented following Symfony conventions, including the use of a fully qualified name for the base exception class (as per your coding style) and the
finalkeyword for the leaf exception type.tests/Integration/AggregatorTest.php (5)
24-27: LGTM!The test correctly validates the objectID parsing logic, ensuring that
getEntityClassFromObjectIDextracts the entity class from the composite identifier format.
29-34: LGTM!The test appropriately validates exception handling for unknown entities in objectID strings.
36-43: LGTM!The test correctly validates that the aggregator rejects entities with composite primary keys, ensuring single-identifier constraints are enforced.
69-84: LGTM!The test correctly validates normalization with the default primary key, properly passing identifier values and verifying both the objectID (stringified) and id fields in the serialized output.
86-100: LGTM!The test correctly validates custom primary key configuration, ensuring that specifying a custom primary key name ('id') properly overrides the default and appears in the serialized output.
README.md (1)
56-59: Clear documentation of optional Doctrine integration.The new section effectively communicates that Doctrine is now an optional dependency and provides straightforward installation instructions.
src/Exception/InvalidIndiceException.php (1)
9-9: LGTM: Type safety improvement.Explicitly typing
$codeasintaligns with the parent\InvalidArgumentExceptionsignature and improves type safety. This matches the pattern used in other new exceptions likeDataProviderNotFoundException.tests/Kernel.php (1)
36-42: Clean simplification of Doctrine config loading.The three-way conditional elegantly handles different Doctrine bundle versions (v3, v2 with PHP 8.4+, and legacy) while removing unnecessary complexity from the previous implementation.
src/SearchableEntity.php (2)
15-17: Proper deprecation notice guiding migration to SearchableObject.The deprecation clearly directs users to the replacement class, supporting a smooth migration path.
83-87: Consistent constant migration to SearchableObject.Both normalization paths (lines 83 and 87) correctly reference
SearchableObject::NORMALIZATION_FORMAT, ensuring consistency across NormalizableInterface and standard normalization flows.src/Event/SettingsUpdatedEvent.php (1)
16-21: Clean adoption of constructor property promotion.Using promoted
private readonlyproperties is idiomatic for PHP 8.1+ and reduces boilerplate while maintaining the same public API through the getter methods.src/Command/MeilisearchDeleteCommand.php (1)
32-32: Correct migration to SearchManagerInterface.The call to
deleteByIndexName()correctly uses$this->searchManagerinstead of the deprecatedsearchService, aligning with the broader API migration across all commands.phpstan-baseline.php (1)
1-23: Baseline appropriately suppresses PHPStan errors for optional Doctrine dependency.The baseline is acceptable. Verification confirms that
MeilisearchExtensionconditionally loads Doctrine-specific services only whenDoctrineBundleis present (line 43-46), and explicitly throws aLogicExceptionwhen ORM data providers are misconfigured without Doctrine (line 120-121).Both
MeilisearchServiceandMeilisearchManagerhave runtime guards viaclass_exists(DefaultProxyClassNameResolver::class)checks before falling back toClassUtils::getClass(), reducing the risk of runtime failures when Doctrine is absent. The@codeCoverageIgnoreannotation marks theClassUtilsfallback as an untested code path, which is appropriate given it only executes in legacy Doctrine versions.src/Command/MeilisearchClearCommand.php (1)
30-30: LGTM! Clean migration to SearchManagerInterface.The method call has been correctly updated from the deprecated SearchService to the new SearchManagerInterface. The
clear()method signature remains unchanged, ensuring backward compatibility.tests/config/framework.yaml (1)
5-7: LGTM! Improved test error handling and observability.Adding
handle_all_throwablesandphp_errorsconfiguration enhances error visibility during test execution, which aligns with the broader test suite improvements in this PR.tests/Integration/Command/MeilisearchImportCommandTest.php (1)
184-184: LGTM! Test expectation updated to reflect new import ordering.The log line order change reflects the updated batching behavior in the import command after migrating to the DataProvider architecture. Both indices are still correctly populated; only the logging order has changed.
tests/Entity/Tag.php (1)
9-9: LGTM! Clean migration to SearchableObject.The import and constant reference have been correctly updated from the old
Searchableto the newSearchableObjectclass. TheNORMALIZATION_FORMATconstant maintains the same value ('searchableArray'), ensuring consistent behavior.Also applies to: 90-90
tests/Integration/DependencyInjectionTest.php (1)
13-18: LGTM! Improved test isolation.The setUp method ensures each test begins with a clean container state by resetting
kernel.bundlesto an empty array. This prevents test pollution and improves reliability when testing DI configuration in isolation.src/Command/IndexCommand.php (2)
8-8: LGTM! Clean refactoring to SearchManagerInterface with constructor promotion.The migration from concrete
SearchServicetoSearchManagerInterfaceimproves testability and follows dependency inversion principles. The use of constructor property promotion is idiomatic for modern PHP 8.1+.Also applies to: 19-21
28-28: LGTM! Consistent usage of the new SearchManagerInterface.Configuration retrieval has been correctly updated to use the injected
$searchManager, maintaining consistency throughout the class.tests/Integration/Command/MeilisearchClearCommandTest.php (1)
39-40: LGTM! Test expectations updated for new test indices.The test assertions have been correctly updated to include the newly added
ActorandCarindices in the expected command output.tests/Integration/EventListener/DoctrineEventSubscriberTest.php (1)
23-23: LGTM! API simplified by removing EntityManager dependency.All
search()calls have been correctly updated to use the new signature that removes the$entityManagerparameter. This decouples the search API from Doctrine and aligns with the PR's objective to support non-Doctrine data sources (#302, #121).The new signature
search(string $className, string $query = '', array $searchParams = []): arrayis cleaner and more flexible.Also applies to: 38-38, 59-59, 81-81, 97-97, 107-107, 121-121, 131-131
src/DataProvider/DataProviderRegistryInterface.php (1)
1-22: LGTM! Clean interface design with proper generic annotations.The
DataProviderRegistryInterfacefollows best practices with strict type declarations, clear PHPDoc annotations including generic type parameters, and explicit exception documentation. The interface contract is straightforward and provides a clean abstraction for retrieving data providers by index and class.config/doctrine.php (1)
1-17: LGTM! Doctrine event subscriber wiring is correct.The service configuration properly wires the
DoctrineEventSubscriberwith the newmeilisearch.managerdependency, aligning with the migration fromSearchServicetoSearchManagerInterface.src/Exception/DataProviderNotFoundException.php (1)
1-13: LGTM! Exception follows codebase conventions.The exception class is consistent with other exceptions in the codebase (
NotSearchableException,InvalidIndiceException) and correctly uses the fully qualified\InvalidArgumentExceptionfollowing Symfony coding standards.tests/Unit/ConfigurationTest.php (3)
29-29: LGTM! Type hints updated appropriately.The explicit
mixedtype hints align with PHP 8.1+ requirements and improve code clarity by removing redundant@paramannotations.Also applies to: 47-47
135-150: LGTM! Test expectations updated to validate new configuration options.The tests now properly validate the new data provider architecture including
type,data_provider,id_normalizer, andprimary_keyconfiguration options across all index configuration scenarios.Also applies to: 193-208, 246-249, 288-291, 330-333
362-441: LGTM! Comprehensive test coverage for new configuration options.The new test scenarios effectively validate:
- Custom primary key configuration (different from the default 'objectID')
- Custom ID normalizer service configuration
This ensures the new data provider architecture is properly tested.
src/Identifier/DefaultIdNormalizer.php (1)
7-40: LGTM! Implementation correctly handles single and composite identifiers.The normalization logic is well-designed:
- Single identifiers are returned as-is (with proper
__toStringhandling)- Composite identifiers are ksorted, JSON-encoded, and converted to URL-safe base64
Note on pipeline failure: The PHPMD warning about missing import for
\InvalidArgumentExceptionat line 19 is expected. As per Symfony coding standards, global PHP classes should be referenced with a leading backslash rather than imported viausestatements.Based on learnings, Symfony projects prefer fully qualified names for global classes.
src/DependencyInjection/Configuration.php (4)
7-7: LGTM! Import updated to reflect new architecture.The change from
SearchabletoSearchableObjectaligns with the broader refactoring in this PR.
53-62: LGTM! New configuration options support the data provider architecture.The new configuration nodes properly support:
- Index
typewith sensible default ('orm') and validation- Configurable
primary_key(defaulting to 'objectID' for BC)- Optional custom
data_provider- Configurable
id_normalizerwith sensible default
64-69: LGTM! Documentation updated to reference new constant.The info text correctly references
SearchableObject::NORMALIZATION_GROUPafter the refactoring.
104-107: LGTM! Validation prevents configuration errors.The validation rule ensures that when
typeis set to 'custom', adata_providermust be configured. This provides clear feedback at configuration time rather than runtime failures.tests/Entity/Car.php (1)
1-34: LGTM! Test entity properly configured for composite primary key testing.The
Carentity provides good test coverage for:
- Composite primary keys (name + year)
- PHP 8.1 promoted constructor properties with attributes
- Property-to-getter name mapping (e.g.,
$name→getModelName())Unlike other test entities (
Tag,Link,SelfNormalizable), this entity doesn't implementNormalizableInterface, which is appropriate for testing default serialization behavior with composite keys.tests/Integration/EngineTest.php (2)
35-42: LGTM!The SearchableObject constructor usage is correct, with all required parameters properly provided. The use of 'objectID' as the primary key is intentional for backward compatibility testing.
67-69: LGTM!Both SearchableObject instantiations correctly provide all required constructor arguments and properly reuse the serializer instance.
tests/Integration/SearchTest.php (4)
72-92: LGTM!The addition of
waitForAllTasks()ensures indexing completes before search assertions, and the updated search calls correctly use the new SearchManagerInterface API with proper signatures.
115-117: LGTM!Proper synchronization with
waitForAllTasks()and correct pagination parameters in the search call.
138-140: LGTM!The test properly waits for tasks and correctly invokes the search API.
145-164: LGTM!The new test properly exercises the cars index with the data provider flow, following the established test pattern with proper synchronization and assertions.
composer.json (1)
21-52: LGTM!The dependency updates properly align with the PR objectives: PHP 8.1+ requirement, Symfony 6.4+ for LTS support, and moving Doctrine to optional dev dependency to support the new DataProvider abstraction. Dev tooling updates are appropriate maintenance.
tests/BaseKernelTestCase.php (1)
10-67: LGTM!The consistent migration from SearchService to SearchManagerInterface is correctly implemented throughout the test base class. All method calls properly match the new interface signatures, and the
waitForAllTasks()improvement now correctly waits for all tasks instead of just the first one.src/Services/SettingsUpdater.php (1)
23-29: LGTM!The constructor properly migrates to SearchManagerInterface dependency and effectively uses PHP 8.1+ property promotion. Configuration retrieval from the manager is correctly implemented.
src/Command/MeilisearchUpdateSettingsCommand.php (1)
22-56: LGTM!The command properly migrates to SearchManagerInterface with correct property promotion, parent constructor delegation, and proper usage of the
isSearchable()interface method.src/SearchableObject.php (3)
28-37: LGTM!The constructor properly uses descriptive parameter names (including
$identifierinstead of the shorter$id), applies appropriate type constraints, and correctly merges the normalization context with the Meilisearch flag.
39-58: LGTM!The getter methods are straightforward property accessors with appropriate return type annotations.
65-79: LGTM!The method correctly avoids mutating instance state by using a local context copy, properly handles Symfony version-specific DateTime normalization, and appropriately delegates to either the object's own normalize method or the injected normalizer.
src/Command/MeilisearchCreateCommand.php (2)
23-30: LGTM!The constructor migration to
SearchManagerInterfacewith readonly property promotion is clean and aligns with the broader refactoring pattern across the codebase.
66-68: LGTM!The usage update from
$this->searchServiceto$this->searchManagercorrectly reflects the new dependency.src/SearchManagerInterface.php (2)
15-17: Well-structured interface with comprehensive PHPDoc.The interface cleanly defines the search manager contract with proper type annotations and exception documentation.
35-42: Verify return type consistency with implementation.The return type
list<array<non-empty-string, DocumentAdditionOrUpdateTask>>suggests a list of per-index task mappings. Confirm this aligns with howMeilisearchManager::index()returns batched results viaarray_merge(...$responses).src/Engine.php (3)
10-43: Comprehensive PHPDoc type definitions.The PHPStan type definitions for task responses and search response shapes provide excellent type safety and documentation for the Engine's return types.
78-79: Good fix for per-index primary key tracking.The batching now correctly associates each index with its own primary key using
['primaryKey' => ..., 'documents' => []], addressing the previously identified issue where a single primary key was applied to all indexes.
174-181: Simplified ID normalization.The
normalizeIdmethod correctly handles\Stringableby casting objects to string. Since the type hint is\Stringable|string|int, any object passed here must implement__toString(), making the explicit method check unnecessary.src/Services/MeilisearchService.php (1)
24-27: Appropriate deprecation strategy.The deprecation docblock and
trigger_deprecationcalls throughout the methods provide a clear migration path while maintaining backward compatibility. The delegation to the new manager when available ensures existing code continues to work.config/services.php (2)
69-77: Manager service correctly wired.The
MeilisearchManagerservice is properly configured with all required dependencies: normalizer, engine, property_accessor, data_provider.registry, and configuration.
126-137: Data provider and ID normalizer services properly registered.The
DataProviderRegistryandDefaultIdNormalizerservices are correctly defined with their interface aliases, enabling dependency injection via interface type-hints.src/Command/MeilisearchImportCommand.php (2)
28-36: Constructor properly migrated to new dependencies.The command now correctly depends on
SearchManagerInterfaceandDataProviderRegistryInterface, with readonly property promotion for cleaner code.
121-151: Data provider-based import loop is well-structured.The loop correctly:
- Obtains the data provider once before the loop
- Breaks early on empty results with cleanup
- Indexes via the manager
- Calls cleanup after each batch
- Uses proper pagination with
$pagecounterThis addresses the earlier concern about repeated provider instantiation.
src/Services/MeilisearchManager.php (3)
51-62: Well-structured constructor with clear dependencies.The constructor properly injects all required dependencies and initializes the internal state via dedicated setup methods.
195-236: Search hydration correctly uses provider's normalizeIdentifiers.The search method now consistently uses
$dataProvider->normalizeIdentifiers()for building object keys, ensuring alignment with how IDs are normalized during indexing. This addresses the earlier concern about custom ID normalizer consistency.
401-421: Static access is acceptable for Doctrine proxy resolution.The PHPMD StaticAccess warnings for
DefaultProxyClassNameResolver::getClass()andClassUtils::getClass()are unavoidable here—these are utility methods provided by Doctrine for resolving proxy class names. The static memoization pattern with$resolveris appropriate for this use case.
f57906b to
b98e992
Compare
b98e992 to
62d5729
Compare
Strift
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’ve reviewed the discussion and the automated CodeRabbit review. Most points have been addressed and checks are passing. I’m happy to trust your technical judgement here.
Approving this PR, thanks for the work 🙌
Pull Request
Early christmas present 🎄
Usage as previously (for forward compatibility provider type is 'orm' by default, just that ORM must be an explicit dependency of the application now):
Usage with custom data provider:
If you have a meilisearch index with different primary key than
objectID, you can now configure it:Deprecations & Upgrade path⚠️
Using
Meilisearch\Bundle\SearchServiceandMeilisearch\Bundle\Service\MeilisearchServiceis now deprecated.Switch to
Meilisearch\Bundle\SearchManagerInterfaceandMeilisearch\Bundle\Service\MeilisearchManagerPreviously methods were accepting doctrine's
ObjectManager:Now it does not ask for
ObjectManageranymore:What's next?
Now that we bump PHP to 8.1, we can later introduce PHP attributes for meilisearch, so instead of configuring everything through yaml, configuration can be linked in the classes (related issue #387).
We should introduce
SearchResultsthat allows to access/iterate found entities, while also exposingfacetResultsand other fields (related issue #353)Related issue
Fixes #66
Fixes #121
Fixes #134
Fixes #240
Fixes #302
Replaces #345
What does this PR do?
PR checklist
Please check if your PR fulfills the following requirements:
cc @remigarcia
cc @tacman in case you are interested
cc @ToshY
Summary by CodeRabbit
New Features
Chores
Deprecations
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.