Skip to content

fix(DynamicContentSubscriber): Mautic 5 migration CI test#1

Open
edouard-mangel wants to merge 16 commits intostagingfrom
fix/dynamic-content-subscriber-mautic5
Open

fix(DynamicContentSubscriber): Mautic 5 migration CI test#1
edouard-mangel wants to merge 16 commits intostagingfrom
fix/dynamic-content-subscriber-mautic5

Conversation

@edouard-mangel
Copy link
Copy Markdown

Internal PR to trigger CI pipeline for branch fix/dynamic-content-subscriber-mautic5 before merging upstream.

volha-pivavarchyk and others added 10 commits January 13, 2025 13:53
* 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.
Copilot AI review requested due to automatic review settings March 11, 2026 16:31
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +12 to +15
public function __construct(ManagerRegistry $registry, string $entityFQCN = null)
{
$entityFQCN = $entityFQCN
?? preg_replace('/(.*)\\\\Repository(.*)Repository?/', '$1\Entity$2', static::class);
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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;
}
}

Copilot uses AI. Check for mistakes.
$builder->setTable('custom_field_value_date');
$builder->addIndex(['value'], 'value_index');
$builder->addNullableField('value', Type::DATE);
$builder->addNullableField('value', Types::DATETIME_MUTABLE);
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
$builder->addNullableField('value', Types::DATETIME_MUTABLE);
$builder->addNullableField('value', Types::DATE_MUTABLE);

Copilot uses AI. Check for mistakes.
Comment on lines 3 to 13
?>
<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>
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines +14 to +15
'routeBase': 'custom_object',
'routeBase': 'form'
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
'routeBase': 'custom_object',
'routeBase': 'form'
'routeBase': 'custom_object'

Copilot uses AI. Check for mistakes.
{% if isIndex %}
<div class="panel panel-default bdr-t-wdh-0 mb-0">
{{ include('@MauticCore/Helper/list_toolbar.html.twig') }}
<div class="page-list">!
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the stray ! that will render into the HTML output.

Suggested change
<div class="page-list">!
<div class="page-list">

Copilot uses AI. Check for mistakes.
'returnUrl' => $routeProvider->buildListRoute($page),
'viewParameters' => ['page' => $page],
'contentTemplate' => 'CustomObjectsBundle:CustomObject\List:list',
'contentTemplate' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomObject\ListController:listAction',
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
'contentTemplate' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomObject\ListController:listAction',
'contentTemplate' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomObject\ListController::listAction',

Copilot uses AI. Check for mistakes.
'returnUrl' => $routeProvider->buildListRoute($objectId, $page),
'viewParameters' => ['objectId' => $objectId, 'page' => $page],
'contentTemplate' => 'CustomObjectsBundle:CustomItem\List:list',
'contentTemplate' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\ListController::listAction',
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
'contentTemplate' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\ListController::listAction',
'contentTemplate' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\ListController:listAction',

Copilot uses AI. Check for mistakes.
'returnUrl' => $routeProvider->buildListRoute($objectId, $page),
'viewParameters' => ['objectId' => $objectId, 'page' => $page],
'contentTemplate' => 'CustomObjectsBundle:CustomItem\List:list',
'contentTemplate' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\ListController::listAction',
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines +44 to +47
{{ customObjectId }},
{{ currentEntityId }},
"{{ currentEntityType }}",
"{{ tabId }}"
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
{{ customObjectId }},
{{ currentEntityId }},
"{{ currentEntityType }}",
"{{ tabId }}"
{{ customObjectId|json_encode|raw }},
{{ currentEntityId|json_encode|raw }},
{{ currentEntityType|json_encode|raw }},
{{ tabId|json_encode|raw }}

Copilot uses AI. Check for mistakes.
Comment on lines +82 to +86
{% if customField.typeObject.usePlaceholder %}
<div class="col-md-6">
{{ form_row(form.params.placeholder) }}
</div>
{% endif %}
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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()).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants