fix(DynamicContentSubscriber): Mautic 5 migration CI test#1
fix(DynamicContentSubscriber): Mautic 5 migration CI test#1edouard-mangel wants to merge 16 commits intostagingfrom
Conversation
* PHPStan fix again * PHPStan * PHPStan * PHPStan * Update README.md * Remove PUT from the available item operations for the custom_objects endpoint. * as PUT method is removed we are using PATCH insted * fix segement filter issue in custom object * fix test cases * add code coverage * fix phpstan issue * fix failing test case * fixing patch request * skip setDefaultValuesForMissingFields for patch request * adding comment * updating note for implementation * Fix warnings in test suite for PHP8.0 upgrade * Remove unused import Co-authored-by: Saurabh Gupta <48244990+dadarya0@users.noreply.github.com> * check lead exist before link to custom item * fixed tests * adding tests * removed php8 only compatibal code * change warning type * correct message * changed warning type * fix tests * check for method exists and csfix * Add merge filter query * Remove const is defined check * Fix test case by adding config param * Add function to check if custom object filters are mergable * Revert CustomFieldFilterQueryBuilder * Update services * Add CustomObjectMergedFilterQueryBuilder * Use CustomObjectMergedFilterQueryBuilder * Check for custom item filter * Change merge filter logic * Make consts * Fix test cases * Test with custom_object_merge_filter param * Move test to appropriate class name * Rename test case * Rename test case * Revert unnecessary code * Remove union return type declaration in favour of PHP7.4 * Remove not exists in favour of negative filters * Fix contact not getting added when one segment filter is used * fix dependencies * add parent constructor call * remove duplicate dependencies; change deprecated methods * fix inserting variable into string * fix an event dispatching issue * fix import with contact ids * fix the allowed memory size exhausted issue * fix the inheritance model issue * Handling custom item links when merging contacts * Adding GH Actions config * Adding PHPSTAN Baseline for existing issues * Remove dead code flagged by Rector * Fixing PHPUNIT config * Debugging tests * PHPSTAN baseline for each PHP version * Fixing tests * Some tests require theofidry/alice-data-fixtures * Test gh-actions * tests.yaml update * PHPSTAN baseline (debug) update * Comment PHPUNIT TESTS * Comment Coverage Report step * skip test * skip test * revert * print commit id * Push commit to mc-cs * Push commit to mc-cs * Push commit to mc-cs * Push commit to mc-cs * Push commit to mc-cs * Push commit to mc-cs * static analysis add * Moving Install composer up and comment phpstan baseline * Upgrade php and mysql version * Uncoomment PHPSTAN step * comment phpstan * Debug: regenerating PHPSTAN baseline * Updating PHPSTAN baseline, enabling PHPSTAN check * Clearing up the baseline files to generate them from scratch * Running PHPSTAN with fresh baselines * Updating action versions to avoid NodeJS warnings * Removing the pull_request settings hoping the CI will run on the commit without merging to staging * Disabling composer cache as theofidry/alice-data-fixtures doesn't seem to be present * Would it help to run the commands separately? * Or lock the version? * The dependency must be also set in kernel. Let's skip the tests that need it for now * The coverage report contains whole Mautic. Testing something different * Fixing kernel class * Another attempt to resolve the kernel class issue * Do we need to set KERNEL_CLASS? * Check API request by the controller name * fix customobject fetch from typeoparatorprovider * split into 2 line * var name change * empty and neq operator fixed * pass true for $filterAlreadyNegated only from CustomFieldFilterQueryBuilder * CustomItemRelationQueryBuilderTestCase was not included within the test suite as its name didn't end with "Test" * Added functional tests for "not equal" and "empty" operators * adding KERNEL_CLASS * fixing test * fixing tests * Update Tests/Functional/Segment/Query/Filter/NegativeOperatorFilterQueryBuilderTest.php Co-authored-by: Avikarsha Saha <avikarsha.saha@gmail.com> * enabling phpstan and fixed issues * I think composer install should run after install mautic * removed dependacy install after mautic installation * removed vendor from scanDirectories from neon file * added between/not between operator for date type field * fix sonar issue * add functional test case * fix syntax * fix issue for development branch failing * Adding inTheLast and inTheNext operator for dat and datetime type fields * Fixed CampaignConditionTest * phpstan-ignore * phpstan-ignore * Comments for workarounds * CS fixes * NegativeOperatorFilterQueryBuilderTest fixed * NegativeOperatorFilterQueryBuilderTest fixed * Update Helper/QueryFilterHelper.php Co-authored-by: Aarohi Prasad <aarohi.prasad@acquia.com> * fixc s * fix date issue if empty/not empty filter is used * fixed UI for between op, test case WIP * fix phpstan * Functioning code and test case for custom item between query for numbers * better handling of types * php7.4 syntax * removed php 8 only syntax * added test case for where assertion * fix failing test case * removed extra parameter * syntax changes * Env variable MAUTIC_PROJECT_VERSION introduced * TypeError : str_starts_with() fixed * fix same for merged filter too * change variable names * fixed failing test * fix not beetween issue * skip for 4.4 * skip for 4.4 csfix * skip for 4.4 csfix * skip for 4.4 csfix * 7.4 syntax * stan fix * stan fix * stan fix * fixes phpstan * skip phpstan * removing ingnore comment * removing unnecessary array filter * Hide the new operators from campaign condition, leave them for segment fitlers * Fixing operators also for int field types * cast string * test * MAUT-11616 : Fix operators do not refresh after selecting a different type of field in campaign event (acquia#356) * fix Operators do not refresh after selecting a different type of field * csfix * adding test which verify the data-operators attr is available * fix phpstan * fix tests * suggessions * MAUT-11617 : Campaign -> Condition -> Custom Object Field values : Date picker unavailable for Date type fields (acquia#357) * fix Operators do not refresh after selecting a different type of field * csfix * adding test which verify the data-operators attr is available * fix phpstan * fix tests * datepicker for date and datetime fields * using const type for fieldType Co-authored-by: Miroslav Fedeleš <miroslav.fedeles@gmail.com> * suggessions * ifx value should not be empty after change operator --------- Co-authored-by: Miroslav Fedeleš <miroslav.fedeles@gmail.com> * Replaced logger with monolog.logger.mautic (acquia#355) * MAUT-11515 : Custom object date segment filters should have have same operators than date custom field filters (acquia#358) * added all date/datetime filters to custom oject date fields * check if getcontext is exist * Added new function instead changing old one * change if condition sequence * increase code coverage * skip test case if mrunning on mautic 4.4 * Maut 11460: Dynamic content in email builder filtered on custom object values (acquia#352) * on replacement * fix test * test * test * test * fix * skiped for 4.4 * WIP * refining * test case * test refine * fix test case * fix test case * split lines * CR * unnecessary query remove * check isset * local cache * key with id * test cases * Update EventListener/TokenSubscriber.php Co-authored-by: John Linhart <admin@escope.cz> * Update EventListener/TokenSubscriber.php Co-authored-by: John Linhart <admin@escope.cz> * WIP * string concat * match logic for CO * test case * test case csfix * test case csfix * const * var in config * fix null case for datetime * cs fix * fix for select and multi select * for noraml lead field * test case * split line * test case * fix for like and select --------- Co-authored-by: Avikarsha Saha <avikarsha.saha@acquia.com> Co-authored-by: John Linhart <admin@escope.cz> * Update Entity/CustomFieldOption.php Co-authored-by: GuzmanBellon <47144569+GuzmanBellon@users.noreply.github.com> * Fix EventDispatcher calling * Fix deprecated fetchColumn call * Use appropriate service to run a command in the test * Add #[AllowDynamicProperties] attribute to allow using dynamic properies * Fix tests of controllers * Fix test of controllers * Fix controller tests * Fix controller tests * Fix model tests * Fix listener tests * Fix Form tests * Fix controller tests * Fix repository tests * Fix functional tests * Fix functional tests * Add a required field to fixtures * Fix created objects for testing * Fix pagination * Remove commented code * MAUT-11383 : incorrect date value being calculating when the segment filter value is "yesterday" and operator is "gt" for date field (acquia#359) * Fix custom parameter date issue * add more test case * Fix config after merging * Fix a variable name * Fix tests after merging * Update dependencies * Get the export directory using the config * CS fixing * Remove unnesessary constant definition * Fix tests * Use master request instead of deprecated * Change phpunit configuration * CS fixing * PHPstan fixes * PHPStan fixes some ORM deprecations * Add phpstan baseline * Fix rector issues * Update phpstan baseline * Fix rector issues * Fix tests after fixing rector failures * Fix rector failures * Temporary set a parameter to allow the pipeline to continue even if Rector fails * Remove the CI Rector's temporary setting * Fix rector issues * Add a CI setting to crate a writable directory --------- Co-authored-by: Don Gilbert <don.gilbert@acquia.com> Co-authored-by: Donald Gilbert <don@dongilbert.net> Co-authored-by: Tejas Navghane <ts.navghane@gmail.com> Co-authored-by: Rohit Pavaskar <66303837+rohitp19@users.noreply.github.com> Co-authored-by: rahuld-dev <rahul.dhande@acquia.com> Co-authored-by: Saurabh Gupta <48244990+dadarya0@users.noreply.github.com> Co-authored-by: Saurabh Gupta <saurabh.gupta@acquia.com> Co-authored-by: Rahul Dhande <68939488+rahuld-dev@users.noreply.github.com> Co-authored-by: Himanshu Prajapati <85485894+himanshu8acquia@users.noreply.github.com> Co-authored-by: John Linhart <jan@linhart.email> Co-authored-by: John Linhart <admin@escope.cz> Co-authored-by: aadarshjain-dev <aadarsh.jain@acquia.com> Co-authored-by: fedys <miroslav.fedeles@gmail.com> Co-authored-by: Avikarsha Saha <avikarsha.saha@acquia.com> Co-authored-by: Avikarsha Saha <avikarsha.saha@gmail.com> Co-authored-by: Aarohi Prasad <aarohi.prasad@acquia.com> Co-authored-by: GuzmanBellon <47144569+GuzmanBellon@users.noreply.github.com>
…king (acquia#369) * fix: Resolve contact tabs not being searchable and pagination not working * chore: Update to v4 upload-artifact
…evaluation The 5.x branch left DynamicContentSubscriber in the old Mautic 4 state: traits (MatchFilterForLeadTrait, DbalQueryTrait) that no longer exist in mautic/core-lib ^5.0, and a QueryBuilder-based filter evaluation path. Changes: - Remove MatchFilterForLeadTrait and DbalQueryTrait (removed from core in 5.x) - Remove QueryFilterHelper and LoggerInterface from constructor - Wire ContactFilterMatcher as the delegate in evaluateFilters() - Simplify hasCustomObjectFilters() — returns true on first non-throwing filter - Rewrite DynamicContentSubscriberTest: correct collaborators, 6 tests / 21 assertions - Add docs/adr/0001-mautic5-migration-strategy.md Verified on Mautic 5.2.9 / Symfony 5.4 / PHP 8.3 via DDEV: - cache:clear succeeds - mautic:plugins:reload installs the plugin (13 DB tables created) - Custom Objects UI fully functional at /s/custom/object/ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ill trait directly The class_alias trick (selecting between Mautic core MatchFilterForLeadTrait and the polyfill at runtime) is not statically analysable by PHPStan, causing 8 false-positive errors. Since this branch targets Mautic 5 where the core trait no longer has transformFilterDataForLead(), the polyfill branch always executes — making the class_alias logic dead code. - Remove class_alias block and Mautic\EmailBundle\EventListener\MatchFilterForLeadTrait import - Use MatchFilterForLeadTraitPolyfill directly with a named alias - Add 2 legitimate PHPStan baseline entries (MAUTIC_TABLE_PREFIX global constant and transformFilterDataForLead trait-override detection limitation) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
DynamicContentSubscriber and ContactFilterMatcher are already discovered by Config/services.php via ->load(). Add ->bind() for the scalar $leadCustomItemFetchLimit parameter so autowiring can resolve it without explicit config.php entries. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace global ->bind() in services.php defaults with a per-service #[Autowire(param: ...)] attribute on ContactFilterMatcher, following the pattern used in Mautic 5 core (JsController, PluginDatabase, etc.).
Covers: no CO filters, NotFoundException/InvalidCustomObjectFormatListException handling, no linked items, name match/mismatch, multi-item match, custom item caching per object+lead, company enrichment, tag enrichment.
…ems linked When a contact has no linked custom items, the lead value array is empty and the foreach never executes, leaving the group result as false. For the 'empty' operator this is semantically wrong — no items means the field IS empty, so the condition should match.
…ing in services.php The #[Autowire] attribute is not reliably processed in Mautic 5.1 environments, causing a container compilation failure. Use a specific service definition with ->arg() in services.php instead — this is scoped to ContactFilterMatcher only and works across all supported Mautic/Symfony versions.
There was a problem hiding this comment.
Pull request overview
Migrates the CustomObjectsBundle codebase toward Mautic 5+ compatibility and stabilizes CI by updating Symfony/Doctrine APIs, controllers, templates, and tests.
Changes:
- Updated Symfony/Doctrine/DBAL usage (types, events, translator interface, Result API) and modernized many classes with typed properties/constructor promotion.
- Refactored multiple controllers to action injection signatures and added/updated Twig templates to replace legacy PHP templates.
- Added/adjusted functional + unit tests and introduced new helpers to handle environment-specific behavior (e.g., fixture dependency skipping, version detection).
Reviewed changes
Copilot reviewed 292 out of 378 changed files in this pull request and generated 20 comments.
Show a summary per file
| File | Description |
|---|---|
| Tests/Unit/Entity/CustomItemXrefCustomItemTest.php | Fully-qualified DateTime/Exception usage for PHP/Symfony compatibility |
| Tests/Unit/Entity/CustomItemXrefContactTest.php | Fully-qualified DateTime usage |
| Tests/Unit/Entity/CustomItemXrefCompanyTest.php | Fully-qualified DateTime usage |
| Tests/Unit/Entity/CustomItemTest.php | TranslatorInterface switched to Symfony Contracts |
| Tests/Unit/Entity/CustomFieldTest.php | TranslatorInterface switched + added integer label test |
| Tests/Unit/CustomObjectTestCase.php | Fully-qualified DateTime/DateTimeZone usage |
| Tests/Unit/CustomFieldType/UrlTypeTest.php | TranslatorInterface switched to Symfony Contracts |
| Tests/Unit/CustomFieldType/SelectTypeTest.php | TranslatorInterface switched to Symfony Contracts |
| Tests/Unit/CustomFieldType/PhoneTypeTest.php | TranslatorInterface switched to Symfony Contracts |
| Tests/Unit/CustomFieldType/MultiselectTypeTest.php | TranslatorInterface switched to Symfony Contracts |
| Tests/Unit/CustomFieldType/IntTypeTest.php | TranslatorInterface switched to Symfony Contracts |
| Tests/Unit/CustomFieldType/EmailTypeTest.php | TranslatorInterface switched to Symfony Contracts |
| Tests/Unit/CustomFieldType/DateTypeTest.php | TranslatorInterface switched to Symfony Contracts |
| Tests/Unit/CustomFieldType/DateTimeTypeTest.php | TranslatorInterface switched to Symfony Contracts |
| Tests/Unit/CustomFieldType/DataTransformer/DateTimeAtomTransformerTest.php | Fully-qualified DateTime usage |
| Tests/Unit/CustomFieldType/CountryTypeTest.php | TranslatorInterface switched to Symfony Contracts |
| Tests/Unit/CustomFieldType/AbstractTextTypeTest.php | TranslatorInterface switched to Symfony Contracts |
| Tests/Unit/CustomFieldType/AbstractMultivalueTypeTest.php | TranslatorInterface switched to Symfony Contracts |
| Tests/Unit/CustomFieldType/AbstractCustomFieldTypeTest.php | TranslatorInterface switched + removed MAUTIC_TABLE_PREFIX define |
| Tests/Unit/Controller/CustomObject/ListControllerTest.php | Updated for controller action injection + AllowDynamicProperties |
| Tests/Unit/Controller/CustomObject/CancelControllerTest.php | Updated for controller action injection |
| Tests/Unit/Controller/CustomItem/LookupControllerTest.php | Updated for controller action injection + constructor removal |
| Tests/Unit/Controller/CustomItem/CancelControllerTest.php | Updated for controller action injection + request stack setup |
| Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php | RequestStack-based mocking updated |
| Tests/Unit/Command/CustomItemExportCommandTest.php | Uses existing client from base test case |
| Tests/ProjectVersionTrait.php | Added helper to detect cloud project version |
| Tests/Functional/UpsertFunctionalTest.php | TranslatorInterface switched to Symfony Contracts |
| Tests/Functional/Token/EmailTokenTest.php | AllowDynamicProperties for PHP 8.2+ |
| Tests/Functional/Segment/Query/Filter/CustomItemRelationQueryBuilderTest.php | Modernized repo calls + stricter assertions |
| Tests/Functional/Segment/Query/Filter/CustomItemNameFilterQueryBuilderTest.php | Updated builder wiring + segment filter mock glue |
| Tests/Functional/Segment/Query/Filter/CustomFieldFilterQueryBuilderTest.php | Updated builder wiring + config override + segment filter mock glue |
| Tests/Functional/EventListener/TokenSubscriberTest.php | AllowDynamicProperties for PHP 8.2+ |
| Tests/Functional/EventListener/ImportSubscriberTest.php | TranslatorInterface switched + fully-qualified DateTimeImmutable |
| Tests/Functional/EventListener/ContactSubscriberTest.php | Added functional coverage for contact merge behavior |
| Tests/Functional/EventListener/CampaignConditionTest.php | Session handling updates + added operators attribute test |
| Tests/Functional/EventListener/ApiSubscriberTest.php | Updated number field expectation on cleared values |
| Tests/Functional/DataFixtures/Traits/FixtureObjectsTrait.php | Skip tests if alice-data-fixtures missing + fixed reverse order bug |
| Tests/Functional/DataFixtures/Traits/CustomObjectsTrait.php | Minor formatting tweak |
| Tests/Functional/DataFixtures/ORM/Data/custom_fields.yml | Fixed fixture typo: type "text" |
| Tests/Functional/Controller/CustomObjectFormTest.php | Fully-qualified DateTime assertions |
| Tests/Functional/Controller/CustomObject/DeleteControllerTest.php | Updated expected ordering of table rows |
| Tests/Functional/Controller/CustomItemListControllerXrefTest.php | Updated CSS selector for nested table |
| Tests/Functional/Controller/CustomItemListControllerShownFieldTest.php | Fully-qualified DateTime + updated heading XPath |
| Tests/Functional/Controller/CustomItemListControllerSearchTest.php | Updated heading XPath |
| Tests/Functional/ApiPlatform/CustomObjectFunctionalTest.php | Uses PATCH for updates |
| Tests/Functional/ApiPlatform/CustomFieldOptionFunctionalTest.php | TranslatorInterface switched to Symfony Contracts |
| Tests/Functional/ApiPlatform/AbstractApiPlatformFunctionalTest.php | Added PATCH helper + DBAL reflection FQCN updates |
| Serializer/ApiNormalizer.php | Constructor promotion + serializer signature tightened |
| Segment/Query/UnionQueryContainer.php | Typed properties + doc improvements |
| Segment/Query/Filter/QueryFilterFactory.php | Constructor promotion |
| Segment/Query/Filter/CustomObjectMergedFilterQueryBuilder.php | Added merged filter query builder |
| Segment/Query/Filter/CustomItemNameFilterQueryBuilder.php | Switched switch->match + constructor promotion |
| Segment/Query/Filter/CustomFieldFilterQueryBuilder.php | Updated helper call + match refactor + signature tightened |
| Security/Permissions/CustomObjectPermissions.php | Constructor promotion + TranslatorInterface switched |
| Resources/views/SubscribedEvents/Timeline/link.html.twig | Added new Twig template |
| Resources/views/SubscribedEvents/Tab/modal.html.twig | Added new Twig template |
| Resources/views/SubscribedEvents/Tab/link.html.twig | Added new Twig template |
| Resources/views/SubscribedEvents/Tab/content.html.twig | Added new Twig template with JS reload |
| Resources/views/FormTheme/FieldValueCondition/campaign_condition_field_value_widget.html.twig | Switched legacy PHP form rows to Twig form_row |
| Resources/views/CustomObject/list.html.twig | Added Twig list page template |
| Resources/views/CustomObject/detail.html.twig | Added Twig detail page template |
| Resources/views/CustomObject/_list.html.twig | Added Twig partial for list table |
| Resources/views/CustomObject/_form-fields.html.twig | Added Twig partial for dynamic field panels |
| Resources/views/CustomObject/_detail_right_section.html.twig | Added Twig recent-activity sidebar |
| Resources/views/CustomObject/Form/Panel/url.html.twig | Added panel template (extends shared field) |
| Resources/views/CustomObject/Form/Panel/textarea.html.twig | Added panel template (extends shared field) |
| Resources/views/CustomObject/Form/Panel/text.html.twig | Added panel template (extends shared field) |
| Resources/views/CustomObject/Form/Panel/select.html.twig | Added panel template (extends shared field) |
| Resources/views/CustomObject/Form/Panel/radio_group.html.twig | Added panel template (extends shared field) |
| Resources/views/CustomObject/Form/Panel/phone.html.twig | Added panel template (extends shared field) |
| Resources/views/CustomObject/Form/Panel/multiselect.html.twig | Added panel template (extends shared field) |
| Resources/views/CustomObject/Form/Panel/int.html.twig | Added panel template (extends shared field) |
| Resources/views/CustomObject/Form/Panel/html_area.html.twig | Added panel template (extends shared field) |
| Resources/views/CustomObject/Form/Panel/hidden.html.twig | Added panel template (extends shared field) |
| Resources/views/CustomObject/Form/Panel/email.html.twig | Added panel template (extends shared field) |
| Resources/views/CustomObject/Form/Panel/datetime.html.twig | Added panel template (extends shared field) |
| Resources/views/CustomObject/Form/Panel/date.html.twig | Added panel template (extends shared field) |
| Resources/views/CustomObject/Form/Panel/country.html.twig | Added panel template (extends shared field) |
| Resources/views/CustomObject/Form/Panel/checkbox_group.html.twig | Added panel template (extends shared field) |
| Resources/views/CustomObject/Form/Panel/_field.html.twig | Added shared panel field rendering |
| Resources/views/CustomItem/list.html.twig | Added Twig list page template |
| Resources/views/CustomItem/form.html.twig | Added Twig form template |
| Resources/views/CustomItem/detail.html.twig | Added Twig detail page template |
| Resources/views/CustomItem/_detail_right_section.html.twig | Added Twig recent-activity sidebar |
| Resources/views/CustomField/value.html.twig | Added Twig rendering for field values |
| Resources/views/CustomField/form.html.twig | Added Twig custom field modal/form |
| Resources/views/CustomField/detail.html.twig | Added Twig detail template |
| Resources/views/CustomField/_detail_right_section.html.twig | Added Twig sidebar template |
| Resources/views/CustomField/_detail_left_section.html.twig | Added Twig main section template |
| Repository/DbalQueryTrait.php | DBAL 3 Result compatibility |
| Repository/CustomObjectRepository.php | Custom base repository + fixed string interpolation |
| Repository/CustomItemXrefCustomItemRepository.php | Custom base repository |
| Repository/CustomItemXrefContactRepository.php | Custom base repository |
| Repository/CustomItemRepository.php | Custom base repository |
| Repository/CustomItemExportSchedulerRepository.php | Custom base repository |
| Repository/CustomFieldRepository.php | Custom base repository |
| Repository/CustomCommonRepository.php | Added base repository for entity FQCN inference |
| Report/ReportColumnsBuilder.php | Constructor promotion + typed columns |
| README.md | Added workflow + static analysis docs |
| Provider/SessionProviderFactory.php | Constructor promotion |
| Provider/SessionProvider.php | Constructor promotion |
| Provider/CustomObjectRouteProvider.php | Constructor promotion |
| Provider/CustomItemRouteProvider.php | Constructor promotion |
| Provider/CustomItemPermissionProvider.php | Constructor promotion |
| Provider/CustomFieldTypeProvider.php | Typed property |
| Provider/CustomFieldRouteProvider.php | Constructor promotion |
| Provider/ConfigProvider.php | Added merge-filter config logic |
| Provider/AbstractPermissionProvider.php | Uses ::class + constructor promotion |
| Model/CustomItemXrefContactModel.php | Uses FormModel-em + fully-qualified DateTime |
| Model/CustomFieldValueModel.php | DBAL fetchAllAssociative + typed closures |
| Model/CustomFieldOptionModel.php | Constructor promotion |
| Model/CustomFieldModel.php | Updated FormModel signature + alias sanitization |
| Migrations/Version_0_0_9.php | Typed props + modern catch |
| Migrations/Version_0_0_8.php | Typed props + modern catch |
| Migrations/Version_0_0_7.php | Typed props + modern catch |
| Migrations/Version_0_0_6.php | Typed props + modern catch |
| Migrations/Version_0_0_5.php | Typed props + modern catch |
| Migrations/Version_0_0_4.php | Typed props |
| Migrations/Version_0_0_3.php | Typed props |
| Migrations/Version_0_0_27.php | Modern catch |
| Migrations/Version_0_0_21.php | Modern catch |
| Migrations/Version_0_0_2.php | Typed props |
| Migrations/Version_0_0_19.php | Typed Schema property |
| Migrations/Version_0_0_18.php | Typed Schema property + modern catch |
| Migrations/Version_0_0_17.php | Typed Schema property + modern catch |
| Migrations/Version_0_0_16.php | Uses DBAL SchemaException + modern catch |
| Migrations/Version_0_0_15.php | Modern catch |
| Migrations/Version_0_0_14.php | Modern catch |
| Migrations/Version_0_0_13.php | Modern catch |
| Migrations/Version_0_0_11.php | Uses DBAL SchemaException + typed props |
| Migrations/Version_0_0_1.php | Typed props + modern catch |
| Helper/TokenParser.php | Modern catch + typed closure return |
| Helper/TokenFormatter.php | Small string concatenation + typed closure return |
| Helper/QueryFilterFactory/Calculator.php | Typed nullable properties |
| Helper/QueryFilterFactory.php | Constructor promotion + added helper accessors |
| Helper/QueryBuilderManipulatorTrait.php | Uses DBAL ParameterType/ArrayParameterType |
| Helper/LockFlashMessageHelper.php | TranslatorInterface switched + constructor promotion |
| Form/Validator/Constraints/CustomObjectTypeValuesValidator.php | Void return type |
| Form/Validator/Constraints/AllowUniqueIdentifierValidator.php | Constructor promotion |
| Form/Type/CustomObjectType.php | Constructor promotion + removed early-return |
| Form/Type/CustomFieldValueType.php | Modern catch |
| Form/Type/CustomFieldType.php | Constructor promotion + empty_data return type |
| Form/Type/CampaignConditionFieldValueType.php | Uses customObjectId option + operators/options data attrs |
| Form/Type/CampaignActionLinkType.php | TranslatorInterface switched + constructor promotion |
| Form/DataTransformer/ParamsToStringTransformer.php | Constructor promotion |
| Form/DataTransformer/OptionsToStringTransformer.php | Constructor promotion + typed cache |
| Form/DataTransformer/CustomObjectHiddenTransformer.php | Constructor promotion |
| Extension/CustomItemListeningExtension.php | Void return type + constructor promotion |
| Exception/UndefinedTransformerException.php | Extends \Exception |
| Exception/NotFoundException.php | Extends \Exception + \Throwable FQCN |
| Exception/NoRelationshipException.php | Extends \Exception + \Throwable FQCN |
| Exception/InvalidValueException.php | Typed customField property |
| Exception/InvalidSegmentFilterException.php | Extends \Exception |
| Exception/InvalidArgumentException.php | Extends \Exception |
| Exception/InUseException.php | Typed segmentList |
| Exception/ForbiddenException.php | Extends \Exception + \Throwable FQCN |
| EventListener/SerializerSubscriber.php | Constructor promotion + modern catch |
| EventListener/SegmentFiltersMergeSubscriber.php | Added subscriber for merged custom object filters |
| EventListener/SegmentFiltersChoicesGenerateSubscriber.php | Uses TypeOperatorProvider + segment-specific operators |
| EventListener/SegmentFilterDecoratorDelegateSubscriber.php | Constructor promotion |
| EventListener/ReportSubscriber.php | TranslatorInterface switched + constructor promotion + starts_with |
| EventListener/MenuSubscriber.php | Constructor promotion |
| EventListener/FilterOperatorSubscriber.php | Void return type + query builder changes |
| EventListener/CustomObjectPreDeleteSubscriber.php | TranslatorInterface switched + constructor promotion |
| EventListener/CustomObjectPostSaveSubscriber.php | Constructor promotion |
| EventListener/CustomObjectListFormatSubscriber.php | Constructor promotion |
| EventListener/CustomItemXrefCustomItemSubscriber.php | Constructor promotion + modern catch |
| EventListener/CustomItemXrefContactSubscriber.php | Constructor promotion + modern catch |
| EventListener/CustomItemTabSubscriber.php | Twig template wiring + TranslatorInterface switched |
| EventListener/CustomItemScheduledExportSubscriber.php | Constructor promotion |
| EventListener/CustomItemPostSaveSubscriber.php | Constructor promotion |
| EventListener/CustomItemPostDeleteSubscriber.php | Constructor promotion |
| EventListener/CustomFieldPreSaveSubscriber.php | Constructor promotion |
| EventListener/CustomFieldPostLoadSubscriber.php | Updated LifecycleEventArgs import + constructor promotion |
| EventListener/ContactTabSubscriber.php | Twig template wiring + TranslatorInterface switched |
| EventListener/AuditLogSubscriber.php | Constructor promotion |
| EventListener/AssetsSubscriber.php | Updated AssetsHelper + RequestEvent + isMainRequest |
| Event/CustomObjectListFormatEvent.php | Uses Contracts Event + constructor promotion |
| Event/CustomObjectEvent.php | Uses Contracts Event + constructor promotion |
| Event/CustomItemXrefEntityEvent.php | Uses Contracts Event + constructor promotion |
| Event/CustomItemXrefEntityDiscoveryEvent.php | Uses Contracts Event + constructor promotion |
| Event/CustomItemListQueryEvent.php | Uses Contracts Event + constructor promotion |
| Event/CustomItemListDbalQueryEvent.php | Uses Contracts Event + constructor promotion |
| Event/CustomItemExportSchedulerEvent.php | Uses Contracts Event + constructor promotion |
| Event/CustomItemEvent.php | Uses Contracts Event + constructor promotion |
| Entity/CustomItemXrefInterface.php | Docblock updated to \DateTimeInterface |
| Entity/CustomItemXrefCustomItem.php | DBAL Types + typed props + fully-qualified DateTime |
| Entity/CustomItemXrefContact.php | DBAL Types + constructor promotion + fully-qualified DateTime |
| Entity/CustomItemXrefCompany.php | DBAL Types + constructor promotion + fully-qualified DateTime |
| Entity/CustomItemExportScheduler.php | Fully-qualified DateTimeImmutable |
| Entity/CustomFieldValueText.php | DBAL Types + constructor promotion |
| Entity/CustomFieldValueOption.php | Void return types |
| Entity/CustomFieldValueInt.php | DBAL Types + constructor promotion |
| Entity/CustomFieldValueDateTime.php | DBAL Types + constructor promotion + \DateTimeInterface checks |
| Entity/CustomFieldValueDate.php | DBAL Types + \DateTimeInterface typing |
| Entity/CustomFieldOption.php | DBAL Types + ArrayAccess signatures |
| Entity/CustomFieldFactory.php | Constructor promotion |
| Entity/AbstractCustomFieldValue.php | Constructor promotion + addValue return type |
| DependencyInjection/CustomObjectsExtension.php | Added DI extension to load services.php |
| DataPersister/CustomItemDataPersister.php | Added ApiPlatform persister integration |
| DTO/Token.php | Constructor promotion + typed defaults |
| DTO/TableConfig.php | Constructor promotion + typed parameters |
| DTO/ImportLogDTO.php | Added DTO for import warnings |
| DTO/CustomItemFieldListData.php | Constructor promotion |
| CustomObjectEvents.php | Docblock links updated |
| CustomFieldType/SelectType.php | Modern catch |
| CustomFieldType/PhoneType.php | Removed unreachable return |
| CustomFieldType/IntType.php | Added operator-options customization |
| CustomFieldType/DateType.php | Added DateOperatorTrait + \DateTimeInterface check |
| CustomFieldType/DateTimeType.php | Added DateOperatorTrait + \DateTimeInterface check |
| CustomFieldType/DateOperatorTrait.php | Added shared operator logic for date types |
| CustomFieldType/DataTransformer/DateTransformer.php | Fully-qualified DateTime usage |
| CustomFieldType/DataTransformer/DateTimeTransformer.php | Fully-qualified DateTime usage |
| CustomFieldType/DataTransformer/DateTimeAtomTransformer.php | Fully-qualified DateTimeImmutable usage |
| CustomFieldType/DataTransformer/CsvTransformer.php | Typed CsvHelper property |
| CustomFieldType/CountryType.php | Nullable cached country list |
| CustomFieldType/AbstractMultivalueType.php | TranslatorInterface switched + typed closure return |
| CustomFieldType/AbstractCustomFieldType.php | TranslatorInterface switched + implements Stringable |
| Controller/JsonController.php | Switched to AbstractController + Twig flash template |
| Controller/CustomObject/ViewController.php | Refactored to action injection + Twig contentTemplate |
| Controller/CustomObject/ListController.php | Refactored to action injection + Twig contentTemplate |
| Controller/CustomObject/DeleteController.php | Refactored to action injection + updated forward controller string |
| Controller/CustomObject/CancelController.php | Refactored to action injection + updated redirect contentTemplate |
| Controller/CustomItem/UnlinkController.php | Refactored to action injection + exception FQCN |
| Controller/CustomItem/LookupController.php | Refactored to action injection + Request param |
| Controller/CustomItem/LinkController.php | Refactored to action injection + exception FQCN |
| Controller/CustomItem/ExportController.php | Refactored to action injection + dispatch signature update |
| Controller/CustomItem/DeleteController.php | Refactored to action injection + updated redirect contentTemplate |
| Controller/CustomItem/ContactListController.php | Updated signature for EntityContactsTrait changes |
| Controller/CustomItem/CancelController.php | Refactored to action injection + updated redirect contentTemplate |
| Config/services.php | Added Symfony PHP DI config with autowire/autoconfigure |
| Command/GenerateSampleDataCommand.php | Updated to Symfony Command + DBAL executeQuery |
| Command/CustomItemsScheduledExportCommand.php | Dispatch signature update + Command::SUCCESS |
| Assets/js/custom-objects.js | Improved campaign condition UI behavior + date/datetime pickers |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| public function __construct(ManagerRegistry $registry, string $entityFQCN = null) | ||
| { | ||
| $entityFQCN = $entityFQCN | ||
| ?? preg_replace('/(.*)\\\\Repository(.*)Repository?/', '$1\Entity$2', static::class); |
There was a problem hiding this comment.
The constructor parameter is typed as string but has a default of null, which will trigger a type error in PHP 8+. Change it to ?string $entityFQCN = null. Also note preg_replace(...) can return null; consider a safe fallback to a known entity FQCN if the regex does not match.
| public function __construct(ManagerRegistry $registry, string $entityFQCN = null) | |
| { | |
| $entityFQCN = $entityFQCN | |
| ?? preg_replace('/(.*)\\\\Repository(.*)Repository?/', '$1\Entity$2', static::class); | |
| public function __construct(ManagerRegistry $registry, ?string $entityFQCN = null) | |
| { | |
| if (null === $entityFQCN) { | |
| $entityFQCN = preg_replace('/(.*)\\\\Repository(.*)Repository?/', '$1\Entity$2', static::class); | |
| if (!is_string($entityFQCN) || '' === $entityFQCN) { | |
| $entityFQCN = static::class; | |
| } | |
| } |
| $builder->setTable('custom_field_value_date'); | ||
| $builder->addIndex(['value'], 'value_index'); | ||
| $builder->addNullableField('value', Type::DATE); | ||
| $builder->addNullableField('value', Types::DATETIME_MUTABLE); |
There was a problem hiding this comment.
This entity represents a date value but the mapping was changed from a DATE type to Types::DATETIME_MUTABLE, which will store a time component and can break date-only semantics and queries. Use an appropriate DBAL date type (e.g., Types::DATE_MUTABLE) to preserve the original behavior.
| $builder->addNullableField('value', Types::DATETIME_MUTABLE); | |
| $builder->addNullableField('value', Types::DATE_MUTABLE); |
| ?> | ||
| <div class="row"> | ||
| <div class="col-xs-4"> | ||
| <?php echo $view['form']->row($form['field']); ?> | ||
| {{ form_row(field) }} | ||
| </div> | ||
| <div class="col-xs-4"> | ||
| <?php echo $view['form']->row($form['operator']); ?> | ||
| {{ form_row(operator) }} | ||
| </div> | ||
| <div class="col-xs-4"> | ||
| <?php echo $view['form']->row($form['value']); ?> | ||
| {{ form_row(value) }} | ||
| </div> |
There was a problem hiding this comment.
This Twig template still contains a PHP closing tag (?>), which will cause template rendering/parsing issues. Remove the PHP tag entirely so the file is valid Twig.
| 'routeBase': 'custom_object', | ||
| 'routeBase': 'form' |
There was a problem hiding this comment.
The options hash defines routeBase twice; the latter value ('form') will overwrite 'custom_object'. Remove the duplicate key and keep the intended value so the table header routes are generated correctly.
| 'routeBase': 'custom_object', | |
| 'routeBase': 'form' | |
| 'routeBase': 'custom_object' |
| {% if isIndex %} | ||
| <div class="panel panel-default bdr-t-wdh-0 mb-0"> | ||
| {{ include('@MauticCore/Helper/list_toolbar.html.twig') }} | ||
| <div class="page-list">! |
There was a problem hiding this comment.
Remove the stray ! that will render into the HTML output.
| <div class="page-list">! | |
| <div class="page-list"> |
| 'returnUrl' => $routeProvider->buildListRoute($page), | ||
| 'viewParameters' => ['page' => $page], | ||
| 'contentTemplate' => 'CustomObjectsBundle:CustomObject\List:list', | ||
| 'contentTemplate' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomObject\ListController:listAction', |
There was a problem hiding this comment.
Same issue as in DeleteController: the controller reference uses a single colon. Update it to a valid callable format (FQCN + ::method) so redirects/rendering can resolve the controller correctly.
| 'contentTemplate' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomObject\ListController:listAction', | |
| 'contentTemplate' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomObject\ListController::listAction', |
| 'returnUrl' => $routeProvider->buildListRoute($objectId, $page), | ||
| 'viewParameters' => ['objectId' => $objectId, 'page' => $page], | ||
| 'contentTemplate' => 'CustomObjectsBundle:CustomItem\List:list', | ||
| 'contentTemplate' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\ListController::listAction', |
There was a problem hiding this comment.
This uses Class::method format, while some other updated controllers in this PR use Class:method (single-colon). Standardize on the valid Symfony callable format everywhere for consistency and to avoid runtime resolution errors.
| 'contentTemplate' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\ListController::listAction', | |
| 'contentTemplate' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\ListController:listAction', |
| 'returnUrl' => $routeProvider->buildListRoute($objectId, $page), | ||
| 'viewParameters' => ['objectId' => $objectId, 'page' => $page], | ||
| 'contentTemplate' => 'CustomObjectsBundle:CustomItem\List:list', | ||
| 'contentTemplate' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\ListController::listAction', |
There was a problem hiding this comment.
Same consistency concern as CustomItem DeleteController: ensure all controller references across redirect/forward calls use the same valid callable format (Class::method) to avoid differing behavior between endpoints.
| {{ customObjectId }}, | ||
| {{ currentEntityId }}, | ||
| "{{ currentEntityType }}", | ||
| "{{ tabId }}" |
There was a problem hiding this comment.
The JS string arguments (currentEntityType, tabId) are injected via string interpolation. If either value can contain quotes/backslashes, this can break the script context. Prefer emitting these values via |json_encode|raw (or escaping for JS) so they are safely encoded as JS literals.
| {{ customObjectId }}, | |
| {{ currentEntityId }}, | |
| "{{ currentEntityType }}", | |
| "{{ tabId }}" | |
| {{ customObjectId|json_encode|raw }}, | |
| {{ currentEntityId|json_encode|raw }}, | |
| {{ currentEntityType|json_encode|raw }}, | |
| {{ tabId|json_encode|raw }} |
| {% if customField.typeObject.usePlaceholder %} | ||
| <div class="col-md-6"> | ||
| {{ form_row(form.params.placeholder) }} | ||
| </div> | ||
| {% endif %} |
There was a problem hiding this comment.
usePlaceholder is called as a property here, but earlier in the template logic it is treated like a method (usePlaceholder()). If usePlaceholder is a method on the type object, this condition may always evaluate truthy or fail depending on Twig's access rules. Use a consistent invocation (typically customField.typeObject.usePlaceholder()).
… non-capturing catches)
…ataForLead methods
Internal PR to trigger CI pipeline for branch fix/dynamic-content-subscriber-mautic5 before merging upstream.