From 62aa70738d28e8c758ec4442ba04ef81382fa6a0 Mon Sep 17 00:00:00 2001 From: Volha Pivavarchyk Date: Mon, 13 Jan 2025 15:53:04 +0300 Subject: [PATCH 01/25] Update to 5.x (#338) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 * 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 * 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 (#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 (#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š * suggessions * ifx value should not be empty after change operator --------- Co-authored-by: Miroslav Fedeleš * Replaced logger with monolog.logger.mautic (#355) * MAUT-11515 : Custom object date segment filters should have have same operators than date custom field filters (#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 (#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 * Update EventListener/TokenSubscriber.php Co-authored-by: John Linhart * 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 Co-authored-by: John Linhart * 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 (#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 Co-authored-by: Donald Gilbert Co-authored-by: Tejas Navghane Co-authored-by: Rohit Pavaskar <66303837+rohitp19@users.noreply.github.com> Co-authored-by: rahuld-dev Co-authored-by: Saurabh Gupta <48244990+dadarya0@users.noreply.github.com> Co-authored-by: Saurabh Gupta 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 Co-authored-by: John Linhart Co-authored-by: aadarshjain-dev Co-authored-by: fedys Co-authored-by: Avikarsha Saha Co-authored-by: Avikarsha Saha Co-authored-by: Aarohi Prasad Co-authored-by: GuzmanBellon <47144569+GuzmanBellon@users.noreply.github.com> --- .github/workflows/tests.yml | 148 + Assets/js/custom-objects.js | 34 +- Command/CustomItemsScheduledExportCommand.php | 25 +- Command/GenerateSampleDataCommand.php | 47 +- Config/config.php | 820 +---- Config/services.php | 26 + Controller/CustomField/FormController.php | 76 +- Controller/CustomField/SaveController.php | 92 +- .../CustomItem/BatchDeleteController.php | 72 +- Controller/CustomItem/CancelController.php | 42 +- .../CustomItem/ContactListController.php | 12 +- Controller/CustomItem/DeleteController.php | 57 +- Controller/CustomItem/ExportController.php | 52 +- Controller/CustomItem/FormController.php | 223 +- Controller/CustomItem/LinkController.php | 48 +- Controller/CustomItem/LinkFormController.php | 125 +- Controller/CustomItem/ListController.php | 67 +- Controller/CustomItem/LookupController.php | 46 +- Controller/CustomItem/SaveController.php | 121 +- Controller/CustomItem/UnlinkController.php | 48 +- Controller/CustomItem/ViewController.php | 74 +- Controller/CustomObject/CancelController.php | 39 +- Controller/CustomObject/DeleteController.php | 59 +- Controller/CustomObject/FormController.php | 150 +- Controller/CustomObject/ListController.php | 56 +- Controller/CustomObject/SaveController.php | 145 +- Controller/CustomObject/ViewController.php | 65 +- Controller/JsonController.php | 6 +- CustomFieldType/AbstractCustomFieldType.php | 24 +- CustomFieldType/AbstractMultivalueType.php | 15 +- CustomFieldType/CountryType.php | 2 +- .../DataTransformer/CsvTransformer.php | 5 +- .../DateTimeAtomTransformer.php | 3 +- .../DataTransformer/DateTimeTransformer.php | 3 +- .../DataTransformer/DateTransformer.php | 5 +- CustomFieldType/DateOperatorTrait.php | 38 + CustomFieldType/DateTimeType.php | 16 +- CustomFieldType/DateType.php | 16 +- CustomFieldType/IntType.php | 16 +- CustomFieldType/PhoneType.php | 4 +- CustomFieldType/SelectType.php | 2 +- CustomItemEvents.php | 28 +- CustomObjectEvents.php | 12 +- DTO/CustomItemFieldListData.php | 14 +- DTO/ImportLogDTO.php | 28 + DTO/TableConfig.php | 36 +- DTO/Token.php | 59 +- DataPersister/CustomItemDataPersister.php | 46 + .../CustomObjectsExtension.php | 22 + Entity/AbstractCustomFieldValue.php | 16 +- Entity/CustomField.php | 73 +- Entity/CustomFieldFactory.php | 8 +- Entity/CustomFieldOption.php | 22 +- Entity/CustomFieldValueDate.php | 11 +- Entity/CustomFieldValueDateTime.php | 16 +- Entity/CustomFieldValueInt.php | 13 +- Entity/CustomFieldValueOption.php | 12 +- Entity/CustomFieldValueText.php | 13 +- Entity/CustomItem.php | 112 +- Entity/CustomItemExportScheduler.php | 7 +- Entity/CustomItemXrefCompany.php | 35 +- Entity/CustomItemXrefContact.php | 35 +- Entity/CustomItemXrefCustomItem.php | 33 +- Entity/CustomItemXrefInterface.php | 4 +- Entity/CustomObject.php | 66 +- Event/CustomItemEvent.php | 16 +- Event/CustomItemExportSchedulerEvent.php | 7 +- Event/CustomItemListDbalQueryEvent.php | 16 +- Event/CustomItemListQueryEvent.php | 20 +- Event/CustomItemXrefEntityDiscoveryEvent.php | 35 +- Event/CustomItemXrefEntityEvent.php | 10 +- Event/CustomObjectEvent.php | 26 +- Event/CustomObjectListFormatEvent.php | 26 +- EventListener/ApiSubscriber.php | 42 +- EventListener/AssetsSubscriber.php | 24 +- EventListener/AuditLogSubscriber.php | 18 +- EventListener/CampaignSubscriber.php | 95 +- EventListener/ContactSubscriber.php | 88 +- EventListener/ContactTabSubscriber.php | 62 +- .../CustomFieldPostLoadSubscriber.php | 10 +- .../CustomFieldPreSaveSubscriber.php | 8 +- EventListener/CustomItemButtonSubscriber.php | 44 +- .../CustomItemPostDeleteSubscriber.php | 16 +- .../CustomItemPostSaveSubscriber.php | 18 +- .../CustomItemScheduledExportSubscriber.php | 5 +- EventListener/CustomItemTabSubscriber.php | 54 +- .../CustomItemXrefContactSubscriber.php | 26 +- .../CustomItemXrefCustomItemSubscriber.php | 23 +- .../CustomObjectButtonSubscriber.php | 56 +- .../CustomObjectListFormatSubscriber.php | 8 +- .../CustomObjectPostSaveSubscriber.php | 8 +- .../CustomObjectPreDeleteSubscriber.php | 20 +- EventListener/DynamicContentSubscriber.php | 37 +- EventListener/FilterOperatorSubscriber.php | 16 +- EventListener/ImportSubscriber.php | 76 +- EventListener/MenuSubscriber.php | 14 +- EventListener/ReportSubscriber.php | 61 +- ...gmentFilterDecoratorDelegateSubscriber.php | 8 +- ...egmentFiltersChoicesGenerateSubscriber.php | 52 +- .../SegmentFiltersDictionarySubscriber.php | 43 +- .../SegmentFiltersMergeSubscriber.php | 99 + EventListener/SerializerSubscriber.php | 34 +- EventListener/TokenSubscriber.php | 414 ++- Exception/ForbiddenException.php | 11 +- Exception/InUseException.php | 9 +- Exception/InvalidArgumentException.php | 4 +- Exception/InvalidSegmentFilterException.php | 4 +- Exception/InvalidValueException.php | 8 +- Exception/NoRelationshipException.php | 7 +- Exception/NotFoundException.php | 7 +- Exception/UndefinedTransformerException.php | 4 +- Extension/CustomItemListeningExtension.php | 16 +- .../CustomObjectHiddenTransformer.php | 8 +- .../OptionsToStringTransformer.php | 20 +- .../ParamsToStringTransformer.php | 8 +- Form/Type/CampaignActionLinkType.php | 20 +- Form/Type/CampaignConditionFieldValueType.php | 56 +- Form/Type/CustomFieldType.php | 61 +- Form/Type/CustomFieldValueType.php | 2 +- Form/Type/CustomObjectType.php | 29 +- .../AllowUniqueIdentifierValidator.php | 5 +- .../CustomObjectTypeValuesValidator.php | 2 +- Helper/LockFlashMessageHelper.php | 34 +- Helper/QueryBuilderManipulatorTrait.php | 4 +- Helper/QueryFilterFactory.php | 55 +- Helper/QueryFilterFactory/Calculator.php | 18 +- Helper/QueryFilterHelper.php | 362 +- Helper/TokenFormatter.php | 5 +- Helper/TokenParser.php | 4 +- Migrations/Version_0_0_1.php | 7 +- Migrations/Version_0_0_11.php | 13 +- Migrations/Version_0_0_13.php | 2 +- Migrations/Version_0_0_14.php | 2 +- Migrations/Version_0_0_15.php | 2 +- Migrations/Version_0_0_16.php | 8 +- Migrations/Version_0_0_17.php | 5 +- Migrations/Version_0_0_18.php | 5 +- Migrations/Version_0_0_19.php | 3 +- Migrations/Version_0_0_2.php | 5 +- Migrations/Version_0_0_21.php | 2 +- Migrations/Version_0_0_27.php | 2 +- Migrations/Version_0_0_3.php | 5 +- Migrations/Version_0_0_4.php | 5 +- Migrations/Version_0_0_5.php | 7 +- Migrations/Version_0_0_6.php | 7 +- Migrations/Version_0_0_7.php | 7 +- Migrations/Version_0_0_8.php | 7 +- Migrations/Version_0_0_9.php | 12 +- Model/CustomFieldModel.php | 38 +- Model/CustomFieldOptionModel.php | 11 +- Model/CustomFieldValueModel.php | 34 +- Model/CustomItemExportSchedulerModel.php | 81 +- Model/CustomItemImportModel.php | 74 +- Model/CustomItemModel.php | 152 +- Model/CustomItemXrefContactModel.php | 22 +- Model/CustomObjectModel.php | 87 +- Provider/AbstractPermissionProvider.php | 10 +- Provider/ConfigProvider.php | 18 +- Provider/CustomFieldRouteProvider.php | 8 +- Provider/CustomFieldTypeProvider.php | 2 +- Provider/CustomItemPermissionProvider.php | 8 +- Provider/CustomItemRouteProvider.php | 8 +- Provider/CustomObjectRouteProvider.php | 11 +- Provider/SessionProvider.php | 20 +- Provider/SessionProviderFactory.php | 14 +- README.md | 21 + Report/ReportColumnsBuilder.php | 12 +- Repository/CustomCommonRepository.php | 18 + Repository/CustomFieldRepository.php | 3 +- .../CustomItemExportSchedulerRepository.php | 4 +- Repository/CustomItemRepository.php | 4 +- .../CustomItemXrefContactRepository.php | 3 +- .../CustomItemXrefCustomItemRepository.php | 3 +- Repository/CustomObjectRepository.php | 7 +- Repository/DbalQueryTrait.php | 5 +- .../_detail_left_section.html.twig | 25 + .../_detail_right_section.html.twig | 23 + Resources/views/CustomField/detail.html.twig | 19 + Resources/views/CustomField/form.html.twig | 97 + Resources/views/CustomField/value.html.twig | 15 + .../CustomItem/_detail_left_section.html.twig | 112 + .../_detail_right_section.html.twig | 6 + Resources/views/CustomItem/_list.html.twig | 96 + Resources/views/CustomItem/detail.html.twig | 27 + Resources/views/CustomItem/form.html.twig | 56 + Resources/views/CustomItem/list.html.twig | 37 + .../CustomObject/Form/Panel/_field.html.twig | 47 + .../Form/Panel/checkbox_group.html.twig | 1 + .../CustomObject/Form/Panel/country.html.twig | 1 + .../CustomObject/Form/Panel/date.html.twig | 1 + .../Form/Panel/datetime.html.twig | 1 + .../CustomObject/Form/Panel/email.html.twig | 1 + .../CustomObject/Form/Panel/hidden.html.twig | 1 + .../Form/Panel/html_area.html.twig | 1 + .../CustomObject/Form/Panel/int.html.twig | 1 + .../Form/Panel/multiselect.html.twig | 1 + .../CustomObject/Form/Panel/phone.html.twig | 1 + .../Form/Panel/radio_group.html.twig | 1 + .../CustomObject/Form/Panel/select.html.twig | 1 + .../CustomObject/Form/Panel/text.html.twig | 1 + .../Form/Panel/textarea.html.twig | 1 + .../CustomObject/Form/Panel/url.html.twig | 1 + .../_detail_left_section.html.twig | 110 + .../_detail_right_section.html.twig | 6 + .../views/CustomObject/_form-fields.html.twig | 19 + Resources/views/CustomObject/_list.html.twig | 74 + Resources/views/CustomObject/detail.html.twig | 27 + Resources/views/CustomObject/form.html.twig | 98 + Resources/views/CustomObject/list.html.twig | 27 + ...ign_condition_field_value_widget.html.twig | 6 +- .../SubscribedEvents/Tab/content.html.twig | 49 + .../views/SubscribedEvents/Tab/link.html.twig | 11 + .../SubscribedEvents/Tab/modal.html.twig | 6 + .../SubscribedEvents/Timeline/link.html.twig | 12 + .../Permissions/CustomObjectPermissions.php | 27 +- .../Filter/CustomFieldFilterQueryBuilder.php | 43 +- .../CustomItemNameFilterQueryBuilder.php | 22 +- .../CustomObjectMergedFilterQueryBuilder.php | 38 + Segment/Query/Filter/QueryFilterFactory.php | 16 +- Segment/Query/UnionQueryContainer.php | 19 +- Serializer/ApiNormalizer.php | 27 +- .../AbstractApiPlatformFunctionalTest.php | 13 +- .../ApiPlatform/CustomFieldFunctionalTest.php | 68 +- .../CustomFieldOptionFunctionalTest.php | 66 +- .../ApiPlatform/CustomItemFunctionalTest.php | 371 +- .../CustomObjectFunctionalTest.php | 132 +- .../CustomItemListControllerSearchTest.php | 2 +- ...CustomItemListControllerShownFieldTest.php | 10 +- .../CustomItemListControllerXrefTest.php | 2 +- .../CustomObject/DeleteControllerTest.php | 4 +- .../Controller/CustomObjectFormTest.php | 5 +- ...elation-filter-query-builder-fixture-2.yml | 12 + .../DataFixtures/ORM/Data/custom_fields.yml | 4 +- .../Traits/CustomObjectsTrait.php | 1 + .../Traits/FixtureObjectsTrait.php | 21 +- .../EventListener/ApiSubscriberTest.php | 2 +- .../EventListener/CampaignConditionTest.php | 59 + .../EventListener/ContactSubscriberTest.php | 81 + .../FilterOperatorSubscriberTest.php | 119 +- .../EventListener/ImportSubscriberTest.php | 15 +- .../EventListener/TokenSubscriberTest.php | 1 + .../Helper/QueryFilterHelperTest.php | 202 +- .../CustomFieldFilterQueryBuilderTest.php | 13 +- .../CustomItemNameFilterQueryBuilderTest.php | 4 +- ...=> CustomItemRelationQueryBuilderTest.php} | 29 +- ...stomObjectMergedFilterQueryBuilderTest.php | 122 + ...NegativeOperatorFilterQueryBuilderTest.php | 205 ++ Tests/Functional/Token/EmailTokenTest.php | 1 + ...stomObjectDynamicContentFunctionalTest.php | 339 ++ Tests/Functional/UpsertFunctionalTest.php | 2 +- Tests/ProjectVersionTrait.php | 13 + .../Command/CustomItemExportCommandTest.php | 3 +- Tests/Unit/Controller/ControllerTestCase.php | 107 +- .../AbstractFieldControllerTest.php | 25 +- .../CustomField/FormControllerTest.php | 243 +- .../CustomField/SaveControllerTest.php | 173 +- .../CustomItem/BatchDeleteControllerTest.php | 79 +- .../CustomItem/CancelControllerTest.php | 49 +- .../CustomItem/DeleteControllerTest.php | 90 +- .../CustomItem/FormControllerTest.php | 300 +- .../CustomItem/LinkControllerTest.php | 68 +- .../CustomItem/ListControllerTest.php | 87 +- .../CustomItem/LookupControllerTest.php | 36 +- .../CustomItem/SaveControllerTest.php | 168 +- .../CustomItem/UnlinkControllerTest.php | 64 +- .../CustomItem/ViewControllerTest.php | 68 +- .../CustomObject/CancelControllerTest.php | 38 +- .../CustomObject/DeleteControllerTest.php | 102 +- .../CustomObject/FormControllerTest.php | 139 +- .../CustomObject/ListControllerTest.php | 60 +- .../CustomObject/SaveControllerTest.php | 106 +- .../CustomObject/ViewControllerTest.php | 60 +- .../AbstractCustomFieldTypeTest.php | 4 +- .../AbstractMultivalueTypeTest.php | 4 +- .../CustomFieldType/AbstractTextTypeTest.php | 2 +- .../Unit/CustomFieldType/CountryTypeTest.php | 2 +- .../DateTimeAtomTransformerTest.php | 3 +- .../Unit/CustomFieldType/DateTimeTypeTest.php | 2 +- Tests/Unit/CustomFieldType/DateTypeTest.php | 2 +- Tests/Unit/CustomFieldType/EmailTypeTest.php | 2 +- Tests/Unit/CustomFieldType/IntTypeTest.php | 2 +- .../CustomFieldType/MultiselectTypeTest.php | 2 +- Tests/Unit/CustomFieldType/PhoneTypeTest.php | 2 +- Tests/Unit/CustomFieldType/SelectTypeTest.php | 4 +- Tests/Unit/CustomFieldType/UrlTypeTest.php | 2 +- Tests/Unit/CustomObjectTestCase.php | 4 +- Tests/Unit/Entity/CustomFieldTest.php | 22 +- Tests/Unit/Entity/CustomItemTest.php | 2 +- .../Unit/Entity/CustomItemXrefCompanyTest.php | 3 +- .../Unit/Entity/CustomItemXrefContactTest.php | 3 +- .../Entity/CustomItemXrefCustomItemTest.php | 10 +- .../Unit/EventListener/ApiSubscriberTest.php | 83 +- .../EventListener/AssetsSubscriberTest.php | 57 +- .../EventListener/CampaignSubscriberTest.php | 20 +- .../EventListener/ContactSubscriberTest.php | 17 +- .../ContactTabSubscriberTest.php | 16 +- .../CustomFieldPostLoadSubscriberTest.php | 2 +- .../CustomItemButtonSubscriberTest.php | 2 +- .../CustomItemPostSaveSubscriberTest.php | 9 +- .../CustomItemTabSubscriberTest.php | 22 +- .../CustomItemXrefContactSubscriberTest.php | 2 - .../CustomObjectButtonSubscriberTest.php | 2 +- .../CustomObjectPostSaveSubscriberTest.php | 5 +- .../DynamicContentSubscriberTest.php | 11 +- .../FilterOperatorSubscriberTest.php | 3 +- .../EventListener/ImportSubscriberTest.php | 2 +- .../Unit/EventListener/MenuSubscriberTest.php | 14 +- .../EventListener/ReportSubscriberTest.php | 13 +- ...ntFiltersChoicesGenerateSubscriberTest.php | 493 ++- .../SerializerSubscriberTest.php | 2 +- .../EventListener/TokenSubscriberTest.php | 21 +- .../CampaignConditionFieldValueTypeTest.php | 23 +- Tests/Unit/Form/Type/CustomFieldTypeTest.php | 6 +- .../Validator/AllowUniqueIdentifierTest.php | 2 +- .../AllowUniqueIdentifierValidatorTest.php | 6 +- .../CustomObjectTypeValuesValidatorTest.php | 4 + .../Helper/LockFlashMessageHelperTest.php | 4 +- Tests/Unit/Helper/QueryFilterFactoryTest.php | 5 +- Tests/Unit/Helper/QueryFilterHelperTest.php | 6 +- .../Unit/Model/CustomFieldOptionModelTest.php | 2 - .../Unit/Model/CustomFieldValueModelTest.php | 18 +- .../Unit/Model/CustomItemImportModelTest.php | 198 +- Tests/Unit/Model/CustomItemModelTest.php | 106 +- .../Model/CustomItemXrefContactModelTest.php | 79 +- Tests/Unit/Model/CustomObjectModelTest.php | 91 +- .../Provider/CustomFieldTypeProviderTest.php | 2 +- .../Unit/Report/ReportColumnsBuilderTest.php | 4 +- .../Repository/CustomFieldRepositoryTest.php | 23 +- .../Repository/CustomItemRepositoryTest.php | 16 +- .../CustomItemXrefContactRepositoryTest.php | 15 +- .../Repository/CustomObjectRepositoryTest.php | 12 +- .../CustomObjectPermissionsTest.php | 2 +- .../CustomItemNameFilterQueryBuilderTest.php | 6 +- .../Query/Filter/QueryFilterFactoryTest.php | 2 - Translations/en_US/messages.ini | 1 + Views/CustomField/detail.html.php | 56 - Views/CustomField/form.html.php | 105 - Views/CustomField/index.html.php | 21 - Views/CustomField/value.html.php | 23 - Views/CustomItem/detail.html.php | 125 - Views/CustomItem/form.html.php | 71 - Views/CustomItem/index.html.php | 27 - Views/CustomItem/list.html.php | 124 - Views/CustomObject/Form/Panel/_field.html.php | 52 - .../Form/Panel/checkbox_group.html.php | 5 - .../CustomObject/Form/Panel/country.html.php | 5 - Views/CustomObject/Form/Panel/date.html.php | 5 - .../CustomObject/Form/Panel/datetime.html.php | 5 - Views/CustomObject/Form/Panel/email.html.php | 5 - Views/CustomObject/Form/Panel/hidden.html.php | 5 - .../Form/Panel/html_area.html.php | 5 - Views/CustomObject/Form/Panel/int.html.php | 5 - .../Form/Panel/multiselect.html.php | 5 - Views/CustomObject/Form/Panel/phone.html.php | 5 - .../Form/Panel/radio_group.html.php | 5 - Views/CustomObject/Form/Panel/select.html.php | 5 - Views/CustomObject/Form/Panel/text.html.php | 5 - .../CustomObject/Form/Panel/textarea.html.php | 5 - Views/CustomObject/Form/Panel/url.html.php | 5 - Views/CustomObject/_form-fields.html.php | 24 - Views/CustomObject/detail.html.php | 149 - Views/CustomObject/form.html.php | 125 - Views/CustomObject/index.html.php | 21 - Views/CustomObject/list.html.php | 94 - Views/SubscribedEvents/Tab/content.html.php | 50 - Views/SubscribedEvents/Tab/link.html.php | 15 - Views/SubscribedEvents/Tab/modal.html.php | 8 - Views/SubscribedEvents/Timeline/link.html.php | 17 - composer.json | 6 +- phpstan-baseline-7.4.neon | 3022 +++++++++++++++++ phpstan-baseline-8.0.neon | 3022 +++++++++++++++++ phpstan-baseline-php-versions.neon.php | 17 + phpstan-baseline.neon | 701 ++++ phpstan.neon | 28 + phpunit.xml | 11 +- 375 files changed, 14904 insertions(+), 6613 deletions(-) create mode 100644 .github/workflows/tests.yml create mode 100644 Config/services.php create mode 100644 CustomFieldType/DateOperatorTrait.php create mode 100644 DTO/ImportLogDTO.php create mode 100644 DataPersister/CustomItemDataPersister.php create mode 100644 DependencyInjection/CustomObjectsExtension.php create mode 100644 EventListener/SegmentFiltersMergeSubscriber.php create mode 100644 Repository/CustomCommonRepository.php create mode 100644 Resources/views/CustomField/_detail_left_section.html.twig create mode 100644 Resources/views/CustomField/_detail_right_section.html.twig create mode 100644 Resources/views/CustomField/detail.html.twig create mode 100644 Resources/views/CustomField/form.html.twig create mode 100644 Resources/views/CustomField/value.html.twig create mode 100644 Resources/views/CustomItem/_detail_left_section.html.twig create mode 100644 Resources/views/CustomItem/_detail_right_section.html.twig create mode 100644 Resources/views/CustomItem/_list.html.twig create mode 100644 Resources/views/CustomItem/detail.html.twig create mode 100644 Resources/views/CustomItem/form.html.twig create mode 100644 Resources/views/CustomItem/list.html.twig create mode 100644 Resources/views/CustomObject/Form/Panel/_field.html.twig create mode 100644 Resources/views/CustomObject/Form/Panel/checkbox_group.html.twig create mode 100644 Resources/views/CustomObject/Form/Panel/country.html.twig create mode 100644 Resources/views/CustomObject/Form/Panel/date.html.twig create mode 100644 Resources/views/CustomObject/Form/Panel/datetime.html.twig create mode 100644 Resources/views/CustomObject/Form/Panel/email.html.twig create mode 100644 Resources/views/CustomObject/Form/Panel/hidden.html.twig create mode 100644 Resources/views/CustomObject/Form/Panel/html_area.html.twig create mode 100644 Resources/views/CustomObject/Form/Panel/int.html.twig create mode 100644 Resources/views/CustomObject/Form/Panel/multiselect.html.twig create mode 100644 Resources/views/CustomObject/Form/Panel/phone.html.twig create mode 100644 Resources/views/CustomObject/Form/Panel/radio_group.html.twig create mode 100644 Resources/views/CustomObject/Form/Panel/select.html.twig create mode 100644 Resources/views/CustomObject/Form/Panel/text.html.twig create mode 100644 Resources/views/CustomObject/Form/Panel/textarea.html.twig create mode 100644 Resources/views/CustomObject/Form/Panel/url.html.twig create mode 100644 Resources/views/CustomObject/_detail_left_section.html.twig create mode 100644 Resources/views/CustomObject/_detail_right_section.html.twig create mode 100644 Resources/views/CustomObject/_form-fields.html.twig create mode 100644 Resources/views/CustomObject/_list.html.twig create mode 100644 Resources/views/CustomObject/detail.html.twig create mode 100644 Resources/views/CustomObject/form.html.twig create mode 100644 Resources/views/CustomObject/list.html.twig rename Views/FormTheme/FieldValueCondition/campaign_condition_field_value_widget.html.php => Resources/views/FormTheme/FieldValueCondition/campaign_condition_field_value_widget.html.twig (56%) create mode 100644 Resources/views/SubscribedEvents/Tab/content.html.twig create mode 100644 Resources/views/SubscribedEvents/Tab/link.html.twig create mode 100644 Resources/views/SubscribedEvents/Tab/modal.html.twig create mode 100644 Resources/views/SubscribedEvents/Timeline/link.html.twig create mode 100644 Segment/Query/Filter/CustomObjectMergedFilterQueryBuilder.php create mode 100644 Tests/Functional/EventListener/ContactSubscriberTest.php rename Tests/Functional/Segment/Query/Filter/{CustomItemRelationQueryBuilderTestCase.php => CustomItemRelationQueryBuilderTest.php} (91%) create mode 100644 Tests/Functional/Segment/Query/Filter/CustomObjectMergedFilterQueryBuilderTest.php create mode 100644 Tests/Functional/Segment/Query/Filter/NegativeOperatorFilterQueryBuilderTest.php create mode 100644 Tests/Functional/Token/EmailWithCustomObjectDynamicContentFunctionalTest.php create mode 100644 Tests/ProjectVersionTrait.php delete mode 100644 Views/CustomField/detail.html.php delete mode 100644 Views/CustomField/form.html.php delete mode 100644 Views/CustomField/index.html.php delete mode 100644 Views/CustomField/value.html.php delete mode 100644 Views/CustomItem/detail.html.php delete mode 100644 Views/CustomItem/form.html.php delete mode 100644 Views/CustomItem/index.html.php delete mode 100644 Views/CustomItem/list.html.php delete mode 100644 Views/CustomObject/Form/Panel/_field.html.php delete mode 100644 Views/CustomObject/Form/Panel/checkbox_group.html.php delete mode 100644 Views/CustomObject/Form/Panel/country.html.php delete mode 100644 Views/CustomObject/Form/Panel/date.html.php delete mode 100644 Views/CustomObject/Form/Panel/datetime.html.php delete mode 100644 Views/CustomObject/Form/Panel/email.html.php delete mode 100644 Views/CustomObject/Form/Panel/hidden.html.php delete mode 100644 Views/CustomObject/Form/Panel/html_area.html.php delete mode 100644 Views/CustomObject/Form/Panel/int.html.php delete mode 100644 Views/CustomObject/Form/Panel/multiselect.html.php delete mode 100644 Views/CustomObject/Form/Panel/phone.html.php delete mode 100644 Views/CustomObject/Form/Panel/radio_group.html.php delete mode 100644 Views/CustomObject/Form/Panel/select.html.php delete mode 100644 Views/CustomObject/Form/Panel/text.html.php delete mode 100644 Views/CustomObject/Form/Panel/textarea.html.php delete mode 100644 Views/CustomObject/Form/Panel/url.html.php delete mode 100644 Views/CustomObject/_form-fields.html.php delete mode 100644 Views/CustomObject/detail.html.php delete mode 100644 Views/CustomObject/form.html.php delete mode 100644 Views/CustomObject/index.html.php delete mode 100644 Views/CustomObject/list.html.php delete mode 100644 Views/SubscribedEvents/Tab/content.html.php delete mode 100644 Views/SubscribedEvents/Tab/link.html.php delete mode 100644 Views/SubscribedEvents/Tab/modal.html.php delete mode 100644 Views/SubscribedEvents/Timeline/link.html.php create mode 100644 phpstan-baseline-7.4.neon create mode 100644 phpstan-baseline-8.0.neon create mode 100644 phpstan-baseline-php-versions.neon.php create mode 100644 phpstan-baseline.neon create mode 100644 phpstan.neon diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 000000000..c21a33557 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,148 @@ +name: Mautic Build and Test + +on: + push: + branches: + - staging # Main branch + - '[0-9]+\.[0-9]+' + - development + - beta + pull_request: + +env: + PLUGIN_DIR: plugins/CustomObjectsBundle # Same as extra.install-directory-name in composer.json + +jobs: + phpunit: + runs-on: ubuntu-latest + + strategy: + matrix: + php-versions: ['8.0'] # The supported PHP versions + db-types: ['mysql'] # can be: ['mysql', 'mariadb'] but not necessary for this plugin that does not add any DB schema + mautic-versions: ['5.1'] # The supported Mautic versions + + name: Tests on PHP ${{ matrix.php-versions }}, ${{ matrix.db-types }}, Mautic ${{ matrix.mautic-versions }} + + services: + database: + image: ${{ matrix.db-types == 'mysql' && 'mysql:8.0' || 'mariadb:10.3' }} + env: + MYSQL_ALLOW_EMPTY_PASSWORD: yes + MYSQL_DATABASE: mautictest + ports: + - 3306 + options: >- + --shm-size=2gb + --name=${{ matrix.db-types }} + --tmpfs=/var/lib/mysql + --health-cmd="mysqladmin ping" + --health-interval=10s + --health-timeout=5s + --health-retries=3 + + steps: + - name: Checkout Mautic + uses: actions/checkout@v4 + with: + repository: mautic/mautic + ref: ${{ matrix.mautic-versions }} + + - name: Checkout this plugin + uses: actions/checkout@v4 + with: + path: ${{ env.PLUGIN_DIR }} + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + ini-values: -dpcov.enabled=0, pcov.directory=." + extensions: mbstring, xml, ctype, iconv, intl, pdo_sqlite, mysql, pdo_mysql + coverage: pcov + + - name: add MySQL config file + run: | + mysqldump --version + mysqldump --print-defaults + cp .github/ci-files/.my.cnf ~/.my.cnf + mysqldump --print-defaults + + - name: Set SYMFONY_ENV to test + run: | + echo "SYMFONY_ENV=test" >> $GITHUB_ENV + echo "MAUTIC_ENV=test" >> $GITHUB_ENV + + - name: Install Composer dependencies + run: | + composer install + + # - name: Get composer cache directory + # id: composer-cache + # run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + # - name: Cache composer dependencies + # uses: actions/cache@v4 + # with: + # path: ${{ steps.composer-cache.outputs.dir }} + # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + # restore-keys: ${{ runner.os }}-composer- + + - name: Install Mautic + env: + DB_PORT: ${{ job.services.database.ports[3306] }} + run: | + cp ./.github/ci-files/local.php ./app/config/local.php + php bin/console mautic:install --force http://localhost + + - name: Install Plugins + env: + DB_PORT: ${{ job.services.database.ports[3306] }} + run: php bin/console mautic:plugins:install --env=dev + + # - name: Run static analysis + # env: + # COMPOSER_ALLOW_SUPERUSER: 1 + # run: composer phpstan -- --no-progress + + - name: Run Code Style check + run: bin/php-cs-fixer fix ${{ env.PLUGIN_DIR }} --config=.php-cs-fixer.php -v --dry-run --show-progress=dots --diff + + # - name: PHPSTAN - baseline (debug, enable if you need to regenerate baseline for all PHP versions) + # run: bin/phpstan --configuration=${{ env.PLUGIN_DIR }}/phpstan.neon --generate-baseline=var/logs/phpstan-baseline-${{ matrix.php-versions }}.neon --allow-empty-baseline + + - name: PHPSTAN + run: bin/phpstan --configuration=${{ env.PLUGIN_DIR }}/phpstan.neon + + - name: Rector + run: composer rector -- --dry-run --no-progress-bar ${{ env.PLUGIN_DIR }} + + - name: Twig Lint + run: bin/console lint:twig ${{ env.PLUGIN_DIR }} + + - name: Create writable directory + run: mkdir -p ./media/files/temp && chmod -R 777 ./media/files/temp + + - name: Run PHPUNIT tests + env: + DB_PORT: ${{ job.services.database.ports[3306] }} + # run: XDEBUG_MODE=coverage APP_DEBUG=0 php -dpcov.enabled=1 -dpcov.directory=. -dpcov.exclude="~tests|themes|vendor~" bin/phpunit -d memory_limit=1G --bootstrap vendor/autoload.php --configuration ${{ env.PLUGIN_DIR }}/phpunit.xml --coverage-clover=${{ env.PLUGIN_DIR }}/coverage.xml --coverage-text + run: XDEBUG_MODE=coverage APP_DEBUG=0 php -dpcov.enabled=1 -dpcov.directory=. bin/phpunit -d memory_limit=1G --bootstrap vendor/autoload.php --configuration ${{ env.PLUGIN_DIR }}/phpunit.xml --filter=CustomObjectsBundle --coverage-clover=${{ env.PLUGIN_DIR }}/coverage.xml --coverage-text + + # - name: Coverage report (debug) + # run: cat ${{ env.PLUGIN_DIR }}/coverage.xml + + # - name: Upload coverage report + # if: ${{ matrix.php-versions == '8.0' && matrix.db-types == 'mysql' && matrix.mautic-versions == '4.4' }} # upload just once, change for your matrix + # uses: codecov/codecov-action@v3 + # with: + # token: ${{ secrets.CODECOV_TOKEN }} + # fail_ci_if_error: true + # working-directory: ${{ env.PLUGIN_DIR }} + # verbose: true + + - name: Upload logs as artifacts + uses: actions/upload-artifact@v3 + with: + name: mautic-logs + path: var/logs/ diff --git a/Assets/js/custom-objects.js b/Assets/js/custom-objects.js index 705f7104d..92dba61b3 100644 --- a/Assets/js/custom-objects.js +++ b/Assets/js/custom-objects.js @@ -44,8 +44,9 @@ CustomObjects = { 'id': valueField.attr('id'), 'name': valueField.attr('name'), 'autocomplete': valueField.attr('autocomplete'), - 'value': valueField.attr('value') + 'value': valueField.val() }; + const fieldType = selectedField.attr('data-field-type'); operatorSelect.empty(); @@ -67,17 +68,40 @@ CustomObjects = { newValueField.append( mQuery("") .attr('value', optionValue) - .attr('selected', valueField.attr('value') == optionValue) + .attr('selected', valueField.val() === optionValue) .text(options[optionValue]) ); - }; + } + } + + if (fieldType === 'date') { + newValueField.datetimepicker({ + timepicker: false, + format: 'Y-m-d', + lazyInit: true, + validateOnBlur: false, + allowBlank: true, + scrollMonth: false, + scrollInput: false, + closeOnDateSelect: true + }); + } else if (fieldType === 'datetime') { + newValueField.datetimepicker({ + format: 'Y-m-d H:i', + lazyInit: true, + validateOnBlur: false, + allowBlank: true, + scrollMonth: false, + scrollInput: false + }); } if (isEmptyOperator) { - newValueField.attr('readonly', true); + newValueField.val(null); newValueField.attr('value', ''); + newValueField.attr('disabled', 'disabled'); } else { - newValueField.attr('value', valueFieldAttrs['value']); + newValueField.val(valueField.val()); } newValueField.attr(valueFieldAttrs); diff --git a/Command/CustomItemsScheduledExportCommand.php b/Command/CustomItemsScheduledExportCommand.php index 74e4e74a5..3212ccc15 100644 --- a/Command/CustomItemsScheduledExportCommand.php +++ b/Command/CustomItemsScheduledExportCommand.php @@ -4,8 +4,7 @@ namespace MauticPlugin\CustomObjectsBundle\Command; -use Mautic\CoreBundle\Helper\ExitCode; -use Mautic\CoreBundle\Templating\Helper\FormatterHelper; +use Mautic\CoreBundle\Twig\Helper\FormatterHelper; use MauticPlugin\CustomObjectsBundle\CustomItemEvents; use MauticPlugin\CustomObjectsBundle\Event\CustomItemExportSchedulerEvent; use MauticPlugin\CustomObjectsBundle\Model\CustomItemExportSchedulerModel; @@ -19,19 +18,11 @@ class CustomItemsScheduledExportCommand extends Command { public const COMMAND_NAME = 'mautic:custom_items:scheduled_export'; - private CustomItemExportSchedulerModel $customItemExportSchedulerModel; - private EventDispatcherInterface $eventDispatcher; - private FormatterHelper $formatterHelper; - public function __construct( - CustomItemExportSchedulerModel $customItemExportSchedulerModel, - EventDispatcherInterface $eventDispatcher, - FormatterHelper $formatterHelper + private CustomItemExportSchedulerModel $customItemExportSchedulerModel, + private EventDispatcherInterface $eventDispatcher, + private FormatterHelper $formatterHelper ) { - $this->customItemExportSchedulerModel = $customItemExportSchedulerModel; - $this->eventDispatcher = $eventDispatcher; - $this->formatterHelper = $formatterHelper; - parent::__construct(); } @@ -58,14 +49,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int foreach ($customItemExportSchedulers as $customItemExportScheduler) { $customItemExportSchedulerEvent = new CustomItemExportSchedulerEvent($customItemExportScheduler); - $this->eventDispatcher->dispatch(CustomItemEvents::CUSTOM_ITEM_PREPARE_EXPORT_FILE, $customItemExportSchedulerEvent); - $this->eventDispatcher->dispatch(CustomItemEvents::CUSTOM_ITEM_MAIL_EXPORT_FILE, $customItemExportSchedulerEvent); - $this->eventDispatcher->dispatch(CustomItemEvents::POST_EXPORT_MAIL_SENT, $customItemExportSchedulerEvent); + $this->eventDispatcher->dispatch($customItemExportSchedulerEvent, CustomItemEvents::CUSTOM_ITEM_PREPARE_EXPORT_FILE); + $this->eventDispatcher->dispatch($customItemExportSchedulerEvent, CustomItemEvents::CUSTOM_ITEM_MAIL_EXPORT_FILE); + $this->eventDispatcher->dispatch($customItemExportSchedulerEvent, CustomItemEvents::POST_EXPORT_MAIL_SENT); ++$count; } $output->writeln('CustomItem export email(s) sent: '.$count); - return ExitCode::SUCCESS; + return Command::SUCCESS; } } diff --git a/Command/GenerateSampleDataCommand.php b/Command/GenerateSampleDataCommand.php index 3ea8458fb..ceb815d44 100644 --- a/Command/GenerateSampleDataCommand.php +++ b/Command/GenerateSampleDataCommand.php @@ -5,10 +5,10 @@ namespace MauticPlugin\CustomObjectsBundle\Command; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\DBALException; +use Doctrine\DBAL\Exception; use Doctrine\ORM\EntityManager; use MauticPlugin\CustomObjectsBundle\Helper\RandomHelper; -use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; +use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -16,32 +16,17 @@ use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\Console\Style\SymfonyStyle; -class GenerateSampleDataCommand extends ContainerAwareCommand +class GenerateSampleDataCommand extends Command { - /** - * @var EntityManager - */ - private $entityManager; - - /** - * @var RandomHelper - */ - private $randomHelper; - - /** - * @var Connection - */ - private $connection; + private Connection $connection; public function __construct( - EntityManager $entityManager, - RandomHelper $randomHelper + private EntityManager $entityManager, + private RandomHelper $randomHelper ) { parent::__construct(); - $this->entityManager = $entityManager; - $this->randomHelper = $randomHelper; - $this->connection = $entityManager->getConnection(); + $this->connection = $entityManager->getConnection(); } /** @@ -111,8 +96,6 @@ protected function execute(InputInterface $input, OutputInterface $output) /** * @return int[] - * - * @throws DBALException */ private function createCustomObjectsWithItems(): array { @@ -150,13 +133,16 @@ private function createCustomObjectsWithItems(): array return [$coProductId, $cfPriceId, $coOrderId]; } + /** + * @throws Exception + */ private function cleanupDB(): void { $query = 'delete from '.MAUTIC_TABLE_PREFIX.'leads where 1'; - $this->connection->query($query); + $this->connection->executeQuery($query); $query = 'delete from '.MAUTIC_TABLE_PREFIX.'custom_object where 1'; - $this->connection->query($query); + $this->connection->executeQuery($query); } private function generateContact(int $coProductId, int $cfPriceId, int $coOrderId, int $priceLimit): void @@ -220,9 +206,11 @@ private function generateProductRelations(int $contactId, int $coProductId, int } /** + * @param array $row + * * @return int Last inserted row ID * - * @throws DBALException + * @throws Exception */ private function insertInto(string $table, array $row): int { @@ -235,13 +223,10 @@ function ($value) { switch (gettype($value)) { case 'string': return "'$value'"; - break; case 'integer': return (string) $value; - break; case 'boolean': return (bool) $value; - break; default: $type = gettype($value); throw new \InvalidArgumentException("Unsupported type '$type' for insert query"); @@ -256,7 +241,7 @@ function ($value) { VALUES ($values) "; - $this->connection->query($query); + $this->connection->executeQuery($query); return (int) $this->connection->lastInsertId(); } diff --git a/Config/config.php b/Config/config.php index 1476deaf4..313fb8820 100644 --- a/Config/config.php +++ b/Config/config.php @@ -18,12 +18,12 @@ // Custom Fields CustomFieldRouteProvider::ROUTE_FORM => [ 'path' => '/custom/field/edit', - 'controller' => 'CustomObjectsBundle:CustomField\Form:renderForm', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomField\FormController::renderFormAction', 'method' => 'GET', ], CustomFieldRouteProvider::ROUTE_SAVE => [ 'path' => '/custom/field/save/{fieldType}', - 'controller' => 'CustomObjectsBundle:CustomField\Save:save', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomField\SaveController::saveAction', 'method' => 'POST', 'defaults' => [ 'fieldId' => null, @@ -33,7 +33,7 @@ // Custom Items CustomItemRouteProvider::ROUTE_LIST => [ 'path' => '/custom/object/{objectId}/item/{page}', - 'controller' => 'CustomObjectsBundle:CustomItem\List:list', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\ListController::listAction', 'method' => 'GET|POST', 'defaults' => [ 'page' => 1, @@ -41,45 +41,44 @@ ], CustomItemRouteProvider::ROUTE_VIEW => [ 'path' => '/custom/object/{objectId}/item/view/{itemId}', - 'controller' => 'CustomObjectsBundle:CustomItem\View:view', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\ViewController::viewAction', 'method' => 'GET|POST', ], CustomItemRouteProvider::ROUTE_NEW => [ 'path' => '/custom/object/{objectId}/item/new', - 'controller' => 'CustomObjectsBundle:CustomItem\Form:new', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\FormController::newAction', 'method' => 'GET', ], CustomItemRouteProvider::ROUTE_NEW_REDIRECT_TO_CONTACT => [ 'path' => '/custom/object/{objectId}/contact/{contactId}/item/new', - 'controller' => 'CustomObjectsBundle:CustomItem\Form:newWithRedirectToContact', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\FormController::newWithRedirectToContactAction', 'method' => 'GET', ], CustomItemRouteProvider::ROUTE_EDIT => [ 'path' => '/custom/object/{objectId}/item/edit/{itemId}', - 'controller' => 'CustomObjectsBundle:CustomItem\Form:edit', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\FormController::editAction', 'method' => 'GET', ], CustomItemRouteProvider::ROUTE_EDIT_REDIRECT_TO_CONTACT => [ 'path' => '/custom/object/{objectId}/item/edit/{itemId}/contact/{contactId}', - 'controller' => 'CustomObjectsBundle:CustomItem\Form:editWithRedirectToContact', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\FormController::editWithRedirectToContactAction', 'method' => 'GET', ], CustomItemRouteProvider::ROUTE_CLONE => [ 'path' => '/custom/object/{objectId}/item/clone/{itemId}', - 'controller' => 'CustomObjectsBundle:CustomItem\Form:clone', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\FormController::cloneAction', 'method' => 'GET', ], CustomItemRouteProvider::ROUTE_CANCEL => [ 'path' => '/custom/object/{objectId}/item/cancel/{itemId}', - 'controller' => 'CustomObjectsBundle:CustomItem\Cancel:cancel', - 'method' => 'POST', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\CancelController::cancelAction', 'defaults' => [ 'itemId' => null, ], ], CustomItemRouteProvider::ROUTE_SAVE => [ 'path' => '/custom/object/{objectId}/item/save/{itemId}', - 'controller' => 'CustomObjectsBundle:CustomItem\Save:save', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\SaveController::saveAction', 'method' => 'POST', 'defaults' => [ 'itemId' => null, @@ -87,57 +86,57 @@ ], CustomItemRouteProvider::ROUTE_DELETE => [ 'path' => '/custom/object/{objectId}/item/delete/{itemId}', - 'controller' => 'CustomObjectsBundle:CustomItem\Delete:delete', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\DeleteController::deleteAction', 'method' => 'GET|POST', ], CustomItemRouteProvider::ROUTE_BATCH_DELETE => [ 'path' => '/custom/object/{objectId}/item/batch/delete', - 'controller' => 'CustomObjectsBundle:CustomItem\BatchDelete:delete', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\BatchDeleteController::deleteAction', 'method' => 'POST', ], CustomItemRouteProvider::ROUTE_LOOKUP => [ 'path' => '/custom/object/{objectId}/item/lookup.json', - 'controller' => 'CustomObjectsBundle:CustomItem\Lookup:list', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\LookupController::listAction', 'method' => 'GET', ], CustomItemRouteProvider::ROUTE_LINK => [ 'path' => '/custom/item/{itemId}/link/{entityType}/{entityId}.json', - 'controller' => 'CustomObjectsBundle:CustomItem\Link:save', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\LinkController::saveAction', 'method' => 'POST', ], CustomItemRouteProvider::ROUTE_LINK_FORM => [ 'path' => '/custom/item/{itemId}/link-form/{entityType}/{entityId}', - 'controller' => 'CustomObjectsBundle:CustomItem\LinkForm:form', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\LinkFormController::formAction', 'method' => 'GET', ], CustomItemRouteProvider::ROUTE_LINK_FORM_SAVE => [ 'path' => '/custom/item/{itemId}/link-form/{entityType}/{entityId}', - 'controller' => 'CustomObjectsBundle:CustomItem\LinkForm:save', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\LinkFormController::saveAction', 'method' => 'POST', ], CustomItemRouteProvider::ROUTE_UNLINK => [ 'path' => '/custom/item/{itemId}/unlink/{entityType}/{entityId}.json', - 'controller' => 'CustomObjectsBundle:CustomItem\Unlink:save', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\UnlinkController::saveAction', 'method' => 'POST', ], CustomItemRouteProvider::ROUTE_CONTACT_LIST => [ 'path' => '/custom/item/{objectId}/contact/{page}', - 'controller' => 'CustomObjectsBundle:CustomItem\ContactList:list', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\ContactListController::listAction', ], CustomItemRouteProvider::ROUTE_EXPORT_ACTION => [ 'path' => 'custom/object/{object}/export', - 'controller' => 'CustomObjectsBundle:CustomItem\Export:export', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\ExportController::exportAction', 'method' => 'POST', ], CustomItemRouteProvider::ROUTE_EXPORT_DOWNLOAD_ACTION => [ 'path' => '/custom/item/export/download/{fileName}', - 'controller' => 'CustomObjectsBundle:CustomItem\Export:downloadExport', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\ExportController::downloadExportAction', ], // Custom Objects CustomObjectRouteProvider::ROUTE_LIST => [ 'path' => '/custom/object/{page}', - 'controller' => 'CustomObjectsBundle:CustomObject\List:list', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomObject\ListController::listAction', 'method' => 'GET|POST', 'defaults' => [ 'page' => 1, @@ -145,35 +144,34 @@ ], CustomObjectRouteProvider::ROUTE_VIEW => [ 'path' => '/custom/object/view/{objectId}', - 'controller' => 'CustomObjectsBundle:CustomObject\View:view', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomObject\ViewController::viewAction', 'method' => 'GET|POST', ], CustomObjectRouteProvider::ROUTE_NEW => [ 'path' => '/custom/object/new', - 'controller' => 'CustomObjectsBundle:CustomObject\Form:new', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomObject\FormController::newAction', 'method' => 'GET', ], CustomObjectRouteProvider::ROUTE_EDIT => [ 'path' => '/custom/object/edit/{objectId}', - 'controller' => 'CustomObjectsBundle:CustomObject\Form:edit', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomObject\FormController::editAction', 'method' => 'GET', ], CustomObjectRouteProvider::ROUTE_CLONE => [ 'path' => '/custom/object/clone/{objectId}', - 'controller' => 'CustomObjectsBundle:CustomObject\Form:clone', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomObject\FormController::cloneAction', 'method' => 'GET', ], CustomObjectRouteProvider::ROUTE_CANCEL => [ 'path' => '/custom/object/cancel/{objectId}', - 'controller' => 'CustomObjectsBundle:CustomObject\Cancel:cancel', - 'method' => 'POST', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomObject\CancelController::cancelAction', 'defaults' => [ 'objectId' => null, ], ], CustomObjectRouteProvider::ROUTE_SAVE => [ 'path' => '/custom/object/save/{objectId}', - 'controller' => 'CustomObjectsBundle:CustomObject\Save:save', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomObject\SaveController::saveAction', 'method' => 'POST', 'defaults' => [ 'objectId' => null, @@ -181,409 +179,126 @@ ], CustomObjectRouteProvider::ROUTE_DELETE => [ 'path' => '/custom/object/delete/{objectId}', - 'controller' => 'CustomObjectsBundle:CustomObject\Delete:delete', + 'controller' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomObject\DeleteController::deleteAction', 'method' => 'GET|POST', ], ], ], 'services' => [ - 'controllers' => [ - // Custom Fields - 'custom_field.form_controller' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Controller\CustomField\FormController::class, - 'arguments' => [ - 'form.factory', - 'mautic.custom.model.field', - 'custom_object.custom_field_factory', - 'custom_field.permission.provider', - 'custom_field.route.provider', - 'mautic.custom.model.object', - 'custom_object.route.provider', - ], - 'methodCalls' => [ - 'setContainer' => [ - '@service_container', - ], - ], - ], - 'custom_field.save_controller' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Controller\CustomField\SaveController::class, - 'arguments' => [ - 'form.factory', - 'translator', - 'mautic.custom.model.field', - 'custom_object.custom_field_factory', - 'custom_field.permission.provider', - 'custom_field.route.provider', - 'mautic.custom.model.object', - ], - 'methodCalls' => [ - 'setContainer' => [ - '@service_container', - ], - ], - ], - - // Custom Items - 'custom_item.list_controller' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Controller\CustomItem\ListController::class, - 'arguments' => [ - 'request_stack', - 'custom_object.session.provider_factory', - 'mautic.custom.model.item', - 'mautic.custom.model.object', - 'custom_item.permission.provider', - 'custom_item.route.provider', - ], - 'methodCalls' => [ - 'setContainer' => [ - '@service_container', - ], - ], - ], - 'custom_item.view_controller' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Controller\CustomItem\ViewController::class, - 'arguments' => [ - 'request_stack', - 'form.factory', - 'mautic.custom.model.item', - 'mautic.custom.model.import.xref.contact', - 'mautic.core.model.auditlog', - 'custom_item.permission.provider', - 'custom_item.route.provider', - ], - 'methodCalls' => [ - 'setContainer' => [ - '@service_container', - ], - ], - ], - 'custom_item.form_controller' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Controller\CustomItem\FormController::class, - 'arguments' => [ - 'form.factory', - 'mautic.custom.model.object', - 'mautic.custom.model.item', - 'custom_item.permission.provider', - 'custom_item.route.provider', - 'custom_object.lock_flash_message.helper', - ], - 'methodCalls' => [ - 'setContainer' => [ - '@service_container', - ], - ], - ], - 'custom_item.save_controller' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Controller\CustomItem\SaveController::class, - 'arguments' => [ - 'request_stack', - 'form.factory', - 'mautic.core.service.flashbag', - 'mautic.custom.model.item', - 'mautic.custom.model.object', - 'custom_item.permission.provider', - 'custom_item.route.provider', - 'custom_object.lock_flash_message.helper', - ], - 'methodCalls' => [ - 'setContainer' => [ - '@service_container', - ], - ], - ], - 'custom_item.delete_controller' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Controller\CustomItem\DeleteController::class, - 'arguments' => [ - 'mautic.custom.model.item', - 'custom_object.session.provider_factory', - 'mautic.core.service.flashbag', - 'custom_item.permission.provider', - 'custom_item.route.provider', - ], - 'methodCalls' => [ - 'setContainer' => [ - '@service_container', - ], - ], - ], - 'custom_item.batch_delete_controller' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Controller\CustomItem\BatchDeleteController::class, - 'arguments' => [ - 'request_stack', - 'mautic.custom.model.item', - 'custom_object.session.provider_factory', - 'custom_item.permission.provider', - 'custom_item.route.provider', - 'mautic.core.service.flashbag', - ], - 'methodCalls' => [ - 'setContainer' => [ - '@service_container', - ], - ], - ], - 'custom_item.cancel_controller' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Controller\CustomItem\CancelController::class, - 'arguments' => [ - 'custom_object.session.provider_factory', - 'custom_item.route.provider', - 'mautic.custom.model.item', - ], - 'methodCalls' => [ - 'setContainer' => [ - '@service_container', - ], - ], - ], - 'custom_item.lookup_controller' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Controller\CustomItem\LookupController::class, - 'arguments' => [ - 'request_stack', - 'mautic.custom.model.item', - 'custom_item.permission.provider', - 'mautic.core.service.flashbag', - ], - 'methodCalls' => [ - 'setContainer' => [ - '@service_container', - ], - ], - ], - 'custom_item.link_controller' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Controller\CustomItem\LinkController::class, - 'arguments' => [ - 'mautic.custom.model.item', - 'custom_item.permission.provider', - 'mautic.core.service.flashbag', - ], - 'methodCalls' => [ - 'setContainer' => [ - '@service_container', - ], - ], - ], - 'custom_item.link_form_controller' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Controller\CustomItem\LinkFormController::class, - 'arguments' => [ - 'form.factory', - 'mautic.custom.model.item', - 'custom_item.permission.provider', - 'custom_item.route.provider', - 'mautic.core.service.flashbag', - ], - 'methodCalls' => [ - 'setContainer' => [ - '@service_container', - ], - ], - ], - 'custom_item.unlink_controller' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Controller\CustomItem\UnlinkController::class, - 'arguments' => [ - 'mautic.custom.model.item', - 'custom_item.permission.provider', - 'mautic.core.service.flashbag', - ], - 'methodCalls' => [ - 'setContainer' => [ - '@service_container', - ], - ], - ], - 'custom_item.contact_list_controller' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Controller\CustomItem\ContactListController::class, - 'methodCalls' => [ - 'setContainer' => [ - '@service_container', - ], - ], - ], - 'custom_item.export_controller' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Controller\CustomItem\ExportController::class, - 'arguments' => [ - 'custom_item.permission.provider', - 'mautic.custom.model.export_scheduler', - ], - ], - - // Custom Objects - 'custom_object.list_controller' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Controller\CustomObject\ListController::class, - 'arguments' => [ - 'request_stack', - 'custom_object.session.provider_factory', - 'mautic.custom.model.object', - 'custom_object.permission.provider', - 'custom_object.route.provider', - ], - 'methodCalls' => [ - 'setContainer' => [ - '@service_container', - ], - ], - ], - 'custom_object.view_controller' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Controller\CustomObject\ViewController::class, - 'arguments' => [ - 'request_stack', - 'form.factory', - 'mautic.custom.model.object', - 'mautic.core.model.auditlog', - 'custom_object.permission.provider', - 'custom_object.route.provider', - ], - 'methodCalls' => [ - 'setContainer' => [ - '@service_container', - ], - ], - ], - 'custom_object.form_controller' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Controller\CustomObject\FormController::class, - 'arguments' => [ - 'form.factory', - 'mautic.custom.model.object', - 'mautic.custom.model.field', - 'custom_object.permission.provider', - 'custom_object.route.provider', - 'custom_field.type.provider', - 'custom_object.lock_flash_message.helper', - ], - 'methodCalls' => [ - 'setContainer' => [ - '@service_container', - ], - ], - ], - 'custom_object.save_controller' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Controller\CustomObject\SaveController::class, - 'arguments' => [ - 'request_stack', - 'mautic.core.service.flashbag', - 'form.factory', - 'mautic.custom.model.object', - 'mautic.custom.model.field', - 'custom_object.permission.provider', - 'custom_object.route.provider', - 'custom_field.type.provider', - 'custom_field.field.params.to.string.transformer', - 'custom_field.field.options.to.string.transformer', - 'custom_object.lock_flash_message.helper', - ], - 'methodCalls' => [ - 'setContainer' => [ - '@service_container', - ], - ], - ], - 'custom_object.delete_controller' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Controller\CustomObject\DeleteController::class, - 'arguments' => [ - 'mautic.custom.model.object', - 'custom_object.session.provider_factory', - 'mautic.core.service.flashbag', - 'custom_object.permission.provider', - 'event_dispatcher', - ], - 'methodCalls' => [ - 'setContainer' => [ - '@service_container', - ], - ], - ], - 'custom_object.cancel_controller' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Controller\CustomObject\CancelController::class, - 'arguments' => [ - 'custom_object.session.provider_factory', - 'custom_object.route.provider', - 'mautic.custom.model.object', - ], - 'methodCalls' => [ - 'setContainer' => [ - '@service_container', - ], - ], - ], - ], 'models' => [ 'mautic.custom.model.field' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Model\CustomFieldModel::class, + 'class' => MauticPlugin\CustomObjectsBundle\Model\CustomFieldModel::class, 'arguments' => [ + 'doctrine.orm.entity_manager', + 'mautic.security', + 'event_dispatcher', + 'router', + 'translator', + 'mautic.helper.user', + 'monolog.logger', + 'mautic.helper.core_parameters', 'custom_field.repository', 'custom_field.permission.provider', - 'mautic.helper.user', ], ], 'mautic.custom.model.field.value' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Model\CustomFieldValueModel::class, + 'class' => MauticPlugin\CustomObjectsBundle\Model\CustomFieldValueModel::class, 'arguments' => [ 'doctrine.orm.entity_manager', 'validator', ], ], 'mautic.custom.model.item' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Model\CustomItemModel::class, + 'class' => MauticPlugin\CustomObjectsBundle\Model\CustomItemModel::class, 'arguments' => [ 'doctrine.orm.entity_manager', + 'mautic.security', + 'event_dispatcher', + 'router', + 'translator', + 'mautic.helper.user', + 'monolog.logger', + 'mautic.helper.core_parameters', 'custom_item.repository', 'custom_item.permission.provider', - 'mautic.helper.user', 'mautic.custom.model.field.value', - 'event_dispatcher', 'validator', ], ], 'mautic.custom.model.import.item' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Model\CustomItemImportModel::class, + 'class' => MauticPlugin\CustomObjectsBundle\Model\CustomItemImportModel::class, 'arguments' => [ 'doctrine.orm.entity_manager', + 'mautic.security', + 'event_dispatcher', + 'router', + 'translator', + 'mautic.helper.user', + 'monolog.logger', + 'mautic.helper.core_parameters', 'mautic.custom.model.item', - 'mautic.helper.template.formatter', + 'mautic.helper.twig.formatter', ], ], 'mautic.custom.model.import.xref.contact' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Model\CustomItemXrefContactModel::class, + 'class' => MauticPlugin\CustomObjectsBundle\Model\CustomItemXrefContactModel::class, 'arguments' => [ 'doctrine.orm.entity_manager', + 'mautic.security', + 'event_dispatcher', + 'router', 'translator', + 'mautic.helper.user', + 'monolog.logger', + 'mautic.helper.core_parameters', ], ], 'mautic.custom.model.field.option' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Model\CustomFieldOptionModel::class, + 'class' => MauticPlugin\CustomObjectsBundle\Model\CustomFieldOptionModel::class, 'arguments' => [ 'doctrine.orm.entity_manager', ], ], 'mautic.custom.model.object' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Model\CustomObjectModel::class, + 'class' => MauticPlugin\CustomObjectsBundle\Model\CustomObjectModel::class, 'arguments' => [ 'doctrine.orm.entity_manager', + 'mautic.security', + 'event_dispatcher', + 'router', + 'translator', + 'mautic.helper.user', + 'monolog.logger', + 'mautic.helper.core_parameters', 'custom_object.repository', 'custom_object.permission.provider', - 'mautic.helper.user', 'mautic.custom.model.field', - 'event_dispatcher', - 'mautic.lead.model.list', ], ], 'mautic.custom.model.export_scheduler' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Model\CustomItemExportSchedulerModel::class, + 'class' => MauticPlugin\CustomObjectsBundle\Model\CustomItemExportSchedulerModel::class, 'arguments' => [ + 'doctrine.orm.entity_manager', + 'mautic.security', + 'event_dispatcher', + 'router', + 'translator', + 'mautic.helper.user', + 'monolog.logger', + 'mautic.helper.core_parameters', 'mautic.helper.export', 'mautic.helper.mailer', 'mautic.custom.model.field.value', 'custom_item.route.provider', 'custom_item.xref.contact.repository', 'custom_item.repository', - 'event_dispatcher', ], ], ], 'permissions' => [ 'custom_object.permissions' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Security\Permissions\CustomObjectPermissions::class, + 'class' => MauticPlugin\CustomObjectsBundle\Security\Permissions\CustomObjectPermissions::class, 'arguments' => [ 'mautic.helper.core_parameters', 'mautic.custom.model.object', @@ -594,42 +309,42 @@ ], 'repositories' => [ 'custom_field.repository' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Repository\CustomFieldRepository::class, + 'class' => Doctrine\ORM\EntityRepository::class, 'factory' => ['@doctrine.orm.entity_manager', 'getRepository'], 'arguments' => [ - \MauticPlugin\CustomObjectsBundle\Entity\CustomField::class, + MauticPlugin\CustomObjectsBundle\Entity\CustomField::class, ], ], 'custom_item.repository' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Repository\CustomItemRepository::class, + 'class' => Doctrine\ORM\EntityRepository::class, 'factory' => ['@doctrine.orm.entity_manager', 'getRepository'], 'arguments' => [ - \MauticPlugin\CustomObjectsBundle\Entity\CustomItem::class, + MauticPlugin\CustomObjectsBundle\Entity\CustomItem::class, ], ], 'custom_object.repository' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Repository\CustomObjectRepository::class, + 'class' => Doctrine\ORM\EntityRepository::class, 'factory' => ['@doctrine.orm.entity_manager', 'getRepository'], 'arguments' => [ - \MauticPlugin\CustomObjectsBundle\Entity\CustomObject::class, + MauticPlugin\CustomObjectsBundle\Entity\CustomObject::class, ], ], 'custom_item.xref.contact.repository' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Repository\CustomItemXrefContactRepository::class, + 'class' => Doctrine\ORM\EntityRepository::class, 'factory' => ['@doctrine.orm.entity_manager', 'getRepository'], 'arguments' => [ - \MauticPlugin\CustomObjectsBundle\Entity\CustomItemXrefContact::class, + MauticPlugin\CustomObjectsBundle\Entity\CustomItemXrefContact::class, ], ], 'custom_item.xref.custom_item.repository' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Repository\CustomItemXrefCustomItemRepository::class, + 'class' => Doctrine\ORM\EntityRepository::class, 'factory' => ['@doctrine.orm.entity_manager', 'getRepository'], 'arguments' => [ - \MauticPlugin\CustomObjectsBundle\Entity\CustomItemXrefCustomItem::class, + MauticPlugin\CustomObjectsBundle\Entity\CustomItemXrefCustomItem::class, ], ], 'custom_object.segment_decorator_multiselect' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Segment\Decorator\MultiselectDecorator::class, + 'class' => MauticPlugin\CustomObjectsBundle\Segment\Decorator\MultiselectDecorator::class, 'arguments' => [ 'mautic.lead.model.lead_segment_filter_operator', 'mautic.lead.repository.lead_segment_filter_descriptor', @@ -637,51 +352,8 @@ ], ], 'events' => [ - 'custom_object.api.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\ApiSubscriber::class, - 'arguments' => [ - 'custom_object.config.provider', - 'mautic.custom.model.object', - 'mautic.custom.model.item', - ], - ], - 'custom_object.assets.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\AssetsSubscriber::class, - 'arguments' => [ - 'templating.helper.assets', - 'custom_object.config.provider', - ], - ], - 'custom_object.menu.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\MenuSubscriber::class, - 'arguments' => [ - 'mautic.custom.model.object', - 'custom_object.config.provider', - ], - ], - 'custom_object.contact.tab.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\ContactTabSubscriber::class, - 'arguments' => [ - 'mautic.custom.model.object', - 'custom_item.repository', - 'custom_object.config.provider', - 'translator', - 'custom_item.route.provider', - 'custom_object.session.provider_factory', - ], - ], - 'custom_object.custom_item.tab.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\CustomItemTabSubscriber::class, - 'arguments' => [ - 'mautic.custom.model.object', - 'custom_item.repository', - 'translator', - 'custom_item.route.provider', - 'custom_object.session.provider_factory', - ], - ], 'custom_field.post_load.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\CustomFieldPostLoadSubscriber::class, + 'class' => MauticPlugin\CustomObjectsBundle\EventListener\CustomFieldPostLoadSubscriber::class, 'arguments' => [ 'custom_field.type.provider', ], @@ -691,113 +363,16 @@ 'lazy' => true, ], ], - 'custom_object.report.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\ReportSubscriber::class, - 'arguments' => [ - 'custom_object.repository', - 'mautic.lead.reportbundle.fields_builder', - 'mautic.lead.model.company_report_data', - 'mautic.report.helper.report', - 'translator', - ], - ], // There's a problem with multiple tags and arguments definition using array. // So subscriber above should contain subscriber method below. But it is not possible now. 'custom_field.pre_save.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\CustomFieldPreSaveSubscriber::class, + 'class' => MauticPlugin\CustomObjectsBundle\EventListener\CustomFieldPreSaveSubscriber::class, 'arguments' => [ 'mautic.custom.model.field.option', ], ], - 'custom_item.button.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\CustomItemButtonSubscriber::class, - 'arguments' => [ - 'custom_item.permission.provider', - 'custom_item.route.provider', - 'translator', - ], - ], - 'custom_item.xref_contact.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\CustomItemXrefContactSubscriber::class, - 'arguments' => [ - 'doctrine.orm.entity_manager', - 'mautic.helper.user', - 'custom_item.repository', - ], - ], - 'custom_item.export.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\CustomItemScheduledExportSubscriber::class, - 'arguments' => [ - 'mautic.custom.model.export_scheduler', - ], - ], - 'custom_item.xref_item.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\CustomItemXrefCustomItemSubscriber::class, - 'arguments' => [ - 'doctrine.orm.entity_manager', - 'custom_item.repository', - ], - ], - 'custom_item.import.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\ImportSubscriber::class, - 'arguments' => [ - 'mautic.custom.model.object', - 'mautic.custom.model.import.item', - 'custom_object.config.provider', - 'custom_item.permission.provider', - 'custom_field.repository', - 'translator', - ], - ], - 'custom_item.contact.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\ContactSubscriber::class, - 'arguments' => [ - 'doctrine.orm.entity_manager', - 'translator', - 'custom_item.route.provider', - 'mautic.custom.model.item', - 'custom_object.config.provider', - ], - ], - 'custom_item.post_save.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\CustomItemPostSaveSubscriber::class, - 'arguments' => [ - 'mautic.custom.model.item', - 'request_stack', - ], - ], - 'custom_item.post_delete.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\CustomItemPostDeleteSubscriber::class, - 'arguments' => [ - 'custom_item.xref.custom_item.repository', - 'custom_item.xref.contact.repository', - ], - ], - 'custom_object.audit.log.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\AuditLogSubscriber::class, - 'arguments' => [ - 'mautic.core.model.auditlog', - 'mautic.helper.ip_lookup', - ], - ], - 'custom_object.filter.operator.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\FilterOperatorSubscriber::class, - 'arguments' => [ - 'mautic.custom.model.object', - ], - ], - 'custom_object.button.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\CustomObjectButtonSubscriber::class, - 'arguments' => [ - 'custom_object.permission.provider', - 'custom_object.route.provider', - 'custom_item.permission.provider', - 'custom_item.route.provider', - 'translator', - ], - ], 'custom_item.campaign.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\CampaignSubscriber::class, + 'class' => MauticPlugin\CustomObjectsBundle\EventListener\CampaignSubscriber::class, 'arguments' => [ 'mautic.custom.model.field', 'mautic.custom.model.object', @@ -809,33 +384,8 @@ 'database_connection', ], ], - 'custom_object.segments.filters_generate.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\SegmentFiltersChoicesGenerateSubscriber::class, - 'arguments'=> [ - 'custom_object.repository', - 'translator', - 'custom_object.config.provider', - 'custom_field.type.provider', - ], - ], - 'custom_object.segments.filters_dictionary.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\SegmentFiltersDictionarySubscriber::class, - 'arguments' => [ - 'doctrine', - 'custom_object.config.provider', - ], - ], - 'custom_object.dynamic_content.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\DynamicContentSubscriber::class, - 'arguments' => [ - 'custom_object.query.filter.factory', - 'custom_object.query.filter.helper', - 'custom_object.config.provider', - 'logger', - ], - ], 'custom_object.serializer.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\SerializerSubscriber::class, + 'class' => MauticPlugin\CustomObjectsBundle\EventListener\SerializerSubscriber::class, 'arguments' => [ 'custom_object.config.provider', 'custom_item.xref.contact.repository', @@ -844,173 +394,99 @@ ], 'tag' => 'jms_serializer.event_subscriber', 'tagArguments' => [ - 'event' => \JMS\Serializer\EventDispatcher\Events::POST_SERIALIZE, + 'event' => JMS\Serializer\EventDispatcher\Events::POST_SERIALIZE, ], ], 'custom_object.emailtoken.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\TokenSubscriber::class, + 'class' => MauticPlugin\CustomObjectsBundle\EventListener\TokenSubscriber::class, 'arguments' => [ 'custom_object.config.provider', 'custom_object.query.filter.helper', 'custom_object.query.filter.factory', 'mautic.custom.model.object', 'mautic.custom.model.item', + 'mautic.custom.model.field', 'custom_object.token.parser', 'mautic.campaign.model.event', 'event_dispatcher', 'custom_object.helper.token_formatter', - ], - ], - 'custom_object.segments.decorator_delegate.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\SegmentFilterDecoratorDelegateSubscriber::class, - 'arguments'=> [ - 'custom_object.segment_decorator_multiselect', - ], - ], - 'custom_object.tokens.list_format.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\CustomObjectListFormatSubscriber::class, - 'arguments' => [ - 'custom_object.helper.token_formatter', - ], - ], - 'custom_object.post_save.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\CustomObjectPostSaveSubscriber::class, - 'arguments' => [ - 'mautic.custom.model.object', - ], - ], - 'custom_object.pre_delete.subscriber' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\EventListener\CustomObjectPreDeleteSubscriber::class, - 'arguments' => [ - 'mautic.custom.model.object', - 'translator', + '%mautic.custom_item_fetch_limit_per_lead%', ], ], ], 'forms' => [ - 'custom_item.item.form' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Form\Type\CustomItemType::class, - ], - 'custom_field.field.form' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Form\Type\CustomFieldType::class, - 'arguments' => [ - 'custom_object.repository', - 'custom_field.type.provider', - 'custom_field.field.params.to.string.transformer', - 'custom_field.field.options.to.string.transformer', - 'custom_object.custom_field_factory', - ], - 'tag' => 'form.type', - ], 'custom_field.field.params.to.string.transformer' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Form\DataTransformer\ParamsToStringTransformer::class, + 'class' => MauticPlugin\CustomObjectsBundle\Form\DataTransformer\ParamsToStringTransformer::class, 'arguments' => [ 'jms_serializer', ], ], 'custom_field.field.options.to.string.transformer' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Form\DataTransformer\OptionsToStringTransformer::class, + 'class' => MauticPlugin\CustomObjectsBundle\Form\DataTransformer\OptionsToStringTransformer::class, 'arguments' => [ 'jms_serializer', 'mautic.custom.model.field', ], ], - 'custom_object.object.form' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Form\Type\CustomObjectType::class, - 'arguments' => [ - 'doctrine.orm.entity_manager', - 'custom_field.type.provider', - 'custom_object.repository', - ], - 'tag' => 'form.type', - ], - 'custom_field.field.value.form' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Form\Type\CustomFieldValueType::class, - ], - 'custom_item.campaign.link.form' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Form\Type\CampaignActionLinkType::class, - 'arguments' => [ - 'custom_item.route.provider', - 'translator', - ], - ], - 'custom_item.campaign.field.value.form' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Form\Type\CampaignConditionFieldValueType::class, - 'arguments' => [ - 'mautic.custom.model.field', - 'custom_item.route.provider', - 'translator', - ], - ], - ], - 'commands' => [ - 'custom_object.command.generate_sample_data' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Command\GenerateSampleDataCommand::class, - 'arguments' => [ - 'doctrine.orm.entity_manager', - 'custom_object.random.helper', - ], - 'tag' => 'console.command', - ], ], 'fieldTypes' => [ 'custom.field.type.country' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\CustomFieldType\CountryType::class, + 'class' => MauticPlugin\CustomObjectsBundle\CustomFieldType\CountryType::class, 'arguments' => ['translator', 'mautic.lead.provider.fillterOperator'], 'tag' => 'custom.field.type', ], 'custom.field.type.date' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\CustomFieldType\DateType::class, + 'class' => MauticPlugin\CustomObjectsBundle\CustomFieldType\DateType::class, 'arguments' => ['translator', 'mautic.lead.provider.fillterOperator'], 'tag' => 'custom.field.type', ], 'custom.field.type.datetime' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\CustomFieldType\DateTimeType::class, + 'class' => MauticPlugin\CustomObjectsBundle\CustomFieldType\DateTimeType::class, 'arguments' => ['translator', 'mautic.lead.provider.fillterOperator'], 'tag' => 'custom.field.type', ], 'custom.field.type.email' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\CustomFieldType\EmailType::class, + 'class' => MauticPlugin\CustomObjectsBundle\CustomFieldType\EmailType::class, 'arguments' => ['translator', 'mautic.lead.provider.fillterOperator'], 'tag' => 'custom.field.type', ], 'custom.field.type.hidden' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\CustomFieldType\HiddenType::class, + 'class' => MauticPlugin\CustomObjectsBundle\CustomFieldType\HiddenType::class, 'arguments' => ['translator', 'mautic.lead.provider.fillterOperator'], 'tag' => 'custom.field.type', ], 'custom.field.type.int' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\CustomFieldType\IntType::class, + 'class' => MauticPlugin\CustomObjectsBundle\CustomFieldType\IntType::class, 'arguments' => ['translator', 'mautic.lead.provider.fillterOperator'], 'tag' => 'custom.field.type', ], 'custom.field.type.phone' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\CustomFieldType\PhoneType::class, + 'class' => MauticPlugin\CustomObjectsBundle\CustomFieldType\PhoneType::class, 'arguments' => ['translator', 'mautic.lead.provider.fillterOperator'], 'tag' => 'custom.field.type', ], 'custom.field.type.select' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\CustomFieldType\SelectType::class, + 'class' => MauticPlugin\CustomObjectsBundle\CustomFieldType\SelectType::class, 'arguments' => ['translator', 'mautic.lead.provider.fillterOperator'], 'tag' => 'custom.field.type', ], 'custom.field.type.multiselect' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\CustomFieldType\MultiselectType::class, + 'class' => MauticPlugin\CustomObjectsBundle\CustomFieldType\MultiselectType::class, 'arguments' => ['translator', 'mautic.lead.provider.fillterOperator', 'custom_object.csv.helper'], 'tag' => 'custom.field.type', ], 'custom.field.type.text' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\CustomFieldType\TextType::class, + 'class' => MauticPlugin\CustomObjectsBundle\CustomFieldType\TextType::class, 'arguments' => ['translator', 'mautic.lead.provider.fillterOperator'], 'tag' => 'custom.field.type', ], 'custom.field.type.textarea' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\CustomFieldType\TextareaType::class, + 'class' => MauticPlugin\CustomObjectsBundle\CustomFieldType\TextareaType::class, 'arguments' => ['translator', 'mautic.lead.provider.fillterOperator'], 'tag' => 'custom.field.type', ], 'custom.field.type.url' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\CustomFieldType\UrlType::class, + 'class' => MauticPlugin\CustomObjectsBundle\CustomFieldType\UrlType::class, 'arguments' => ['translator', 'mautic.lead.provider.fillterOperator'], 'tag' => 'custom.field.type', ], @@ -1035,13 +511,13 @@ ], ], 'custom_field.type.provider' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Provider\CustomFieldTypeProvider::class, + 'class' => MauticPlugin\CustomObjectsBundle\Provider\CustomFieldTypeProvider::class, 'arguments' => [ 'event_dispatcher', ], ], 'custom_field.permission.provider' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Provider\CustomFieldPermissionProvider::class, + 'class' => MauticPlugin\CustomObjectsBundle\Provider\CustomFieldPermissionProvider::class, 'arguments' => [ 'mautic.security', ], @@ -1059,13 +535,13 @@ ], ], 'custom_item.permission.provider' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Provider\CustomItemPermissionProvider::class, + 'class' => MauticPlugin\CustomObjectsBundle\Provider\CustomItemPermissionProvider::class, 'arguments' => [ 'mautic.security', ], ], 'custom_object.session.provider_factory' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Provider\SessionProviderFactory::class, + 'class' => MauticPlugin\CustomObjectsBundle\Provider\SessionProviderFactory::class, 'arguments' => [ 'session', 'mautic.helper.core_parameters', @@ -1078,13 +554,13 @@ ], ], 'custom_object.permission.provider' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Provider\CustomObjectPermissionProvider::class, + 'class' => MauticPlugin\CustomObjectsBundle\Provider\CustomObjectPermissionProvider::class, 'arguments' => [ 'mautic.security', ], ], 'custom_object.lock_flash_message.helper' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Helper\LockFlashMessageHelper::class, + 'class' => MauticPlugin\CustomObjectsBundle\Helper\LockFlashMessageHelper::class, 'arguments' => [ 'mautic.helper.core_parameters', 'translator', @@ -1093,20 +569,20 @@ ], ], 'custom_object.csv.helper' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Helper\CsvHelper::class, + 'class' => MauticPlugin\CustomObjectsBundle\Helper\CsvHelper::class, ], 'custom_object.token.parser' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Helper\TokenParser::class, + 'class' => MauticPlugin\CustomObjectsBundle\Helper\TokenParser::class, ], 'custom_object.random.helper' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Helper\RandomHelper::class, + 'class' => MauticPlugin\CustomObjectsBundle\Helper\RandomHelper::class, ], 'custom_object.custom_field_factory' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Entity\CustomFieldFactory::class, + 'class' => MauticPlugin\CustomObjectsBundle\Entity\CustomFieldFactory::class, 'arguments' => ['custom_field.type.provider'], ], 'mautic.lead.query.builder.custom_field.value' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Segment\Query\Filter\CustomFieldFilterQueryBuilder::class, + 'class' => MauticPlugin\CustomObjectsBundle\Segment\Query\Filter\CustomFieldFilterQueryBuilder::class, 'arguments' => [ 'mautic.lead.model.random_parameter_name', 'event_dispatcher', @@ -1114,25 +590,33 @@ ], ], 'mautic.lead.query.builder.custom_item.value' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Segment\Query\Filter\CustomItemNameFilterQueryBuilder::class, + 'class' => MauticPlugin\CustomObjectsBundle\Segment\Query\Filter\CustomItemNameFilterQueryBuilder::class, 'arguments' => [ 'mautic.lead.model.random_parameter_name', 'custom_object.query.filter.helper', 'event_dispatcher', ], ], + 'mautic.lead.query.builder.custom_object.merged.value' => [ + 'class' => MauticPlugin\CustomObjectsBundle\Segment\Query\Filter\CustomObjectMergedFilterQueryBuilder::class, + 'arguments' => [ + 'mautic.lead.model.random_parameter_name', + 'event_dispatcher', + 'custom_object.query.filter.helper', + ], + ], 'custom_object.query.filter.factory' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Segment\Query\Filter\QueryFilterFactory::class, + 'class' => MauticPlugin\CustomObjectsBundle\Segment\Query\Filter\QueryFilterFactory::class, 'arguments' => [ 'mautic.lead.model.lead_segment_filter_factory', 'custom_object.query.filter.helper', ], ], 'query_filter_factory_calculator' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Helper\QueryFilterFactory\Calculator::class, + 'class' => MauticPlugin\CustomObjectsBundle\Helper\QueryFilterFactory\Calculator::class, ], 'query_filter_factory' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Helper\QueryFilterFactory::class, + 'class' => MauticPlugin\CustomObjectsBundle\Helper\QueryFilterFactory::class, 'arguments' => [ 'doctrine.orm.entity_manager', 'custom_field.type.provider', @@ -1142,37 +626,37 @@ ], ], 'custom_object.query.filter.helper' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Helper\QueryFilterHelper::class, + 'class' => MauticPlugin\CustomObjectsBundle\Helper\QueryFilterHelper::class, 'arguments' => [ 'doctrine.orm.entity_manager', 'query_filter_factory', + 'mautic.lead.model.random_parameter_name', ], ], 'custom_object.helper.token_formatter' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Helper\TokenFormatter::class, + 'class' => MauticPlugin\CustomObjectsBundle\Helper\TokenFormatter::class, ], - ], - 'validators' => [ - 'custom_object.allow.unique_identifier.validator' => [ - 'class' => \MauticPlugin\CustomObjectsBundle\Form\Validator\Constraints\AllowUniqueIdentifierValidator::class, + 'custom_object.data_persister.custom_item' => [ + 'class' => MauticPlugin\CustomObjectsBundle\DataPersister\CustomItemDataPersister::class, + 'tag' => 'api_platform.data_persister', 'arguments' => [ 'mautic.custom.model.item', - 'translator', ], - 'tag' => 'validator.constraint_validator', ], ], ], 'parameters' => [ - ConfigProvider::CONFIG_PARAM_ENABLED => true, - ConfigProvider::CONFIG_PARAM_ITEM_VALUE_TO_CONTACT_RELATION_LIMIT => 3, - 'custom_item_export_dir' => '%kernel.root_dir%/../media/files/temp', + ConfigProvider::CONFIG_PARAM_ENABLED => true, + ConfigProvider::CONFIG_PARAM_ITEM_VALUE_TO_CONTACT_RELATION_LIMIT => ConfigProvider::CONFIG_PARAM_ITEM_VALUE_TO_CONTACT_RELATION_DEFAULT_LIMIT, + 'custom_item_export_dir' => '%kernel.project_dir%/media/files/temp', + 'custom_object_merge_filter' => false, + 'custom_item_fetch_limit_per_lead' => 15, ], ]; if (interface_exists('ApiPlatform\\Core\\Api\\IriConverterInterface')) { $coParams['services']['other']['api_platform.custom_object.serializer.api_normalizer_jsonld'] = [ - 'class' => \MauticPlugin\CustomObjectsBundle\Serializer\ApiNormalizer::class, + 'class' => MauticPlugin\CustomObjectsBundle\Serializer\ApiNormalizer::class, 'decoratedService' => ['api_platform.jsonld.normalizer.item', 'api_platform.jsonld.normalizer.item.inner'], 'arguments' => [ 'api_platform.jsonld.normalizer.item.inner', @@ -1183,7 +667,7 @@ ], ]; $coParams['services']['other']['api_platform.custom_object.serializer.api_normalizer_json'] = [ - 'class' => \MauticPlugin\CustomObjectsBundle\Serializer\ApiNormalizer::class, + 'class' => MauticPlugin\CustomObjectsBundle\Serializer\ApiNormalizer::class, 'decoratedService' => ['api_platform.serializer.normalizer.item', 'api_platform.serializer.normalizer.item.inner'], 'arguments' => [ 'api_platform.serializer.normalizer.item.inner', @@ -1194,7 +678,7 @@ ], ]; $coParams['services']['other']['api_platform.custom_object.custom_item.extension'] = [ - 'class' => \MauticPlugin\CustomObjectsBundle\Extension\CustomItemListeningExtension::class, + 'class' => MauticPlugin\CustomObjectsBundle\Extension\CustomItemListeningExtension::class, 'arguments' => [ 'mautic.helper.user', 'mautic.security', diff --git a/Config/services.php b/Config/services.php new file mode 100644 index 000000000..2f7e94f21 --- /dev/null +++ b/Config/services.php @@ -0,0 +1,26 @@ +services() + ->defaults() + ->autowire() + ->autoconfigure() + ->public(); + + $excludes = [ + 'Provider/SessionProvider.php', + 'Report/ReportColumnsBuilder.php', + 'Serializer/ApiNormalizer.php', + 'Extension/CustomItemListeningExtension.php', + ]; + + $services->load('MauticPlugin\\CustomObjectsBundle\\', '../') + ->exclude('../{'.implode(',', array_merge(MauticCoreExtension::DEFAULT_EXCLUDES, $excludes)).'}'); + + $services->load('MauticPlugin\\CustomObjectsBundle\\Repository\\', '../Repository/*Repository.php'); +}; diff --git a/Controller/CustomField/FormController.php b/Controller/CustomField/FormController.php index a2342f093..cc2e8a2cd 100644 --- a/Controller/CustomField/FormController.php +++ b/Controller/CustomField/FormController.php @@ -15,67 +15,21 @@ use MauticPlugin\CustomObjectsBundle\Provider\CustomFieldPermissionProvider; use MauticPlugin\CustomObjectsBundle\Provider\CustomFieldRouteProvider; use MauticPlugin\CustomObjectsBundle\Provider\CustomObjectRouteProvider; -use Symfony\Component\Form\FormFactory; -use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\HttpFoundation\Response; class FormController extends CommonController { - /** - * @var FormFactory - */ - private $formFactory; - - /** - * @var CustomFieldModel - */ - private $customFieldModel; - - /** - * @var CustomFieldPermissionProvider - */ - private $permissionProvider; - - /** - * @var CustomFieldRouteProvider - */ - private $fieldRouteProvider; - - /** - * @var CustomFieldFactory - */ - private $customFieldFactory; - - /** - * @var CustomObjectModel - */ - private $customObjectModel; - - /** - * @var CustomObjectRouteProvider - */ - private $objectRouteProvider; - - public function __construct( - FormFactory $formFactory, + public function renderFormAction( + FormFactoryInterface $formFactory, CustomFieldModel $customFieldModel, CustomFieldFactory $customFieldFactory, CustomFieldPermissionProvider $permissionProvider, CustomFieldRouteProvider $fieldRouteProvider, CustomObjectModel $customObjectModel, CustomObjectRouteProvider $objectRouteProvider - ) { - $this->formFactory = $formFactory; - $this->customFieldModel = $customFieldModel; - $this->customFieldFactory = $customFieldFactory; - $this->permissionProvider = $permissionProvider; - $this->fieldRouteProvider = $fieldRouteProvider; - $this->customObjectModel = $customObjectModel; - $this->objectRouteProvider = $objectRouteProvider; - } - - public function renderFormAction(Request $request): Response - { + ): Response { + $request = $this->getCurrentRequest(); $objectId = (int) $request->get('objectId'); $fieldId = (int) $request->get('fieldId'); $fieldType = $request->get('fieldType'); @@ -83,18 +37,18 @@ public function renderFormAction(Request $request): Response $panelCount = is_numeric($request->get('panelCount')) ? (int) $request->get('panelCount') : null; if ($objectId) { - $customObject = $this->customObjectModel->fetchEntity($objectId); + $customObject = $customObjectModel->fetchEntity($objectId); } else { $customObject = new CustomObject(); } try { if ($fieldId) { - $customField = $this->customFieldModel->fetchEntity($fieldId); - $this->permissionProvider->canEdit($customField); + $customField = $customFieldModel->fetchEntity($fieldId); + $permissionProvider->canEdit($customField); } else { - $this->permissionProvider->canCreate(); - $customField = $this->customFieldFactory->create($fieldType, $customObject); + $permissionProvider->canCreate(); + $customField = $customFieldFactory->create($fieldType, $customObject); } } catch (NotFoundException $e) { return $this->notFound($e->getMessage()); @@ -102,19 +56,19 @@ public function renderFormAction(Request $request): Response return $this->accessDenied(false, $e->getMessage()); } - $route = $this->fieldRouteProvider->buildFormRoute($customField->getId()); - $action = $this->fieldRouteProvider->buildSaveRoute($fieldType, $fieldId, $customObject->getId(), $panelCount, $panelId); - $form = $this->formFactory->create(CustomFieldType::class, $customField, ['action' => $action]); + $route = $fieldRouteProvider->buildFormRoute($customField->getId()); + $action = $fieldRouteProvider->buildSaveRoute($fieldType, $fieldId, $customObject->getId(), $panelCount, $panelId); + $form = $formFactory->create(CustomFieldType::class, $customField, ['action' => $action]); return $this->delegateView( [ - 'returnUrl' => $this->objectRouteProvider->buildEditRoute($customObject->getId()), + 'returnUrl' => $objectRouteProvider->buildEditRoute($customObject->getId()), 'viewParameters' => [ 'customObject' => $customObject, 'customField' => $customField, 'form' => $form->createView(), ], - 'contentTemplate' => 'CustomObjectsBundle:CustomField:form.html.php', + 'contentTemplate' => '@CustomObjects/CustomField/form.html.twig', 'passthroughVars' => [ 'mauticContent' => 'customField', 'route' => $route, diff --git a/Controller/CustomField/SaveController.php b/Controller/CustomField/SaveController.php index 7aff22a2f..7d91b2790 100644 --- a/Controller/CustomField/SaveController.php +++ b/Controller/CustomField/SaveController.php @@ -17,11 +17,10 @@ use MauticPlugin\CustomObjectsBundle\Model\CustomObjectModel; use MauticPlugin\CustomObjectsBundle\Provider\CustomFieldPermissionProvider; use MauticPlugin\CustomObjectsBundle\Provider\CustomFieldRouteProvider; -use Symfony\Component\Form\FormFactory; +use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Translation\TranslatorInterface; /** * This controller is not used for saving to database, it is used only to generate forms and data validation. @@ -32,60 +31,20 @@ class SaveController extends CommonController { /** - * @var FormFactory - */ - private $formFactory; - - /** - * @var CustomFieldModel - */ - private $customFieldModel; - - /** - * @var CustomFieldFactory - */ - private $customFieldFactory; - - /** - * @var CustomFieldPermissionProvider - */ - private $permissionProvider; - - /** - * @var CustomFieldRouteProvider - */ - private $fieldRouteProvider; - - /** - * @var CustomObjectModel + * Not save but validate Custom Field data and return proper response. Check class description. + * + * @return Response|JsonResponse */ - private $customObjectModel; - - public function __construct( - FormFactory $formFactory, - TranslatorInterface $translator, + public function saveAction( + FormFactoryInterface $formFactory, CustomFieldModel $customFieldModel, CustomFieldFactory $customFieldFactory, CustomFieldPermissionProvider $permissionProvider, CustomFieldRouteProvider $fieldRouteProvider, CustomObjectModel $customObjectModel ) { - $this->formFactory = $formFactory; - $this->translator = $translator; - $this->customFieldModel = $customFieldModel; - $this->customFieldFactory = $customFieldFactory; - $this->permissionProvider = $permissionProvider; - $this->fieldRouteProvider = $fieldRouteProvider; - $this->customObjectModel = $customObjectModel; - } + $request = $this->getCurrentRequest(); - /** - * Not save but validate Custom Field data and return proper response. Check class description. - * - * @return Response|JsonResponse - */ - public function saveAction(Request $request) - { $objectId = (int) $request->get('objectId'); $fieldId = (int) $request->query->get('fieldId'); $fieldType = $request->get('fieldType'); @@ -93,18 +52,18 @@ public function saveAction(Request $request) $panelCount = is_numeric($request->get('panelCount')) ? (int) $request->get('panelCount') : null; if ($objectId) { - $customObject = $this->customObjectModel->fetchEntity($objectId); + $customObject = $customObjectModel->fetchEntity($objectId); } else { $customObject = new CustomObject(); } try { if ($fieldId) { - $customField = $this->customFieldModel->fetchEntity($fieldId); - $this->permissionProvider->canEdit($customField); + $customField = $customFieldModel->fetchEntity($fieldId); + $permissionProvider->canEdit($customField); } else { - $this->permissionProvider->canCreate(); - $customField = $this->customFieldFactory->create($fieldType, $customObject); + $permissionProvider->canCreate(); + $customField = $customFieldFactory->create($fieldType, $customObject); } } catch (NotFoundException $e) { return $this->notFound($e->getMessage()); @@ -114,17 +73,17 @@ public function saveAction(Request $request) $this->recreateOptionsFromPost($request->get('custom_field'), $customField); - $action = $this->fieldRouteProvider->buildSaveRoute($fieldType, $fieldId, $customObject->getId(), $panelCount, $panelId); - $form = $this->formFactory->create(CustomFieldType::class, $customField, ['action' => $action]); + $action = $fieldRouteProvider->buildSaveRoute($fieldType, $fieldId, $customObject->getId(), $panelCount, $panelId); + $form = $formFactory->create(CustomFieldType::class, $customField, ['action' => $action]); $form->handleRequest($request); if ($form->isValid()) { // Render Custom Field form RAT for Custom Object form. - return $this->buildSuccessForm($customObject, $form->getData(), $request); + return $this->buildSuccessForm($customObject, $form->getData(), $request, $customFieldModel, $formFactory); } - $route = $fieldId ? $this->fieldRouteProvider->buildFormRoute($fieldId) : ''; + $route = $fieldId ? $fieldRouteProvider->buildFormRoute($fieldId) : ''; // Render Custom Field form for modal. return $this->delegateView( @@ -134,7 +93,7 @@ public function saveAction(Request $request) 'customField' => $customField, 'form' => $form->createView(), ], - 'contentTemplate' => 'CustomObjectsBundle:CustomField:form.html.php', + 'contentTemplate' => '@CustomObjects/CustomField/form.html.twig', 'passthroughVars' => [ 'mauticContent' => 'customField', 'route' => $route, @@ -147,8 +106,13 @@ public function saveAction(Request $request) /** * Here is CO form panel part build and injected in the frontend as part of existing CO form. */ - private function buildSuccessForm(CustomObject $customObject, CustomField $customField, Request $request): JsonResponse - { + private function buildSuccessForm( + CustomObject $customObject, + CustomField $customField, + Request $request, + CustomFieldModel $customFieldModel, + FormFactoryInterface $formFactory + ): JsonResponse { $panelId = is_numeric($request->get('panelId')) ? (int) $request->get('panelId') : null; // Is edit of existing panel in view if (null === $panelId) { @@ -167,18 +131,18 @@ private function buildSuccessForm(CustomObject $customObject, CustomField $custo $option->setCustomField($customField); } - $this->customFieldModel->setAlias($customField); + $customFieldModel->setAlias($customField); $customFields = new ArrayCollection([$customField]); $customObject->setCustomFields($customFields); - $form = $this->formFactory->create( + $form = $formFactory->create( CustomObjectType::class, $customObject ); $template = $this->render( - 'CustomObjectsBundle:CustomObject:_form-fields.html.php', + '@CustomObjects/CustomObject/_form-fields.html.twig', [ 'form' => $form->createView(), 'panelId' => $panelId, // Panel id to me replaced if edit @@ -212,7 +176,7 @@ private function buildSuccessForm(CustomObject $customObject, CustomField $custo * * @see \Symfony\Component\Form\Exception\TransformationFailedException * - * @param string[] $customFieldPost + * @param mixed[] $customFieldPost */ private function recreateOptionsFromPost(array $customFieldPost, CustomField $customField): void { diff --git a/Controller/CustomItem/BatchDeleteController.php b/Controller/CustomItem/BatchDeleteController.php index aacfc6306..f4b41e0ca 100644 --- a/Controller/CustomItem/BatchDeleteController.php +++ b/Controller/CustomItem/BatchDeleteController.php @@ -12,88 +12,48 @@ use MauticPlugin\CustomObjectsBundle\Provider\CustomItemPermissionProvider; use MauticPlugin\CustomObjectsBundle\Provider\CustomItemRouteProvider; use MauticPlugin\CustomObjectsBundle\Provider\SessionProviderFactory; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; class BatchDeleteController extends CommonController { - /** - * @var RequestStack - */ - private $requestStack; - - /** - * @var CustomItemModel - */ - private $customItemModel; - - /** - * @var SessionProviderFactory - */ - private $sessionProviderFactory; - - /** - * @var CustomItemPermissionProvider - */ - private $permissionProvider; - - /** - * @var CustomItemRouteProvider - */ - private $routeProvider; - - /** - * @var FlashBag - */ - private $flashBag; - - public function __construct( - RequestStack $requestStack, + public function deleteAction( CustomItemModel $customItemModel, SessionProviderFactory $sessionProviderFactory, CustomItemPermissionProvider $permissionProvider, CustomItemRouteProvider $routeProvider, - FlashBag $flashBag - ) { - $this->requestStack = $requestStack; - $this->customItemModel = $customItemModel; - $this->sessionProviderFactory = $sessionProviderFactory; - $this->permissionProvider = $permissionProvider; - $this->routeProvider = $routeProvider; - $this->flashBag = $flashBag; - } + FlashBag $flashBag, + int $objectId + ): Response { + $request = $this->getCurrentRequest(); - public function deleteAction(int $objectId): Response - { - $request = $this->requestStack->getCurrentRequest(); $itemIds = json_decode($request->get('ids', '[]'), true); - $page = $this->sessionProviderFactory->createItemProvider($objectId)->getPage(); + $page = $sessionProviderFactory->createItemProvider($objectId)->getPage(); $notFound = []; $denied = []; $deleted = []; foreach ($itemIds as $itemId) { try { - $customItem = $this->customItemModel->fetchEntity((int) $itemId); - $this->permissionProvider->canDelete($customItem); - $this->customItemModel->delete($customItem); + $customItem = $customItemModel->fetchEntity((int) $itemId); + $permissionProvider->canDelete($customItem); + $customItemModel->delete($customItem); $deleted[] = $itemId; - } catch (NotFoundException $e) { + } catch (NotFoundException) { $notFound[] = $itemId; - } catch (ForbiddenException $e) { + } catch (ForbiddenException) { $denied[] = $itemId; } } if ($deleted) { - $this->flashBag->add( + $flashBag->add( 'mautic.core.notice.batch_deleted', ['%count%' => count($deleted)] ); } if ($notFound) { - $this->flashBag->add( + $flashBag->add( 'custom.item.error.items.not.found', ['%ids%' => implode(',', $notFound)], FlashBag::LEVEL_ERROR @@ -101,7 +61,7 @@ public function deleteAction(int $objectId): Response } if ($denied) { - $this->flashBag->add( + $flashBag->add( 'custom.item.error.items.denied', ['%ids%' => implode(',', $denied)], FlashBag::LEVEL_ERROR @@ -110,9 +70,9 @@ public function deleteAction(int $objectId): Response return $this->postActionRedirect( [ - 'returnUrl' => $this->routeProvider->buildListRoute($objectId, $page), + 'returnUrl' => $routeProvider->buildListRoute($objectId, $page), 'viewParameters' => ['objectId' => $objectId, 'page' => $page], - 'contentTemplate' => 'CustomObjectsBundle:CustomItem\List:list', + 'contentTemplate' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\ListController::listAction', 'passthroughVars' => [ 'mauticContent' => 'customItem', ], diff --git a/Controller/CustomItem/CancelController.php b/Controller/CustomItem/CancelController.php index 7179f1f07..49e211e38 100644 --- a/Controller/CustomItem/CancelController.php +++ b/Controller/CustomItem/CancelController.php @@ -14,47 +14,27 @@ class CancelController extends CommonController { /** - * @var SessionProviderFactory - */ - private $sessionProviderFactory; - - /** - * @var CustomItemRouteProvider - */ - private $routeProvider; - - /** - * @var CustomItemModel + * @throws NotFoundException */ - private $customItemModel; - - public function __construct( + public function cancelAction( SessionProviderFactory $sessionProviderFactory, CustomItemRouteProvider $routeProvider, - CustomItemModel $customItemModel - ) { - $this->sessionProviderFactory = $sessionProviderFactory; - $this->routeProvider = $routeProvider; - $this->customItemModel = $customItemModel; - } - - /** - * @throws NotFoundException - */ - public function cancelAction(int $objectId, ?int $itemId = null): Response - { - $page = $this->sessionProviderFactory->createItemProvider($objectId)->getPage(); + CustomItemModel $customItemModel, + int $objectId, + ?int $itemId = null + ): Response { + $page = $sessionProviderFactory->createItemProvider($objectId)->getPage(); if ($itemId) { - $customItem = $this->customItemModel->fetchEntity($itemId); - $this->customItemModel->unlockEntity($customItem); + $customItem = $customItemModel->fetchEntity($itemId); + $customItemModel->unlockEntity($customItem); } return $this->postActionRedirect( [ - 'returnUrl' => $this->routeProvider->buildListRoute($objectId, $page), + 'returnUrl' => $routeProvider->buildListRoute($objectId, $page), 'viewParameters' => ['objectId' => $objectId, 'page' => $page], - 'contentTemplate' => 'CustomObjectsBundle:CustomItem\List:list', + 'contentTemplate' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\ListController::listAction', 'passthroughVars' => [ 'mauticContent' => 'customItem', ], diff --git a/Controller/CustomItem/ContactListController.php b/Controller/CustomItem/ContactListController.php index cc6a4edf3..a1af5def4 100644 --- a/Controller/CustomItem/ContactListController.php +++ b/Controller/CustomItem/ContactListController.php @@ -5,7 +5,9 @@ namespace MauticPlugin\CustomObjectsBundle\Controller\CustomItem; use Mautic\CoreBundle\Controller\CommonController; +use Mautic\CoreBundle\Factory\PageHelperFactoryInterface; use Mautic\LeadBundle\Controller\EntityContactsTrait; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; class ContactListController extends CommonController @@ -15,9 +17,15 @@ class ContactListController extends CommonController /** * @codeCoverageIgnore as this just calls a Mautic core method */ - public function listAction(int $objectId, int $page = 1): Response - { + public function listAction( + Request $request, + PageHelperFactoryInterface $pageHelperFactory, + int $objectId, + int $page = 1 + ): Response { return $this->generateContactsGrid( + $request, + $pageHelperFactory, $objectId, $page, 'lead:lists:viewother', diff --git a/Controller/CustomItem/DeleteController.php b/Controller/CustomItem/DeleteController.php index cb9e4c578..651f86abf 100644 --- a/Controller/CustomItem/DeleteController.php +++ b/Controller/CustomItem/DeleteController.php @@ -16,59 +16,27 @@ class DeleteController extends CommonController { - /** - * @var CustomItemModel - */ - private $customItemModel; - - /** - * @var SessionProviderFactory - */ - private $sessionProviderFactory; - - /** - * @var CustomItemPermissionProvider - */ - private $permissionProvider; - - /** - * @var CustomItemRouteProvider - */ - private $routeProvider; - - /** - * @var FlashBag - */ - private $flashBag; - - public function __construct( + public function deleteAction( CustomItemModel $customItemModel, SessionProviderFactory $sessionProviderFactory, FlashBag $flashBag, CustomItemPermissionProvider $permissionProvider, - CustomItemRouteProvider $routeProvider - ) { - $this->customItemModel = $customItemModel; - $this->sessionProviderFactory = $sessionProviderFactory; - $this->flashBag = $flashBag; - $this->permissionProvider = $permissionProvider; - $this->routeProvider = $routeProvider; - } - - public function deleteAction(int $objectId, int $itemId): Response - { + CustomItemRouteProvider $routeProvider, + int $objectId, + int $itemId + ): Response { try { - $customItem = $this->customItemModel->fetchEntity($itemId); - $this->permissionProvider->canDelete($customItem); + $customItem = $customItemModel->fetchEntity($itemId); + $permissionProvider->canDelete($customItem); } catch (NotFoundException $e) { return $this->notFound($e->getMessage()); } catch (ForbiddenException $e) { return $this->accessDenied(false, $e->getMessage()); } - $this->customItemModel->delete($customItem); + $customItemModel->delete($customItem); - $this->flashBag->add( + $flashBag->add( 'mautic.core.notice.deleted', [ '%name%' => $customItem->getName(), @@ -76,14 +44,13 @@ public function deleteAction(int $objectId, int $itemId): Response ] ); - $page = $this->sessionProviderFactory->createItemProvider($objectId) - ->getPage(); + $page = $sessionProviderFactory->createItemProvider($objectId)->getPage(); return $this->postActionRedirect( [ - 'returnUrl' => $this->routeProvider->buildListRoute($objectId, $page), + 'returnUrl' => $routeProvider->buildListRoute($objectId, $page), 'viewParameters' => ['objectId' => $objectId, 'page' => $page], - 'contentTemplate' => 'CustomObjectsBundle:CustomItem\List:list', + 'contentTemplate' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\ListController::listAction', 'passthroughVars' => [ 'mauticContent' => 'customItem', ], diff --git a/Controller/CustomItem/ExportController.php b/Controller/CustomItem/ExportController.php index 52a9c1979..0f9a1b05e 100644 --- a/Controller/CustomItem/ExportController.php +++ b/Controller/CustomItem/ExportController.php @@ -4,60 +4,54 @@ namespace MauticPlugin\CustomObjectsBundle\Controller\CustomItem; +use Doctrine\ORM\OptimisticLockException; +use Doctrine\ORM\ORMException; use Mautic\CoreBundle\Controller\AbstractFormController; use MauticPlugin\CustomObjectsBundle\CustomItemEvents; use MauticPlugin\CustomObjectsBundle\Event\CustomItemExportSchedulerEvent; +use MauticPlugin\CustomObjectsBundle\Exception\ForbiddenException; use MauticPlugin\CustomObjectsBundle\Model\CustomItemExportSchedulerModel; use MauticPlugin\CustomObjectsBundle\Provider\CustomItemPermissionProvider; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; class ExportController extends AbstractFormController { - private CustomItemPermissionProvider $permissionProvider; - - private CustomItemExportSchedulerModel $model; - - public function __construct( - CustomItemPermissionProvider $permissionProvider, - CustomItemExportSchedulerModel $model - ) { - $this->permissionProvider = $permissionProvider; - $this->model = $model; - } - /** - * @throws \Doctrine\ORM\ORMException - * @throws \Doctrine\ORM\OptimisticLockException - * @throws \MauticPlugin\CustomObjectsBundle\Exception\ForbiddenException + * @throws ORMException + * @throws OptimisticLockException + * @throws ForbiddenException */ - public function exportAction(int $object): Response - { - $this->permissionProvider->canCreate($object); + public function exportAction( + CustomItemPermissionProvider $permissionProvider, + CustomItemExportSchedulerModel $model, + int $object + ): Response { + $permissionProvider->canCreate($object); - $customItemExportScheduler = $this->model->saveEntity($object); + $customItemExportScheduler = $model->saveEntity($object); - /** @var EventDispatcherInterface $dispatcher */ - $dispatcher = $this->get('event_dispatcher'); - $dispatcher->dispatch( - CustomItemEvents::ON_CUSTOM_ITEM_SCHEDULE_EXPORT, - new CustomItemExportSchedulerEvent($customItemExportScheduler) + $this->dispatcher->dispatch( + new CustomItemExportSchedulerEvent($customItemExportScheduler), + CustomItemEvents::ON_CUSTOM_ITEM_SCHEDULE_EXPORT ); - $this->addFlash('custom.item.export.being.prepared', ['%user_email%' => $this->user->getEmail()]); + $this->addFlashMessage( + 'custom.item.export.being.prepared', + ['%user_email%' => $this->user->getEmail()] + ); $response['message'] = 'Custom Item export scheduled.'; $response['flashes'] = $this->getFlashContent(); return new JsonResponse($response); } - public function downloadExportAction(string $fileName): Response + public function downloadExportAction(CustomItemExportSchedulerModel $model, string $fileName): Response { try { - return $this->model->getExportFileToDownload($fileName); - } catch (FileNotFoundException $exception) { + return $model->getExportFileToDownload($fileName); + } catch (FileNotFoundException) { return $this->notFound(); } } diff --git a/Controller/CustomItem/FormController.php b/Controller/CustomItem/FormController.php index 5be8c013e..74873f61b 100644 --- a/Controller/CustomItem/FormController.php +++ b/Controller/CustomItem/FormController.php @@ -14,171 +14,177 @@ use MauticPlugin\CustomObjectsBundle\Model\CustomObjectModel; use MauticPlugin\CustomObjectsBundle\Provider\CustomItemPermissionProvider; use MauticPlugin\CustomObjectsBundle\Provider\CustomItemRouteProvider; -use Symfony\Component\Form\FormFactory; +use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\HttpFoundation\Response; class FormController extends AbstractFormController { - /** - * @var FormFactory - */ - private $formFactory; - - /** - * @var CustomItemModel - */ - private $customItemModel; - - /** - * @var CustomObjectModel - */ - private $customObjectModel; - - /** - * @var CustomItemPermissionProvider - */ - private $permissionProvider; - - /** - * @var CustomItemRouteProvider - */ - private $routeProvider; - - /** - * @var LockFlashMessageHelper - */ - private $lockFlashMessageHelper; - - public function __construct( - FormFactory $formFactory, - CustomObjectModel $customObjectModel, + public function newAction( + FormFactoryInterface $formFactory, + CustomItemRouteProvider $routeProvider, CustomItemModel $customItemModel, + CustomObjectModel $customObjectModel, CustomItemPermissionProvider $permissionProvider, - CustomItemRouteProvider $routeProvider, - LockFlashMessageHelper $lockFlashMessageHelper - ) { - $this->formFactory = $formFactory; - $this->customObjectModel = $customObjectModel; - $this->customItemModel = $customItemModel; - $this->permissionProvider = $permissionProvider; - $this->routeProvider = $routeProvider; - $this->lockFlashMessageHelper = $lockFlashMessageHelper; - } - - public function newAction(int $objectId): Response - { + int $objectId + ): Response { try { - $customItem = $this->performNewAction($objectId); + $customItem = $this->performNewAction($customObjectModel, $customItemModel, $permissionProvider, $objectId); } catch (ForbiddenException $e) { return $this->accessDenied(false, $e->getMessage()); } - return $this->renderFormForItem($customItem, $this->routeProvider->buildNewRoute($objectId)); + return $this->renderFormForItem( + $formFactory, + $routeProvider, + $customItem, + $routeProvider->buildNewRoute($objectId) + ); } - public function newWithRedirectToContactAction(int $objectId, int $contactId): Response - { + public function newWithRedirectToContactAction( + FormFactoryInterface $formFactory, + CustomItemRouteProvider $routeProvider, + CustomItemModel $customItemModel, + CustomObjectModel $customObjectModel, + CustomItemPermissionProvider $permissionProvider, + int $objectId, + int $contactId + ): Response { try { - $customItem = $this->performNewAction($objectId); + $customItem = $this->performNewAction($customObjectModel, $customItemModel, $permissionProvider, $objectId); } catch (ForbiddenException $e) { return $this->accessDenied(false, $e->getMessage()); } if ($customItem->getCustomObject()->getRelationshipObject()) { $customItem->setChildCustomItem( - $this->customItemModel->populateCustomFields( + $customItemModel->populateCustomFields( new CustomItem($customItem->getCustomObject()->getRelationshipObject()) ) ); } - return $this->renderFormForItem($customItem, $this->routeProvider->buildNewRouteWithRedirectToContact($objectId, $contactId), $contactId); + return $this->renderFormForItem( + $formFactory, + $routeProvider, + $customItem, + $routeProvider->buildNewRouteWithRedirectToContact($objectId, $contactId), + $contactId + ); } - private function performNewAction(int $objectId): CustomItem - { - $this->permissionProvider->canCreate($objectId); + private function performNewAction( + CustomObjectModel $customObjectModel, + CustomItemModel $customItemModel, + CustomItemPermissionProvider $permissionProvider, + int $objectId + ): CustomItem { + $permissionProvider->canCreate($objectId); - return $this->customItemModel->populateCustomFields( + return $customItemModel->populateCustomFields( new CustomItem( - $this->customObjectModel->fetchEntity($objectId) + $customObjectModel->fetchEntity($objectId) ) ); } - public function editAction(int $objectId, int $itemId): Response - { + public function editAction( + FormFactoryInterface $formFactory, + CustomItemRouteProvider $routeProvider, + CustomItemModel $customItemModel, + LockFlashMessageHelper $lockFlashMessageHelper, + CustomItemPermissionProvider $permissionProvider, + int $objectId, + int $itemId + ): Response { try { - $customItem = $this->performEditAction($itemId); + $customItem = $this->performEditAction($customItemModel, $permissionProvider, $itemId); } catch (NotFoundException $e) { return $this->notFound($e->getMessage()); } catch (ForbiddenException $e) { return $this->accessDenied(false, $e->getMessage()); } - if ($this->customItemModel->isLocked($customItem)) { - $this->lockFlashMessageHelper->addFlash( + if ($customItemModel->isLocked($customItem)) { + $lockFlashMessageHelper->addFlash( $customItem, - $this->routeProvider->buildEditRoute($objectId, $itemId), + $routeProvider->buildEditRoute($objectId, $itemId), $this->canEdit($customItem), 'custom.item' ); - return $this->redirect($this->routeProvider->buildViewRoute($objectId, $itemId)); + return $this->redirect($routeProvider->buildViewRoute($objectId, $itemId)); } - $this->customItemModel->lockEntity($customItem); + $customItemModel->lockEntity($customItem); - return $this->renderFormForItem($customItem, $this->routeProvider->buildEditRoute($objectId, $itemId)); + return $this->renderFormForItem( + $formFactory, + $routeProvider, + $customItem, + $routeProvider->buildEditRoute($objectId, $itemId) + ); } - public function editWithRedirectToContactAction(int $objectId, int $itemId, int $contactId): Response - { + public function editWithRedirectToContactAction( + FormFactoryInterface $formFactory, + CustomItemRouteProvider $routeProvider, + CustomItemModel $customItemModel, + LockFlashMessageHelper $lockFlashMessageHelper, + CustomItemPermissionProvider $permissionProvider, + int $objectId, + int $itemId, + int $contactId + ): Response { try { - $customItem = $this->performEditAction($itemId); + $customItem = $this->performEditAction($customItemModel, $permissionProvider, $itemId); } catch (NotFoundException $e) { return $this->notFound($e->getMessage()); } catch (ForbiddenException $e) { return $this->accessDenied(false, $e->getMessage()); } - if ($this->customItemModel->isLocked($customItem)) { - $this->lockFlashMessageHelper->addFlash( + if ($customItemModel->isLocked($customItem)) { + $lockFlashMessageHelper->addFlash( $customItem, - $this->routeProvider->buildEditRouteWithRedirectToContact($objectId, $itemId, $contactId), + $routeProvider->buildEditRouteWithRedirectToContact($objectId, $itemId, $contactId), $this->canEdit($customItem), 'custom.item' ); - return $this->redirect($this->routeProvider->buildViewRoute($objectId, $itemId)); + return $this->redirect($routeProvider->buildViewRoute($objectId, $itemId)); } if ($customItem->getCustomObject()->getRelationshipObject()) { $customItem->setChildCustomItem( - $this->customItemModel->populateCustomFields( + $customItemModel->populateCustomFields( $customItem->findChildCustomItem() ) ); } - $this->customItemModel->lockEntity($customItem); - - return $this->renderFormForItem($customItem, $this->routeProvider->buildEditRouteWithRedirectToContact($objectId, $itemId, $contactId), $contactId); - } - - private function performEditAction(int $itemId): CustomItem - { - $customItem = $this->customItemModel->fetchEntity($itemId); - $this->permissionProvider->canEdit($customItem); + $customItemModel->lockEntity($customItem); - return $customItem; + return $this->renderFormForItem( + $formFactory, + $routeProvider, + $customItem, + $routeProvider->buildEditRouteWithRedirectToContact($objectId, $itemId, $contactId), + $contactId + ); } - public function cloneAction(int $objectId, int $itemId): Response - { + public function cloneAction( + FormFactoryInterface $formFactory, + CustomItemRouteProvider $routeProvider, + CustomItemModel $customItemModel, + CustomItemPermissionProvider $permissionProvider, + int $objectId, + int $itemId + ): Response { try { - $customItem = clone $this->customItemModel->fetchEntity($itemId); - $this->permissionProvider->canClone($customItem); + $customItem = clone $customItemModel->fetchEntity($itemId); + $permissionProvider->canClone($customItem); } catch (NotFoundException $e) { return $this->notFound($e->getMessage()); } catch (ForbiddenException $e) { @@ -187,20 +193,41 @@ public function cloneAction(int $objectId, int $itemId): Response $customItem->setName($customItem->getName().' '.$this->translator->trans('mautic.core.form.clone')); - return $this->renderFormForItem($customItem, $this->routeProvider->buildCloneRoute($objectId, $itemId)); + return $this->renderFormForItem( + $formFactory, + $routeProvider, + $customItem, + $routeProvider->buildCloneRoute($objectId, $itemId) + ); + } + + private function performEditAction( + CustomItemModel $customItemModel, + CustomItemPermissionProvider $permissionProvider, + int $itemId + ): CustomItem { + $customItem = $customItemModel->fetchEntity($itemId); + $permissionProvider->canEdit($customItem); + + return $customItem; } - private function renderFormForItem(CustomItem $customItem, string $route, ?int $contactId = null): Response - { - $action = $this->routeProvider->buildSaveRoute($customItem->getCustomObject()->getId(), $customItem->getId()); + private function renderFormForItem( + FormFactoryInterface $formFactory, + CustomItemRouteProvider $routeProvider, + CustomItem $customItem, + string $route, + ?int $contactId = null + ): Response { + $action = $routeProvider->buildSaveRoute($customItem->getCustomObject()->getId(), $customItem->getId()); $options = [ 'action' => $action, 'objectId' => $customItem->getCustomObject()->getId(), 'contactId' => $contactId, - 'cancelUrl' => 0 < $contactId ? $this->routeProvider->buildContactViewRoute($contactId) : null, + 'cancelUrl' => 0 < $contactId ? $routeProvider->buildContactViewRoute($contactId) : null, ]; - $form = $this->formFactory->create( + $form = $formFactory->create( CustomItemType::class, $customItem, $options @@ -208,13 +235,13 @@ private function renderFormForItem(CustomItem $customItem, string $route, ?int $ return $this->delegateView( [ - 'returnUrl' => $this->routeProvider->buildListRoute($customItem->getCustomObject()->getId()), + 'returnUrl' => $routeProvider->buildListRoute($customItem->getCustomObject()->getId()), 'viewParameters' => [ 'entity' => $customItem, 'customObject' => $customItem->getCustomObject(), 'form' => $form->createView(), ], - 'contentTemplate' => 'CustomObjectsBundle:CustomItem:form.html.php', + 'contentTemplate' => '@CustomObjects/CustomItem/form.html.twig', 'passthroughVars' => [ 'mauticContent' => 'customItem', 'route' => $route, diff --git a/Controller/CustomItem/LinkController.php b/Controller/CustomItem/LinkController.php index fcf3192b9..6b4e33607 100644 --- a/Controller/CustomItem/LinkController.php +++ b/Controller/CustomItem/LinkController.php @@ -12,56 +12,36 @@ use MauticPlugin\CustomObjectsBundle\Model\CustomItemModel; use MauticPlugin\CustomObjectsBundle\Provider\CustomItemPermissionProvider; use Symfony\Component\HttpFoundation\JsonResponse; -use UnexpectedValueException; class LinkController extends JsonController { - /** - * @var CustomItemModel - */ - private $customItemModel; - - /** - * @var CustomItemPermissionProvider - */ - private $permissionProvider; - - /** - * @var FlashBag - */ - private $flashBag; - - public function __construct( + public function saveAction( CustomItemModel $customItemModel, CustomItemPermissionProvider $permissionProvider, - FlashBag $flashBag - ) { - $this->customItemModel = $customItemModel; - $this->permissionProvider = $permissionProvider; - $this->flashBag = $flashBag; - } - - public function saveAction(int $itemId, string $entityType, int $entityId): JsonResponse - { + FlashBag $flashBag, + int $itemId, + string $entityType, + int $entityId + ): JsonResponse { try { - $customItem = $this->customItemModel->fetchEntity($itemId); + $customItem = $customItemModel->fetchEntity($itemId); - $this->permissionProvider->canEdit($customItem); + $permissionProvider->canEdit($customItem); - $this->customItemModel->linkEntity($customItem, $entityType, $entityId); + $customItemModel->linkEntity($customItem, $entityType, $entityId); - $this->flashBag->add( + $flashBag->add( 'custom.item.linked', ['%itemId%' => $customItem->getId(), '%itemName%' => $customItem->getName(), '%entityType%' => $entityType, '%entityId%' => $entityId] ); - } catch (UniqueConstraintViolationException $e) { - $this->flashBag->add( + } catch (UniqueConstraintViolationException) { + $flashBag->add( 'custom.item.error.link.exists.already', ['%itemId%' => $itemId, '%entityType%' => $entityType, '%entityId%' => $entityId], FlashBag::LEVEL_ERROR ); - } catch (ForbiddenException|NotFoundException|UnexpectedValueException $e) { - $this->flashBag->add($e->getMessage(), [], FlashBag::LEVEL_ERROR); + } catch (ForbiddenException|NotFoundException|\UnexpectedValueException $e) { + $flashBag->add($e->getMessage(), [], FlashBag::LEVEL_ERROR); } return $this->renderJson(); diff --git a/Controller/CustomItem/LinkFormController.php b/Controller/CustomItem/LinkFormController.php index 763778af4..0e1cb6a3a 100644 --- a/Controller/CustomItem/LinkFormController.php +++ b/Controller/CustomItem/LinkFormController.php @@ -16,71 +16,40 @@ use MauticPlugin\CustomObjectsBundle\Model\CustomItemModel; use MauticPlugin\CustomObjectsBundle\Provider\CustomItemPermissionProvider; use MauticPlugin\CustomObjectsBundle\Provider\CustomItemRouteProvider; -use Symfony\Component\Form\FormFactory; +use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use UnexpectedValueException; class LinkFormController extends AbstractFormController { - /** - * @var FormFactory - */ - private $formFactory; - - /** - * @var CustomItemModel - */ - private $customItemModel; - - /** - * @var CustomItemPermissionProvider - */ - private $permissionProvider; - - /** - * @var FlashBag - */ - private $flashBag; - - /** - * @var CustomItemRouteProvider - */ - private $routeProvider; - - public function __construct( - FormFactory $formFactory, + public function formAction( + FormFactoryInterface $formFactory, CustomItemModel $customItemModel, CustomItemPermissionProvider $permissionProvider, CustomItemRouteProvider $customItemRouteProvider, - FlashBag $flashBag - ) { - $this->formFactory = $formFactory; - $this->customItemModel = $customItemModel; - $this->permissionProvider = $permissionProvider; - $this->routeProvider = $customItemRouteProvider; - $this->flashBag = $flashBag; - } - - public function formAction(int $itemId, string $entityType, int $entityId): Response - { + FlashBag $flashBag, + int $itemId, + string $entityType, + int $entityId + ): Response { try { - $customItem = $this->customItemModel->fetchEntity($itemId); + $customItem = $customItemModel->fetchEntity($itemId); if (null === $relationshipObject = $customItem->getCustomObject()->getRelationshipObject()) { throw new NoRelationshipException(); } - $this->permissionProvider->canEdit($customItem); + $permissionProvider->canEdit($customItem); - $relationshipItem = $this->getRelationshipItem($relationshipObject, $customItem, $entityType, $entityId); + $relationshipItem = $this->getRelationshipItem($customItemModel, $relationshipObject, $customItem, $entityType, $entityId); $relationshipItem->generateNameForChildObject($entityType, $entityId, $customItem); - $form = $this->formFactory->create( + $form = $formFactory->create( CustomItemType::class, $relationshipItem, [ - 'action' => $this->routeProvider->buildLinkFormSaveRoute($customItem->getId(), $entityType, $entityId), + 'action' => $customItemRouteProvider->buildLinkFormSaveRoute($customItem->getId(), $entityType, $entityId), 'objectId' => $relationshipObject->getId(), 'contactId' => $entityId, 'cancelUrl' => '', @@ -89,112 +58,126 @@ public function formAction(int $itemId, string $entityType, int $entityId): Resp return $this->delegateView( [ - 'returnUrl' => $this->routeProvider->buildContactViewRoute($entityId), + 'returnUrl' => $customItemRouteProvider->buildContactViewRoute($entityId), 'viewParameters' => [ 'entity' => $relationshipItem, 'customObject' => $relationshipObject, 'form' => $form->createView(), ], - 'contentTemplate' => 'CustomObjectsBundle:CustomItem:form.html.php', + 'contentTemplate' => '@CustomObjects/CustomItem/form.html.twig', 'passthroughVars' => [ 'callback' => 'customItemLinkFormLoad', 'mauticContent' => 'customItem', - 'route' => $this->routeProvider->buildNewRoute($relationshipObject->getId()), + 'route' => $customItemRouteProvider->buildNewRoute($relationshipObject->getId()), ], ] ); - } catch (ForbiddenException|NotFoundException|UnexpectedValueException|NoRelationshipException $e) { - $this->flashBag->add($e->getMessage(), [], FlashBag::LEVEL_ERROR); + } catch (ForbiddenException|NotFoundException|\UnexpectedValueException|NoRelationshipException $e) { + $flashBag->add($e->getMessage(), [], FlashBag::LEVEL_ERROR); } $responseData = [ 'closeModal' => true, - 'flashes' => $this->renderView('MauticCoreBundle:Notification:flash_messages.html.php'), + 'flashes' => $this->renderView('@MauticCore/Notification/flash_messages.html.twig'), ]; return new JsonResponse($responseData); } - public function saveAction(int $itemId, string $entityType, int $entityId): Response - { + public function saveAction( + Request $request, + FormFactoryInterface $formFactory, + CustomItemModel $customItemModel, + CustomItemPermissionProvider $permissionProvider, + CustomItemRouteProvider $customItemRouteProvider, + FlashBag $flashBag, + int $itemId, + string $entityType, + int $entityId + ): Response { $relationshipItem = null; $relationshipObject = null; $form = null; try { - $customItem = $this->customItemModel->fetchEntity($itemId); + $customItem = $customItemModel->fetchEntity($itemId); if (null === $relationshipObject = $customItem->getCustomObject()->getRelationshipObject()) { throw new NoRelationshipException(); } - $this->permissionProvider->canCreate($relationshipObject->getId()); + $permissionProvider->canCreate($relationshipObject->getId()); - $relationshipItem = $this->getRelationshipItem($relationshipObject, $customItem, $entityType, $entityId); + $relationshipItem = $this->getRelationshipItem($customItemModel, $relationshipObject, $customItem, $entityType, $entityId); $relationshipItem->generateNameForChildObject($entityType, $entityId, $customItem); - $form = $this->formFactory->create( + $form = $formFactory->create( CustomItemType::class, $relationshipItem, [ - 'action' => $this->routeProvider->buildLinkFormSaveRoute($customItem->getId(), $entityType, $entityId), + 'action' => $customItemRouteProvider->buildLinkFormSaveRoute($customItem->getId(), $entityType, $entityId), 'objectId' => $relationshipObject->getId(), 'contactId' => $entityId, ] ); - $form->handleRequest($this->request); + $form->handleRequest($request); if ($form->isValid()) { $callback = $relationshipItem->getId() ? null : 'customItemLinkFormPostSubmit'; - $relationshipItem = $this->customItemModel->save($relationshipItem); + $relationshipItem = $customItemModel->save($relationshipItem); $responseData = [ 'closeModal' => true, 'callback' => $callback, - 'flashes' => $this->renderView('MauticCoreBundle:Notification:flash_messages.html.php'), + 'flashes' => $this->renderView('@MauticCore/Notification/flash_messages.html.twig'), ]; return new JsonResponse($responseData); } } catch (ForbiddenException|NoRelationshipException|NotFoundException $e) { - $this->flashBag->add($e->getMessage(), [], FlashBag::LEVEL_ERROR); + $flashBag->add($e->getMessage(), [], FlashBag::LEVEL_ERROR); } return $this->delegateView( [ - 'returnUrl' => $this->routeProvider->buildContactViewRoute($entityId), + 'returnUrl' => $customItemRouteProvider->buildContactViewRoute($entityId), 'viewParameters' => [ 'entity' => $relationshipItem, 'customObject' => $relationshipObject, 'form' => $form->createView(), - 'tmpl' => $this->request->isXmlHttpRequest() ? $this->request->get('tmpl', 'index') : 'index', + 'tmpl' => $request->isXmlHttpRequest() ? $request->get('tmpl', 'index') : 'index', ], - 'contentTemplate' => 'CustomObjectsBundle:CustomItem:form.html.php', + 'contentTemplate' => '@CustomObjects/CustomItem/form.html.twig', 'passthroughVars' => [ 'closeModal' => false, 'callback' => 'customItemLinkFormLoad', 'mauticContent' => 'customItem', - 'route' => $this->routeProvider->buildLinkFormRoute($itemId, $entityType, $entityId), + 'route' => $customItemRouteProvider->buildLinkFormRoute($itemId, $entityType, $entityId), ], ] ); } - protected function getRelationshipItem(CustomObject $relationshipObject, CustomItem $customItem, string $entityType, int $entityId): CustomItem - { + protected function getRelationshipItem( + CustomItemModel $customItemModel, + CustomObject $relationshipObject, + CustomItem $customItem, + string $entityType, + int $entityId + ): CustomItem { /** @var CustomItemXrefCustomItem|null $relationshipItemXref */ $relationshipItemXref = $customItem->getCustomItemLowerReferences() - ->filter(function (CustomItemXrefCustomItem $item) use ($entityType, $entityId) { + ->filter(function (CustomItemXrefCustomItem $item) use ($entityType, $entityId): bool { $higher = $item->getCustomItemHigher(); return $higher->getRelationsByType($entityType) - ->filter(function ($relation) use ($entityId) { + ->filter(function ($relation) use ($entityId): bool { return (int) $relation->getLinkedEntity()->getId() === (int) $entityId; })->count() > 0; })->first(); - return $this->customItemModel->populateCustomFields( + return $customItemModel->populateCustomFields( $relationshipItemXref ? $relationshipItemXref->getCustomItemHigher() : new CustomItem($relationshipObject) ); } diff --git a/Controller/CustomItem/ListController.php b/Controller/CustomItem/ListController.php index 3dfed2e3e..381081f40 100644 --- a/Controller/CustomItem/ListController.php +++ b/Controller/CustomItem/ListController.php @@ -15,73 +15,34 @@ use MauticPlugin\CustomObjectsBundle\Provider\CustomItemPermissionProvider; use MauticPlugin\CustomObjectsBundle\Provider\CustomItemRouteProvider; use MauticPlugin\CustomObjectsBundle\Provider\SessionProviderFactory; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; class ListController extends CommonController { - /** - * @var RequestStack - */ - private $requestStack; - - /** - * @var SessionProviderFactory - */ - private $sessionProviderFactory; - - /** - * @var CustomItemModel - */ - private $customItemModel; - - /** - * @var CustomObjectModel - */ - private $customObjectModel; - - /** - * @var CustomItemPermissionProvider - */ - private $permissionProvider; - - /** - * @var CustomItemRouteProvider - */ - private $routeProvider; - - public function __construct( - RequestStack $requestStack, + public function listAction( SessionProviderFactory $sessionProviderFactory, CustomItemModel $customItemModel, CustomObjectModel $customObjectModel, CustomItemPermissionProvider $permissionProvider, - CustomItemRouteProvider $routeProvider - ) { - $this->requestStack = $requestStack; - $this->sessionProviderFactory = $sessionProviderFactory; - $this->customItemModel = $customItemModel; - $this->customObjectModel = $customObjectModel; - $this->permissionProvider = $permissionProvider; - $this->routeProvider = $routeProvider; - } + CustomItemRouteProvider $routeProvider, + int $objectId, + int $page = 1 + ): Response { + $request = $this->getCurrentRequest(); - public function listAction(int $objectId, int $page = 1): Response - { try { - $this->permissionProvider->canViewAtAll($objectId); - $customObject = $this->customObjectModel->fetchEntity($objectId); + $permissionProvider->canViewAtAll($objectId); + $customObject = $customObjectModel->fetchEntity($objectId); } catch (NotFoundException $e) { return $this->notFound($e->getMessage()); } catch (ForbiddenException $e) { return $this->accessDenied(false, $e->getMessage()); } - $request = $this->requestStack->getCurrentRequest(); $filterEntityId = (int) $request->get('filterEntityId'); $filterEntityType = InputHelper::clean($request->get('filterEntityType')); $lookup = (bool) $request->get('lookup'); - $sessionProvider = $this->sessionProviderFactory->createItemProvider($objectId, $filterEntityType, $filterEntityId, $lookup); + $sessionProvider = $sessionProviderFactory->createItemProvider($objectId, $filterEntityType, $filterEntityId, $lookup); $search = InputHelper::clean($request->get('search', $sessionProvider->getFilter())); $limit = (int) $request->get('limit', $sessionProvider->getPageLimit()); $orderBy = $sessionProvider->getOrderBy(CustomItem::TABLE_ALIAS.'.id'); @@ -105,8 +66,8 @@ public function listAction(int $objectId, int $page = 1): Response $sessionProvider->setPageLimit($limit); $sessionProvider->setFilter($search); - $route = $this->routeProvider->buildListRoute($objectId, $page, $filterEntityType ?: null, $filterEntityId ?: null, ['lookup' => $lookup ?: null]); - $items = $this->customItemModel->getTableData($tableConfig); + $route = $routeProvider->buildListRoute($objectId, $page, $filterEntityType ?: null, $filterEntityId ?: null, ['lookup' => $lookup ?: null]); + $items = $customItemModel->getTableData($tableConfig); $namespace = $sessionProvider->getNamespace(); $response = [ 'viewParameters' => [ @@ -116,7 +77,7 @@ public function listAction(int $objectId, int $page = 1): Response 'filterEntityType' => $filterEntityType, 'lookup' => $lookup, 'items' => $items, - 'itemCount' => $this->customItemModel->getCountForTable($tableConfig), + 'itemCount' => $customItemModel->getCountForTable($tableConfig), 'page' => $page, 'limit' => $limit, 'tmpl' => $request->isXmlHttpRequest() ? $request->get('tmpl', 'index') : 'index', @@ -124,7 +85,7 @@ public function listAction(int $objectId, int $page = 1): Response 'sessionVar' => $namespace, 'namespace' => $namespace, ], - 'contentTemplate' => 'CustomObjectsBundle:CustomItem:list.html.php', + 'contentTemplate' => '@CustomObjects/CustomItem/list.html.twig', 'passthroughVars' => [ 'mauticContent' => 'customItem', 'route' => $filterEntityType ? null : $route, @@ -132,7 +93,7 @@ public function listAction(int $objectId, int $page = 1): Response ]; if ($filterEntityId) { - $response['viewParameters']['fieldData'] = $this->customItemModel->getFieldListData($customObject, $items, $filterEntityType); + $response['viewParameters']['fieldData'] = $customItemModel->getFieldListData($customObject, $items, $filterEntityType); } if (!$request->isXmlHttpRequest()) { diff --git a/Controller/CustomItem/LookupController.php b/Controller/CustomItem/LookupController.php index 29d1255f8..38c4c813b 100644 --- a/Controller/CustomItem/LookupController.php +++ b/Controller/CustomItem/LookupController.php @@ -13,53 +13,25 @@ use MauticPlugin\CustomObjectsBundle\Model\CustomItemModel; use MauticPlugin\CustomObjectsBundle\Provider\CustomItemPermissionProvider; use Symfony\Component\HttpFoundation\JsonResponse; -use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpFoundation\Request; class LookupController extends JsonController { - /** - * @var RequestStack - */ - private $requestStack; - - /** - * @var CustomItemModel - */ - private $customItemModel; - - /** - * @var CustomItemPermissionProvider - */ - private $permissionProvider; - - /** - * @var FlashBag - */ - private $flashBag; - - public function __construct( - RequestStack $requestStack, + public function listAction( + Request $request, CustomItemModel $customItemModel, CustomItemPermissionProvider $permissionProvider, - FlashBag $flashBag - ) { - $this->requestStack = $requestStack; - $this->customItemModel = $customItemModel; - $this->permissionProvider = $permissionProvider; - $this->flashBag = $flashBag; - } - - public function listAction(int $objectId): JsonResponse - { + FlashBag $flashBag, + int $objectId + ): JsonResponse { try { - $this->permissionProvider->canViewAtAll($objectId); + $permissionProvider->canViewAtAll($objectId); } catch (ForbiddenException $e) { - $this->flashBag->add($e->getMessage(), [], FlashBag::LEVEL_ERROR); + $flashBag->add($e->getMessage(), [], FlashBag::LEVEL_ERROR); return $this->renderJson(); } - $request = $this->requestStack->getCurrentRequest(); $search = InputHelper::clean($request->get('filter')); $filterEntityId = (int) $request->get('filterEntityId'); $filterEntityType = InputHelper::clean($request->get('filterEntityType')); @@ -69,6 +41,6 @@ public function listAction(int $objectId): JsonResponse $tableConfig->addParameter('filterEntityType', $filterEntityType); $tableConfig->addParameter('filterEntityId', $filterEntityId); - return $this->renderJson(['items' => $this->customItemModel->getLookupData($tableConfig)]); + return $this->renderJson(['items' => $customItemModel->getLookupData($tableConfig)]); } } diff --git a/Controller/CustomItem/SaveController.php b/Controller/CustomItem/SaveController.php index eea863601..0350b4800 100644 --- a/Controller/CustomItem/SaveController.php +++ b/Controller/CustomItem/SaveController.php @@ -17,93 +17,42 @@ use MauticPlugin\CustomObjectsBundle\Provider\CustomItemRouteProvider; use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; class SaveController extends AbstractFormController { - /** - * @var RequestStack - */ - private $requestStack; - - /** - * @var FormFactoryInterface - */ - private $formFactory; - - /** - * @var FlashBag - */ - private $flashBag; - - /** - * @var CustomItemModel - */ - private $customItemModel; - - /** - * @var CustomObjectModel - */ - private $customObjectModel; - - /** - * @var CustomItemPermissionProvider - */ - private $permissionProvider; - - /** - * @var CustomItemRouteProvider - */ - private $routeProvider; - - /** - * @var LockFlashMessageHelper - */ - private $lockFlashMessageHelper; - - public function __construct( - RequestStack $requestStack, + public function saveAction( FormFactoryInterface $formFactory, FlashBag $flashBag, CustomItemModel $customItemModel, CustomObjectModel $customObjectModel, CustomItemPermissionProvider $permissionProvider, CustomItemRouteProvider $routeProvider, - LockFlashMessageHelper $lockFlashMessageHelper - ) { - $this->requestStack = $requestStack; - $this->formFactory = $formFactory; - $this->flashBag = $flashBag; - $this->customItemModel = $customItemModel; - $this->customObjectModel = $customObjectModel; - $this->permissionProvider = $permissionProvider; - $this->routeProvider = $routeProvider; - $this->lockFlashMessageHelper = $lockFlashMessageHelper; - } + LockFlashMessageHelper $lockFlashMessageHelper, + int $objectId, + ?int $itemId = null + ): Response { + $request = $this->getCurrentRequest(); - public function saveAction(int $objectId, ?int $itemId = null): Response - { - $request = $this->requestStack->getCurrentRequest(); $customItemData = $request->request->get('custom_item'); $contactId = intval($customItemData['contact_id'] ?? 0); try { if ($itemId) { $message = 'mautic.core.notice.updated'; - $customItem = $this->customItemModel->fetchEntity($itemId); + $customItem = $customItemModel->fetchEntity($itemId); $route = 0 < $contactId - ? $this->routeProvider->buildEditRouteWithRedirectToContact($objectId, $itemId, $contactId) - : $this->routeProvider->buildEditRoute($objectId, $itemId); - $this->permissionProvider->canEdit($customItem); + ? $routeProvider->buildEditRouteWithRedirectToContact($objectId, $itemId, $contactId) + : $routeProvider->buildEditRoute($objectId, $itemId); + $permissionProvider->canEdit($customItem); } else { - $this->permissionProvider->canCreate($objectId); + $permissionProvider->canCreate($objectId); $message = 'mautic.core.notice.created'; - $customObject = $this->customObjectModel->fetchEntity($objectId); - $customItem = $this->customItemModel->populateCustomFields(new CustomItem($customObject)); + $customObject = $customObjectModel->fetchEntity($objectId); + $customItem = $customItemModel->populateCustomFields(new CustomItem($customObject)); $route = 0 < $contactId - ? $this->routeProvider->buildNewRouteWithRedirectToContact($objectId, $contactId) - : $this->routeProvider->buildNewRoute($objectId); + ? $routeProvider->buildNewRouteWithRedirectToContact($objectId, $contactId) + : $routeProvider->buildNewRoute($objectId); } } catch (NotFoundException $e) { return $this->notFound($e->getMessage()); @@ -111,53 +60,53 @@ public function saveAction(int $objectId, ?int $itemId = null): Response return $this->accessDenied(false, $e->getMessage()); } - if ($this->customItemModel->isLocked($customItem)) { - $this->lockFlashMessageHelper->addFlash( + if ($customItemModel->isLocked($customItem)) { + $lockFlashMessageHelper->addFlash( $customItem, - $this->routeProvider->buildEditRoute($objectId, $itemId), + $routeProvider->buildEditRoute($objectId, $itemId), $this->canEdit($customItem), 'custom.item' ); - return $this->redirect($this->routeProvider->buildViewRoute($objectId, $itemId)); + return $this->redirect($routeProvider->buildViewRoute($objectId, $itemId)); } - $action = $this->routeProvider->buildSaveRoute($objectId, $itemId); + $action = $routeProvider->buildSaveRoute($objectId, $itemId); if (!$customItem->getId() && $customItem->getCustomObject()->getRelationshipObject() && $contactId) { $customItem->setChildCustomItem( - $this->customItemModel->populateCustomFields( + $customItemModel->populateCustomFields( new CustomItem($customItem->getCustomObject()->getRelationshipObject()) ) ); } - $form = $this->formFactory->create(CustomItemType::class, $customItem, ['action' => $action, 'objectId' => $objectId]); + $form = $formFactory->create(CustomItemType::class, $customItem, ['action' => $action, 'objectId' => $objectId]); $form->handleRequest($request); if ($form->isValid()) { - $customItem = $this->customItemModel->save($customItem); + $customItem = $customItemModel->save($customItem); if ($customItem->getChildCustomItem()) { $customItem->getChildCustomItem()->generateNameForChildObject('contact', $contactId, $customItem); - $customItem = $this->customItemModel->save($customItem->getChildCustomItem()); + $customItem = $customItemModel->save($customItem->getChildCustomItem()); } - if($customItem->hasBeenUpdated()){ + if ($customItem->hasBeenUpdated()) { $message = 'custom.item.notice.merged'; } - $this->flashBag->add( + $flashBag->add( $message, [ '%name%' => $customItem->getName(), - '%url%' => $this->routeProvider->buildEditRoute($objectId, $customItem->getId()), + '%url%' => $routeProvider->buildEditRoute($objectId, $customItem->getId()), ] ); $saveClicked = $form->get('buttons')->get('save')->isClicked(); - $detailView = 'CustomObjectsBundle:CustomItem\View:view'; - $formView = 'CustomObjectsBundle:CustomItem\Form:edit'; + $detailView = 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\ViewController:viewAction'; + $formView = 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\FormController:editAction'; $pathParameters = [ 'objectId' => $objectId, @@ -167,25 +116,25 @@ public function saveAction(int $objectId, ?int $itemId = null): Response if (0 < $contactId) { // For parent-child items we want to link both items together and the child item with the contact. if ($customItem->getChildCustomItem()) { - $this->customItemModel->linkEntity($customItem->getChildCustomItem(), 'contact', $contactId); - $this->customItemModel->linkEntity($customItem->getChildCustomItem(), 'customItem', $customItem->getId()); + $customItemModel->linkEntity($customItem->getChildCustomItem(), 'contact', $contactId); + $customItemModel->linkEntity($customItem->getChildCustomItem(), 'customItem', $customItem->getId()); } // For parent items we want to connect the parent item directly to the contact. - $this->customItemModel->linkEntity($customItem, 'contact', $contactId); + $customItemModel->linkEntity($customItem, 'contact', $contactId); if ($saveClicked) { return $this->redirectToRoute('mautic_contact_action', ['objectAction' => 'view', 'objectId' => $contactId]); } - $formView = 'CustomObjectsBundle:CustomItem\Form:editWithRedirectToContact'; + $formView = 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\FormController:editWithRedirectToContactAction'; $pathParameters['contactId'] = $contactId; } $request->setMethod(Request::METHOD_GET); if ($saveClicked) { - $this->customItemModel->unlockEntity($customItem); + $customItemModel->unlockEntity($customItem); } return $this->forward( @@ -203,7 +152,7 @@ public function saveAction(int $objectId, ?int $itemId = null): Response 'form' => $form->createView(), 'tmpl' => $request->isXmlHttpRequest() ? $request->get('tmpl', 'index') : 'index', ], - 'contentTemplate' => 'CustomObjectsBundle:CustomItem:form.html.php', + 'contentTemplate' => '@CustomObjects/CustomItem/form.html.twig', 'passthroughVars' => [ 'mauticContent' => 'customItem', 'route' => $route, diff --git a/Controller/CustomItem/UnlinkController.php b/Controller/CustomItem/UnlinkController.php index 9e1a68698..fd0a724d5 100644 --- a/Controller/CustomItem/UnlinkController.php +++ b/Controller/CustomItem/UnlinkController.php @@ -11,61 +11,41 @@ use MauticPlugin\CustomObjectsBundle\Model\CustomItemModel; use MauticPlugin\CustomObjectsBundle\Provider\CustomItemPermissionProvider; use Symfony\Component\HttpFoundation\JsonResponse; -use UnexpectedValueException; class UnlinkController extends JsonController { - /** - * @var CustomItemModel - */ - private $customItemModel; - - /** - * @var CustomItemPermissionProvider - */ - private $permissionProvider; - - /** - * @var FlashBag - */ - private $flashBag; - - public function __construct( + public function saveAction( CustomItemModel $customItemModel, CustomItemPermissionProvider $permissionProvider, - FlashBag $flashBag - ) { - $this->customItemModel = $customItemModel; - $this->permissionProvider = $permissionProvider; - $this->flashBag = $flashBag; - } - - public function saveAction(int $itemId, string $entityType, int $entityId): JsonResponse - { + FlashBag $flashBag, + int $itemId, + string $entityType, + int $entityId + ): JsonResponse { try { - $customItem = $this->customItemModel->fetchEntity($itemId); + $customItem = $customItemModel->fetchEntity($itemId); - $this->permissionProvider->canEdit($customItem); + $permissionProvider->canEdit($customItem); if ($customItem->getCustomObject()->getRelationshipObject()) { try { $childCustomItem = $customItem->findChildCustomItem(); - } catch (NotFoundException $e) { + } catch (NotFoundException) { } if (isset($childCustomItem)) { - $this->customItemModel->delete($childCustomItem); + $customItemModel->delete($childCustomItem); } } - $this->customItemModel->unlinkEntity($customItem, $entityType, $entityId); + $customItemModel->unlinkEntity($customItem, $entityType, $entityId); - $this->flashBag->add( + $flashBag->add( 'custom.item.unlinked', ['%itemId%' => $customItem->getId(), '%itemName%' => $customItem->getName(), '%entityType%' => $entityType, '%entityId%' => $entityId] ); - } catch (ForbiddenException|NotFoundException|UnexpectedValueException $e) { - $this->flashBag->add($e->getMessage(), [], FlashBag::LEVEL_ERROR); + } catch (ForbiddenException|NotFoundException|\UnexpectedValueException $e) { + $flashBag->add($e->getMessage(), [], FlashBag::LEVEL_ERROR); } return $this->renderJson(); diff --git a/Controller/CustomItem/ViewController.php b/Controller/CustomItem/ViewController.php index c29166ba9..62885f8cd 100644 --- a/Controller/CustomItem/ViewController.php +++ b/Controller/CustomItem/ViewController.php @@ -14,88 +14,44 @@ use MauticPlugin\CustomObjectsBundle\Provider\CustomItemPermissionProvider; use MauticPlugin\CustomObjectsBundle\Provider\CustomItemRouteProvider; use Symfony\Component\Form\FormFactoryInterface; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; class ViewController extends CommonController { - /** - * @var RequestStack - */ - private $requestStack; - - /** - * @var CustomItemModel - */ - private $customItemModel; - - /** - * @var CustomItemXrefContactModel - */ - private $customItemXrefContactModel; - - /** - * @var AuditLogModel - */ - private $auditLogModel; - - /** - * @var CustomItemPermissionProvider - */ - private $permissionProvider; - - /** - * @var CustomItemRouteProvider - */ - private $routeProvider; - - /** - * @var FormFactoryInterface - */ - private $formFactory; - - public function __construct( - RequestStack $requestStack, + public function viewAction( FormFactoryInterface $formFactory, CustomItemModel $customItemModel, CustomItemXrefContactModel $customItemXrefContactModel, AuditLogModel $auditLogModel, CustomItemPermissionProvider $permissionProvider, - CustomItemRouteProvider $routeProvider - ) { - $this->requestStack = $requestStack; - $this->formFactory = $formFactory; - $this->customItemModel = $customItemModel; - $this->customItemXrefContactModel = $customItemXrefContactModel; - $this->auditLogModel = $auditLogModel; - $this->permissionProvider = $permissionProvider; - $this->routeProvider = $routeProvider; - } + CustomItemRouteProvider $routeProvider, + int $objectId, + int $itemId + ): Response { + $request = $this->getCurrentRequest(); - public function viewAction(int $objectId, int $itemId): Response - { try { - $customItem = $this->customItemModel->fetchEntity($itemId); - $this->permissionProvider->canView($customItem); + $customItem = $customItemModel->fetchEntity($itemId); + $permissionProvider->canView($customItem); } catch (NotFoundException $e) { return $this->notFound($e->getMessage()); } catch (ForbiddenException $e) { return $this->accessDenied(false, $e->getMessage()); } - $route = $this->routeProvider->buildViewRoute($objectId, $itemId); - $dateRangeForm = $this->formFactory->create( + $route = $routeProvider->buildViewRoute($objectId, $itemId); + $dateRangeForm = $formFactory->create( DateRangeType::class, - $this->requestStack->getCurrentRequest()->get('daterange', []), + $request->get('daterange', []), ['action' => $route] ); - $stats = $this->customItemXrefContactModel->getLinksLineChartData( + $stats = $customItemXrefContactModel->getLinksLineChartData( new \DateTime($dateRangeForm->get('date_from')->getData()), new \DateTime($dateRangeForm->get('date_to')->getData()), $customItem ); - $auditLogs = $this->auditLogModel->getLogForObject('customItem', $itemId, $customItem->getDateAdded(), 10, 'customObjects'); + $auditLogs = $auditLogModel->getLogForObject('customItem', $itemId, $customItem->getDateAdded(), 10, 'customObjects'); return $this->delegateView( [ @@ -106,7 +62,7 @@ public function viewAction(int $objectId, int $itemId): Response 'stats' => $stats, 'logs' => $auditLogs, 'contacts' => $this->forward( - 'CustomObjectsBundle:CustomItem\ContactList:list', + 'MauticPlugin\CustomObjectsBundle\Controller\CustomItem\ContactListController::listAction', [ 'objectId' => $itemId, 'page' => 1, @@ -114,7 +70,7 @@ public function viewAction(int $objectId, int $itemId): Response ] )->getContent(), ], - 'contentTemplate' => 'CustomObjectsBundle:CustomItem:detail.html.php', + 'contentTemplate' => '@CustomObjects/CustomItem/detail.html.twig', 'passthroughVars' => [ 'mauticContent' => 'customItem', 'activeLink' => "#mautic_custom_object_{$objectId}", diff --git a/Controller/CustomObject/CancelController.php b/Controller/CustomObject/CancelController.php index d0c0ec82f..97798ef5d 100644 --- a/Controller/CustomObject/CancelController.php +++ b/Controller/CustomObject/CancelController.php @@ -12,45 +12,24 @@ class CancelController extends CommonController { - /** - * @var SessionProviderFactory - */ - private $sessionProviderFactory; - - /** - * @var CustomObjectRouteProvider - */ - private $routeProvider; - - /** - * @var CustomObjectModel - */ - private $customObjectModel; - - public function __construct( + public function cancelAction( SessionProviderFactory $sessionProviderFactory, CustomObjectRouteProvider $routeProvider, - CustomObjectModel $customObjectModel - ) { - $this->sessionProviderFactory = $sessionProviderFactory; - $this->routeProvider = $routeProvider; - $this->customObjectModel = $customObjectModel; - } - - public function cancelAction(?int $objectId): Response - { - $page = $this->sessionProviderFactory->createObjectProvider()->getPage(); + CustomObjectModel $customObjectModel, + ?int $objectId + ): Response { + $page = $sessionProviderFactory->createObjectProvider()->getPage(); if ($objectId) { - $customObject = $this->customObjectModel->fetchEntity($objectId); - $this->customObjectModel->unlockEntity($customObject); + $customObject = $customObjectModel->fetchEntity($objectId); + $customObjectModel->unlockEntity($customObject); } return $this->postActionRedirect( [ - 'returnUrl' => $this->routeProvider->buildListRoute($page), + 'returnUrl' => $routeProvider->buildListRoute($page), 'viewParameters' => ['page' => $page], - 'contentTemplate' => 'CustomObjectsBundle:CustomObject\List:list', + 'contentTemplate' => 'MauticPlugin\CustomObjectsBundle\Controller\CustomObject\ListController:listAction', 'passthroughVars' => [ 'mauticContent' => 'customObject', ], diff --git a/Controller/CustomObject/DeleteController.php b/Controller/CustomObject/DeleteController.php index 3bd6e6b95..4eb96c95a 100644 --- a/Controller/CustomObject/DeleteController.php +++ b/Controller/CustomObject/DeleteController.php @@ -19,61 +19,28 @@ class DeleteController extends CommonController { - /** - * @var CustomObjectModel - */ - private $customObjectModel; - - /** - * @var SessionProviderFactory - */ - private $sessionProviderFactory; - - /** - * @var FlashBag - */ - private $flashBag; - - /** - * @var CustomObjectPermissionProvider - */ - private $permissionProvider; - - /** - * @var EventDispatcherInterface - */ - private $eventDispatcher; - - public function __construct( - CustomObjectModel $customObjectModel, + public function deleteAction( SessionProviderFactory $sessionProviderFactory, + CustomObjectModel $customObjectModel, FlashBag $flashBag, CustomObjectPermissionProvider $permissionProvider, - EventDispatcherInterface $eventDispatcher - ) { - $this->customObjectModel = $customObjectModel; - $this->sessionProviderFactory = $sessionProviderFactory; - $this->flashBag = $flashBag; - $this->permissionProvider = $permissionProvider; - $this->eventDispatcher = $eventDispatcher; - } - - public function deleteAction(int $objectId): Response - { - $controller = 'CustomObjectsBundle:CustomObject\List:list'; + EventDispatcherInterface $eventDispatcher, + int $objectId + ): Response { + $controller = 'MauticPlugin\CustomObjectsBundle\Controller\CustomObject\ListController:listAction'; $page = [ - 'page' => $this->sessionProviderFactory->createObjectProvider()->getPage(), + 'page' => $sessionProviderFactory->createObjectProvider()->getPage(), ]; try { - $customObject = $this->customObjectModel->fetchEntity($objectId); + $customObject = $customObjectModel->fetchEntity($objectId); $translationParameters = [ '%name%' => $customObject->getName(), '%id%' => $customObject->getId(), ]; - $this->permissionProvider->canDelete($customObject); - $this->customObjectModel->checkIfTheCustomObjectIsUsedInSegmentFilters($customObject); + $permissionProvider->canDelete($customObject); + $customObjectModel->checkIfTheCustomObjectIsUsedInSegmentFilters($customObject); } catch (NotFoundException $e) { return $this->notFound($e->getMessage()); } catch (ForbiddenException $e) { @@ -85,7 +52,7 @@ public function deleteAction(int $objectId): Response } $translationParameters['%segments%'] = implode(', ', $segments); - $this->flashBag->add('custom.object.error.used.in.segments', $translationParameters, FlashBag::LEVEL_ERROR); + $flashBag->add('custom.object.error.used.in.segments', $translationParameters, FlashBag::LEVEL_ERROR); return $this->forward( $controller, @@ -94,8 +61,8 @@ public function deleteAction(int $objectId): Response } $customObjectEvent = new CustomObjectEvent($customObject); - $customObjectEvent->setFlashBag($this->flashBag); - $this->eventDispatcher->dispatch(CustomObjectEvents::ON_CUSTOM_OBJECT_USER_PRE_DELETE, $customObjectEvent); + $customObjectEvent->setFlashBag($flashBag); + $eventDispatcher->dispatch($customObjectEvent, CustomObjectEvents::ON_CUSTOM_OBJECT_USER_PRE_DELETE); return $this->forward( $controller, diff --git a/Controller/CustomObject/FormController.php b/Controller/CustomObject/FormController.php index 5d3284d6e..581b00c1f 100644 --- a/Controller/CustomObject/FormController.php +++ b/Controller/CustomObject/FormController.php @@ -15,136 +15,130 @@ use MauticPlugin\CustomObjectsBundle\Provider\CustomFieldTypeProvider; use MauticPlugin\CustomObjectsBundle\Provider\CustomObjectPermissionProvider; use MauticPlugin\CustomObjectsBundle\Provider\CustomObjectRouteProvider; -use Symfony\Component\Form\FormFactory; +use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\HttpFoundation\Response; class FormController extends AbstractFormController { - /** - * @var FormFactory - */ - private $formFactory; - - /** - * @var CustomObjectModel - */ - private $customObjectModel; - - /** - * @var CustomFieldModel - */ - private $customFieldModel; - - /** - * @var CustomObjectPermissionProvider - */ - private $permissionProvider; - - /** - * @var CustomObjectRouteProvider - */ - private $routeProvider; - - /** - * @var CustomFieldTypeProvider - */ - private $customFieldTypeProvider; - - /** - * @var LockFlashMessageHelper - */ - private $lockFlashMessageHelper; - - public function __construct( - FormFactory $formFactory, - CustomObjectModel $customObjectModel, - CustomFieldModel $customFieldModel, + public function newAction( CustomObjectPermissionProvider $permissionProvider, + FormFactoryInterface $formFactory, CustomObjectRouteProvider $routeProvider, CustomFieldTypeProvider $customFieldTypeProvider, - LockFlashMessageHelper $lockFlashMessageHelper - ) { - $this->formFactory = $formFactory; - $this->customObjectModel = $customObjectModel; - $this->customFieldModel = $customFieldModel; - $this->permissionProvider = $permissionProvider; - $this->routeProvider = $routeProvider; - $this->customFieldTypeProvider = $customFieldTypeProvider; - $this->lockFlashMessageHelper = $lockFlashMessageHelper; - } - - public function newAction(): Response - { + CustomFieldModel $customFieldModel + ): Response { try { - $this->permissionProvider->canCreate(); + $permissionProvider->canCreate(); $customObject = new CustomObject(); } catch (ForbiddenException $e) { return $this->accessDenied(false, $e->getMessage()); } - return $this->renderForm($customObject, $this->routeProvider->buildNewRoute()); + return $this->renderFormForObject( + $formFactory, + $routeProvider, + $customFieldTypeProvider, + $customFieldModel, + $customObject, + $routeProvider->buildNewRoute() + ); } - public function editAction(int $objectId): Response - { + public function editAction( + CustomObjectModel $customObjectModel, + CustomObjectPermissionProvider $permissionProvider, + LockFlashMessageHelper $lockFlashMessageHelper, + FormFactoryInterface $formFactory, + CustomObjectRouteProvider $routeProvider, + CustomFieldTypeProvider $customFieldTypeProvider, + CustomFieldModel $customFieldModel, + int $objectId + ): Response { try { - $customObject = $this->customObjectModel->fetchEntity($objectId); - $this->permissionProvider->canEdit($customObject); + $customObject = $customObjectModel->fetchEntity($objectId); + $permissionProvider->canEdit($customObject); } catch (NotFoundException $e) { return $this->notFound($e->getMessage()); } catch (ForbiddenException $e) { return $this->accessDenied(false, $e->getMessage()); } - if ($this->customObjectModel->isLocked($customObject)) { - $this->lockFlashMessageHelper->addFlash( + if ($customObjectModel->isLocked($customObject)) { + $lockFlashMessageHelper->addFlash( $customObject, - $this->routeProvider->buildEditRoute($objectId), + $routeProvider->buildEditRoute($objectId), $this->canEdit($customObject), 'custom.object' ); - return $this->redirect($this->routeProvider->buildViewRoute($objectId)); + return $this->redirect($routeProvider->buildViewRoute($objectId)); } - $this->customObjectModel->lockEntity($customObject); + $customObjectModel->lockEntity($customObject); - return $this->renderForm($customObject, $this->routeProvider->buildEditRoute($objectId)); + return $this->renderFormForObject( + $formFactory, + $routeProvider, + $customFieldTypeProvider, + $customFieldModel, + $customObject, + $routeProvider->buildEditRoute($objectId) + ); } - public function cloneAction(int $objectId): Response - { + public function cloneAction( + CustomObjectModel $customObjectModel, + CustomObjectPermissionProvider $permissionProvider, + FormFactoryInterface $formFactory, + CustomObjectRouteProvider $routeProvider, + CustomFieldTypeProvider $customFieldTypeProvider, + CustomFieldModel $customFieldModel, + int $objectId + ): Response { try { - $customObject = clone $this->customObjectModel->fetchEntity($objectId); - $this->permissionProvider->canClone($customObject); + $customObject = clone $customObjectModel->fetchEntity($objectId); + $permissionProvider->canClone($customObject); } catch (NotFoundException $e) { return $this->notFound($e->getMessage()); } catch (ForbiddenException $e) { return $this->accessDenied(false, $e->getMessage()); } - return $this->renderForm($customObject, $this->routeProvider->buildCloneRoute($objectId)); + return $this->renderFormForObject( + $formFactory, + $routeProvider, + $customFieldTypeProvider, + $customFieldModel, + $customObject, + $routeProvider->buildCloneRoute($objectId) + ); } - private function renderForm(CustomObject $customObject, string $route): Response - { - $form = $this->formFactory->create( + private function renderFormForObject( + FormFactoryInterface $formFactory, + CustomObjectRouteProvider $routeProvider, + CustomFieldTypeProvider $customFieldTypeProvider, + CustomFieldModel $customFieldModel, + CustomObject $customObject, + string $route + ): Response { + $form = $formFactory->create( CustomObjectType::class, $customObject, - ['action' => $this->routeProvider->buildSaveRoute($customObject->getId())] + ['action' => $routeProvider->buildSaveRoute($customObject->getId())] ); return $this->delegateView( [ - 'returnUrl' => $this->routeProvider->buildListRoute(), + 'returnUrl' => $routeProvider->buildListRoute(), 'viewParameters' => [ 'customObject' => $customObject, - 'availableFieldTypes' => $this->customFieldTypeProvider->getTypes(), - 'customFields' => $this->customFieldModel->fetchCustomFieldsForObject($customObject), + 'availableFieldTypes' => $customFieldTypeProvider->getTypes(), + 'customFields' => $customFieldModel->fetchCustomFieldsForObject($customObject), 'deletedFields' => [], 'form' => $form->createView(), ], - 'contentTemplate' => 'CustomObjectsBundle:CustomObject:form.html.php', + 'contentTemplate' => '@CustomObjects/CustomObject/form.html.twig', 'passthroughVars' => [ 'mauticContent' => 'customObject', 'route' => $route, diff --git a/Controller/CustomObject/ListController.php b/Controller/CustomObject/ListController.php index ab8af89b5..130186518 100644 --- a/Controller/CustomObject/ListController.php +++ b/Controller/CustomObject/ListController.php @@ -13,65 +13,31 @@ use MauticPlugin\CustomObjectsBundle\Provider\CustomObjectPermissionProvider; use MauticPlugin\CustomObjectsBundle\Provider\CustomObjectRouteProvider; use MauticPlugin\CustomObjectsBundle\Provider\SessionProviderFactory; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; class ListController extends CommonController { - /** - * @var RequestStack - */ - private $requestStack; - - /** - * @var SessionProviderFactory - */ - private $sessionProviderFactory; - - /** - * @var CustomObjectModel - */ - private $customObjectModel; - - /** - * @var CustomObjectPermissionProvider - */ - private $permissionProvider; - - /** - * @var CustomObjectRouteProvider - */ - private $routeProvider; - - public function __construct( - RequestStack $requestStack, + public function listAction( SessionProviderFactory $sessionProviderFactory, CustomObjectModel $customObjectModel, CustomObjectPermissionProvider $permissionProvider, - CustomObjectRouteProvider $routeProvider - ) { - $this->requestStack = $requestStack; - $this->sessionProviderFactory = $sessionProviderFactory; - $this->customObjectModel = $customObjectModel; - $this->permissionProvider = $permissionProvider; - $this->routeProvider = $routeProvider; - } + CustomObjectRouteProvider $routeProvider, + int $page = 1 + ): Response { + $request = $this->getCurrentRequest(); - public function listAction(int $page = 1): Response - { try { - $this->permissionProvider->canViewAtAll(); + $permissionProvider->canViewAtAll(); } catch (ForbiddenException $e) { return $this->accessDenied(false, $e->getMessage()); } - $request = $this->requestStack->getCurrentRequest(); - $sessionProvider = $this->sessionProviderFactory->createObjectProvider(); + $sessionProvider = $sessionProviderFactory->createObjectProvider(); $search = InputHelper::clean($request->get('search', $sessionProvider->getFilter())); $limit = (int) $request->get('limit', $sessionProvider->getPageLimit()); $orderBy = $sessionProvider->getOrderBy(CustomObject::TABLE_ALIAS.'.id'); $orderByDir = $sessionProvider->getOrderByDir('ASC'); - $route = $this->routeProvider->buildListRoute($page); + $route = $routeProvider->buildListRoute($page); if ($request->query->has('orderby')) { $orderBy = InputHelper::clean($request->query->get('orderby'), true); @@ -91,14 +57,14 @@ public function listAction(int $page = 1): Response 'returnUrl' => $route, 'viewParameters' => [ 'searchValue' => $search, - 'items' => $this->customObjectModel->getTableData($tableConfig), - 'count' => $this->customObjectModel->getCountForTable($tableConfig), + 'items' => $customObjectModel->getTableData($tableConfig), + 'count' => $customObjectModel->getCountForTable($tableConfig), 'page' => $page, 'limit' => $limit, 'tmpl' => $request->isXmlHttpRequest() ? $request->get('tmpl', 'index') : 'index', 'sessionVar' => $sessionProvider->getNamespace(), ], - 'contentTemplate' => 'CustomObjectsBundle:CustomObject:list.html.php', + 'contentTemplate' => '@CustomObjects/CustomObject/list.html.twig', 'passthroughVars' => [ 'mauticContent' => 'customObject', 'route' => $route, diff --git a/Controller/CustomObject/SaveController.php b/Controller/CustomObject/SaveController.php index c77f2dd52..603a569c7 100644 --- a/Controller/CustomObject/SaveController.php +++ b/Controller/CustomObject/SaveController.php @@ -22,68 +22,11 @@ use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; class SaveController extends AbstractFormController { - /** - * @var RequestStack - */ - private $requestStack; - - /** - * @var FlashBag - */ - private $flashBag; - - /** - * @var FormFactoryInterface - */ - private $formFactory; - - /** - * @var CustomObjectModel - */ - private $customObjectModel; - - /** - * @var CustomFieldModel - */ - private $customFieldModel; - - /** - * @var CustomObjectPermissionProvider - */ - private $permissionProvider; - - /** - * @var CustomObjectRouteProvider - */ - private $routeProvider; - - /** - * @var CustomFieldTypeProvider - */ - private $customFieldTypeProvider; - - /** - * @var ParamsToStringTransformer - */ - private $paramsToStringTransformer; - - /** - * @var OptionsToStringTransformer - */ - private $optionsToStringTransformer; - - /** - * @var LockFlashMessageHelper - */ - private $lockFlashMessageHelper; - - public function __construct( - RequestStack $requestStack, + public function saveAction( FlashBag $flashBag, FormFactoryInterface $formFactory, CustomObjectModel $customObjectModel, @@ -93,29 +36,17 @@ public function __construct( CustomFieldTypeProvider $customFieldTypeProvider, ParamsToStringTransformer $paramsToStringTransformer, OptionsToStringTransformer $optionsToStringTransformer, - LockFlashMessageHelper $lockFlashMessageHelper - ) { - $this->requestStack = $requestStack; - $this->flashBag = $flashBag; - $this->formFactory = $formFactory; - $this->customObjectModel = $customObjectModel; - $this->customFieldModel = $customFieldModel; - $this->permissionProvider = $permissionProvider; - $this->routeProvider = $routeProvider; - $this->customFieldTypeProvider = $customFieldTypeProvider; - $this->paramsToStringTransformer = $paramsToStringTransformer; - $this->optionsToStringTransformer = $optionsToStringTransformer; - $this->lockFlashMessageHelper = $lockFlashMessageHelper; - } + LockFlashMessageHelper $lockFlashMessageHelper, + ?int $objectId = null + ): Response { + $request = $this->getCurrentRequest(); - public function saveAction(?int $objectId = null): Response - { try { - $customObject = $objectId ? $this->customObjectModel->fetchEntity($objectId) : new CustomObject(); + $customObject = $objectId ? $customObjectModel->fetchEntity($objectId) : new CustomObject(); if ($customObject->isNew()) { - $this->permissionProvider->canCreate(); + $permissionProvider->canCreate(); } else { - $this->permissionProvider->canEdit($customObject); + $permissionProvider->canEdit($customObject); } } catch (NotFoundException $e) { return $this->notFound($e->getMessage()); @@ -123,20 +54,19 @@ public function saveAction(?int $objectId = null): Response return $this->accessDenied(false, $e->getMessage()); } - if ($this->customObjectModel->isLocked($customObject)) { - $this->lockFlashMessageHelper->addFlash( + if ($customObjectModel->isLocked($customObject)) { + $lockFlashMessageHelper->addFlash( $customObject, - $this->routeProvider->buildEditRoute($objectId), + $routeProvider->buildEditRoute($objectId), $this->canEdit($customObject), 'custom.object' ); - return $this->redirect($this->routeProvider->buildViewRoute($objectId)); + return $this->redirect($routeProvider->buildViewRoute($objectId)); } - $request = $this->requestStack->getCurrentRequest(); - $action = $this->routeProvider->buildSaveRoute($objectId); - $form = $this->formFactory->create( + $action = $routeProvider->buildSaveRoute($objectId); + $form = $formFactory->create( CustomObjectType::class, $customObject, ['action' => $action] @@ -148,23 +78,29 @@ public function saveAction(?int $objectId = null): Response $form->submit($postData, false); if ($form->isValid()) { - $this->handleRawPost($customObject, $postData); + $this->handleRawPost( + $customObjectModel, + $paramsToStringTransformer, + $optionsToStringTransformer, + $customObject, + $postData + ); - $this->customObjectModel->save($customObject); + $customObjectModel->save($customObject); - $this->flashBag->add( + $flashBag->add( $objectId ? 'mautic.core.notice.updated' : 'mautic.core.notice.created', [ '%name%' => $customObject->getName(), - '%url%' => $this->routeProvider->buildEditRoute($objectId), + '%url%' => $routeProvider->buildEditRoute($objectId), ] ); if ($form->get('buttons')->get('save')->isClicked()) { - $this->customObjectModel->unlockEntity($customObject); - $route = $this->routeProvider->buildViewRoute($customObject->getId()); + $customObjectModel->unlockEntity($customObject); + $route = $routeProvider->buildViewRoute($customObject->getId()); } else { - $route = $this->routeProvider->buildEditRoute($customObject->getId()); + $route = $routeProvider->buildEditRoute($customObject->getId()); } return $this->redirectWithCompletePageRefresh($request, $route); @@ -172,18 +108,18 @@ public function saveAction(?int $objectId = null): Response return $this->delegateView( [ - 'returnUrl' => $this->routeProvider->buildListRoute(), + 'returnUrl' => $routeProvider->buildListRoute(), 'viewParameters' => [ 'customObject' => $customObject, - 'availableFieldTypes' => $this->customFieldTypeProvider->getTypes(), - 'customFields' => $this->customFieldModel->fetchCustomFieldsForObject($customObject), + 'availableFieldTypes' => $customFieldTypeProvider->getTypes(), + 'customFields' => $customFieldModel->fetchCustomFieldsForObject($customObject), 'deletedFields' => [], 'form' => $form->createView(), ], - 'contentTemplate' => 'CustomObjectsBundle:CustomObject:form.html.php', + 'contentTemplate' => '@CustomObjects/CustomObject/form.html.twig', 'passthroughVars' => [ 'mauticContent' => 'customObject', - 'route' => $objectId ? $this->routeProvider->buildEditRoute($customObject->getId()) : $this->routeProvider->buildNewRoute(), + 'route' => $objectId ? $routeProvider->buildEditRoute($customObject->getId()) : $routeProvider->buildNewRoute(), ], ] ); @@ -192,18 +128,23 @@ public function saveAction(?int $objectId = null): Response /** * @param string[] $rawCustomObject */ - private function handleRawPost(CustomObject $customObject, array $rawCustomObject): void - { + private function handleRawPost( + CustomObjectModel $customObjectModel, + ParamsToStringTransformer $paramsToStringTransformer, + OptionsToStringTransformer $optionsToStringTransformer, + CustomObject $customObject, + array $rawCustomObject + ): void { if (empty($rawCustomObject['customFields'])) { return; } - // Let's order received $_POST data and apply delete for existing CFs + // Let's order received $_POST data and apply to delete for existing CFs $customFields = []; foreach ($rawCustomObject['customFields'] as $customField) { if ($customField['deleted'] && $customField['id']) { // Remove deleted custom fields - $this->customObjectModel->removeCustomFieldById($customObject, (int) $customField['id']); + $customObjectModel->removeCustomFieldById($customObject, (int) $customField['id']); } else { // We are using order key as key to access collection of CustomFields below $customFields[(int) $customField['order']] = $customField; @@ -213,10 +154,10 @@ private function handleRawPost(CustomObject $customObject, array $rawCustomObjec foreach ($customFields as $order => $rawCustomField) { // Should be resolved better in form/transformer, but here it is more clear $params = $rawCustomField['params']; - $params = $this->paramsToStringTransformer->reverseTransform($params); + $params = $paramsToStringTransformer->reverseTransform($params); $options = $rawCustomField['options']; - $options = $this->optionsToStringTransformer->reverseTransform($options); + $options = $optionsToStringTransformer->reverseTransform($options); /** @var CustomField $customField */ $customField = $customObject->getCustomFieldByOrder((int) $order); diff --git a/Controller/CustomObject/ViewController.php b/Controller/CustomObject/ViewController.php index 222e5ee66..d8dd3e449 100644 --- a/Controller/CustomObject/ViewController.php +++ b/Controller/CustomObject/ViewController.php @@ -13,81 +13,42 @@ use MauticPlugin\CustomObjectsBundle\Provider\CustomObjectPermissionProvider; use MauticPlugin\CustomObjectsBundle\Provider\CustomObjectRouteProvider; use Symfony\Component\Form\FormFactoryInterface; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; class ViewController extends CommonController { - /** - * @var RequestStack - */ - private $requestStack; - - /** - * @var FormFactoryInterface - */ - private $formFactory; - - /** - * @var CustomObjectModel - */ - private $customObjectModel; - - /** - * @var AuditLogModel - */ - private $auditLogModel; - - /** - * @var CustomObjectPermissionProvider - */ - private $permissionProvider; - - /** - * @var CustomObjectRouteProvider - */ - private $routeProvider; - - public function __construct( - RequestStack $requestStack, + public function viewAction( FormFactoryInterface $formFactory, CustomObjectModel $customObjectModel, AuditLogModel $auditLogModel, CustomObjectPermissionProvider $permissionProvider, - CustomObjectRouteProvider $routeProvider - ) { - $this->requestStack = $requestStack; - $this->formFactory = $formFactory; - $this->customObjectModel = $customObjectModel; - $this->auditLogModel = $auditLogModel; - $this->permissionProvider = $permissionProvider; - $this->routeProvider = $routeProvider; - } + CustomObjectRouteProvider $routeProvider, + int $objectId + ): Response { + $request = $this->getCurrentRequest(); - public function viewAction(int $objectId): Response - { try { - $customObject = $this->customObjectModel->fetchEntity($objectId); - $this->permissionProvider->canView($customObject); + $customObject = $customObjectModel->fetchEntity($objectId); + $permissionProvider->canView($customObject); } catch (NotFoundException $e) { return $this->notFound($e->getMessage()); } catch (ForbiddenException $e) { return $this->accessDenied(false, $e->getMessage()); } - $route = $this->routeProvider->buildViewRoute($objectId); - $dateRangeForm = $this->formFactory->create( + $route = $routeProvider->buildViewRoute($objectId); + $dateRangeForm = $formFactory->create( DateRangeType::class, - $this->requestStack->getCurrentRequest()->get('daterange', []), + $request->get('daterange', []), ['action' => $route] ); - $stats = $this->customObjectModel->getItemsLineChartData( + $stats = $customObjectModel->getItemsLineChartData( new \DateTime($dateRangeForm->get('date_from')->getData()), new \DateTime($dateRangeForm->get('date_to')->getData()), $customObject ); - $auditLogs = $this->auditLogModel->getLogForObject( + $auditLogs = $auditLogModel->getLogForObject( 'customObject', $objectId, $customObject->getDateAdded(), @@ -104,7 +65,7 @@ public function viewAction(int $objectId): Response 'stats' => $stats, 'logs' => $auditLogs, ], - 'contentTemplate' => 'CustomObjectsBundle:CustomObject:detail.html.php', + 'contentTemplate' => '@CustomObjects/CustomObject/detail.html.twig', 'passthroughVars' => [ 'mauticContent' => 'customObject', 'activeLink' => "#mautic_custom_object_{$objectId}", diff --git a/Controller/JsonController.php b/Controller/JsonController.php index 77a86d128..331f27363 100644 --- a/Controller/JsonController.php +++ b/Controller/JsonController.php @@ -4,10 +4,10 @@ namespace MauticPlugin\CustomObjectsBundle\Controller; -use Symfony\Bundle\FrameworkBundle\Controller\Controller; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; -class JsonController extends Controller +class JsonController extends AbstractController { /** * Adds flashes stored in session (by addFlash() method) to the JsonResponse. @@ -16,7 +16,7 @@ class JsonController extends Controller */ protected function renderJson(array $responseData = []): JsonResponse { - $responseData['flashes'] = $this->renderView('MauticCoreBundle:Notification:flash_messages.html.php'); + $responseData['flashes'] = $this->renderView('@MauticCore/Notification/flash_messages.html.twig'); return new JsonResponse($responseData); } diff --git a/CustomFieldType/AbstractCustomFieldType.php b/CustomFieldType/AbstractCustomFieldType.php index ff96d4563..5a8b3199e 100644 --- a/CustomFieldType/AbstractCustomFieldType.php +++ b/CustomFieldType/AbstractCustomFieldType.php @@ -10,9 +10,9 @@ use MauticPlugin\CustomObjectsBundle\Exception\UndefinedTransformerException; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; -abstract class AbstractCustomFieldType implements CustomFieldTypeInterface +abstract class AbstractCustomFieldType implements CustomFieldTypeInterface, \Stringable { /** * @var string @@ -24,22 +24,10 @@ abstract class AbstractCustomFieldType implements CustomFieldTypeInterface */ protected $formTypeOptions = []; - /** - * @var TranslatorInterface - */ - protected $translator; - - /** - * @var FilterOperatorProviderInterface - */ - protected $filterOperatorProvider; - public function __construct( - TranslatorInterface $translator, - FilterOperatorProviderInterface $filterOperatorProvider + protected TranslatorInterface $translator, + protected FilterOperatorProviderInterface $filterOperatorProvider ) { - $this->translator = $translator; - $this->filterOperatorProvider = $filterOperatorProvider; } public function __toString(): string @@ -110,8 +98,8 @@ public function hasChoices(): bool { $type = $this->getSymfonyFormFieldType(); - return ChoiceType::class === $type || - is_subclass_of($this->getSymfonyFormFieldType(), ChoiceType::class); + return ChoiceType::class === $type + || is_subclass_of($this->getSymfonyFormFieldType(), ChoiceType::class); } /** diff --git a/CustomFieldType/AbstractMultivalueType.php b/CustomFieldType/AbstractMultivalueType.php index 9d85c71ab..e46757d22 100644 --- a/CustomFieldType/AbstractMultivalueType.php +++ b/CustomFieldType/AbstractMultivalueType.php @@ -16,25 +16,18 @@ use MauticPlugin\CustomObjectsBundle\Helper\CsvHelper; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; abstract class AbstractMultivalueType extends AbstractCustomFieldType { public const TABLE_NAME = 'custom_field_value_option'; - /** - * @var CsvHelper - */ - private $csvHelper; - public function __construct( TranslatorInterface $translator, FilterOperatorProviderInterface $filterOperatorProvider, - CsvHelper $csvHelper + private CsvHelper $csvHelper ) { parent::__construct($translator, $filterOperatorProvider); - - $this->csvHelper = $csvHelper; } /** @@ -94,7 +87,7 @@ public function validateValue(CustomField $customField, $value): void } $options = $customField->getOptions(); - $possibleValues = $options->map(function (CustomFieldOption $option) { + $possibleValues = $options->map(function (CustomFieldOption $option): string { return $option->getValue(); })->getValues(); @@ -129,7 +122,7 @@ public function valueToString(CustomFieldValueInterface $fieldValue): string foreach ($values as $value) { try { $labels[] = $fieldValue->getCustomField()->valueToLabel((string) $value); - } catch (NotFoundException $e) { + } catch (NotFoundException) { // When the value does not exist anymore, use the value instead. $labels[] = $value; } diff --git a/CustomFieldType/CountryType.php b/CustomFieldType/CountryType.php index a6dfa364c..71969db5a 100644 --- a/CustomFieldType/CountryType.php +++ b/CustomFieldType/CountryType.php @@ -23,7 +23,7 @@ class CountryType extends SelectType implements StaticChoiceTypeInterface /** * @var string[] */ - private $countryList; + private ?array $countryList = null; /** * {@inheritdoc} diff --git a/CustomFieldType/DataTransformer/CsvTransformer.php b/CustomFieldType/DataTransformer/CsvTransformer.php index e0f756f00..6173f0c7d 100644 --- a/CustomFieldType/DataTransformer/CsvTransformer.php +++ b/CustomFieldType/DataTransformer/CsvTransformer.php @@ -9,10 +9,7 @@ class CsvTransformer implements DataTransformerInterface { - /** - * @var CsvHelper - */ - private $csvHelper; + private CsvHelper $csvHelper; public function __construct() { diff --git a/CustomFieldType/DataTransformer/DateTimeAtomTransformer.php b/CustomFieldType/DataTransformer/DateTimeAtomTransformer.php index 46028ef57..96317e535 100644 --- a/CustomFieldType/DataTransformer/DateTimeAtomTransformer.php +++ b/CustomFieldType/DataTransformer/DateTimeAtomTransformer.php @@ -4,7 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\CustomFieldType\DataTransformer; -use DateTimeImmutable; use Symfony\Component\Form\DataTransformerInterface; class DateTimeAtomTransformer implements DataTransformerInterface @@ -15,7 +14,7 @@ class DateTimeAtomTransformer implements DataTransformerInterface public function transform($value) { if ($value) { - return new DateTimeImmutable($value); + return new \DateTimeImmutable($value); } return null; diff --git a/CustomFieldType/DataTransformer/DateTimeTransformer.php b/CustomFieldType/DataTransformer/DateTimeTransformer.php index 9bf96fb7c..77bb081cd 100644 --- a/CustomFieldType/DataTransformer/DateTimeTransformer.php +++ b/CustomFieldType/DataTransformer/DateTimeTransformer.php @@ -4,7 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\CustomFieldType\DataTransformer; -use DateTime; use Symfony\Component\Form\DataTransformerInterface; class DateTimeTransformer implements DataTransformerInterface @@ -15,7 +14,7 @@ class DateTimeTransformer implements DataTransformerInterface public function transform($value) { if ($value) { - return new DateTime($value); + return new \DateTime($value); } return null; diff --git a/CustomFieldType/DataTransformer/DateTransformer.php b/CustomFieldType/DataTransformer/DateTransformer.php index 19c439503..9855405ee 100644 --- a/CustomFieldType/DataTransformer/DateTransformer.php +++ b/CustomFieldType/DataTransformer/DateTransformer.php @@ -4,7 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\CustomFieldType\DataTransformer; -use DateTime; use Symfony\Component\Form\DataTransformerInterface; class DateTransformer implements DataTransformerInterface @@ -15,7 +14,7 @@ class DateTransformer implements DataTransformerInterface public function transform($value) { if ($value) { - return new DateTime($value); + return new \DateTime($value); } return null; @@ -31,7 +30,7 @@ public function reverseTransform($value) } if (is_string($value)) { - $value = new DateTime($value); + $value = new \DateTime($value); } return $value->format('Y-m-d'); diff --git a/CustomFieldType/DateOperatorTrait.php b/CustomFieldType/DateOperatorTrait.php new file mode 100644 index 000000000..c81d9f73c --- /dev/null +++ b/CustomFieldType/DateOperatorTrait.php @@ -0,0 +1,38 @@ +getValue(); - if ($value instanceof DateTimeInterface) { + if ($value instanceof \DateTimeInterface) { return $value->format('Y-m-d H:i:s'); } diff --git a/CustomFieldType/DateType.php b/CustomFieldType/DateType.php index 9d7b81626..d2fcd09b7 100644 --- a/CustomFieldType/DateType.php +++ b/CustomFieldType/DateType.php @@ -4,7 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\CustomFieldType; -use DateTimeInterface; use MauticPlugin\CustomObjectsBundle\CustomFieldType\DataTransformer\DateTransformer; use MauticPlugin\CustomObjectsBundle\CustomFieldType\DataTransformer\ViewDateTransformer; use MauticPlugin\CustomObjectsBundle\Entity\CustomField; @@ -16,6 +15,8 @@ class DateType extends AbstractCustomFieldType { + use DateOperatorTrait; + /** * @var string */ @@ -70,17 +71,6 @@ public function getEntityClass(): string return CustomFieldValueDate::class; } - /** - * @return mixed[] - */ - public function getOperators(): array - { - $allOperators = parent::getOperators(); - $allowedOperators = array_flip(['=', '!=', 'gt', 'gte', 'lt', 'lte', 'empty', '!empty']); - - return array_intersect_key($allOperators, $allowedOperators); - } - /** * {@inheritdoc} */ @@ -112,7 +102,7 @@ public function valueToString(CustomFieldValueInterface $fieldValue): string { $value = $fieldValue->getValue(); - if ($value instanceof DateTimeInterface) { + if ($value instanceof \DateTimeInterface) { return $value->format('Y-m-d'); } diff --git a/CustomFieldType/IntType.php b/CustomFieldType/IntType.php index dc20ba308..d4e1c95c1 100644 --- a/CustomFieldType/IntType.php +++ b/CustomFieldType/IntType.php @@ -41,13 +41,27 @@ public function createValueEntity(CustomField $customField, CustomItem $customIt return new CustomFieldValueInt($customField, $customItem, (int) $value); } + /** + * Remove operators that are supported only by segment filters. + * + * @return string[] + */ + public function getOperatorOptions(): array + { + $options = parent::getOperatorOptions(); + + unset($options['between'], $options['!between']); + + return $options; + } + /** * @return mixed[] */ public function getOperators(): array { $allOperators = parent::getOperators(); - $allowedOperators = array_flip(['=', '!=', 'gt', 'gte', 'lt', 'lte', 'empty', '!empty']); + $allowedOperators = array_flip(['=', '!=', 'gt', 'gte', 'lt', 'lte', 'empty', '!empty', 'between', '!between']); return array_intersect_key($allOperators, $allowedOperators); } diff --git a/CustomFieldType/PhoneType.php b/CustomFieldType/PhoneType.php index 5efab7d9a..a7790dcd2 100644 --- a/CustomFieldType/PhoneType.php +++ b/CustomFieldType/PhoneType.php @@ -36,10 +36,8 @@ public function validateValue(CustomField $customField, $value): void try { $phoneNumber = $phoneUtil->parse($value, PhoneNumberUtil::UNKNOWN_REGION); - } catch (NumberParseException $e) { + } catch (NumberParseException) { throw new \UnexpectedValueException($message); - - return; } if (false === $phoneUtil->isValidNumber($phoneNumber)) { diff --git a/CustomFieldType/SelectType.php b/CustomFieldType/SelectType.php index d9d3a0950..3ff8b5a8e 100644 --- a/CustomFieldType/SelectType.php +++ b/CustomFieldType/SelectType.php @@ -53,7 +53,7 @@ public function valueToString(CustomFieldValueInterface $fieldValue): string try { return $fieldValue->getCustomField()->valueToLabel((string) $value); - } catch (NotFoundException $e) { + } catch (NotFoundException) { // When the value does not exist anymore, use the value instead. return $value; } diff --git a/CustomItemEvents.php b/CustomItemEvents.php index 6ee649120..e040afdf5 100644 --- a/CustomItemEvents.php +++ b/CustomItemEvents.php @@ -14,7 +14,7 @@ final class CustomItemEvents * * The event listener receives a * - * @see \MauticPlugin\CustomObjectsBundle\Event\CustomItemEvent + * @see Event\CustomItemEvent * * @var string */ @@ -25,7 +25,7 @@ final class CustomItemEvents * * The event listener receives a * - * @see \MauticPlugin\CustomObjectsBundle\Event\CustomItemEvent + * @see Event\CustomItemEvent * * @var string */ @@ -36,7 +36,7 @@ final class CustomItemEvents * * The event listener receives a * - * @see \MauticPlugin\CustomObjectsBundle\Event\CustomItemEvent + * @see Event\CustomItemEvent * * @var string */ @@ -47,7 +47,7 @@ final class CustomItemEvents * * The event listener receives a * - * @see \MauticPlugin\CustomObjectsBundle\Event\CustomItemEvent + * @see Event\CustomItemEvent * * @var string */ @@ -58,7 +58,7 @@ final class CustomItemEvents * * The event listener receives a * - * @see \MauticPlugin\CustomObjectsBundle\Event\CustomItemListQueryEvent + * @see Event\CustomItemListQueryEvent * * @var string */ @@ -69,7 +69,7 @@ final class CustomItemEvents * * The event listener receives a * - * @see \MauticPlugin\CustomObjectsBundle\Event\CustomItemListQueryEvent + * @see Event\CustomItemListQueryEvent * * @var string */ @@ -80,7 +80,7 @@ final class CustomItemEvents * * The event listener receives a * - * @see \MauticPlugin\CustomObjectsBundle\Event\CustomItemListQueryEvent + * @see Event\CustomItemListQueryEvent * * @var string */ @@ -91,7 +91,7 @@ final class CustomItemEvents * * The event listener receives a * - * @see \MauticPlugin\CustomObjectsBundle\Event\CustomItemXrefEntityDiscoveryEvent + * @see Event\CustomItemXrefEntityDiscoveryEvent * * @var string */ @@ -102,7 +102,7 @@ final class CustomItemEvents * * The event listener receives a * - * @see \MauticPlugin\CustomObjectsBundle\Event\CustomItemXrefEntityEvent + * @see Event\CustomItemXrefEntityEvent * * @var string */ @@ -113,7 +113,7 @@ final class CustomItemEvents * * The event listener receives a * - * @see \MauticPlugin\CustomObjectsBundle\Event\CustomItemXrefEntityEvent + * @see Event\CustomItemXrefEntityEvent * * @var string */ @@ -124,7 +124,7 @@ final class CustomItemEvents * * The event listener receives a * - * @see \Mautic\CampaignBundle\Event\CampaignExecutionEvent + * @see Event\CampaignExecutionEvent * * @var string */ @@ -135,7 +135,7 @@ final class CustomItemEvents * * The event listener receives a * - * @see \Mautic\CampaignBundle\Event\CampaignExecutionEvent + * @see Event\CampaignExecutionEvent * * @var string */ @@ -144,7 +144,7 @@ final class CustomItemEvents /** * The custom.item.on_custom_item_export event is fired when the custom item is being exported. * - * @see MauticPlugin\CustomObjectsBundle\Event\CustomItemExportSchedulerEvent + * @see Event\CustomItemExportSchedulerEvent * * @var string */ @@ -153,7 +153,7 @@ final class CustomItemEvents /** * The custom.item.custom_item_prepare_export_file event is fired when the custom item data is being prepared to be exported. * - * @see MauticPlugin\CustomObjectsBundle\Event\CustomItemExportSchedulerEvent + * @see Event\CustomItemExportSchedulerEvent * * @var string */ diff --git a/CustomObjectEvents.php b/CustomObjectEvents.php index 6116107ac..2ef16f1c4 100644 --- a/CustomObjectEvents.php +++ b/CustomObjectEvents.php @@ -14,7 +14,7 @@ final class CustomObjectEvents * * The event listener receives a * - * @see \MauticPlugin\CustomObjectsBundle\Event\CustomObjectEvent + * @see Event\CustomObjectEvent * * @var string */ @@ -25,7 +25,7 @@ final class CustomObjectEvents * * The event listener receives a * - * @see \MauticPlugin\CustomObjectsBundle\Event\CustomObjectEvent + * @see Event\CustomObjectEvent * * @var string */ @@ -36,7 +36,7 @@ final class CustomObjectEvents * * The event listener receives a * - * @see \MauticPlugin\CustomObjectsBundle\Event\CustomObjectEvent + * @see Event\CustomObjectEvent * * @var string */ @@ -47,7 +47,7 @@ final class CustomObjectEvents * * The event listener receives a * - * @see \MauticPlugin\CustomObjectsBundle\Event\CustomObjectEvent + * @see Event\CustomObjectEvent * * @var string */ @@ -58,7 +58,7 @@ final class CustomObjectEvents * * The event listener receives a * - * @see \MauticPlugin\CustomObjectsBundle\Event\CustomObjectEvent + * @see Event\CustomObjectEvent * * @var string */ @@ -69,7 +69,7 @@ final class CustomObjectEvents * * The event listener receives a * - * @see \MauticPlugin\CustomObjectsBundle\Event\CustomObjectListFormatEvent + * @see Event\CustomObjectListFormatEvent * * @var string */ diff --git a/DTO/CustomItemFieldListData.php b/DTO/CustomItemFieldListData.php index fb7e1f823..aa440bc3c 100644 --- a/DTO/CustomItemFieldListData.php +++ b/DTO/CustomItemFieldListData.php @@ -8,20 +8,8 @@ class CustomItemFieldListData { - /** - * @var array - */ - private $columns; - - /** - * @var array - */ - private $data; - - public function __construct(array $columns, array $data) + public function __construct(private array $columns, private array $data) { - $this->columns = $columns; - $this->data = $data; } public function getColumnLabels(): array diff --git a/DTO/ImportLogDTO.php b/DTO/ImportLogDTO.php new file mode 100644 index 000000000..14b4338dc --- /dev/null +++ b/DTO/ImportLogDTO.php @@ -0,0 +1,28 @@ + + */ + private array $warnings = []; + + public function hasWarning(): bool + { + return !empty($this->warnings); + } + + public function addWarning(string $warning): void + { + $this->warnings[] = $warning; + } + + public function getWarningsAsString(): string + { + return implode('\n', $this->warnings); + } +} diff --git a/DTO/TableConfig.php b/DTO/TableConfig.php index 3d37011f4..70132dd11 100644 --- a/DTO/TableConfig.php +++ b/DTO/TableConfig.php @@ -10,37 +10,17 @@ class TableConfig { - /** - * @var int - */ - private $limit; - - /** - * @var int - */ - private $page; - - /** - * @var string - */ - private $orderBy; - - /** - * @var string - */ - private $orderDirection; - /** * @var mixed[] */ - private $parameters = []; - - public function __construct(int $limit, int $page, string $orderBy, string $orderDirection = 'ASC') - { - $this->limit = $limit; - $this->page = $page; - $this->orderBy = $orderBy; - $this->orderDirection = $orderDirection; + private array $parameters = []; + + public function __construct( + private int $limit, + private int $page, + private string $orderBy, + private string $orderDirection = 'ASC' + ) { } public function getOrderBy(): string diff --git a/DTO/Token.php b/DTO/Token.php index 7deea6f7c..cfa38fa2d 100644 --- a/DTO/Token.php +++ b/DTO/Token.php @@ -11,49 +11,22 @@ */ class Token { - /** - * @var string - */ - private $token; - - /** - * @var int - */ - private $limit = 1; - - /** - * @var string - */ - private $where = ''; - - /** - * @var string - */ - private $order = 'latest'; - - /** - * @var string - */ - private $defaultValue = ''; - - /** - * @var string - */ - private $format = ''; - - /** - * @var string - */ - private $customFieldAlias = ''; - - /** - * @var string - */ - private $customObjectAlias = ''; - - public function __construct(string $token) - { - $this->token = $token; + private int $limit = 1; + + private string $where = ''; + + private string $order = 'latest'; + + private string $defaultValue = ''; + + private string $format = ''; + + private string $customFieldAlias = ''; + + private string $customObjectAlias = ''; + + public function __construct(private string $token) + { } public function setDefaultValue(string $defaultValue): void diff --git a/DataPersister/CustomItemDataPersister.php b/DataPersister/CustomItemDataPersister.php new file mode 100644 index 000000000..e35043b55 --- /dev/null +++ b/DataPersister/CustomItemDataPersister.php @@ -0,0 +1,46 @@ +customItemModel->save($data); + + return $data; + } + + /** + * @param mixed $data + */ + public function remove($data): void + { + \assert($data instanceof CustomItem); + + $this->customItemModel->delete($data); + } +} diff --git a/DependencyInjection/CustomObjectsExtension.php b/DependencyInjection/CustomObjectsExtension.php new file mode 100644 index 000000000..f54828d57 --- /dev/null +++ b/DependencyInjection/CustomObjectsExtension.php @@ -0,0 +1,22 @@ +load('services.php'); + } +} diff --git a/Entity/AbstractCustomFieldValue.php b/Entity/AbstractCustomFieldValue.php index abb4907f8..a4cdacbba 100644 --- a/Entity/AbstractCustomFieldValue.php +++ b/Entity/AbstractCustomFieldValue.php @@ -12,16 +12,6 @@ abstract class AbstractCustomFieldValue implements CustomFieldValueInterface { - /** - * @var CustomField - */ - protected $customField; - - /** - * @var CustomItem - */ - protected $customItem; - public static function loadMetadata(ORM\ClassMetadata $metadata): void { $builder = new ClassMetadataBuilder($metadata); @@ -29,10 +19,8 @@ public static function loadMetadata(ORM\ClassMetadata $metadata): void $builder->setMappedSuperClass(); } - public function __construct(CustomField $customField, CustomItem $customItem) + public function __construct(protected CustomField $customField, protected CustomItem $customItem) { - $this->customField = $customField; - $this->customItem = $customItem; } public static function loadValidatorMetadata(ClassMetadata $metadata): void @@ -81,7 +69,7 @@ public function getCustomItem(): CustomItem /** * @param mixed $value */ - public function addValue($value = null) + public function addValue($value = null): void { throw new \Exception('addValue is not implemented for '.self::class); } diff --git a/Entity/CustomField.php b/Entity/CustomField.php index 198494cc1..1c77ade48 100644 --- a/Entity/CustomField.php +++ b/Entity/CustomField.php @@ -11,7 +11,6 @@ use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; -use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping\JoinColumn; @@ -51,6 +50,7 @@ * normalizationContext={"groups"={"custom_field:read"}, "swagger_definition_name"="Read"}, * denormalizationContext={"groups"={"custom_field:write"}, "swagger_definition_name"="Write"} * ) + * * @ApiFilter(SearchFilter::class, properties={"alias": "partial"}) */ class CustomField extends FormEntity implements UniqueEntityInterface, UuidInterface @@ -62,7 +62,9 @@ class CustomField extends FormEntity implements UniqueEntityInterface, UuidInter /** * @var int|null + * * @Groups({"custom_field:read", "custom_object:read"}) + * * @ApiProperty( * attributes={ * "openapi_context"={ @@ -77,7 +79,9 @@ class CustomField extends FormEntity implements UniqueEntityInterface, UuidInter /** * @var string|null + * * @Groups({"custom_field:read", "custom_field:write", "custom_object:read", "custom_object:write"}) + * * @ApiProperty( * attributes={ * "openapi_context"={ @@ -93,7 +97,9 @@ class CustomField extends FormEntity implements UniqueEntityInterface, UuidInter /** * @var string|null + * * @Groups({"custom_field:read", "custom_field:write", "custom_object:read", "custom_object:write"}) + * * @ApiProperty( * attributes={ * "openapi_context"={ @@ -109,7 +115,9 @@ class CustomField extends FormEntity implements UniqueEntityInterface, UuidInter /** * @var string|null + * * @Groups({"custom_field:read", "custom_field:write", "custom_object:read", "custom_object:write"}) + * * @ApiProperty( * attributes={ * "openapi_context"={ @@ -143,7 +151,9 @@ class CustomField extends FormEntity implements UniqueEntityInterface, UuidInter /** * @ManyToOne(targetEntity="CustomObject", inversedBy="customFields") + * * @JoinColumn(name="custom_object_id", referencedColumnName="id") + * * @Groups({"custom_field:read", "custom_field:write", "custom_object:read", "custom_object:write"}) * * @var CustomObject|null @@ -152,6 +162,7 @@ class CustomField extends FormEntity implements UniqueEntityInterface, UuidInter /** * @Groups({"custom_field:read", "custom_field:write", "custom_object:read", "custom_object:write"}) + * * @ApiProperty( * attributes={ * "openapi_context"={ @@ -168,26 +179,32 @@ class CustomField extends FormEntity implements UniqueEntityInterface, UuidInter /** * @var bool + * * @Groups({"custom_field:read", "custom_field:write", "custom_object:read", "custom_object:write"}) */ private $required = false; /** * @var mixed + * * @Groups({"custom_field:read", "custom_field:write", "custom_object:read", "custom_object:write"}) */ private $defaultValue; /** * @var Collection|CustomFieldOption[] + * * @OneToMany(targetEntity="CustomFieldOption", mappedBy="customField") + * * @Groups({"custom_field:read", "custom_field:write", "custom_object:read", "custom_object:write"}) + * * @ApiSubresource() */ private $options; /** * @var Params|string[] + * * @Groups({"custom_field:read", "custom_field:write", "custom_object:read", "custom_object:write"}) */ private $params; @@ -203,11 +220,10 @@ class CustomField extends FormEntity implements UniqueEntityInterface, UuidInter private $showInContactDetailList = true; /** - * @var bool * @Groups({"custom_field:read", "custom_field:write", "custom_object:read", "custom_object:write"}) */ private bool $isUniqueIdentifier = false; - + private bool $wasChangeIsUniqueIdentifier = false; public function __construct() @@ -221,9 +237,9 @@ public function __clone() $this->alias = null; } - public function __toString() + public function __toString(): string { - return $this->getLabel(); + return (string) $this->getLabel(); } /** @@ -256,20 +272,20 @@ public static function loadMetadata(ORM\ClassMetadata $metadata): void ->build(); $builder->addId(); - $builder->addField('label', Type::STRING); - $builder->addField('alias', Type::STRING); - $builder->addField('type', Type::STRING); + $builder->addField('label', Types::STRING); + $builder->addField('alias', Types::STRING); + $builder->addField('type', Types::STRING); $builder->createField('order', 'integer') ->columnName('field_order') ->nullable() ->build(); - $builder->createField('required', Type::BOOLEAN) + $builder->createField('required', Types::BOOLEAN) ->columnName('required') ->option('default', false) ->build(); - $builder->createField('defaultValue', Type::STRING) + $builder->createField('defaultValue', Types::STRING) ->columnName('default_value') ->nullable() ->build(); @@ -281,17 +297,17 @@ public static function loadMetadata(ORM\ClassMetadata $metadata): void ->fetchExtraLazy() ->build(); - $builder->createField('params', Type::JSON_ARRAY) + $builder->createField('params', Types::JSON) ->columnName('params') ->nullable() ->build(); - $builder->createField('showInCustomObjectDetailList', Type::BOOLEAN) + $builder->createField('showInCustomObjectDetailList', Types::BOOLEAN) ->columnName('show_in_custom_object_detail_list') ->option('default', true) ->build(); - $builder->createField('showInContactDetailList', Type::BOOLEAN) + $builder->createField('showInContactDetailList', Types::BOOLEAN) ->columnName('show_in_contact_detail_list') ->option('default', true) ->build(); @@ -366,7 +382,7 @@ public function getName(): ?string /** * @param string|null $alias */ - public function setAlias($alias) + public function setAlias($alias): void { $this->isChanged('alias', $alias); $this->alias = $alias; @@ -418,6 +434,15 @@ public function getFormFieldOptions(array $customOptions = []): array 'attr' => ['class' => 'form-control'], ]; + if ('datetime' === $this->getType()) { + $fieldOptions = array_merge( + $fieldOptions, + [ + 'html5' => false, + ] + ); + } + if ($placeholder) { $fieldOptions['attr']['data-placeholder'] = $placeholder; } @@ -434,9 +459,6 @@ public function getCustomObject(): ?CustomObject return $this->customObject; } - /** - * @param CustomObject $customObject - */ public function setCustomObject(?CustomObject $customObject = null): void { $this->customObject = $customObject; @@ -460,9 +482,6 @@ public function isRequired(): bool return $this->required; } - /** - * @param bool $required - */ public function setRequired(?bool $required): void { $this->required = $this->isUniqueIdentifier ?: (bool) $required; @@ -475,7 +494,7 @@ public function getDefaultValue() { try { return $this->getTypeObject()->createDefaultValueTransformer()->transform($this->defaultValue); - } catch (UndefinedTransformerException $e) { + } catch (UndefinedTransformerException) { // Nothing to transform, return string below } @@ -491,7 +510,7 @@ public function setDefaultValue($defaultValue): void $this->defaultValue = $this->getTypeObject()->createDefaultValueTransformer()->reverseTransform($defaultValue); return; - } catch (UndefinedTransformerException $e) { + } catch (UndefinedTransformerException) { // Nothing to transform, use string below } @@ -579,7 +598,7 @@ public function valueToLabel(string $value): string throw new NotFoundException("Label was not found for value {$value}"); } - return $label; + return (string) $label; } /** @@ -629,8 +648,8 @@ public function setShowInContactDetailList(?bool $showInContactDetailList): void public function isChoiceType(): bool { - return ChoiceType::class === $this->getTypeObject()->getSymfonyFormFieldType() || - is_subclass_of($this->getTypeObject()->getSymfonyFormFieldType(), ChoiceType::class); + return ChoiceType::class === $this->getTypeObject()->getSymfonyFormFieldType() + || is_subclass_of($this->getTypeObject()->getSymfonyFormFieldType(), ChoiceType::class); } public function canHaveMultipleValues(): bool @@ -668,7 +687,7 @@ public function getIsPublished() /** * @Groups({"custom_field:read", "custom_object:read"}) * - * @return \DateTime + * @return \DateTimeInterface|null */ public function getDateAdded() { @@ -678,7 +697,7 @@ public function getDateAdded() /** * @Groups({"custom_field:read", "custom_object:read"}) * - * @return \DateTime + * @return \DateTimeInterface|null */ public function getDateModified() { diff --git a/Entity/CustomFieldFactory.php b/Entity/CustomFieldFactory.php index 7b14cd48e..abe900830 100644 --- a/Entity/CustomFieldFactory.php +++ b/Entity/CustomFieldFactory.php @@ -10,14 +10,8 @@ class CustomFieldFactory { - /** - * @var CustomFieldTypeProvider - */ - private $customFieldTypeProvider; - - public function __construct(CustomFieldTypeProvider $customFieldTypeProvider) + public function __construct(private CustomFieldTypeProvider $customFieldTypeProvider) { - $this->customFieldTypeProvider = $customFieldTypeProvider; } /** diff --git a/Entity/CustomFieldOption.php b/Entity/CustomFieldOption.php index 3843fd72a..f76e68eef 100644 --- a/Entity/CustomFieldOption.php +++ b/Entity/CustomFieldOption.php @@ -5,9 +5,8 @@ namespace MauticPlugin\CustomObjectsBundle\Entity; use ApiPlatform\Core\Annotation\ApiResource; -use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; -use Doctrine\ORM\Mapping\Column; use Doctrine\ORM\Mapping\Id; use Doctrine\ORM\Mapping\JoinColumn; use Doctrine\ORM\Mapping\ManyToOne; @@ -35,27 +34,34 @@ class CustomFieldOption implements \ArrayAccess { /** * @var CustomField|null + * * @Id @Column(type="integer") + * * @ManyToOne(targetEntity="CustomField", inversedBy="options") + * * @JoinColumn("custom_field_id") */ private $customField; /** * @var string|null + * * @Groups({"custom_object:read", "custom_object:write", "custom_field:read", "custom_field:write"}) */ private $label; /** * @var string|null + * * @Id @Column(type="integer") + * * @Groups({"custom_object:read", "custom_object:write", "custom_field:read", "custom_field:write"}) */ private $value; /** * @var int|null + * * @Groups({"custom_object:read", "custom_field:read"}) */ private $order; @@ -99,11 +105,11 @@ public static function loadMetadata(ORM\ClassMetadata $metadata): void ->makePrimaryKey() ->build(); - $builder->createField('value', Type::STRING) + $builder->createField('value', Types::STRING) ->makePrimaryKey() ->build(); - $builder->addField('label', Type::STRING); + $builder->addField('label', Types::STRING); $builder->createField('order', 'integer') ->columnName('option_order') @@ -164,7 +170,7 @@ public function setOrder(?int $order): void /** * {@inheritdoc} */ - public function offsetExists($offset) + public function offsetExists(mixed $offset): bool { return isset($this->{$offset}); } @@ -172,7 +178,7 @@ public function offsetExists($offset) /** * {@inheritdoc} */ - public function offsetGet($offset) + public function offsetGet(mixed $offset): mixed { return $this->offsetExists($offset) ? $this->{$offset} : null; } @@ -180,7 +186,7 @@ public function offsetGet($offset) /** * {@inheritdoc} */ - public function offsetSet($offset, $value) + public function offsetSet(mixed $offset, mixed $value): void { $this->{$offset} = $value; } @@ -188,7 +194,7 @@ public function offsetSet($offset, $value) /** * {@inheritdoc} */ - public function offsetUnset($offset) + public function offsetUnset(mixed $offset): void { $this->{$offset} = null; } diff --git a/Entity/CustomFieldValueDate.php b/Entity/CustomFieldValueDate.php index 844d45074..d06c2b377 100644 --- a/Entity/CustomFieldValueDate.php +++ b/Entity/CustomFieldValueDate.php @@ -4,19 +4,18 @@ namespace MauticPlugin\CustomObjectsBundle\Entity; -use DateTimeInterface; -use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use Mautic\CoreBundle\Doctrine\Mapping\ClassMetadataBuilder; class CustomFieldValueDate extends AbstractCustomFieldValue { /** - * @var DateTimeInterface|null + * @var \DateTimeInterface|null */ private $value; - public function __construct(CustomField $customField, CustomItem $customItem, ?DateTimeInterface $value = null) + public function __construct(CustomField $customField, CustomItem $customItem, ?\DateTimeInterface $value = null) { parent::__construct($customField, $customItem); @@ -28,7 +27,7 @@ public static function loadMetadata(ORM\ClassMetadata $metadata): void $builder = new ClassMetadataBuilder($metadata); $builder->setTable('custom_field_value_date'); $builder->addIndex(['value'], 'value_index'); - $builder->addNullableField('value', Type::DATE); + $builder->addNullableField('value', Types::DATETIME_MUTABLE); parent::addReferenceColumns($builder); } @@ -44,7 +43,7 @@ public function setValue($value = null): void return; } - if (!$value instanceof DateTimeInterface) { + if (!$value instanceof \DateTimeInterface) { $value = new \DateTimeImmutable($value); } diff --git a/Entity/CustomFieldValueDateTime.php b/Entity/CustomFieldValueDateTime.php index f696ff2f5..891588c41 100644 --- a/Entity/CustomFieldValueDateTime.php +++ b/Entity/CustomFieldValueDateTime.php @@ -4,23 +4,15 @@ namespace MauticPlugin\CustomObjectsBundle\Entity; -use DateTimeInterface; -use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use Mautic\CoreBundle\Doctrine\Mapping\ClassMetadataBuilder; class CustomFieldValueDateTime extends AbstractCustomFieldValue { - /** - * @var DateTimeInterface|null - */ - private $value; - - public function __construct(CustomField $customField, CustomItem $customItem, ?DateTimeInterface $value = null) + public function __construct(CustomField $customField, CustomItem $customItem, private ?\DateTimeInterface $value = null) { parent::__construct($customField, $customItem); - - $this->value = $value; } public static function loadMetadata(ORM\ClassMetadata $metadata): void @@ -28,7 +20,7 @@ public static function loadMetadata(ORM\ClassMetadata $metadata): void $builder = new ClassMetadataBuilder($metadata); $builder->setTable('custom_field_value_datetime'); $builder->addIndex(['value'], 'value_index'); - $builder->addNullableField('value', Type::DATETIME); + $builder->addNullableField('value', Types::DATETIME_MUTABLE); parent::addReferenceColumns($builder); } @@ -44,7 +36,7 @@ public function setValue($value = null): void return; } - if (!$value instanceof DateTimeInterface) { + if (!$value instanceof \DateTimeInterface) { $value = new \DateTimeImmutable($value); } diff --git a/Entity/CustomFieldValueInt.php b/Entity/CustomFieldValueInt.php index d1378cf84..ac42f2341 100644 --- a/Entity/CustomFieldValueInt.php +++ b/Entity/CustomFieldValueInt.php @@ -4,22 +4,15 @@ namespace MauticPlugin\CustomObjectsBundle\Entity; -use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use Mautic\CoreBundle\Doctrine\Mapping\ClassMetadataBuilder; class CustomFieldValueInt extends AbstractCustomFieldValue { - /** - * @var int|null - */ - private $value; - - public function __construct(CustomField $customField, CustomItem $customItem, ?int $value = null) + public function __construct(CustomField $customField, CustomItem $customItem, private ?int $value = null) { parent::__construct($customField, $customItem); - - $this->value = $value; } public static function loadMetadata(ORM\ClassMetadata $metadata): void @@ -27,7 +20,7 @@ public static function loadMetadata(ORM\ClassMetadata $metadata): void $builder = new ClassMetadataBuilder($metadata); $builder->setTable('custom_field_value_int'); $builder->addIndex(['value'], 'value_index'); - $builder->addNullableField('value', Type::INTEGER); + $builder->addNullableField('value', Types::INTEGER); parent::addReferenceColumns($builder); } diff --git a/Entity/CustomFieldValueOption.php b/Entity/CustomFieldValueOption.php index 7ae077a9a..742dbcc2f 100644 --- a/Entity/CustomFieldValueOption.php +++ b/Entity/CustomFieldValueOption.php @@ -14,7 +14,15 @@ class CustomFieldValueOption extends AbstractCustomFieldValue { /** + * The identifier of the record, used by Doctrine ORM. + * * @var int|null + * + * @ORM\Id + * + * @ORM\Column(type="integer") + * + * @ORM\GeneratedValue */ private $id; @@ -59,7 +67,7 @@ public static function loadMetadata(ORM\ClassMetadata $metadata): void /** * @param mixed $value */ - public function addValue($value = null) + public function addValue($value = null): void { if (!$this->value) { $this->value = []; @@ -75,7 +83,7 @@ public function addValue($value = null) /** * @param mixed $value */ - public function setValue($value = null) + public function setValue($value = null): void { if (is_array($value)) { $value = array_unique($value); diff --git a/Entity/CustomFieldValueText.php b/Entity/CustomFieldValueText.php index 30082eab5..598af5f87 100644 --- a/Entity/CustomFieldValueText.php +++ b/Entity/CustomFieldValueText.php @@ -4,22 +4,15 @@ namespace MauticPlugin\CustomObjectsBundle\Entity; -use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use Mautic\CoreBundle\Doctrine\Mapping\ClassMetadataBuilder; class CustomFieldValueText extends AbstractCustomFieldValue { - /** - * @var string|null - */ - private $value; - - public function __construct(CustomField $customField, CustomItem $customItem, ?string $value = null) + public function __construct(CustomField $customField, CustomItem $customItem, private ?string $value = null) { parent::__construct($customField, $customItem); - - $this->value = $value; } /** @@ -30,7 +23,7 @@ public static function loadMetadata(ORM\ClassMetadata $metadata): void { $builder = new ClassMetadataBuilder($metadata); $builder->setTable('custom_field_value_text') - ->addNullableField('value', Type::TEXT) + ->addNullableField('value', Types::TEXT) ->addFulltextIndex(['value'], 'value_fulltext'); parent::addReferenceColumns($builder); diff --git a/Entity/CustomItem.php b/Entity/CustomItem.php index 2c5b4df8b..99a658f9a 100644 --- a/Entity/CustomItem.php +++ b/Entity/CustomItem.php @@ -8,7 +8,6 @@ use ApiPlatform\Core\Annotation\ApiResource; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; -use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping\JoinColumn; @@ -42,6 +41,7 @@ * denormalizationContext={"groups"={"custom_item:write"}, "swagger_definition_name"="Write"} * ) */ +#[\AllowDynamicProperties] class CustomItem extends FormEntity implements UniqueEntityInterface, UpsertInterface { use UpsertTrait; @@ -50,7 +50,9 @@ class CustomItem extends FormEntity implements UniqueEntityInterface, UpsertInte /** * @var int|null + * * @Groups({"custom_item:read"}) + * * @ApiProperty( * attributes={ * "openapi_context"={ @@ -65,7 +67,9 @@ class CustomItem extends FormEntity implements UniqueEntityInterface, UpsertInte /** * @var string|null + * * @Groups({"custom_item:read", "custom_item:write"}) + * * @ApiProperty( * attributes={ * "openapi_context"={ @@ -79,14 +83,6 @@ class CustomItem extends FormEntity implements UniqueEntityInterface, UpsertInte */ private $name; - /** - * @var CustomObject - * @ManyToOne(targetEntity="CustomObject") - * @JoinColumn(name="custom_object_id", referencedColumnName="id") - * @Groups({"custom_item:read", "custom_item:write"}) - */ - private $customObject; - /** * @var CustomItem|null */ @@ -94,7 +90,9 @@ class CustomItem extends FormEntity implements UniqueEntityInterface, UpsertInte /** * @var string|null + * * @Groups({"custom_item:read", "custom_item:write"}) + * * @ApiProperty( * attributes={ * "openapi_context"={ @@ -109,9 +107,13 @@ class CustomItem extends FormEntity implements UniqueEntityInterface, UpsertInte /** * @var Category|null + * * @ManyToOne(targetEntity="Category") + * * @JoinColumn(name="category_id", referencedColumnName="id") + * * @ApiProperty(readableLink=false, writableLink=false) + * * @Groups({"custom_item:read", "custom_item:write"}) **/ private $category; @@ -123,6 +125,7 @@ class CustomItem extends FormEntity implements UniqueEntityInterface, UpsertInte /** * @var array + * * @ApiProperty( * attributes={ * "openapi_context"={ @@ -149,6 +152,7 @@ class CustomItem extends FormEntity implements UniqueEntityInterface, UpsertInte * } * } * ) + * * @Groups({"custom_item:read", "custom_item:write"}) */ private $fieldValues; @@ -175,9 +179,17 @@ class CustomItem extends FormEntity implements UniqueEntityInterface, UpsertInte private ?string $uniqueHash = null; - public function __construct(CustomObject $customObject) - { - $this->customObject = $customObject; + public function __construct(/** + * @var CustomObject + * + * @ManyToOne(targetEntity="CustomObject") + * + * @JoinColumn(name="custom_object_id", referencedColumnName="id") + * + * @Groups({"custom_item:read", "custom_item:write"}) + */ + private CustomObject $customObject + ) { $this->customFieldValues = new ArrayCollection(); $this->contactReferences = new ArrayCollection(); $this->companyReferences = new ArrayCollection(); @@ -225,8 +237,8 @@ public static function loadMetadata(ORM\ClassMetadata $metadata): void $builder->addBigIntIdField(); $builder->addCategory(); - $builder->addField('name', Type::STRING); - $builder->addNullableField('language', Type::STRING, 'lang'); + $builder->addField('name', Types::STRING); + $builder->addNullableField('language', Types::STRING, 'lang'); } public static function loadValidatorMetadata(ClassMetadata $metadata): void @@ -242,14 +254,12 @@ public function populateFromArray(array $data): void { foreach ($data as $property => $value) { $camelCaseProperty = lcfirst(ucwords($property, '_')); + // $this->__set($camelCaseProperty, $value); $this->{$camelCaseProperty} = $value; } } - /** - * @return int|null - */ - public function getId() + public function getId(): int { return (int) $this->id; } @@ -257,7 +267,7 @@ public function getId() /** * @param string|null $name */ - public function setName($name) + public function setName($name): void { $this->isChanged('name', $name); $this->name = $name; @@ -295,7 +305,7 @@ public function getCategory() /** * @param Category|null $category */ - public function setCategory($category) + public function setCategory($category): void { $this->isChanged('category', $category ? $category : null); $this->category = $category; @@ -312,7 +322,7 @@ public function getLanguage() /** * @param string|null $language */ - public function setLanguage($language) + public function setLanguage($language): void { $this->isChanged('language', $language); $this->language = $language; @@ -347,7 +357,7 @@ public function generateNameForChildObject(string $entityType, int $entityId, Cu /** * @param CustomFieldValueInterface $customFieldValue */ - public function addCustomFieldValue($customFieldValue) + public function addCustomFieldValue($customFieldValue): void { if (null === $this->customFieldValues) { $this->customFieldValues = new ArrayCollection(); @@ -361,13 +371,13 @@ public function addCustomFieldValue($customFieldValue) * * @throws NotFoundException */ - public function setCustomFieldValues($values) + public function setCustomFieldValues($values): void { foreach ($values as $fieldName => $fieldValue) { try { $customFieldValue = $this->findCustomFieldValueForFieldAlias((string) $fieldName); $customFieldValue->setValue($fieldValue); - } catch (NotFoundException $e) { + } catch (NotFoundException) { $this->createNewCustomFieldValueByFieldAlias((string) $fieldName, $fieldValue); } } @@ -377,7 +387,7 @@ public function setCustomFieldValues($values) /** * Called when the custom field values are loaded from the database. */ - public function createFieldValuesSnapshot() + public function createFieldValuesSnapshot(): void { foreach ($this->customFieldValues as $customFieldValue) { $this->initialCustomFieldValues[$customFieldValue->getCustomField()->getId()] = $customFieldValue->getValue(); @@ -387,7 +397,7 @@ public function createFieldValuesSnapshot() /** * Called before CustomItemSave. It will record changes that happened for custom field values. */ - public function recordCustomFieldValueChanges() + public function recordCustomFieldValueChanges(): void { foreach ($this->customFieldValues as $customFieldValue) { $customFieldId = $customFieldValue->getCustomField()->getId(); @@ -446,11 +456,20 @@ public function setFieldValues(array $values): void try { $customFieldValue = $this->findCustomFieldValueForFieldId((int) $value['id']); $customFieldValue->setValue($value['value']); - } catch (NotFoundException $e) { + } catch (NotFoundException) { $this->createNewCustomFieldValueByFieldId((int) $value['id'], $value['value']); } } - $this->setDefaultValuesForMissingFields(); + + /** + * We could have done it in CustomItemDataPersister::persist() by + * injecting Symfony\Component\HttpFoundation\RequestStack and get request method. + * Since, CustomItem entity has multiple public methods which could lead to BC break. + * Hence, we are using $_SERVER here to get the request method type. + */ + if ('PATCH' !== $_SERVER['REQUEST_METHOD']) { + $this->setDefaultValuesForMissingFields(); + } } /** @@ -480,9 +499,10 @@ public function findCustomFieldValueForFieldId($customFieldId) */ public function findCustomFieldValueForFieldAlias($customFieldAlias) { - $filteredValues = $this->customFieldValues->filter(function (CustomFieldValueInterface $customFieldValue) use ($customFieldAlias) { - return $customFieldValue->getCustomField()->getAlias() === $customFieldAlias; - }); + $filteredValues = $this->customFieldValues->filter( + function (CustomFieldValueInterface $customFieldValue) use ($customFieldAlias): bool { + return $customFieldValue->getCustomField()->getAlias() === $customFieldAlias; + }); if (!$filteredValues->count()) { throw new NotFoundException("Custom Field Value for alias = {$customFieldAlias} was not found."); @@ -495,7 +515,7 @@ public function findChildCustomItem(): CustomItem { /** @var CustomItemXrefCustomItem|null $childXref */ $childXref = $this->getCustomItemLowerReferences() - ->filter(function (CustomItemXrefCustomItem $xref) { + ->filter(function (CustomItemXrefCustomItem $xref): bool { // The child custom item's object must have the same ID as the current custom item child object. return $xref->getCustomItemLinkedTo($this)->getCustomObject()->getMasterObject()->getId() === $this->getCustomObject()->getId(); })->first(); @@ -551,10 +571,10 @@ public function createNewCustomFieldValueByFieldAlias(string $customFieldAlias, public function setDefaultValuesForMissingFields(): void { - $this->getCustomObject()->getCustomFields()->map(function (CustomField $customField) { + $this->getCustomObject()->getCustomFields()->map(function (CustomField $customField): void { try { $this->findCustomFieldValueForFieldId($customField->getId()); - } catch (NotFoundException $e) { + } catch (NotFoundException) { $this->addCustomFieldValue( $customField->getTypeObject()->createValueEntity($customField, $this, $customField->getDefaultValue()) ); @@ -565,7 +585,7 @@ public function setDefaultValuesForMissingFields(): void /** * @param CustomItemXrefInterface $reference */ - public function addContactReference($reference) + public function addContactReference($reference): void { $this->contactReferences->add($reference); } @@ -581,7 +601,7 @@ public function getContactReferences() /** * @param CustomItemXrefInterface $reference */ - public function addCompanyReference($reference) + public function addCompanyReference($reference): void { $this->companyReferences->add($reference); } @@ -597,7 +617,7 @@ public function getCompanyReferences() /** * @param CustomItemXrefInterface $reference */ - public function addCustomItemReference($reference) + public function addCustomItemReference($reference): void { $this->customItemLowerReferences->add($reference); } @@ -612,16 +632,12 @@ public function getCustomItemLowerReferences() public function getRelationsByType(string $entityType): Collection { - switch ($entityType) { - case 'contact': - return $this->getContactReferences(); - case 'company': - return $this->getCompanyReferences(); - case 'customItem': - return $this->getCustomItemLowerReferences(); - default: - return new ArrayCollection([]); - } + return match ($entityType) { + 'contact' => $this->getContactReferences(), + 'company' => $this->getCompanyReferences(), + 'customItem' => $this->getCustomItemLowerReferences(), + default => new ArrayCollection([]), + }; } public function getUniqueHash(): ?string @@ -649,7 +665,7 @@ public function updateUniqueHash(): void $uniqueIdentifierFieldAlias = $uniqueIdentifierField->getAlias(); $uniqueHash[$uniqueIdentifierFieldAlias] = $this->findCustomFieldValueForFieldAlias($uniqueIdentifierFieldAlias)->getValue(); } - //To prevent creation of duplicates (in case of multiple unique ID fields) due to the order of key-values in the array + // To prevent creation of duplicates (in case of multiple unique ID fields) due to the order of key-values in the array // Eg. {id => 1, name => "Jay"} and {name => "Jay", id => 1} are duplicates ksort($uniqueHash); diff --git a/Entity/CustomItemExportScheduler.php b/Entity/CustomItemExportScheduler.php index 78eedde11..0f135048a 100644 --- a/Entity/CustomItemExportScheduler.php +++ b/Entity/CustomItemExportScheduler.php @@ -4,7 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\Entity; -use DateTimeImmutable; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping\ClassMetadata; use Mautic\CoreBundle\Doctrine\Mapping\ClassMetadataBuilder; @@ -19,7 +18,7 @@ class CustomItemExportScheduler private User $user; // Created by - private DateTimeImmutable $scheduledDateTime; + private \DateTimeImmutable $scheduledDateTime; private int $customObjectId; @@ -78,12 +77,12 @@ public function setUser(User $user): self return $this; } - public function getScheduledDateTime(): ?DateTimeImmutable + public function getScheduledDateTime(): ?\DateTimeImmutable { return $this->scheduledDateTime; } - public function setScheduledDateTime(DateTimeImmutable $scheduledDateTime): self + public function setScheduledDateTime(\DateTimeImmutable $scheduledDateTime): self { $this->scheduledDateTime = $scheduledDateTime; $this->addChange('scheduledDateTime', $scheduledDateTime); diff --git a/Entity/CustomItemXrefCompany.php b/Entity/CustomItemXrefCompany.php index 659f0b267..8d03163f3 100644 --- a/Entity/CustomItemXrefCompany.php +++ b/Entity/CustomItemXrefCompany.php @@ -4,10 +4,7 @@ namespace MauticPlugin\CustomObjectsBundle\Entity; -use DateTimeImmutable; -use DateTimeInterface; -use DateTimeZone; -use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use Mautic\CoreBundle\Doctrine\Mapping\ClassMetadataBuilder; use Mautic\LeadBundle\Entity\Company; @@ -17,26 +14,14 @@ class CustomItemXrefCompany implements CustomItemXrefInterface public const TABLE_NAME = 'custom_item_xref_company'; public const TABLE_ALIAS = 'CustomItemXrefCompany'; - /** - * @var Company - */ - private $company; - - /** - * @var CustomItem - */ - private $customItem; + private \DateTimeInterface $dateAdded; - /** - * @var DateTimeInterface - */ - private $dateAdded; - - public function __construct(CustomItem $customItem, Company $company, ?DateTimeInterface $dateAdded = null) - { - $this->customItem = $customItem; - $this->company = $company; - $this->dateAdded = $dateAdded ?: new DateTimeImmutable('now', new DateTimeZone('UTC')); + public function __construct( + private CustomItem $customItem, + private Company $company, + ?\DateTimeInterface $dateAdded = null + ) { + $this->dateAdded = $dateAdded ?: new \DateTimeImmutable('now', new \DateTimeZone('UTC')); } public static function loadMetadata(ORM\ClassMetadata $metadata): void @@ -58,7 +43,7 @@ public static function loadMetadata(ORM\ClassMetadata $metadata): void ->fetchExtraLazy() ->build(); - $builder->createField('dateAdded', Type::DATETIME) + $builder->createField('dateAdded', Types::DATETIME_MUTABLE) ->columnName('date_added') ->build(); } @@ -88,7 +73,7 @@ public function getLinkedEntity() } /** - * @return DateTimeInterface + * @return \DateTimeInterface */ public function getDateAdded() { diff --git a/Entity/CustomItemXrefContact.php b/Entity/CustomItemXrefContact.php index 6f6b88a71..0648a0ea7 100644 --- a/Entity/CustomItemXrefContact.php +++ b/Entity/CustomItemXrefContact.php @@ -4,10 +4,7 @@ namespace MauticPlugin\CustomObjectsBundle\Entity; -use DateTimeImmutable; -use DateTimeInterface; -use DateTimeZone; -use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use Mautic\CoreBundle\Doctrine\Mapping\ClassMetadataBuilder; use Mautic\LeadBundle\Entity\Lead; @@ -18,26 +15,14 @@ class CustomItemXrefContact implements CustomItemXrefInterface public const TABLE_NAME = 'custom_item_xref_contact'; public const TABLE_ALIAS = 'CustomItemXrefContact'; - /** - * @var Lead - */ - private $contact; - - /** - * @var CustomItem - */ - private $customItem; + private \DateTimeInterface $dateAdded; - /** - * @var DateTimeInterface - */ - private $dateAdded; - - public function __construct(CustomItem $customItem, Lead $contact, ?DateTimeInterface $dateAdded = null) - { - $this->customItem = $customItem; - $this->contact = $contact; - $this->dateAdded = $dateAdded ?: new DateTimeImmutable('now', new DateTimeZone('UTC')); + public function __construct( + private CustomItem $customItem, + private Lead $contact, + ?\DateTimeInterface $dateAdded = null + ) { + $this->dateAdded = $dateAdded ?: new \DateTimeImmutable('now', new \DateTimeZone('UTC')); } public static function loadMetadata(ORM\ClassMetadata $metadata): void @@ -60,7 +45,7 @@ public static function loadMetadata(ORM\ClassMetadata $metadata): void ->fetchExtraLazy() ->build(); - $builder->createField('dateAdded', Type::DATETIME) + $builder->createField('dateAdded', Types::DATETIME_MUTABLE) ->columnName('date_added') ->build(); } @@ -90,7 +75,7 @@ public function getLinkedEntity() } /** - * @return DateTimeInterface + * @return \DateTimeInterface */ public function getDateAdded() { diff --git a/Entity/CustomItemXrefCustomItem.php b/Entity/CustomItemXrefCustomItem.php index c447ca596..d60730d5b 100644 --- a/Entity/CustomItemXrefCustomItem.php +++ b/Entity/CustomItemXrefCustomItem.php @@ -4,14 +4,10 @@ namespace MauticPlugin\CustomObjectsBundle\Entity; -use DateTimeImmutable; -use DateTimeInterface; -use DateTimeZone; -use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use Mautic\CoreBundle\Doctrine\Mapping\ClassMetadataBuilder; use MauticPlugin\CustomObjectsBundle\Repository\CustomItemXrefCustomItemRepository; -use UnexpectedValueException; /** * As the {custom item} - {custom item} table can store the IDs both ways (higher - lower, lower - higher) @@ -25,28 +21,19 @@ class CustomItemXrefCustomItem implements CustomItemXrefInterface { public const TABLE_ALIAS = 'CustomItemXrefCustomItem'; - /** - * @var CustomItem - */ - private $customItemLower; + private CustomItem $customItemLower; - /** - * @var CustomItem - */ - private $customItemHigher; + private CustomItem $customItemHigher; - /** - * @var DateTimeInterface - */ - private $dateAdded; + private \DateTimeInterface $dateAdded; /** - * @throws UnexpectedValueException + * @throws \UnexpectedValueException */ - public function __construct(CustomItem $customItemA, CustomItem $customItemB, ?DateTimeInterface $dateAdded = null) + public function __construct(CustomItem $customItemA, CustomItem $customItemB, ?\DateTimeInterface $dateAdded = null) { if ($customItemA->getId() && $customItemA->getId() === $customItemB->getId()) { - throw new UnexpectedValueException('It is not possible to link identical custom item.'); + throw new \UnexpectedValueException('It is not possible to link identical custom item.'); } if ($customItemA->getId() < $customItemB->getId()) { @@ -57,7 +44,7 @@ public function __construct(CustomItem $customItemA, CustomItem $customItemB, ?D $this->customItemHigher = $customItemA; } - $this->dateAdded = $dateAdded ?: new DateTimeImmutable('now', new DateTimeZone('UTC')); + $this->dateAdded = $dateAdded ?: new \DateTimeImmutable('now', new \DateTimeZone('UTC')); } public static function loadMetadata(ORM\ClassMetadata $metadata): void @@ -80,7 +67,7 @@ public static function loadMetadata(ORM\ClassMetadata $metadata): void ->fetchExtraLazy() ->build(); - $builder->createField('dateAdded', Type::DATETIME) + $builder->createField('dateAdded', Types::DATETIME_MUTABLE) ->columnName('date_added') ->build(); } @@ -118,7 +105,7 @@ public function getCustomItemHigher() } /** - * @return DateTimeInterface + * @return \DateTimeInterface */ public function getDateAdded() { diff --git a/Entity/CustomItemXrefInterface.php b/Entity/CustomItemXrefInterface.php index 1f99dbb1c..8452d1bb8 100644 --- a/Entity/CustomItemXrefInterface.php +++ b/Entity/CustomItemXrefInterface.php @@ -4,8 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\Entity; -use DateTimeInterface; - interface CustomItemXrefInterface { /** @@ -19,7 +17,7 @@ public function getCustomItem(); public function getLinkedEntity(); /** - * @return DateTimeInterface + * @return \DateTimeInterface */ public function getDateAdded(); } diff --git a/Entity/CustomObject.php b/Entity/CustomObject.php index bc35327a6..8f2c8a210 100644 --- a/Entity/CustomObject.php +++ b/Entity/CustomObject.php @@ -8,7 +8,7 @@ use ApiPlatform\Core\Annotation\ApiResource; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; -use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping\JoinColumn; use Doctrine\ORM\Mapping\OneToOne; @@ -31,7 +31,6 @@ * }, * itemOperations={ * "get"={"security"="'custom_objects:custom_objects:view'"}, - * "put"={"security"="'custom_objects:custom_objects:edit'"}, * "patch"={"security"="'custom_objects:custom_objects:edit'"}, * "delete"={"security"="'custom_objects:custom_objects:delete'"} * }, @@ -51,7 +50,9 @@ class CustomObject extends FormEntity implements UniqueEntityInterface /** * @var int|null + * * @Groups({"custom_object:read"}) + * * @ApiProperty( * attributes={ * "openapi_context"={ @@ -66,66 +67,82 @@ class CustomObject extends FormEntity implements UniqueEntityInterface /** * @var string|null + * * @Groups({"custom_object:read", "custom_object:write"}) */ private $alias; /** * @var string|null + * * @Groups({"custom_object:read", "custom_object:write"}) */ private $nameSingular; /** * @var string|null + * * @Groups({"custom_object:read", "custom_object:write"}) */ private $namePlural; /** * @var string|null + * * @Groups({"custom_object:read", "custom_object:write"}) */ private $description; /** * @var string|null + * * @Groups({"custom_object:read", "custom_object:write"}) */ private $language; /** * @var Category|null + * * @Assert\Valid **/ private $category; /** * @var ArrayCollection + * * @Groups({"custom_object:read", "custom_object:write"}) */ private $customFields; /** * @var int|null + * * @Groups({"custom_object:read", "custom_object:write"}) */ private $type = self::TYPE_MASTER; /** * @var CustomObject|null + * * @OneToOne(targetEntity="CustomObject") + * * @JoinColumn(name="master_object", referencedColumnName="id") + * * @Groups({"custom_object:read", "custom_object:write"}) + * * @ApiProperty(readableLink=false, writableLink=false) */ private $masterObject; /** * @var CustomObject|null + * * @OneToOne(targetEntity="CustomObject") + * * @JoinColumn(name="relationship_object", referencedColumnName="id", onDelete="SET NULL") + * * @Groups({"custom_object:read", "custom_object:write"}) + * * @ApiProperty(readableLink=false, writableLink=false) */ private $relationshipObject; @@ -165,12 +182,12 @@ public static function loadMetadata(ORM\ClassMetadata $metadata): void $builder->addId(); $builder->addCategory(); - $builder->addField('alias', Type::STRING); - $builder->addNamedField('nameSingular', Type::STRING, 'name_singular'); - $builder->addNamedField('namePlural', Type::STRING, 'name_plural'); - $builder->addNullableField('description', Type::STRING, 'description'); - $builder->addNullableField('language', Type::STRING, 'lang'); - $builder->addNullableField('type', Type::INTEGER); + $builder->addField('alias', Types::STRING); + $builder->addNamedField('nameSingular', Types::STRING, 'name_singular'); + $builder->addNamedField('namePlural', Types::STRING, 'name_plural'); + $builder->addNullableField('description', Types::STRING, 'description'); + $builder->addNullableField('language', Types::STRING, 'lang'); + $builder->addNullableField('type', Types::INTEGER); $builder->createOneToOne('relationshipObject', CustomObject::class) ->addJoinColumn('relationship_object', 'id', true, false, 'SET NULL') @@ -221,7 +238,7 @@ public function getName() /** * @param string|null $alias */ - public function setAlias($alias) + public function setAlias($alias): void { $this->isChanged('alias', $alias); $this->alias = $alias; @@ -268,7 +285,7 @@ public function setRelationshipObject(?CustomObject $customObject): void /** * @param string|null $nameSingular */ - public function setNameSingular($nameSingular) + public function setNameSingular($nameSingular): void { $this->isChanged('nameSingular', $nameSingular); $this->nameSingular = $nameSingular; @@ -285,7 +302,7 @@ public function getNameSingular() /** * @param string|null $namePlural */ - public function setNamePlural($namePlural) + public function setNamePlural($namePlural): void { $this->isChanged('namePlural', $namePlural); $this->namePlural = $namePlural; @@ -302,7 +319,7 @@ public function getNamePlural() /** * @param string|null $description */ - public function setDescription($description) + public function setDescription($description): void { $this->isChanged('description', $description); $this->description = $description; @@ -327,7 +344,7 @@ public function getCategory() /** * @param Category|null $category */ - public function setCategory($category) + public function setCategory($category): void { $this->category = $category; } @@ -343,24 +360,24 @@ public function getLanguage() /** * @param string|null $language */ - public function setLanguage($language) + public function setLanguage($language): void { $this->isChanged('language', $language); $this->language = $language; } - public function addCustomField(CustomField $customField) + public function addCustomField(CustomField $customField): void { $customField->setCustomObject($this); $this->customFields->add($customField); } - public function setCustomFields(ArrayCollection $customFields) + public function setCustomFields(ArrayCollection $customFields): void { $this->customFields = $customFields; } - public function removeCustomField(CustomField $customField) + public function removeCustomField(CustomField $customField): void { $this->customFields->removeElement($customField); $customField->setCustomObject(); @@ -390,13 +407,13 @@ public function getCustomFieldByOrder($order) } } - throw new NotFoundException("Custom field with order index '${order}' not found."); + throw new NotFoundException('Custom field with order index '.$order.' not found.'); } public function getPublishedFields(): Collection { return $this->customFields->filter( - function (CustomField $customField) { + function (CustomField $customField): bool { return $customField->isPublished(); } ); @@ -405,7 +422,7 @@ function (CustomField $customField) { public function getFieldsShowInCustomObjectDetailList(): Collection { return $this->customFields->filter( - function (CustomField $customField) { + function (CustomField $customField): bool { return $customField->isShowInCustomObjectDetailList(); } ); @@ -414,7 +431,7 @@ function (CustomField $customField) { public function getFieldsShowInContactDetailList(): Collection { return $this->customFields->filter( - function (CustomField $customField) { + function (CustomField $customField): bool { return $customField->isShowInContactDetailList(); } ); @@ -423,15 +440,14 @@ function (CustomField $customField) { public function getUniqueIdentifierFields(): ?ArrayCollection { return $this->customFields->filter( - static fn(CustomField $customField) => $customField->getIsUniqueIdentifier() + static fn (CustomField $customField) => $customField->getIsUniqueIdentifier() ); } - /** * Called when the custom fields are loaded from the database. */ - public function createFieldsSnapshot() + public function createFieldsSnapshot(): void { foreach ($this->customFields as $customField) { $this->initialCustomFields[$customField->getId()] = $customField->toArray(); @@ -441,7 +457,7 @@ public function createFieldsSnapshot() /** * Called before CustomObjectSave. It will record changes that happened for custom fields. */ - public function recordCustomFieldChanges() + public function recordCustomFieldChanges(): void { $existingFields = []; foreach ($this->customFields as $i => $customField) { diff --git a/Event/CustomItemEvent.php b/Event/CustomItemEvent.php index 152ff9ee6..e44334fbe 100644 --- a/Event/CustomItemEvent.php +++ b/Event/CustomItemEvent.php @@ -5,24 +5,12 @@ namespace MauticPlugin\CustomObjectsBundle\Event; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; -use Symfony\Component\EventDispatcher\Event; +use Symfony\Contracts\EventDispatcher\Event; class CustomItemEvent extends Event { - /** - * @var CustomItem - */ - private $customItem; - - /** - * @var bool - */ - private $isNew; - - public function __construct(CustomItem $customItem, bool $isNew = false) + public function __construct(private CustomItem $customItem, private bool $isNew = false) { - $this->customItem = $customItem; - $this->isNew = $isNew; } public function getCustomItem(): CustomItem diff --git a/Event/CustomItemExportSchedulerEvent.php b/Event/CustomItemExportSchedulerEvent.php index d2164e986..0ac3da983 100644 --- a/Event/CustomItemExportSchedulerEvent.php +++ b/Event/CustomItemExportSchedulerEvent.php @@ -5,17 +5,14 @@ namespace MauticPlugin\CustomObjectsBundle\Event; use MauticPlugin\CustomObjectsBundle\Entity\CustomItemExportScheduler; -use Symfony\Component\EventDispatcher\Event; +use Symfony\Contracts\EventDispatcher\Event; class CustomItemExportSchedulerEvent extends Event { - private CustomItemExportScheduler $customItemExportScheduler; - private string $filePath; - public function __construct(CustomItemExportScheduler $customItemExportScheduler) + public function __construct(private CustomItemExportScheduler $customItemExportScheduler) { - $this->customItemExportScheduler = $customItemExportScheduler; } public function getCustomItemExportScheduler(): CustomItemExportScheduler diff --git a/Event/CustomItemListDbalQueryEvent.php b/Event/CustomItemListDbalQueryEvent.php index 02c74d38c..fd38ee435 100644 --- a/Event/CustomItemListDbalQueryEvent.php +++ b/Event/CustomItemListDbalQueryEvent.php @@ -6,24 +6,12 @@ use Doctrine\DBAL\Query\QueryBuilder; use MauticPlugin\CustomObjectsBundle\DTO\TableConfig; -use Symfony\Component\EventDispatcher\Event; +use Symfony\Contracts\EventDispatcher\Event; class CustomItemListDbalQueryEvent extends Event { - /** - * @var QueryBuilder - */ - private $queryBuilder; - - /** - * @var TableConfig - */ - private $tableConfig; - - public function __construct(QueryBuilder $queryBuilder, TableConfig $tableConfig) + public function __construct(private QueryBuilder $queryBuilder, private TableConfig $tableConfig) { - $this->queryBuilder = $queryBuilder; - $this->tableConfig = $tableConfig; } public function getQueryBuilder(): QueryBuilder diff --git a/Event/CustomItemListQueryEvent.php b/Event/CustomItemListQueryEvent.php index fb6943993..78f06e662 100644 --- a/Event/CustomItemListQueryEvent.php +++ b/Event/CustomItemListQueryEvent.php @@ -6,24 +6,14 @@ use Doctrine\ORM\QueryBuilder; use MauticPlugin\CustomObjectsBundle\DTO\TableConfig; -use Symfony\Component\EventDispatcher\Event; +use Symfony\Contracts\EventDispatcher\Event; class CustomItemListQueryEvent extends Event { - /** - * @var QueryBuilder - */ - private $queryBuilder; - - /** - * @var TableConfig - */ - private $tableConfig; - - public function __construct(QueryBuilder $queryBuilder, TableConfig $tableConfig) - { - $this->queryBuilder = $queryBuilder; - $this->tableConfig = $tableConfig; + public function __construct( + private QueryBuilder $queryBuilder, + private TableConfig $tableConfig + ) { } public function getQueryBuilder(): QueryBuilder diff --git a/Event/CustomItemXrefEntityDiscoveryEvent.php b/Event/CustomItemXrefEntityDiscoveryEvent.php index b55024fb5..8e6d4ce81 100644 --- a/Event/CustomItemXrefEntityDiscoveryEvent.php +++ b/Event/CustomItemXrefEntityDiscoveryEvent.php @@ -6,35 +6,17 @@ use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Entity\CustomItemXrefInterface; -use Symfony\Component\EventDispatcher\Event; +use Symfony\Contracts\EventDispatcher\Event; class CustomItemXrefEntityDiscoveryEvent extends Event { - /** - * @var CustomItem - */ - private $customItem; + private ?CustomItemXrefInterface $customItemXrefEntity = null; - /** - * @var string - */ - private $entityType; - - /** - * @var int - */ - private $entityId; - - /** - * @var CustomItemXrefInterface|null - */ - private $customItemXrefEntity; - - public function __construct(CustomItem $customItem, string $entityType, int $entityId) - { - $this->customItem = $customItem; - $this->entityType = $entityType; - $this->entityId = $entityId; + public function __construct( + private CustomItem $customItem, + private string $entityType, + private int $entityId + ) { } public function getCustomItem(): CustomItem @@ -57,9 +39,6 @@ public function setXrefEntity(CustomItemXrefInterface $customItemXrefEntity): vo $this->customItemXrefEntity = $customItemXrefEntity; } - /** - * @return ?CustomItemXrefInterface - */ public function getXrefEntity(): ?CustomItemXrefInterface { return $this->customItemXrefEntity; diff --git a/Event/CustomItemXrefEntityEvent.php b/Event/CustomItemXrefEntityEvent.php index 3981c9fb4..e7195978c 100644 --- a/Event/CustomItemXrefEntityEvent.php +++ b/Event/CustomItemXrefEntityEvent.php @@ -5,18 +5,12 @@ namespace MauticPlugin\CustomObjectsBundle\Event; use MauticPlugin\CustomObjectsBundle\Entity\CustomItemXrefInterface; -use Symfony\Component\EventDispatcher\Event; +use Symfony\Contracts\EventDispatcher\Event; class CustomItemXrefEntityEvent extends Event { - /** - * @var CustomItemXrefInterface - */ - private $xRef; - - public function __construct(CustomItemXrefInterface $xRef) + public function __construct(private CustomItemXrefInterface $xRef) { - $this->xRef = $xRef; } public function getXref(): CustomItemXrefInterface diff --git a/Event/CustomObjectEvent.php b/Event/CustomObjectEvent.php index d37f1e43d..7e8acb8f9 100644 --- a/Event/CustomObjectEvent.php +++ b/Event/CustomObjectEvent.php @@ -6,34 +6,16 @@ use Mautic\CoreBundle\Service\FlashBag; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; -use Symfony\Component\EventDispatcher\Event; +use Symfony\Contracts\EventDispatcher\Event; class CustomObjectEvent extends Event { - /** - * @var CustomObject - */ - private $customObject; + private string $message; - /** - * @var bool - */ - private $isNew; + private FlashBag $flashBag; - /** - * @var string - */ - private $message; - - /** - * @var FlashBag - */ - private $flashBag; - - public function __construct(CustomObject $customObject, bool $isNew = false) + public function __construct(private CustomObject $customObject, private bool $isNew = false) { - $this->customObject = $customObject; - $this->isNew = $isNew; } public function getCustomObject(): CustomObject diff --git a/Event/CustomObjectListFormatEvent.php b/Event/CustomObjectListFormatEvent.php index 257c95941..ef2433240 100644 --- a/Event/CustomObjectListFormatEvent.php +++ b/Event/CustomObjectListFormatEvent.php @@ -4,34 +4,16 @@ namespace MauticPlugin\CustomObjectsBundle\Event; -use Symfony\Component\EventDispatcher\Event; +use Symfony\Contracts\EventDispatcher\Event; class CustomObjectListFormatEvent extends Event { - /** - * @var array - */ - private $customObjectValues; + private string $formattedString = ''; - /** - * @var string - */ - private $format; + private bool $hasBeenFormatted = false; - /** - * @var string - */ - private $formattedString = ''; - - /** - * @var bool - */ - private $hasBeenFormatted = false; - - public function __construct(array $customObjectValues, string $format = 'default') + public function __construct(private array $customObjectValues, private string $format = 'default') { - $this->customObjectValues = $customObjectValues; - $this->format = $format; } public function getCustomObjectValues(): array diff --git a/EventListener/ApiSubscriber.php b/EventListener/ApiSubscriber.php index 472846d1f..7125f145d 100644 --- a/EventListener/ApiSubscriber.php +++ b/EventListener/ApiSubscriber.php @@ -4,9 +4,9 @@ namespace MauticPlugin\CustomObjectsBundle\EventListener; -use InvalidArgumentException; use Mautic\ApiBundle\ApiEvents; use Mautic\ApiBundle\Event\ApiEntityEvent; +use Mautic\LeadBundle\Controller\Api\LeadApiController; use Mautic\LeadBundle\Entity\Lead; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; @@ -21,29 +21,11 @@ class ApiSubscriber implements EventSubscriberInterface { - /** - * @var ConfigProvider - */ - private $configProvider; - - /** - * @var CustomObjectModel - */ - private $customObjectModel; - - /** - * @var CustomItemModel - */ - private $customItemModel; - public function __construct( - ConfigProvider $configProvider, - CustomObjectModel $customObjectModel, - CustomItemModel $customItemModel + private ConfigProvider $configProvider, + private CustomObjectModel $customObjectModel, + private CustomItemModel $customItemModel ) { - $this->configProvider = $configProvider; - $this->customObjectModel = $customObjectModel; - $this->customItemModel = $customItemModel; } /** @@ -78,7 +60,7 @@ private function saveCustomItems(ApiEntityEvent $event, bool $dryRun = false): v $event->getEntityRequestParameters(), $event->getRequest() ); - } catch (InvalidArgumentException $e) { + } catch (\InvalidArgumentException) { return; } @@ -111,20 +93,20 @@ private function saveCustomItems(ApiEntityEvent $event, bool $dryRun = false): v * * @return mixed[] * - * @throws InvalidArgumentException + * @throws \InvalidArgumentException */ private function getCustomObjectsFromContactCreateRequest(array $entityRequestParameters, Request $request): array { if (!$this->configProvider->pluginIsEnabled()) { - throw new InvalidArgumentException('Custom Object Plugin is disabled'); + throw new \InvalidArgumentException('Custom Object Plugin is disabled'); } - if (1 !== preg_match('/^\/api\/contacts\/.*(new|edit)/', $request->getPathInfo())) { - throw new InvalidArgumentException('Not a API request we care about'); + if (1 !== preg_match('~^'.preg_quote(LeadApiController::class, '~').'(::|:)(new|edit)(Entity|Entities)Action$~i', $request->attributes->get('_controller'))) { + throw new \InvalidArgumentException('Not a API request we care about'); } if (empty($entityRequestParameters['customObjects']['data']) || !is_array($entityRequestParameters['customObjects']['data'])) { - throw new InvalidArgumentException('The request payload does not contain any custom items in the customObjects attribute.'); + throw new \InvalidArgumentException('The request payload does not contain any custom items in the customObjects attribute.'); } return $entityRequestParameters['customObjects']; @@ -133,7 +115,7 @@ private function getCustomObjectsFromContactCreateRequest(array $entityRequestPa /** * @param mixed[] $customObjectData * - * @throws NotFoundException|InvalidArgumentException + * @throws NotFoundException|\InvalidArgumentException */ private function getCustomObject(array $customObjectData): CustomObject { @@ -144,7 +126,7 @@ private function getCustomObject(array $customObjectData): CustomObject return $this->customObjectModel->fetchEntityByAlias($customObjectData['alias']); } - throw new InvalidArgumentException('customObject[data][][id] or customObject[data][][alias] must exist in the request to identify a Custom Object.', Response::HTTP_BAD_REQUEST); + throw new \InvalidArgumentException('customObject[data][][id] or customObject[data][][alias] must exist in the request to identify a Custom Object.', Response::HTTP_BAD_REQUEST); } catch (NotFoundException $e) { throw new NotFoundException($e->getMessage(), Response::HTTP_BAD_REQUEST, $e); } diff --git a/EventListener/AssetsSubscriber.php b/EventListener/AssetsSubscriber.php index 997431a27..0b5e7e264 100644 --- a/EventListener/AssetsSubscriber.php +++ b/EventListener/AssetsSubscriber.php @@ -4,31 +4,19 @@ namespace MauticPlugin\CustomObjectsBundle\EventListener; -use Mautic\CoreBundle\Templating\Helper\AssetsHelper; +use Mautic\CoreBundle\Twig\Helper\AssetsHelper; use MauticPlugin\CustomObjectsBundle\Provider\ConfigProvider; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\KernelEvents; class AssetsSubscriber implements EventSubscriberInterface { - /** - * @var AssetsHelper - */ - private $assetHelper; - - /** - * @var ConfigProvider - */ - private $configProvider; - public function __construct( - AssetsHelper $assetHelper, - ConfigProvider $configProvider + private AssetsHelper $assetHelper, + private ConfigProvider $configProvider ) { - $this->assetHelper = $assetHelper; - $this->configProvider = $configProvider; } /** @@ -41,9 +29,9 @@ public static function getSubscribedEvents(): array ]; } - public function loadAssets(GetResponseEvent $event): void + public function loadAssets(RequestEvent $event): void { - if ($this->configProvider->pluginIsEnabled() && $event->isMasterRequest() && $this->isMauticAdministrationPage($event->getRequest())) { + if ($this->configProvider->pluginIsEnabled() && $event->isMainRequest() && $this->isMauticAdministrationPage($event->getRequest())) { $this->assetHelper->addScript('plugins/CustomObjectsBundle/Assets/js/custom-objects.js'); $this->assetHelper->addScript('plugins/CustomObjectsBundle/Assets/js/co-form.js'); $this->assetHelper->addStylesheet('plugins/CustomObjectsBundle/Assets/css/custom-objects.css'); diff --git a/EventListener/AuditLogSubscriber.php b/EventListener/AuditLogSubscriber.php index 8290ca51b..1dc86ebc0 100644 --- a/EventListener/AuditLogSubscriber.php +++ b/EventListener/AuditLogSubscriber.php @@ -15,20 +15,10 @@ class AuditLogSubscriber implements EventSubscriberInterface { - /** - * @var AuditLogModel - */ - private $auditLogModel; - - /** - * @var IpLookupHelper - */ - private $ipLookupHelper; - - public function __construct(AuditLogModel $auditLogModel, IpLookupHelper $ipLookupHelper) - { - $this->auditLogModel = $auditLogModel; - $this->ipLookupHelper = $ipLookupHelper; + public function __construct( + private AuditLogModel $auditLogModel, + private IpLookupHelper $ipLookupHelper + ) { } /** diff --git a/EventListener/CampaignSubscriber.php b/EventListener/CampaignSubscriber.php index 706ff2670..01e437e79 100644 --- a/EventListener/CampaignSubscriber.php +++ b/EventListener/CampaignSubscriber.php @@ -5,7 +5,7 @@ namespace MauticPlugin\CustomObjectsBundle\EventListener; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\DBALException; +use Doctrine\DBAL\Exception; use Doctrine\DBAL\Query\QueryBuilder; use Mautic\CampaignBundle\CampaignEvents; use Mautic\CampaignBundle\Event\CampaignBuilderEvent; @@ -16,7 +16,6 @@ use MauticPlugin\CustomObjectsBundle\CustomItemEvents; use MauticPlugin\CustomObjectsBundle\Entity\CustomField; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; -use MauticPlugin\CustomObjectsBundle\Exception\InvalidArgumentException; use MauticPlugin\CustomObjectsBundle\Exception\InvalidSegmentFilterException; use MauticPlugin\CustomObjectsBundle\Exception\NotFoundException; use MauticPlugin\CustomObjectsBundle\Form\Type\CampaignActionLinkType; @@ -31,71 +30,23 @@ use MauticPlugin\CustomObjectsBundle\Segment\Query\Filter\QueryFilterFactory; use MauticPlugin\CustomObjectsBundle\Segment\Query\UnionQueryContainer; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class CampaignSubscriber implements EventSubscriberInterface { use DbalQueryTrait; use QueryBuilderManipulatorTrait; - /** - * @var TranslatorInterface - */ - private $translator; - - /** - * @var CustomFieldModel - */ - private $customFieldModel; - - /** - * @var CustomObjectModel - */ - private $customObjectModel; - - /** - * @var CustomItemModel - */ - private $customItemModel; - - /** - * @var ConfigProvider - */ - private $configProvider; - - /** - * @var QueryFilterHelper - */ - private $queryFilterHelper; - - /** - * @var QueryFilterFactory - */ - private $queryFilterFactory; - - /** - * @var Connection - */ - private $connection; - public function __construct( - CustomFieldModel $customFieldModel, - CustomObjectModel $customObjectModel, - CustomItemModel $customItemModel, - TranslatorInterface $translator, - ConfigProvider $configProvider, - QueryFilterHelper $queryFilterHelper, - QueryFilterFactory $queryFilterFactory, - Connection $connection + private CustomFieldModel $customFieldModel, + private CustomObjectModel $customObjectModel, + private CustomItemModel $customItemModel, + private TranslatorInterface $translator, + private ConfigProvider $configProvider, + private QueryFilterHelper $queryFilterHelper, + private QueryFilterFactory $queryFilterFactory, + private Connection $connection ) { - $this->customFieldModel = $customFieldModel; - $this->customObjectModel = $customObjectModel; - $this->customItemModel = $customItemModel; - $this->translator = $translator; - $this->configProvider = $configProvider; - $this->queryFilterHelper = $queryFilterHelper; - $this->queryFilterFactory = $queryFilterFactory; - $this->connection = $connection; } /** @@ -140,8 +91,8 @@ public function onCampaignBuild(CampaignBuilderEvent $event): void 'description' => $this->translator->trans('custom.item.events.field.value_descr', ['%customObject%' => $customObject->getNameSingular()]), 'eventName' => CustomItemEvents::ON_CAMPAIGN_TRIGGER_CONDITION, 'formType' => CampaignConditionFieldValueType::class, - 'formTheme' => 'CustomObjectsBundle:FormTheme\FieldValueCondition', - 'formTypeOptions' => ['customObject' => $customObject], + 'formTheme' => '@MauticForm/FormTheme/FieldValueCondition/_campaignevent_form_field_value_widget.html.twig', + 'formTypeOptions' => ['customObjectId' => $customObject->getId()], ]); } } @@ -165,7 +116,7 @@ public function onCampaignTriggerAction(CampaignExecutionEvent $event): void try { $customItem = $this->customItemModel->fetchEntity($linkCustomItemId); $this->customItemModel->linkEntity($customItem, 'contact', $contactId); - } catch (NotFoundException $e) { + } catch (NotFoundException) { // Do nothing if the custom item doesn't exist anymore. } } @@ -174,7 +125,7 @@ public function onCampaignTriggerAction(CampaignExecutionEvent $event): void try { $customItem = $this->customItemModel->fetchEntity($unlinkCustomItemId); $this->customItemModel->unlinkEntity($customItem, 'contact', $contactId); - } catch (NotFoundException $e) { + } catch (NotFoundException) { // Do nothing if the custom item doesn't exist anymore. } } @@ -182,9 +133,7 @@ public function onCampaignTriggerAction(CampaignExecutionEvent $event): void /** * @throws NotFoundException - * @throws DBALException - * @throws InvalidArgumentException - * @throws InvalidSegmentFilterException + * @throws InvalidSegmentFilterException|Exception */ public function onCampaignTriggerCondition(CampaignExecutionEvent $event): void { @@ -206,7 +155,7 @@ public function onCampaignTriggerCondition(CampaignExecutionEvent $event): void try { $customField = $this->customFieldModel->fetchEntity((int) $event->getConfig()['field']); - } catch (NotFoundException $e) { + } catch (NotFoundException) { $event->setResult(false); return; @@ -221,14 +170,14 @@ public function onCampaignTriggerCondition(CampaignExecutionEvent $event): void ); if ($innerQueryBuilder instanceof UnionQueryContainer) { - $this->applyParamsToMultipleQueries($innerQueryBuilder, $queryAlias, $contact, $operator); + $this->applyParamsToMultipleQueries($innerQueryBuilder, $queryAlias, $contact); } else { - $this->applyParamsToQuery($innerQueryBuilder, $queryAlias, $contact, $operator); + $this->applyParamsToQuery($innerQueryBuilder, $queryAlias, $contact); } $queryBuilder = $this->buildOuterQuery($innerQueryBuilder, $queryAlias); - $customItemId = $this->executeSelect($queryBuilder)->fetchColumn(); + $customItemId = $this->executeSelect($queryBuilder)->fetchOne(); if ($customItemId) { $event->setChannel('customItem', $customItemId); @@ -238,14 +187,14 @@ public function onCampaignTriggerCondition(CampaignExecutionEvent $event): void } } - private function applyParamsToMultipleQueries(UnionQueryContainer $unionQueryContainer, string $queryAlias, Lead $contact, string $operator): void + private function applyParamsToMultipleQueries(UnionQueryContainer $unionQueryContainer, string $queryAlias, Lead $contact): void { foreach ($unionQueryContainer as $segmentQueryBuilder) { - $this->applyParamsToQuery($segmentQueryBuilder, $queryAlias, $contact, $operator); + $this->applyParamsToQuery($segmentQueryBuilder, $queryAlias, $contact); } } - private function applyParamsToQuery(SegmentQueryBuilder $innerQueryBuilder, string $queryAlias, Lead $contact, string $operator): void + private function applyParamsToQuery(SegmentQueryBuilder $innerQueryBuilder, string $queryAlias, Lead $contact): void { $innerQueryBuilder->select($queryAlias.'_value.custom_item_id'); $this->queryFilterHelper->addContactIdRestriction($innerQueryBuilder, $queryAlias, (int) $contact->getId()); diff --git a/EventListener/ContactSubscriber.php b/EventListener/ContactSubscriber.php index 16e27da98..24cf17c35 100644 --- a/EventListener/ContactSubscriber.php +++ b/EventListener/ContactSubscriber.php @@ -7,54 +7,28 @@ use Doctrine\ORM\EntityManager; use Mautic\LeadBundle\Entity\LeadEventLog; use Mautic\LeadBundle\Entity\LeadEventLogRepository; +use Mautic\LeadBundle\Event\LeadMergeEvent; use Mautic\LeadBundle\Event\LeadTimelineEvent; use Mautic\LeadBundle\LeadEvents; +use MauticPlugin\CustomObjectsBundle\Entity\CustomItemXrefContact; use MauticPlugin\CustomObjectsBundle\Exception\NotFoundException; use MauticPlugin\CustomObjectsBundle\Model\CustomItemModel; use MauticPlugin\CustomObjectsBundle\Provider\ConfigProvider; use MauticPlugin\CustomObjectsBundle\Provider\CustomItemRouteProvider; +use MauticPlugin\CustomObjectsBundle\Repository\CustomItemXrefContactRepository; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class ContactSubscriber implements EventSubscriberInterface { - /** - * @var TranslatorInterface - */ - private $translator; - - /** - * @var EntityManager - */ - private $entityManager; - - /** - * @var CustomItemRouteProvider - */ - private $routeProvider; - - /** - * @var CustomItemModel - */ - private $customItemModel; - - /** - * @var ConfigProvider - */ - private $configProvider; - public function __construct( - EntityManager $entityManager, - TranslatorInterface $translator, - CustomItemRouteProvider $routeProvider, - CustomItemModel $customItemModel, - ConfigProvider $configProvider + private EntityManager $entityManager, + private TranslatorInterface $translator, + private CustomItemRouteProvider $routeProvider, + private CustomItemModel $customItemModel, + private ConfigProvider $configProvider, + private CustomItemXrefContactRepository $customItemXrefContactRepository ) { - $this->entityManager = $entityManager; - $this->translator = $translator; - $this->routeProvider = $routeProvider; - $this->customItemModel = $customItemModel; - $this->configProvider = $configProvider; } /** @@ -64,6 +38,7 @@ public static function getSubscribedEvents(): array { return [ LeadEvents::TIMELINE_ON_GENERATE => 'onTimelineGenerate', + LeadEvents::LEAD_PRE_MERGE => 'onCongactPreMerge', ]; } @@ -99,6 +74,43 @@ public function onTimelineGenerate(LeadTimelineEvent $event): void } } + /** + * Moves the custom item links from the loser to the victor if they don't exist in the victor's list. + * Removes the remaining links from the loser. + */ + public function onCongactPreMerge(LeadMergeEvent $event): void + { + if (!$this->configProvider->pluginIsEnabled()) { + return; + } + + $loser = $event->getLoser(); + + /** @var CustomItemXrefContact[] $loserLinks */ + $loserLinks = $this->customItemXrefContactRepository->findBy(['contact' => $loser]); + + if (!$loserLinks) { + return; + } + + $victor = $event->getVictor(); + + /** @var CustomItemXrefContact[] $victorLinks */ + $victorLinks = $this->customItemXrefContactRepository->findBy(['contact' => $victor]); + $victorItemsIds = array_map(fn (CustomItemXrefContact $link) => $link->getCustomItem()->getId(), $victorLinks); + + foreach ($loserLinks as $loserLink) { + if (!in_array($loserLink->getCustomItem()->getId(), $victorItemsIds)) { + $newLink = new CustomItemXrefContact($loserLink->getCustomItem(), $victor, $loserLink->getDateAdded()); + $this->entityManager->persist($newLink); + } + + $this->entityManager->remove($loserLink); + } + + $this->entityManager->flush(); + } + /** * @return mixed[] */ @@ -130,7 +142,7 @@ private function addLinkTimelineEntry(LeadTimelineEvent $event, string $eventTyp 'label' => $this->translator->trans("custom.item.{$action}.event", ['%customItemName%' => $customItem->getName()]), 'href' => $this->routeProvider->buildViewRoute($customItem->getCustomObject()->getId(), $customItem->getId()), ]; - } catch (NotFoundException $e) { + } catch (NotFoundException) { $eventLabel = $this->translator->trans("custom.item.{$action}.event.not.found", ['%customItemId%' => $link['object_id']]); } $event->addEvent([ @@ -142,7 +154,7 @@ private function addLinkTimelineEntry(LeadTimelineEvent $event, string $eventTyp 'icon' => "fa-{$action}", 'extra' => $link, 'contactId' => $link['lead_id'], - 'contentTemplate' => 'CustomObjectsBundle:SubscribedEvents\Timeline:link.html.php', + 'contentTemplate' => '@CustomObjects/SubscribedEvents/Timeline/link.html.twig', ]); } } diff --git a/EventListener/ContactTabSubscriber.php b/EventListener/ContactTabSubscriber.php index 70ec02190..d2f78f032 100644 --- a/EventListener/ContactTabSubscriber.php +++ b/EventListener/ContactTabSubscriber.php @@ -14,59 +14,23 @@ use MauticPlugin\CustomObjectsBundle\Provider\SessionProviderFactory; use MauticPlugin\CustomObjectsBundle\Repository\CustomItemRepository; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class ContactTabSubscriber implements EventSubscriberInterface { - /** - * @var TranslatorInterface - */ - private $translator; - - /** - * @var CustomObjectModel - */ - private $customObjectModel; - - /** - * @var CustomItemRepository - */ - private $customItemRepository; - - /** - * @var ConfigProvider - */ - private $configProvider; - - /** - * @var CustomItemRouteProvider - */ - private $customItemRouteProvider; - /** * @var CustomObject[] */ - private $customObjects = []; - - /** - * @var SessionProviderFactory - */ - private $sessionProviderFactory; + private array $customObjects = []; public function __construct( - CustomObjectModel $customObjectModel, - CustomItemRepository $customItemRepository, - ConfigProvider $configProvider, - TranslatorInterface $translator, - CustomItemRouteProvider $customItemRouteProvider, - SessionProviderFactory $sessionProviderFactory + private CustomObjectModel $customObjectModel, + private CustomItemRepository $customItemRepository, + private ConfigProvider $configProvider, + private TranslatorInterface $translator, + private CustomItemRouteProvider $customItemRouteProvider, + private SessionProviderFactory $sessionProviderFactory ) { - $this->customObjectModel = $customObjectModel; - $this->customItemRepository = $customItemRepository; - $this->configProvider = $configProvider; - $this->translator = $translator; - $this->customItemRouteProvider = $customItemRouteProvider; - $this->sessionProviderFactory = $sessionProviderFactory; } /** @@ -85,7 +49,7 @@ public function injectTabs(CustomContentEvent $event): void return; } - if ($event->checkContext('MauticLeadBundle:Lead:lead.html.php', 'tabs')) { + if ($event->checkContext('@MauticLead/Lead/lead.html.twig', 'tabs')) { $vars = $event->getVars(); $objects = $this->customObjectModel->getMasterCustomObjects(); @@ -100,13 +64,13 @@ public function injectTabs(CustomContentEvent $event): void 'tabId' => "custom-object-{$object->getId()}", ]; - $event->addTemplate('CustomObjectsBundle:SubscribedEvents/Tab:link.html.php', $data); + $event->addTemplate('@CustomObjects/SubscribedEvents/Tab/link.html.twig', $data); } - $event->addTemplate('CustomObjectsBundle:SubscribedEvents/Tab:modal.html.php'); + $event->addTemplate('@CustomObjects/SubscribedEvents/Tab/modal.html.twig'); } - if ($event->checkContext('MauticLeadBundle:Lead:lead.html.php', 'tabs.content')) { + if ($event->checkContext('@MauticLead/Lead/lead.html.twig', 'tabs.content')) { $vars = $event->getVars(); $objects = $this->getCustomObjects(); @@ -133,7 +97,7 @@ public function injectTabs(CustomContentEvent $event): void 'namespace' => $sessionProvider->getNamespace(), ]; - $event->addTemplate('CustomObjectsBundle:SubscribedEvents/Tab:content.html.php', $data); + $event->addTemplate('@CustomObjects/SubscribedEvents/Tab/content.html.twig', $data); } } } diff --git a/EventListener/CustomFieldPostLoadSubscriber.php b/EventListener/CustomFieldPostLoadSubscriber.php index db8be307b..5f3b6699b 100644 --- a/EventListener/CustomFieldPostLoadSubscriber.php +++ b/EventListener/CustomFieldPostLoadSubscriber.php @@ -5,8 +5,8 @@ namespace MauticPlugin\CustomObjectsBundle\EventListener; use Doctrine\Common\EventSubscriber; -use Doctrine\ORM\Event\LifecycleEventArgs; use Doctrine\ORM\Events; +use Doctrine\Persistence\Event\LifecycleEventArgs; use MauticPlugin\CustomObjectsBundle\Entity\CustomField; use MauticPlugin\CustomObjectsBundle\Exception\NotFoundException; use MauticPlugin\CustomObjectsBundle\Provider\CustomFieldTypeProvider; @@ -16,14 +16,8 @@ */ class CustomFieldPostLoadSubscriber implements EventSubscriber { - /** - * @var CustomFieldTypeProvider - */ - private $customFieldTypeProvider; - - public function __construct(CustomFieldTypeProvider $customFieldTypeProvider) + public function __construct(private CustomFieldTypeProvider $customFieldTypeProvider) { - $this->customFieldTypeProvider = $customFieldTypeProvider; } /** diff --git a/EventListener/CustomFieldPreSaveSubscriber.php b/EventListener/CustomFieldPreSaveSubscriber.php index c168d7ff1..511e98035 100644 --- a/EventListener/CustomFieldPreSaveSubscriber.php +++ b/EventListener/CustomFieldPreSaveSubscriber.php @@ -16,17 +16,11 @@ */ class CustomFieldPreSaveSubscriber implements EventSubscriberInterface { - /** - * @var CustomFieldOptionModel - */ - private $customFieldOptionModel; - /** * CustomFieldPreSaveSubscriber constructor. */ - public function __construct(CustomFieldOptionModel $customFieldOptionModel) + public function __construct(private CustomFieldOptionModel $customFieldOptionModel) { - $this->customFieldOptionModel = $customFieldOptionModel; } /** diff --git a/EventListener/CustomItemButtonSubscriber.php b/EventListener/CustomItemButtonSubscriber.php index 5b2fdb61e..9ce55717f 100644 --- a/EventListener/CustomItemButtonSubscriber.php +++ b/EventListener/CustomItemButtonSubscriber.php @@ -6,39 +6,21 @@ use Mautic\CoreBundle\CoreEvents; use Mautic\CoreBundle\Event\CustomButtonEvent; -use Mautic\CoreBundle\Templating\Helper\ButtonHelper; +use Mautic\CoreBundle\Twig\Helper\ButtonHelper; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Exception\ForbiddenException; use MauticPlugin\CustomObjectsBundle\Provider\CustomItemPermissionProvider; use MauticPlugin\CustomObjectsBundle\Provider\CustomItemRouteProvider; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class CustomItemButtonSubscriber implements EventSubscriberInterface { - /** - * @var TranslatorInterface - */ - private $translator; - - /** - * @var CustomItemPermissionProvider - */ - private $permissionProvider; - - /** - * @var CustomItemRouteProvider - */ - private $routeProvider; - public function __construct( - CustomItemPermissionProvider $permissionProvider, - CustomItemRouteProvider $routeProvider, - TranslatorInterface $translator + private CustomItemPermissionProvider $permissionProvider, + private CustomItemRouteProvider $routeProvider, + private TranslatorInterface $translator ) { - $this->permissionProvider = $permissionProvider; - $this->routeProvider = $routeProvider; - $this->translator = $translator; } /** @@ -57,8 +39,8 @@ public function injectViewButtons(CustomButtonEvent $event): void case CustomItemRouteProvider::ROUTE_LIST: try { $customObjectId = $this->getCustomObjectIdFromEvent($event); - $filterEntityId = $event->getRequest()->query->get('filterEntityId', false); - $filterEntityType = $event->getRequest()->query->get('filterEntityType', false); + $filterEntityId = $event->getRequest()->query->get('filterEntityId'); + $filterEntityType = $event->getRequest()->query->get('filterEntityType'); $loadedInTab = (bool) $filterEntityId; if ($loadedInTab && in_array($filterEntityType, ['contact', 'customItem'], true)) { $customItem = $event->getItem(); @@ -112,7 +94,7 @@ public function injectViewButtons(CustomButtonEvent $event): void $event->getRoute() ); } - } catch (ForbiddenException $e) { + } catch (ForbiddenException) { } break; @@ -136,17 +118,17 @@ private function addEntityButtons(CustomButtonEvent $event, string $location, in if ($customItem && $customItem instanceof CustomItem) { try { $event->addButton($this->defineDeleteButton($customObjectId, $customItem), $location, $event->getRoute()); - } catch (ForbiddenException $e) { + } catch (ForbiddenException) { } try { $event->addButton($this->defineCloneButton($customObjectId, $customItem), $location, $event->getRoute()); - } catch (ForbiddenException $e) { + } catch (ForbiddenException) { } try { $event->addButton($this->defineEditButton($customObjectId, $customItem), $location, $event->getRoute()); - } catch (ForbiddenException $e) { + } catch (ForbiddenException) { } } } @@ -295,7 +277,7 @@ private function defineLinkButton(int $customObjectId, CustomItem $customItem, s return [ 'attr' => [ 'href' => '#', - 'onclick' => "CustomObjects.linkCustomItemWithEntity(this, event, ${customObjectId}, '${entityType}', ${entityId}, 'custom-object-${customObjectId}', ".($relationshipObjectId ?: 'null').');', + 'onclick' => "CustomObjects.linkCustomItemWithEntity(this, event, {$customObjectId}, '{$entityType}', {$entityId}, 'custom-object-{$customObjectId}', ".($relationshipObjectId ?: 'null').');', 'data-action' => $action, 'data-toggle' => '', ], @@ -317,7 +299,7 @@ private function defineUnlinkButton(int $customObjectId, int $customItemId, stri return [ 'attr' => [ 'href' => '#', - 'onclick' => "CustomObjects.unlinkCustomItemFromEntity(this, event, ${customObjectId}, '${entityType}', ${entityId}, 'custom-object-${customObjectId}');", + 'onclick' => "CustomObjects.unlinkCustomItemFromEntity(this, event, {$customObjectId}, '{$entityType}', {$entityId}, 'custom-object-{$customObjectId}');", 'data-action' => $this->routeProvider->buildUnlinkRoute($customItemId, $entityType, $entityId), 'data-toggle' => '', ], diff --git a/EventListener/CustomItemPostDeleteSubscriber.php b/EventListener/CustomItemPostDeleteSubscriber.php index 7182a2d03..e94ec4e96 100644 --- a/EventListener/CustomItemPostDeleteSubscriber.php +++ b/EventListener/CustomItemPostDeleteSubscriber.php @@ -12,22 +12,10 @@ final class CustomItemPostDeleteSubscriber implements EventSubscriberInterface { - /** - * @var CustomItemXrefCustomItemRepository - */ - private $customItemXrefCustomItemRepository; - - /** - * @var CustomItemXrefContactRepository - */ - private $customItemXrefContactRepository; - public function __construct( - CustomItemXrefCustomItemRepository $customItemXrefCustomItemRepository, - CustomItemXrefContactRepository $customItemXrefContactRepository + private CustomItemXrefCustomItemRepository $customItemXrefCustomItemRepository, + private CustomItemXrefContactRepository $customItemXrefContactRepository ) { - $this->customItemXrefCustomItemRepository = $customItemXrefCustomItemRepository; - $this->customItemXrefContactRepository = $customItemXrefContactRepository; } public static function getSubscribedEvents() diff --git a/EventListener/CustomItemPostSaveSubscriber.php b/EventListener/CustomItemPostSaveSubscriber.php index fc590b7e5..f784bd8f1 100644 --- a/EventListener/CustomItemPostSaveSubscriber.php +++ b/EventListener/CustomItemPostSaveSubscriber.php @@ -14,20 +14,10 @@ class CustomItemPostSaveSubscriber implements EventSubscriberInterface { - /** - * @var CustomItemModel - */ - private $customItemModel; - - /** - * @var RequestStack - */ - private $requestStack; - - public function __construct(CustomItemModel $customItemModel, RequestStack $requestStack) - { - $this->customItemModel = $customItemModel; - $this->requestStack = $requestStack; + public function __construct( + private CustomItemModel $customItemModel, + private RequestStack $requestStack + ) { } public static function getSubscribedEvents() diff --git a/EventListener/CustomItemScheduledExportSubscriber.php b/EventListener/CustomItemScheduledExportSubscriber.php index d9f372b43..b824ef210 100644 --- a/EventListener/CustomItemScheduledExportSubscriber.php +++ b/EventListener/CustomItemScheduledExportSubscriber.php @@ -11,11 +11,8 @@ class CustomItemScheduledExportSubscriber implements EventSubscriberInterface { - private CustomItemExportSchedulerModel $customItemExportSchedulerModel; - - public function __construct(CustomItemExportSchedulerModel $customItemExportSchedulerModel) + public function __construct(private CustomItemExportSchedulerModel $customItemExportSchedulerModel) { - $this->customItemExportSchedulerModel = $customItemExportSchedulerModel; } /** diff --git a/EventListener/CustomItemTabSubscriber.php b/EventListener/CustomItemTabSubscriber.php index b80a5feb0..18fa93fd1 100644 --- a/EventListener/CustomItemTabSubscriber.php +++ b/EventListener/CustomItemTabSubscriber.php @@ -13,52 +13,22 @@ use MauticPlugin\CustomObjectsBundle\Provider\SessionProviderFactory; use MauticPlugin\CustomObjectsBundle\Repository\CustomItemRepository; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class CustomItemTabSubscriber implements EventSubscriberInterface { - /** - * @var TranslatorInterface - */ - private $translator; - - /** - * @var CustomObjectModel - */ - private $customObjectModel; - - /** - * @var CustomItemRepository - */ - private $customItemRepository; - - /** - * @var CustomItemRouteProvider - */ - private $customItemRouteProvider; - /** * @var CustomObject[] */ - private $customObjects = []; - - /** - * @var SessionProviderFactory - */ - private $sessionProviderFactory; + private array $customObjects = []; public function __construct( - CustomObjectModel $customObjectModel, - CustomItemRepository $customItemRepository, - TranslatorInterface $translator, - CustomItemRouteProvider $customItemRouteProvider, - SessionProviderFactory $sessionProviderFactory + private CustomObjectModel $customObjectModel, + private CustomItemRepository $customItemRepository, + private TranslatorInterface $translator, + private CustomItemRouteProvider $customItemRouteProvider, + private SessionProviderFactory $sessionProviderFactory ) { - $this->customObjectModel = $customObjectModel; - $this->customItemRepository = $customItemRepository; - $this->translator = $translator; - $this->customItemRouteProvider = $customItemRouteProvider; - $this->sessionProviderFactory = $sessionProviderFactory; } /** @@ -73,7 +43,7 @@ public static function getSubscribedEvents(): array public function injectTabs(CustomContentEvent $event): void { - if ($event->checkContext('CustomObjectsBundle:CustomItem:detail.html.php', 'tabs')) { + if ($event->checkContext('@CustomObjects/CustomItem/detail.html.twig', 'tabs')) { $vars = $event->getVars(); $objects = $this->customObjectModel->getMasterCustomObjects(); @@ -92,13 +62,13 @@ public function injectTabs(CustomContentEvent $event): void 'tabId' => "custom-object-{$object->getId()}", ]; - $event->addTemplate('CustomObjectsBundle:SubscribedEvents/Tab:link.html.php', $data); + $event->addTemplate('@CustomObjects/SubscribedEvents/Tab/link.html.twig', $data); } - $event->addTemplate('CustomObjectsBundle:SubscribedEvents/Tab:modal.html.php'); + $event->addTemplate('@CustomObjects/SubscribedEvents/Tab/modal.html.twig'); } - if ($event->checkContext('CustomObjectsBundle:CustomItem:detail.html.php', 'tabs.content')) { + if ($event->checkContext('@CustomObjects/CustomItem/detail.html.twig', 'tabs.content')) { $vars = $event->getVars(); $objects = $this->getCustomObjects(); @@ -129,7 +99,7 @@ public function injectTabs(CustomContentEvent $event): void 'namespace' => $sessionProvider->getNamespace(), ]; - $event->addTemplate('CustomObjectsBundle:SubscribedEvents/Tab:content.html.php', $data); + $event->addTemplate('@CustomObjects/SubscribedEvents/Tab/content.html.twig', $data); } } } diff --git a/EventListener/CustomItemXrefContactSubscriber.php b/EventListener/CustomItemXrefContactSubscriber.php index 57fb4c18d..b47ca0fd0 100644 --- a/EventListener/CustomItemXrefContactSubscriber.php +++ b/EventListener/CustomItemXrefContactSubscriber.php @@ -25,29 +25,11 @@ class CustomItemXrefContactSubscriber implements EventSubscriberInterface { - /** - * @var EntityManager - */ - private $entityManager; - - /** - * @var UserHelper - */ - private $userHelper; - - /** - * @var CustomItemRepository - */ - private $customItemRepository; - public function __construct( - EntityManager $entityManager, - UserHelper $userHelper, - CustomItemRepository $customItemRepository + private EntityManager $entityManager, + private UserHelper $userHelper, + private CustomItemRepository $customItemRepository ) { - $this->entityManager = $entityManager; - $this->userHelper = $userHelper; - $this->customItemRepository = $customItemRepository; } /** @@ -118,7 +100,7 @@ public function onEntityLinkDiscovery(CustomItemXrefEntityDiscoveryEvent $event) if ('contact' === $event->getEntityType()) { try { $xRef = $this->getContactXrefEntity($event->getCustomItem()->getId(), $event->getEntityId()); - } catch (NoResultException $e) { + } catch (NoResultException) { /** @var Lead $contact */ $contact = $this->entityManager->getReference(Lead::class, $event->getEntityId()); $xRef = new CustomItemXrefContact($event->getCustomItem(), $contact); diff --git a/EventListener/CustomItemXrefCustomItemSubscriber.php b/EventListener/CustomItemXrefCustomItemSubscriber.php index 4f1599a72..cfefa82ae 100644 --- a/EventListener/CustomItemXrefCustomItemSubscriber.php +++ b/EventListener/CustomItemXrefCustomItemSubscriber.php @@ -17,24 +17,13 @@ use MauticPlugin\CustomObjectsBundle\Event\CustomItemXrefEntityEvent; use MauticPlugin\CustomObjectsBundle\Repository\CustomItemRepository; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use UnexpectedValueException; class CustomItemXrefCustomItemSubscriber implements EventSubscriberInterface { - /** - * @var EntityManager - */ - private $entityManager; - - /** - * @var CustomItemRepository - */ - private $customItemRepository; - - public function __construct(EntityManager $entityManager, CustomItemRepository $customItemRepository) - { - $this->entityManager = $entityManager; - $this->customItemRepository = $customItemRepository; + public function __construct( + private EntityManager $entityManager, + private CustomItemRepository $customItemRepository + ) { } /** @@ -81,7 +70,7 @@ public function onLookupQuery(CustomItemListQueryEvent $event): void } /** - * @throws UnexpectedValueException + * @throws \UnexpectedValueException * @throws ORMException */ public function onEntityLinkDiscovery(CustomItemXrefEntityDiscoveryEvent $event): void @@ -89,7 +78,7 @@ public function onEntityLinkDiscovery(CustomItemXrefEntityDiscoveryEvent $event) if ('customItem' === $event->getEntityType()) { try { $xRef = $this->getXrefEntity($event->getCustomItem()->getId(), $event->getEntityId()); - } catch (NoResultException $e) { + } catch (NoResultException) { /** @var CustomItem $customItemB */ $customItemB = $this->entityManager->getReference(CustomItem::class, $event->getEntityId()); $xRef = new CustomItemXrefCustomItem($event->getCustomItem(), $customItemB); diff --git a/EventListener/CustomObjectButtonSubscriber.php b/EventListener/CustomObjectButtonSubscriber.php index 63d801a70..1e68d13c3 100644 --- a/EventListener/CustomObjectButtonSubscriber.php +++ b/EventListener/CustomObjectButtonSubscriber.php @@ -6,7 +6,7 @@ use Mautic\CoreBundle\CoreEvents; use Mautic\CoreBundle\Event\CustomButtonEvent; -use Mautic\CoreBundle\Templating\Helper\ButtonHelper; +use Mautic\CoreBundle\Twig\Helper\ButtonHelper; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; use MauticPlugin\CustomObjectsBundle\Exception\ForbiddenException; use MauticPlugin\CustomObjectsBundle\Provider\CustomItemPermissionProvider; @@ -14,47 +14,17 @@ use MauticPlugin\CustomObjectsBundle\Provider\CustomObjectPermissionProvider; use MauticPlugin\CustomObjectsBundle\Provider\CustomObjectRouteProvider; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class CustomObjectButtonSubscriber implements EventSubscriberInterface { - /** - * @var CustomObjectPermissionProvider - */ - private $permissionProvider; - - /** - * @var CustomObjectRouteProvider - */ - private $routeProvider; - - /** - * @var CustomItemPermissionProvider - */ - private $customItemPermissionProvider; - - /** - * @var CustomItemRouteProvider - */ - private $customItemRouteProvider; - - /** - * @var TranslatorInterface - */ - private $translator; - public function __construct( - CustomObjectPermissionProvider $permissionProvider, - CustomObjectRouteProvider $routeProvider, - CustomItemPermissionProvider $customItemPermissionProvider, - CustomItemRouteProvider $customItemRouteProvider, - TranslatorInterface $translator + private CustomObjectPermissionProvider $permissionProvider, + private CustomObjectRouteProvider $routeProvider, + private CustomItemPermissionProvider $customItemPermissionProvider, + private CustomItemRouteProvider $customItemRouteProvider, + private TranslatorInterface $translator ) { - $this->permissionProvider = $permissionProvider; - $this->routeProvider = $routeProvider; - $this->customItemPermissionProvider = $customItemPermissionProvider; - $this->customItemRouteProvider = $customItemRouteProvider; - $this->translator = $translator; } /** @@ -75,7 +45,7 @@ public function injectViewButtons(CustomButtonEvent $event): void try { $event->addButton($this->defineNewButton(), ButtonHelper::LOCATION_PAGE_ACTIONS, $event->getRoute()); - } catch (ForbiddenException $e) { + } catch (ForbiddenException) { } break; @@ -89,12 +59,12 @@ public function injectViewButtons(CustomButtonEvent $event): void if ($customObject) { try { $event->addButton($this->defineViewCustomItemsButton($customObject), ButtonHelper::LOCATION_PAGE_ACTIONS, $event->getRoute()); - } catch (ForbiddenException $e) { + } catch (ForbiddenException) { } try { $event->addButton($this->defineCreateNewCustomItemButton($customObject), ButtonHelper::LOCATION_PAGE_ACTIONS, $event->getRoute()); - } catch (ForbiddenException $e) { + } catch (ForbiddenException) { } } @@ -108,17 +78,17 @@ private function addEntityButtons(CustomButtonEvent $event, string $location): v if ($entity && $entity instanceof CustomObject) { try { $event->addButton($this->defineDeleteButton($entity), $location, $event->getRoute()); - } catch (ForbiddenException $e) { + } catch (ForbiddenException) { } try { $event->addButton($this->defineCloneButton($entity), $location, $event->getRoute()); - } catch (ForbiddenException $e) { + } catch (ForbiddenException) { } try { $event->addButton($this->defineEditButton($entity), $location, $event->getRoute()); - } catch (ForbiddenException $e) { + } catch (ForbiddenException) { } } } diff --git a/EventListener/CustomObjectListFormatSubscriber.php b/EventListener/CustomObjectListFormatSubscriber.php index 4baf4de19..5eec8ea3b 100644 --- a/EventListener/CustomObjectListFormatSubscriber.php +++ b/EventListener/CustomObjectListFormatSubscriber.php @@ -11,14 +11,8 @@ class CustomObjectListFormatSubscriber implements EventSubscriberInterface { - /** - * @var TokenFormatter - */ - private $tokenFormatter; - - public function __construct(TokenFormatter $tokenFormatter) + public function __construct(private TokenFormatter $tokenFormatter) { - $this->tokenFormatter = $tokenFormatter; } public static function getSubscribedEvents(): array diff --git a/EventListener/CustomObjectPostSaveSubscriber.php b/EventListener/CustomObjectPostSaveSubscriber.php index ee08c9166..db7cf4c8d 100644 --- a/EventListener/CustomObjectPostSaveSubscriber.php +++ b/EventListener/CustomObjectPostSaveSubscriber.php @@ -12,14 +12,8 @@ class CustomObjectPostSaveSubscriber implements EventSubscriberInterface { - /** - * @var CustomObjectModel - */ - private $customObjectModel; - - public function __construct(CustomObjectModel $customObjectModel) + public function __construct(private CustomObjectModel $customObjectModel) { - $this->customObjectModel = $customObjectModel; } public static function getSubscribedEvents() diff --git a/EventListener/CustomObjectPreDeleteSubscriber.php b/EventListener/CustomObjectPreDeleteSubscriber.php index 75df9122a..f711b251e 100644 --- a/EventListener/CustomObjectPreDeleteSubscriber.php +++ b/EventListener/CustomObjectPreDeleteSubscriber.php @@ -8,24 +8,14 @@ use MauticPlugin\CustomObjectsBundle\Event\CustomObjectEvent; use MauticPlugin\CustomObjectsBundle\Model\CustomObjectModel; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class CustomObjectPreDeleteSubscriber implements EventSubscriberInterface { - /** - * @var CustomObjectModel - */ - private $customObjectModel; - - /** - * @var TranslatorInterface - */ - private $translator; - - public function __construct(CustomObjectModel $customObjectModel, TranslatorInterface $translator) - { - $this->customObjectModel = $customObjectModel; - $this->translator = $translator; + public function __construct( + private CustomObjectModel $customObjectModel, + private TranslatorInterface $translator + ) { } public static function getSubscribedEvents() diff --git a/EventListener/DynamicContentSubscriber.php b/EventListener/DynamicContentSubscriber.php index 6487fba6d..054bcf5f6 100644 --- a/EventListener/DynamicContentSubscriber.php +++ b/EventListener/DynamicContentSubscriber.php @@ -14,7 +14,6 @@ use MauticPlugin\CustomObjectsBundle\Provider\ConfigProvider; use MauticPlugin\CustomObjectsBundle\Repository\DbalQueryTrait; use MauticPlugin\CustomObjectsBundle\Segment\Query\Filter\QueryFilterFactory; -use PDOException; use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; @@ -23,36 +22,12 @@ class DynamicContentSubscriber implements EventSubscriberInterface use MatchFilterForLeadTrait; use DbalQueryTrait; - /** - * @var QueryFilterFactory - */ - private $queryFilterFactory; - - /** - * @var QueryFilterHelper - */ - private $queryFilterHelper; - - /** - * @var ConfigProvider - */ - private $configProvider; - - /** - * @var LoggerInterface - */ - private $logger; - public function __construct( - QueryFilterFactory $queryFilterFactory, - QueryFilterHelper $queryFilterHelper, - ConfigProvider $configProvider, - LoggerInterface $logger + private QueryFilterFactory $queryFilterFactory, + private QueryFilterHelper $queryFilterHelper, + private ConfigProvider $configProvider, + private LoggerInterface $logger ) { - $this->queryFilterFactory = $queryFilterFactory; - $this->queryFilterHelper = $queryFilterHelper; - $this->configProvider = $configProvider; - $this->logger = $logger; } /** @@ -99,8 +74,8 @@ public function evaluateFilters(ContactFiltersEvaluateEvent $event): void } else { $event->setIsEvaluated(true); } - } catch (PDOException $e) { - $this->logger->addError('Failed to evaluate dynamic content for custom object '.$e->getMessage()); + } catch (\PDOException $e) { + $this->logger->error('Failed to evaluate dynamic content for custom object '.$e->getMessage()); throw $e; } diff --git a/EventListener/FilterOperatorSubscriber.php b/EventListener/FilterOperatorSubscriber.php index ff9d25221..d8b0c09e1 100644 --- a/EventListener/FilterOperatorSubscriber.php +++ b/EventListener/FilterOperatorSubscriber.php @@ -21,14 +21,8 @@ class FilterOperatorSubscriber implements EventSubscriberInterface public const NOT_IN_CUSTOM_OBJECTS = 'notInCustomObjects'; - /** - * @var CustomObjectModel - */ - private $customObjectModel; - - public function __construct(CustomObjectModel $customObjectModel) + public function __construct(private CustomObjectModel $customObjectModel) { - $this->customObjectModel = $customObjectModel; } /** @@ -45,7 +39,7 @@ public static function getSubscribedEvents(): array ]; } - public function onOperatorsGenerate(LeadListFiltersOperatorsEvent $event) + public function onOperatorsGenerate(LeadListFiltersOperatorsEvent $event): void { $event->addOperator(self::WITHIN_CUSTOM_OBJECTS, [ 'label' => 'custom.within.custom.objects.label', @@ -121,9 +115,9 @@ public function onWithinFieldValuesBuilder(SegmentOperatorQueryBuilderEvent $eve ); } elseif ($event->operatorIsOneOf(self::NOT_IN_CUSTOM_OBJECTS)) { $queryBuilder = $event->getQueryBuilder(); - $subQueryBuilder = $queryBuilder->getConnection()->createQueryBuilder(); - $expr = $subQueryBuilder->expr(); - $customItemQueryBuilder = $subQueryBuilder->select('ci.name') + // $subQueryBuilder = $queryBuilder->getConnection()->createQueryBuilder(); + $expr = $queryBuilder->expr(); + $customItemQueryBuilder = $queryBuilder->select('ci.name') ->from(MAUTIC_TABLE_PREFIX.'custom_item', 'ci') ->andWhere($expr->eq('ci.custom_object_id', $customObjectId)) ->andWhere($expr->eq('ci.is_published', 1)); diff --git a/EventListener/ImportSubscriber.php b/EventListener/ImportSubscriber.php index 98fba5826..51bf22026 100644 --- a/EventListener/ImportSubscriber.php +++ b/EventListener/ImportSubscriber.php @@ -10,6 +10,7 @@ use Mautic\LeadBundle\Event\ImportProcessEvent; use Mautic\LeadBundle\Event\ImportValidateEvent; use Mautic\LeadBundle\LeadEvents; +use MauticPlugin\CustomObjectsBundle\DTO\ImportLogDTO; use MauticPlugin\CustomObjectsBundle\Entity\CustomField; use MauticPlugin\CustomObjectsBundle\Exception\ForbiddenException; use MauticPlugin\CustomObjectsBundle\Exception\NotFoundException; @@ -20,56 +21,20 @@ use MauticPlugin\CustomObjectsBundle\Provider\CustomItemRouteProvider; use MauticPlugin\CustomObjectsBundle\Repository\CustomFieldRepository; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\Form\Form; use Symfony\Component\Form\FormError; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Component\Form\FormInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class ImportSubscriber implements EventSubscriberInterface { - /** - * @var TranslatorInterface - */ - private $translator; - - /** - * @var CustomObjectModel - */ - private $customObjectModel; - - /** - * @var CustomItemImportModel - */ - private $customItemImportModel; - - /** - * @var ConfigProvider - */ - private $configProvider; - - /** - * @var CustomItemPermissionProvider - */ - private $permissionProvider; - - /** - * @var CustomFieldRepository - */ - private $customFieldRepository; - public function __construct( - CustomObjectModel $customObjectModel, - CustomItemImportModel $customItemImportModel, - ConfigProvider $configProvider, - CustomItemPermissionProvider $permissionProvider, - CustomFieldRepository $customFieldRepository, - TranslatorInterface $translator + private CustomObjectModel $customObjectModel, + private CustomItemImportModel $customItemImportModel, + private ConfigProvider $configProvider, + private CustomItemPermissionProvider $permissionProvider, + private CustomFieldRepository $customFieldRepository, + private TranslatorInterface $translator ) { - $this->customObjectModel = $customObjectModel; - $this->customItemImportModel = $customItemImportModel; - $this->configProvider = $configProvider; - $this->permissionProvider = $permissionProvider; - $this->customFieldRepository = $customFieldRepository; - $this->translator = $translator; } /** @@ -101,7 +66,7 @@ public function onImportInit(ImportInitEvent $event): void $event->activeLink = "#mautic_custom_object_$customObjectId"; $event->setIndexRoute(CustomItemRouteProvider::ROUTE_LIST, ['objectId' => $customObjectId]); $event->stopPropagation(); - } catch (NotFoundException|ForbiddenException $e) { + } catch (NotFoundException|ForbiddenException) { } } @@ -133,7 +98,7 @@ public function onFieldMapping(ImportMappingEvent $event): void $customObject->getNamePlural() => $fieldList, 'mautic.lead.special_fields' => $specialFields, ]; - } catch (NotFoundException|ForbiddenException $e) { + } catch (NotFoundException|ForbiddenException) { } } @@ -145,7 +110,7 @@ public function onValidateImport(ImportValidateEvent $event): void try { $customObjectId = $this->getCustomObjectId($event->getRouteObjectName()); - } catch (NotFoundException $e) { + } catch (NotFoundException) { // This is not a Custom Object import. Abort. return; } @@ -162,7 +127,7 @@ public function onValidateImport(ImportValidateEvent $event): void if (empty($matchedFields)) { $form->addError( new FormError( - $this->translator->trans('mautic.lead.import.matchfields', [], 'validators') + $this->translator->trans('mautic.lead.import.matchfields', [], 'validators') ?? '' ) ); @@ -187,9 +152,14 @@ public function onImportProcess(ImportProcessEvent $event): void $customObjectId = $this->getCustomObjectId($event->import->getObject()); $this->permissionProvider->canCreate($customObjectId); $customObject = $this->customObjectModel->fetchEntity($customObjectId); - $merged = $this->customItemImportModel->import($event->import, $event->rowData, $customObject); + $importLogDto = new ImportLogDTO(); + $merged = $this->customItemImportModel->import($event->import, $event->rowData, $customObject, $importLogDto); $event->setWasMerged($merged); - } catch (NotFoundException $e) { + + if ($importLogDto->hasWarning()) { + $event->addWarning($importLogDto->getWarningsAsString()); + } + } catch (NotFoundException) { // Not a Custom Object import or the custom object doesn't exist anymore. Move on. } } @@ -223,13 +193,13 @@ private function handleValidateOwner(array $matchedFields): ?int * * @param mixed[] $matchedFields */ - private function handleValidateRequired(Form $form, int $customObjectId, array $matchedFields): void + private function handleValidateRequired(FormInterface $form, int $customObjectId, array $matchedFields): void { $requiredFields = $this->customFieldRepository->getRequiredCustomFieldsForCustomObject($customObjectId); - $missingRequiredFields = $requiredFields->filter(function (CustomField $customField) use ($matchedFields) { + $missingRequiredFields = $requiredFields->filter(function (CustomField $customField) use ($matchedFields): bool { return !array_key_exists($customField->getAlias(), $matchedFields); - })->map(function (CustomField $customField) { + })->map(function (CustomField $customField): string { return "{$customField->getLabel()} ({$customField->getAlias()})"; }); diff --git a/EventListener/MenuSubscriber.php b/EventListener/MenuSubscriber.php index 83ee2bb5c..f0e7a9d70 100644 --- a/EventListener/MenuSubscriber.php +++ b/EventListener/MenuSubscriber.php @@ -14,20 +14,8 @@ class MenuSubscriber implements EventSubscriberInterface { - /** - * @var CustomObjectModel - */ - private $customObjectModel; - - /** - * @var ConfigProvider - */ - private $configProvider; - - public function __construct(CustomObjectModel $customObjectModel, ConfigProvider $configProvider) + public function __construct(private CustomObjectModel $customObjectModel, private ConfigProvider $configProvider) { - $this->customObjectModel = $customObjectModel; - $this->configProvider = $configProvider; } /** diff --git a/EventListener/ReportSubscriber.php b/EventListener/ReportSubscriber.php index 49bf3b71c..80229bfff 100644 --- a/EventListener/ReportSubscriber.php +++ b/EventListener/ReportSubscriber.php @@ -18,7 +18,7 @@ use MauticPlugin\CustomObjectsBundle\Report\ReportColumnsBuilder; use MauticPlugin\CustomObjectsBundle\Repository\CustomObjectRepository; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class ReportSubscriber implements EventSubscriberInterface { @@ -35,43 +35,15 @@ class ReportSubscriber implements EventSubscriberInterface public const USERS_TABLE_ALIAS = 'u'; public const COMPANIES_TABLE_ALIAS = 'comp'; - /** - * @var ArrayCollection - */ - private $customObjects; - - /** - * @var CustomObjectRepository - */ - private $customObjectRepository; - - /** - * @var FieldsBuilder - */ - private $fieldsBuilder; - - /** - * @var CompanyReportData - */ - private $companyReportData; - - /** - * @var ReportHelper - */ - private $reportHelper; - - /** - * @var TranslatorInterface - */ - private $translator; + private ?ArrayCollection $customObjects = null; - public function __construct(CustomObjectRepository $customObjectRepository, FieldsBuilder $fieldsBuilder, CompanyReportData $companyReportData, ReportHelper $reportHelper, TranslatorInterface $translator) - { - $this->customObjectRepository = $customObjectRepository; - $this->fieldsBuilder = $fieldsBuilder; - $this->companyReportData = $companyReportData; - $this->reportHelper = $reportHelper; - $this->translator = $translator; + public function __construct( + private CustomObjectRepository $customObjectRepository, + private FieldsBuilder $fieldsBuilder, + private CompanyReportData $companyReportData, + private ReportHelper $reportHelper, + private TranslatorInterface $translator + ) { } private function getCustomObjects(): ArrayCollection @@ -90,10 +62,8 @@ private function getCustomObjects(): ArrayCollection foreach ($parentCustomObjects as $parentCustomObject) { $this->customObjects->add($parentCustomObject); $childCustomObject = $allCustomObjects->filter(function (CustomObject $childCustomObject) use ($parentCustomObject): bool { - return $childCustomObject->getMasterObject() ? - $parentCustomObject->getId() === $childCustomObject->getMasterObject()->getId() - : - false; + return $childCustomObject->getMasterObject() && $parentCustomObject->getId() + === $childCustomObject->getMasterObject()->getId(); })->first(); if (!$childCustomObject) { @@ -133,13 +103,16 @@ private function getContext(CustomObject $customObject): string private function getContexts(): array { return $this->getCustomObjects() - ->map(function (CustomObject $customObject) { + ->map(function (CustomObject $customObject): string { return $this->getContext($customObject); }) ->toArray(); } - private function getStandardColumns(string $prefix) + /** + * @return mixed[] + */ + private function getStandardColumns(string $prefix): array { return $this->reportHelper->getStandardColumns($prefix, ['description', 'publish_up', 'publish_down']); } @@ -148,7 +121,7 @@ private function addPrefixToColumnLabel(array $columns, string $prefix): array { foreach ($columns as $alias => $column) { $columnLabel = $this->translator->trans($columns[$alias]['label']); - if (0 === strpos($columnLabel, $prefix)) { + if (str_starts_with($columnLabel, $prefix)) { $columns[$alias]['label'] = $columnLabel; // Don't add the prefix twice continue; diff --git a/EventListener/SegmentFilterDecoratorDelegateSubscriber.php b/EventListener/SegmentFilterDecoratorDelegateSubscriber.php index ccd6ae9a6..6d8048aac 100644 --- a/EventListener/SegmentFilterDecoratorDelegateSubscriber.php +++ b/EventListener/SegmentFilterDecoratorDelegateSubscriber.php @@ -11,14 +11,8 @@ class SegmentFilterDecoratorDelegateSubscriber implements EventSubscriberInterface { - /** - * @var MultiselectDecorator - */ - private $multiselectDecorator; - - public function __construct(MultiselectDecorator $multiselectDecorator) + public function __construct(private MultiselectDecorator $multiselectDecorator) { - $this->multiselectDecorator = $multiselectDecorator; } /** diff --git a/EventListener/SegmentFiltersChoicesGenerateSubscriber.php b/EventListener/SegmentFiltersChoicesGenerateSubscriber.php index 2d9bb0564..66d26dda3 100644 --- a/EventListener/SegmentFiltersChoicesGenerateSubscriber.php +++ b/EventListener/SegmentFiltersChoicesGenerateSubscriber.php @@ -8,6 +8,7 @@ use Mautic\LeadBundle\Entity\OperatorListTrait; use Mautic\LeadBundle\Event\LeadListFiltersChoicesEvent; use Mautic\LeadBundle\LeadEvents; +use Mautic\LeadBundle\Provider\TypeOperatorProviderInterface; use MauticPlugin\CustomObjectsBundle\CustomFieldType\HiddenType; use MauticPlugin\CustomObjectsBundle\Entity\CustomField; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; @@ -15,42 +16,25 @@ use MauticPlugin\CustomObjectsBundle\Provider\CustomFieldTypeProvider; use MauticPlugin\CustomObjectsBundle\Repository\CustomObjectRepository; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class SegmentFiltersChoicesGenerateSubscriber implements EventSubscriberInterface { use OperatorListTrait; - /** - * @var CustomObjectRepository - */ - private $customObjectRepository; - /** * @var TranslatorInterface */ private $translator; - /** - * @var ConfigProvider - */ - private $configProvider; - - /** - * @var CustomFieldTypeProvider - */ - private $fieldTypeProvider; - public function __construct( - CustomObjectRepository $customObjectRepository, + private CustomObjectRepository $customObjectRepository, TranslatorInterface $translator, - ConfigProvider $configProvider, - CustomFieldTypeProvider $fieldTypeProvider + private ConfigProvider $configProvider, + private CustomFieldTypeProvider $fieldTypeProvider, + private TypeOperatorProviderInterface $typeOperatorProvider ) { - $this->customObjectRepository = $customObjectRepository; - $this->translator = $translator; - $this->configProvider = $configProvider; - $this->fieldTypeProvider = $fieldTypeProvider; + $this->translator = $translator; } /** @@ -79,21 +63,31 @@ function (CustomObject $customObject) use ($event, $fieldTypes): void { [ 'label' => $customObject->getName().' '.$this->translator->trans('custom.item.name.label'), 'properties' => ['type' => 'text'], - 'operators' => $this->getOperatorsForFieldType('text'), + 'operators' => $this->typeOperatorProvider->getOperatorsForFieldType('text'), 'object' => $customObject->getId(), ] ); /** @var CustomField $customField */ foreach ($customObject->getCustomFields()->getIterator() as $customField) { - if ($customField->getType() === $fieldTypes[HiddenType::NAME]) { // We don't want to show hidden types in filter list + if ($customField->getType() === $fieldTypes[HiddenType::NAME]) { + // We don't want to show hidden types in filter list continue; } - $allowedOperators = $customField->getTypeObject()->getOperators(); - $availableOperators = array_flip($this->getOperatorsForFieldType($customField->getType())); - $operators = array_intersect_key($availableOperators, $allowedOperators); - $operators = array_flip($operators); + if (method_exists($this->typeOperatorProvider, 'getContext') + && 'segment' === $this->typeOperatorProvider->getContext() + && method_exists($customField->getTypeObject(), 'getOperatorsForSegment') + ) { + $allowedOperators = $customField->getTypeObject()->getOperatorsForSegment(); + } else { + $allowedOperators = $customField->getTypeObject()->getOperators(); + } + + $typeOperators = $this->typeOperatorProvider->getOperatorsForFieldType($customField->getType()); + $availableOperators = array_flip($typeOperators); + $operators = array_intersect_key($availableOperators, $allowedOperators); + $operators = array_flip($operators); $event->addChoice( 'custom_object', diff --git a/EventListener/SegmentFiltersDictionarySubscriber.php b/EventListener/SegmentFiltersDictionarySubscriber.php index 98dd245e9..12b2b4a7c 100644 --- a/EventListener/SegmentFiltersDictionarySubscriber.php +++ b/EventListener/SegmentFiltersDictionarySubscriber.php @@ -4,8 +4,9 @@ namespace MauticPlugin\CustomObjectsBundle\EventListener; -use Doctrine\Bundle\DoctrineBundle\Registry; use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Exception; +use Doctrine\Persistence\ManagerRegistry; use Mautic\LeadBundle\Event\SegmentDictionaryGenerationEvent; use Mautic\LeadBundle\LeadEvents; use Mautic\LeadBundle\Segment\Query\QueryBuilder; @@ -13,26 +14,17 @@ use MauticPlugin\CustomObjectsBundle\Repository\DbalQueryTrait; use MauticPlugin\CustomObjectsBundle\Segment\Query\Filter\CustomFieldFilterQueryBuilder; use MauticPlugin\CustomObjectsBundle\Segment\Query\Filter\CustomItemNameFilterQueryBuilder; +use MauticPlugin\CustomObjectsBundle\Segment\Query\Filter\CustomObjectMergedFilterQueryBuilder; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class SegmentFiltersDictionarySubscriber implements EventSubscriberInterface { use DbalQueryTrait; - /** - * @var Registry - */ - private $doctrineRegistry; - - /** - * @var ConfigProvider - */ - private $configProvider; - - public function __construct(Registry $registry, ConfigProvider $configProvider) - { - $this->doctrineRegistry = $registry; - $this->configProvider = $configProvider; + public function __construct( + private ManagerRegistry $doctrineRegistry, + private ConfigProvider $configProvider + ) { } /** @@ -46,7 +38,7 @@ public static function getSubscribedEvents(): array } /** - * @throws \Doctrine\DBAL\DBALException + * @throws Exception */ public function onGenerateSegmentDictionary(SegmentDictionaryGenerationEvent $event): void { @@ -64,21 +56,28 @@ public function onGenerateSegmentDictionary(SegmentDictionaryGenerationEvent $ev ->from(MAUTIC_TABLE_PREFIX.'custom_object', 'o') ->leftJoin('o', MAUTIC_TABLE_PREFIX.'custom_field', 'f', 'f.custom_object_id = o.id'); - $registeredObjects = []; - $fields = $this->executeSelect($queryBuilder)->fetchAll(); + $registeredObjects = []; + $fields = $this->executeSelect($queryBuilder)->fetchAllAssociative(); + $isCustomObjectMergeFilterEnabled = $this->configProvider->isCustomObjectMergeFilterEnabled(); + $cmoType = CustomItemNameFilterQueryBuilder::getServiceId(); + $cmfType = CustomFieldFilterQueryBuilder::getServiceId(); + + if ($isCustomObjectMergeFilterEnabled) { + $cmoType = $cmfType = CustomObjectMergedFilterQueryBuilder::getServiceId(); + } foreach ($fields as $field) { $COId = $field['custom_object_id']; if (!in_array($COId, $registeredObjects, true)) { $event->addTranslation('cmo_'.$COId, [ - 'type' => CustomItemNameFilterQueryBuilder::getServiceId(), + 'type' => $cmoType, 'field' => $COId, 'foreign_table' => 'custom_objects', ]); $registeredObjects[] = $COId; } if (!$event->hasTranslation('cmf_'.$field['id']) && !empty($field['id'])) { - $event->addTranslation('cmf_'.$field['id'], $this->createTranslation($field)); + $event->addTranslation('cmf_'.$field['id'], $this->createTranslation($field, $cmfType)); } } } @@ -88,12 +87,12 @@ public function onGenerateSegmentDictionary(SegmentDictionaryGenerationEvent $ev * * @return mixed[] */ - private function createTranslation(array $fieldAttributes): array + private function createTranslation(array $fieldAttributes, string $cmfType): array { $segmentValueType = 'custom_field_value_'.$fieldAttributes['type']; return [ - 'type' => CustomFieldFilterQueryBuilder::getServiceId(), + 'type' => $cmfType, 'table' => $segmentValueType, 'field' => $fieldAttributes['id'], 'foreign_table' => 'custom_objects', diff --git a/EventListener/SegmentFiltersMergeSubscriber.php b/EventListener/SegmentFiltersMergeSubscriber.php new file mode 100644 index 000000000..133ce0f99 --- /dev/null +++ b/EventListener/SegmentFiltersMergeSubscriber.php @@ -0,0 +1,99 @@ + 'mergeCustomObjectFilters', + ]; + } + + public function mergeCustomObjectFilters(LeadListMergeFiltersEvent $event): void + { + if (!$this->configProvider->pluginIsEnabled() || (!$this->configProvider->isCustomObjectMergeFilterEnabled())) { + return; + } + + $filters = $event->getFilters(); + + $finalMergedFilters = []; + $customFieldArr = []; + $customObjectIndex = null; + foreach ($filters as $index => $filter) { + $glue = $filter['glue']; + if ('or' === strtolower($glue) && !empty($customFieldArr)) { + $finalMergedFilters = array_merge($finalMergedFilters, $this->groupCustomObject($customFieldArr)); + $customObjectIndex = null; + $customFieldArr = []; + } + + if ('custom_object' !== ($filter['object'] ?? '')) { + $finalMergedFilters[] = $filter; + continue; + } + if (!$customObjectIndex) { + $customObjectIndex = $index; + } + $key = implode('_', [$filter['object'], $filter['glue']]); + $customFieldArr[$key][$index] = $filter; + } + if (!empty($customFieldArr)) { + $finalMergedFilters = array_merge($finalMergedFilters, $this->groupCustomObject($customFieldArr)); + } + $event->setFilters($finalMergedFilters); + } + + /** + * @param array $customObjectFilters + * + * @return array + */ + private function groupCustomObject(array $customObjectFilters): array + { + $newGroupedArr = []; + foreach ($customObjectFilters as $customObjects) { + $key = key($customObjects); + $newGroupedArr[$key] = $customObjects[$key]; + $newGroupedArr[$key]['operator'] = ContactSegmentFilterFactory::CUSTOM_OPERATOR; + unset($newGroupedArr[$key]['filter']); + $mergedProperty = []; + + foreach ($customObjects as $filter) { + $mergedProperty[] = [ + 'operator' => $filter['operator'], + 'filter_value' => $filter['properties']['filter'], + 'field' => $filter['field'], + 'cmo_filter' => str_starts_with($filter['field'], 'cmo_'), + ]; + $newGroupedArr[$key]['properties'][] = $filter; + } + + unset($newGroupedArr[$key]['properties']['filter']); + $newGroupedArr[$key]['merged_property'] = $mergedProperty; + } + + return $newGroupedArr; + } +} diff --git a/EventListener/SerializerSubscriber.php b/EventListener/SerializerSubscriber.php index 9b7aa8c62..fcd3e130d 100644 --- a/EventListener/SerializerSubscriber.php +++ b/EventListener/SerializerSubscriber.php @@ -23,36 +23,12 @@ class SerializerSubscriber implements EventSubscriberInterface { - /** - * @var ConfigProvider - */ - private $configProvider; - - /** - * @var CustomItemXrefContactRepository - */ - private $customItemXrefContactRepository; - - /** - * @var CustomItemModel - */ - private $customItemModel; - - /** - * @var RequestStack - */ - private $requestStack; - public function __construct( - ConfigProvider $configProvider, - CustomItemXrefContactRepository $customItemXrefContactRepository, - CustomItemModel $customItemModel, - RequestStack $requestStack + private ConfigProvider $configProvider, + private CustomItemXrefContactRepository $customItemXrefContactRepository, + private CustomItemModel $customItemModel, + private RequestStack $requestStack ) { - $this->configProvider = $configProvider; - $this->customItemXrefContactRepository = $customItemXrefContactRepository; - $this->customItemModel = $customItemModel; - $this->requestStack = $requestStack; } /** @@ -181,7 +157,7 @@ private function serializeCustomFieldValues(Collection $customFieldValues): arra try { $transformer = $customFieldValue->getCustomField()->getTypeObject()->createApiValueTransformer(); $value = $transformer->reverseTransform($customFieldValue->getValue()); - } catch (UndefinedTransformerException $e) { + } catch (UndefinedTransformerException) { $value = $customFieldValue->getValue(); } diff --git a/EventListener/TokenSubscriber.php b/EventListener/TokenSubscriber.php index d4a2e4427..61b7cb8b6 100644 --- a/EventListener/TokenSubscriber.php +++ b/EventListener/TokenSubscriber.php @@ -7,11 +7,14 @@ use Mautic\CampaignBundle\Entity\Event; use Mautic\CampaignBundle\Model\EventModel; use Mautic\CoreBundle\Event\BuilderEvent; +use Mautic\CoreBundle\Event\TokenReplacementEvent; use Mautic\EmailBundle\EmailEvents; use Mautic\EmailBundle\Entity\Email; use Mautic\EmailBundle\Event\EmailSendEvent; use Mautic\EmailBundle\EventListener\MatchFilterForLeadTrait; use Mautic\LeadBundle\Entity\LeadList; +use Mautic\LeadBundle\Exception\OperatorsNotFoundException; +use Mautic\LeadBundle\Segment\OperatorOptions; use MauticPlugin\CustomObjectsBundle\CustomItemEvents; use MauticPlugin\CustomObjectsBundle\CustomObjectEvents; use MauticPlugin\CustomObjectsBundle\DTO\TableConfig; @@ -29,6 +32,7 @@ use MauticPlugin\CustomObjectsBundle\Helper\QueryFilterHelper; use MauticPlugin\CustomObjectsBundle\Helper\TokenFormatter; use MauticPlugin\CustomObjectsBundle\Helper\TokenParser; +use MauticPlugin\CustomObjectsBundle\Model\CustomFieldModel; use MauticPlugin\CustomObjectsBundle\Model\CustomItemModel; use MauticPlugin\CustomObjectsBundle\Model\CustomObjectModel; use MauticPlugin\CustomObjectsBundle\Provider\ConfigProvider; @@ -44,71 +48,19 @@ class TokenSubscriber implements EventSubscriberInterface use MatchFilterForLeadTrait; use QueryBuilderManipulatorTrait; - /** - * @var ConfigProvider - */ - private $configProvider; - - /** - * @var QueryFilterHelper - */ - private $queryFilterHelper; - - /** - * @var QueryFilterFactory - */ - private $queryFilterFactory; - - /** - * @var CustomObjectModel - */ - private $customObjectModel; - - /** - * @var CustomItemModel - */ - private $customItemModel; - - /** - * @var TokenParser - */ - private $tokenParser; - - /** - * @var EventModel - */ - private $eventModel; - - /** - * @var EventDispatcherInterface - */ - private $eventDispatcher; - - /** - * @var TokenFormatter - */ - private $tokenFormatter; - public function __construct( - ConfigProvider $configProvider, - QueryFilterHelper $queryFilterHelper, - QueryFilterFactory $queryFilterFactory, - CustomObjectModel $customObjectModel, - CustomItemModel $customItemModel, - TokenParser $tokenParser, - EventModel $eventModel, - EventDispatcherInterface $eventDispatcher, - TokenFormatter $tokenFormatter + private ConfigProvider $configProvider, + private QueryFilterHelper $queryFilterHelper, + private QueryFilterFactory $queryFilterFactory, + private CustomObjectModel $customObjectModel, + private CustomItemModel $customItemModel, + private CustomFieldModel $customFieldModel, + private TokenParser $tokenParser, + private EventModel $eventModel, + private EventDispatcherInterface $eventDispatcher, + private TokenFormatter $tokenFormatter, + private int $leadCustomItemFetchLimit ) { - $this->configProvider = $configProvider; - $this->queryFilterHelper = $queryFilterHelper; - $this->queryFilterFactory = $queryFilterFactory; - $this->customObjectModel = $customObjectModel; - $this->customItemModel = $customItemModel; - $this->tokenParser = $tokenParser; - $this->eventModel = $eventModel; - $this->eventDispatcher = $eventDispatcher; - $this->tokenFormatter = $tokenFormatter; } /** @@ -121,6 +73,7 @@ public static function getSubscribedEvents() EmailEvents::EMAIL_ON_SEND => ['decodeTokens', 0], EmailEvents::EMAIL_ON_DISPLAY => ['decodeTokens', 0], CustomItemEvents::ON_CUSTOM_ITEM_LIST_DBAL_QUERY => ['onListQuery', -1], + EmailEvents::TOKEN_REPLACEMENT => ['onTokenReplacement', 100], ]; } @@ -167,8 +120,8 @@ public function decodeTokens(EmailSendEvent $event): void $tokens->map(function (Token $token) use ($event): void { try { $customObject = $this->customObjectModel->fetchEntityByAlias($token->getCustomObjectAlias()); - $fieldValues = $this->getCustomFieldValues($customObject, $token, $event); - } catch (NotFoundException $e) { + $fieldValues = $this->getCustomFieldValues($customObject, $token, $event); + } catch (NotFoundException) { $fieldValues = null; } @@ -180,14 +133,14 @@ public function decodeTokens(EmailSendEvent $event): void $formatEvent = new CustomObjectListFormatEvent($fieldValues, $token->getFormat()); $this->eventDispatcher->dispatch( - CustomObjectEvents::ON_CUSTOM_OBJECT_LIST_FORMAT, - $formatEvent + $formatEvent, + CustomObjectEvents::ON_CUSTOM_OBJECT_LIST_FORMAT ); $result = $formatEvent->hasBeenFormatted() ? $formatEvent->getFormattedString() : $this->tokenFormatter->format($fieldValues, TokenFormatter::DEFAULT_FORMAT); - } catch (InvalidCustomObjectFormatListException $e) { + } catch (InvalidCustomObjectFormatListException) { $result = $this->tokenFormatter->format($fieldValues, TokenFormatter::DEFAULT_FORMAT); } } else { @@ -227,7 +180,7 @@ public function onListQuery(CustomItemListDbalQueryEvent $event): void } elseif ('template' && isset($source[0]) && 'campaign.event' === $source[0] && !empty($source[1])) { $campaignEventId = (int) $source[1]; - /** @var Event $campaignEvent */ + /** @var ?Event $campaignEvent */ $campaignEvent = $this->eventModel->getEntity($campaignEventId); if (!$campaignEvent) { @@ -248,7 +201,7 @@ public function onListQuery(CustomItemListDbalQueryEvent $event): void try { $queryAlias = 'filter_'.$id; $innerQueryBuilder = $this->queryFilterFactory->configureQueryBuilderFromSegmentFilter($filter, $queryAlias); - } catch (InvalidSegmentFilterException $e) { + } catch (InvalidSegmentFilterException) { continue; } @@ -312,15 +265,332 @@ private function getCustomFieldValues(CustomObject $customObject, Token $token, try { $fieldValue = $customItem->findCustomFieldValueForFieldAlias($token->getCustomFieldAlias()); // If the CO item doesn't have a value, get the default value - if ('' == $fieldValue->getValue()) { + if (empty($fieldValue->getValue())) { $fieldValue->setValue($fieldValue->getCustomField()->getDefaultValue()); } $fieldValues[] = $fieldValue->getCustomField()->getTypeObject()->valueToString($fieldValue); - } catch (NotFoundException $e) { + } catch (NotFoundException) { // Custom field not found. } } return $fieldValues; } + + public function onTokenReplacement(TokenReplacementEvent $event): void + { + $clickthrough = $event->getClickthrough(); + + if (!array_key_exists('dynamicContent', $clickthrough)) { + return; + } + + $lead = $event->getLead(); + $tokenData = $clickthrough['dynamicContent']; + + foreach ($tokenData as $data) { + $filterContent = $data['content']; + + $isCustomObject = false; + foreach ($data['filters'] as $filter) { + $customFieldValues = $this->getCustomFieldDataForLead($filter['filters'], (string) $lead['id']); + + if (!empty($customFieldValues)) { + $isCustomObject = true; + $lead = array_merge($lead, $customFieldValues); + } + + if ($isCustomObject && $this->matchFilterForLeadInCustomObject($filter['filters'], $lead)) { + $filterContent = $filter['content']; + break; + } + } + + if ($isCustomObject) { + $event->addToken('{dynamiccontent="'.$data['tokenName'].'"}', $filterContent); + } + } + } + + /** + * @param array $filters + * + * @return array + */ + private function getCustomFieldDataForLead(array $filters, string $leadId): array + { + $customFieldValues = $cachedCustomItems = []; + + foreach ($filters as $condition) { + try { + if ('custom_object' !== $condition['object']) { + continue; + } + + if (str_starts_with($condition['field'], 'cmf_')) { + $customField = $this->customFieldModel->fetchEntity( + (int) explode('cmf_', $condition['field'])[1] + ); + $customObject = $customField->getCustomObject(); + $fieldAlias = $customField->getAlias(); + } elseif (str_starts_with($condition['field'], 'cmo_')) { + $customObject = $this->customObjectModel->fetchEntity( + (int) explode('cmo_', $condition['field'])[1] + ); + $fieldAlias = 'name'; + } else { + continue; + } + + $key = $customObject->getId().'-'.$leadId; + if (!isset($cachedCustomItems[$key])) { + $cachedCustomItems[$key] = $this->getCustomItems($customObject, $leadId); + } + + $result = $this->getCustomFieldValue($customObject, $fieldAlias, $cachedCustomItems[$key]); + + $customFieldValues[$condition['field']] = $result; + } catch (NotFoundException|InvalidCustomObjectFormatListException) { + continue; + } + } + + return $customFieldValues; + } + + /** + * @param array $customItems + * + * @return array + */ + private function getCustomFieldValue( + CustomObject $customObject, + string $customFieldAlias, + array $customItems + ): array { + $fieldValues = []; + + foreach ($customItems as $customItemData) { + // Name is known from the CI data array. + if ('name' === $customFieldAlias) { + $fieldValues[] = $customItemData['name']; + + continue; + } + + // Custom Field values are handled like this. + $customItem = new CustomItem($customObject); + $customItem->populateFromArray($customItemData); + $customItem = $this->customItemModel->populateCustomFields($customItem); + + try { + $fieldValue = $customItem->findCustomFieldValueForFieldAlias($customFieldAlias); + // If the CO item doesn't have a value, get the default value + if (empty($fieldValue->getValue())) { + $fieldValue->setValue($fieldValue->getCustomField()->getDefaultValue()); + } + + if (in_array($fieldValue->getCustomField()->getType(), ['multiselect', 'select'])) { + $fieldValues[] = $fieldValue->getValue(); + } else { + $fieldValues[] = $fieldValue->getCustomField()->getTypeObject()->valueToString($fieldValue); + } + } catch (NotFoundException) { + // Custom field not found. + } + } + + return $fieldValues; + } + + /** + * @return array + */ + private function getCustomItems(CustomObject $customObject, string $leadId): array + { + $orderBy = CustomItem::TABLE_ALIAS.'.id'; + $orderDir = 'DESC'; + + $tableConfig = new TableConfig($this->leadCustomItemFetchLimit, 1, $orderBy, $orderDir); + $tableConfig->addParameter('customObjectId', $customObject->getId()); + $tableConfig->addParameter('filterEntityType', 'contact'); + $tableConfig->addParameter('filterEntityId', $leadId); + + return $this->customItemModel->getArrayTableData($tableConfig); + } + + // We have a similar function in MatchFilterForLeadTrait since we are unable to alter anything in Mautic 4.4, + // hence there is some duplication of code. + + /** + * @param array $filter + * @param array $lead + * + * @throws OperatorsNotFoundException + */ + protected function matchFilterForLeadInCustomObject(array $filter, array $lead): bool + { + if (empty($lead['id'])) { + // Lead in generated for preview with faked data + return false; + } + + $groups = []; + $groupNum = 0; + + foreach ($filter as $data) { + if (!array_key_exists($data['field'], $lead)) { + continue; + } + + /* + * Split the filters into groups based on the glue. + * The first filter and any filters whose glue is + * "or" will start a new group. + */ + if (0 === $groupNum || 'or' === $data['glue']) { + ++$groupNum; + $groups[$groupNum] = null; + } + + /* + * If the group has been marked as false, there + * is no need to continue checking the others + * in the group. + */ + if (false === $groups[$groupNum]) { + continue; + } + + /* + * If we are checking the first filter in a group + * assume that the group will not match. + */ + if (null === $groups[$groupNum]) { + $groups[$groupNum] = false; + } + + $leadValues = $lead[$data['field']]; + $leadValues = 'custom_object' === $data['object'] ? $leadValues : [$leadValues]; + $filterVal = $data['filter']; + $subgroup = null; + + if (is_array($leadValues)) { + foreach ($leadValues as $leadVal) { + if ($subgroup) { + break; + } + + switch ($data['type']) { + case 'boolean': + if (null !== $leadVal) { + $leadVal = (bool) $leadVal; + } + + if (null !== $filterVal) { + $filterVal = (bool) $filterVal; + } + break; + case 'datetime': + case 'time': + if (!is_null($leadVal) && !is_null($filterVal)) { + $leadValCount = substr_count($leadVal, ':'); + $filterValCount = substr_count($filterVal, ':'); + + if (2 === $leadValCount && 1 === $filterValCount) { + $filterVal .= ':00'; + } + } + break; + case 'tags': + case 'select': + case 'multiselect': + if (!is_array($leadVal) && !empty($leadVal)) { + $leadVal = explode('|', $leadVal); + } + if (!is_null($filterVal) && !is_array($filterVal)) { + $filterVal = explode('|', $filterVal); + } + break; + case 'number': + $leadVal = (int) $leadVal; + $filterVal = (int) $filterVal; + break; + } + + switch ($data['operator']) { + case '=': + if ('boolean' === $data['type']) { + $groups[$groupNum] = $leadVal === $filterVal; + } else { + $groups[$groupNum] = $leadVal == $filterVal; + } + break; + case '!=': + if ('boolean' === $data['type']) { + $groups[$groupNum] = $leadVal !== $filterVal; + } else { + $groups[$groupNum] = $leadVal != $filterVal; + } + break; + case 'gt': + $groups[$groupNum] = $leadVal > $filterVal; + break; + case 'gte': + $groups[$groupNum] = $leadVal >= $filterVal; + break; + case 'lt': + $groups[$groupNum] = $leadVal < $filterVal; + break; + case 'lte': + $groups[$groupNum] = $leadVal <= $filterVal; + break; + case 'empty': + $groups[$groupNum] = empty($leadVal); + break; + case '!empty': + $groups[$groupNum] = !empty($leadVal); + break; + case 'like': + $matchVal = str_replace(['.', '*', '%'], ['\.', '\*', '.*'], $filterVal); + $groups[$groupNum] = 1 === preg_match('/'.$matchVal.'/', $leadVal); + break; + case '!like': + $matchVal = str_replace(['.', '*'], ['\.', '\*'], $filterVal); + $matchVal = str_replace('%', '.*', $matchVal); + $groups[$groupNum] = 1 !== preg_match('/'.$matchVal.'/', $leadVal); + break; + case OperatorOptions::IN: + $groups[$groupNum] = $this->checkLeadValueIsInFilter($leadVal, $filterVal, false); + break; + case OperatorOptions::NOT_IN: + $groups[$groupNum] = $this->checkLeadValueIsInFilter($leadVal, $filterVal, true); + break; + case 'regexp': + $groups[$groupNum] = 1 === preg_match('/'.$filterVal.'/i', $leadVal); + break; + case '!regexp': + $groups[$groupNum] = 1 !== preg_match('/'.$filterVal.'/i', $leadVal); + break; + case 'startsWith': + $groups[$groupNum] = str_starts_with($leadVal, $filterVal); + break; + case 'endsWith': + $endOfString = substr($leadVal, strlen($leadVal) - strlen($filterVal)); + $groups[$groupNum] = 0 === strcmp($endOfString, $filterVal); + break; + case 'contains': + $groups[$groupNum] = str_contains((string) $leadVal, (string) $filterVal); + break; + default: + throw new OperatorsNotFoundException('Operator is not defined or invalid operator found.'); + } + + $subgroup = $groups[$groupNum]; + } + } + } + + return in_array(true, $groups); + } } diff --git a/Exception/ForbiddenException.php b/Exception/ForbiddenException.php index 13a5b0784..d0ddb1bd5 100644 --- a/Exception/ForbiddenException.php +++ b/Exception/ForbiddenException.php @@ -4,21 +4,14 @@ namespace MauticPlugin\CustomObjectsBundle\Exception; -use Exception; -use Throwable; - -class ForbiddenException extends Exception +class ForbiddenException extends \Exception { - /** - * @param string $entityType - * @param int $entityId - */ public function __construct( string $permission, ?string $entityType = null, ?int $entityId = null, int $code = 403, - ?Throwable $throwable = null + ?\Throwable $throwable = null ) { parent::__construct( trim("You do not have permission to {$permission} {$entityType} {$entityId}"), diff --git a/Exception/InUseException.php b/Exception/InUseException.php index 9fcda2b48..cf764e80e 100644 --- a/Exception/InUseException.php +++ b/Exception/InUseException.php @@ -4,14 +4,9 @@ namespace MauticPlugin\CustomObjectsBundle\Exception; -use Exception; - -class InUseException extends Exception +class InUseException extends \Exception { - /** - * @var array - */ - private $segmentList = []; + private array $segmentList = []; public function setSegmentList(array $segmentList): void { diff --git a/Exception/InvalidArgumentException.php b/Exception/InvalidArgumentException.php index 5252a1180..2b957473f 100644 --- a/Exception/InvalidArgumentException.php +++ b/Exception/InvalidArgumentException.php @@ -4,8 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\Exception; -use Exception; - -class InvalidArgumentException extends Exception +class InvalidArgumentException extends \Exception { } diff --git a/Exception/InvalidSegmentFilterException.php b/Exception/InvalidSegmentFilterException.php index 736d3c665..595efe218 100644 --- a/Exception/InvalidSegmentFilterException.php +++ b/Exception/InvalidSegmentFilterException.php @@ -4,8 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\Exception; -use Exception; - -class InvalidSegmentFilterException extends Exception +class InvalidSegmentFilterException extends \Exception { } diff --git a/Exception/InvalidValueException.php b/Exception/InvalidValueException.php index 4a3e8e856..ee91504e3 100644 --- a/Exception/InvalidValueException.php +++ b/Exception/InvalidValueException.php @@ -4,15 +4,11 @@ namespace MauticPlugin\CustomObjectsBundle\Exception; -use Exception; use MauticPlugin\CustomObjectsBundle\Entity\CustomField; -class InvalidValueException extends Exception +class InvalidValueException extends \Exception { - /** - * @var CustomField|null - */ - private $customField; + private ?CustomField $customField = null; public function setCustomField(CustomField $customField): void { diff --git a/Exception/NoRelationshipException.php b/Exception/NoRelationshipException.php index 501cd1c17..51dc8d76f 100644 --- a/Exception/NoRelationshipException.php +++ b/Exception/NoRelationshipException.php @@ -4,14 +4,11 @@ namespace MauticPlugin\CustomObjectsBundle\Exception; -use Exception; -use Throwable; - -class NoRelationshipException extends Exception +class NoRelationshipException extends \Exception { public function __construct( int $code = 403, - ?Throwable $throwable = null + ?\Throwable $throwable = null ) { parent::__construct( 'This custom object does not have relationship fields defined.', diff --git a/Exception/NotFoundException.php b/Exception/NotFoundException.php index c99dadbb6..1961082db 100644 --- a/Exception/NotFoundException.php +++ b/Exception/NotFoundException.php @@ -4,15 +4,12 @@ namespace MauticPlugin\CustomObjectsBundle\Exception; -use Exception; -use Throwable; - -class NotFoundException extends Exception +class NotFoundException extends \Exception { public function __construct( string $message = 'Not found', int $code = 404, - ?Throwable $throwable = null + ?\Throwable $throwable = null ) { parent::__construct($message, $code, $throwable); } diff --git a/Exception/UndefinedTransformerException.php b/Exception/UndefinedTransformerException.php index 15683cac9..f93e83ec0 100644 --- a/Exception/UndefinedTransformerException.php +++ b/Exception/UndefinedTransformerException.php @@ -4,8 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\Exception; -use Exception; - -class UndefinedTransformerException extends Exception +class UndefinedTransformerException extends \Exception { } diff --git a/Extension/CustomItemListeningExtension.php b/Extension/CustomItemListeningExtension.php index 04d52b972..289074ada 100644 --- a/Extension/CustomItemListeningExtension.php +++ b/Extension/CustomItemListeningExtension.php @@ -14,20 +14,8 @@ class CustomItemListeningExtension implements QueryCollectionExtensionInterface { - /** - * @var UserHelper - */ - private $userHelper; - - /** - * @var CorePermissions - */ - private $security; - - public function __construct(UserHelper $userHelper, CorePermissions $security) + public function __construct(private UserHelper $userHelper, private CorePermissions $security) { - $this->userHelper = $userHelper; - $this->security = $security; } /** @@ -38,7 +26,7 @@ public function applyToCollection( QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null - ) { + ): void { if (CustomItem::class !== $resourceClass) { return; } diff --git a/Form/DataTransformer/CustomObjectHiddenTransformer.php b/Form/DataTransformer/CustomObjectHiddenTransformer.php index 26b0d798e..b509286e7 100644 --- a/Form/DataTransformer/CustomObjectHiddenTransformer.php +++ b/Form/DataTransformer/CustomObjectHiddenTransformer.php @@ -11,14 +11,8 @@ class CustomObjectHiddenTransformer implements DataTransformerInterface { - /** - * @var CustomObjectRepository - */ - private $customObjectRepository; - - public function __construct(CustomObjectRepository $customObjectRepository) + public function __construct(private CustomObjectRepository $customObjectRepository) { - $this->customObjectRepository = $customObjectRepository; } /** diff --git a/Form/DataTransformer/OptionsToStringTransformer.php b/Form/DataTransformer/OptionsToStringTransformer.php index 3f1769ffc..db23ba498 100644 --- a/Form/DataTransformer/OptionsToStringTransformer.php +++ b/Form/DataTransformer/OptionsToStringTransformer.php @@ -15,24 +15,12 @@ class OptionsToStringTransformer implements DataTransformerInterface { /** - * @var SerializerInterface + * @var mixed[] */ - private $serializer; + private array $customFieldCache = []; - /** - * @var CustomFieldModel - */ - private $customFieldModel; - - /** - * @var CustomField[]; - */ - private $customFieldCache = []; - - public function __construct(SerializerInterface $serializer, CustomFieldModel $customFieldModel) + public function __construct(private SerializerInterface $serializer, private CustomFieldModel $customFieldModel) { - $this->serializer = $serializer; - $this->customFieldModel = $customFieldModel; } /** @@ -48,7 +36,7 @@ public function transform($options = null): string } return $this->serializer->serialize( - $options->map(function (CustomFieldOption $option) { + $options->map(function (CustomFieldOption $option): array { return $option->__toArray(); })->toArray(), 'json' diff --git a/Form/DataTransformer/ParamsToStringTransformer.php b/Form/DataTransformer/ParamsToStringTransformer.php index 48c9256fc..a90b4ebdf 100644 --- a/Form/DataTransformer/ParamsToStringTransformer.php +++ b/Form/DataTransformer/ParamsToStringTransformer.php @@ -10,14 +10,8 @@ class ParamsToStringTransformer implements DataTransformerInterface { - /** - * @var SerializerInterface - */ - private $serializer; - - public function __construct(SerializerInterface $serializer) + public function __construct(private SerializerInterface $serializer) { - $this->serializer = $serializer; } /** diff --git a/Form/Type/CampaignActionLinkType.php b/Form/Type/CampaignActionLinkType.php index 30890daf3..5021dce64 100644 --- a/Form/Type/CampaignActionLinkType.php +++ b/Form/Type/CampaignActionLinkType.php @@ -10,24 +10,14 @@ use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class CampaignActionLinkType extends AbstractType { - /** - * @var CustomItemRouteProvider - */ - protected $routeProvider; - - /** - * @var TranslatorInterface - */ - protected $translator; - - public function __construct(CustomItemRouteProvider $routeProvider, TranslatorInterface $translator) - { - $this->routeProvider = $routeProvider; - $this->translator = $translator; + public function __construct( + protected CustomItemRouteProvider $routeProvider, + protected TranslatorInterface $translator + ) { } /** diff --git a/Form/Type/CampaignConditionFieldValueType.php b/Form/Type/CampaignConditionFieldValueType.php index 93f18ffb7..87da53a87 100644 --- a/Form/Type/CampaignConditionFieldValueType.php +++ b/Form/Type/CampaignConditionFieldValueType.php @@ -5,6 +5,7 @@ namespace MauticPlugin\CustomObjectsBundle\Form\Type; use MauticPlugin\CustomObjectsBundle\Model\CustomFieldModel; +use MauticPlugin\CustomObjectsBundle\Model\CustomObjectModel; use MauticPlugin\CustomObjectsBundle\Provider\CustomItemRouteProvider; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; @@ -12,33 +13,16 @@ use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class CampaignConditionFieldValueType extends AbstractType { - /** - * @var CustomFieldModel - */ - protected $customFieldModel; - - /** - * @var CustomItemRouteProvider - */ - protected $routeProvider; - - /** - * @var TranslatorInterface - */ - protected $translator; - public function __construct( - CustomFieldModel $customFieldModel, - CustomItemRouteProvider $routeProvider, - TranslatorInterface $translator + protected CustomFieldModel $customFieldModel, + private CustomObjectModel $customObjectModel, + protected CustomItemRouteProvider $routeProvider, + protected TranslatorInterface $translator ) { - $this->customFieldModel = $customFieldModel; - $this->routeProvider = $routeProvider; - $this->translator = $translator; } /** @@ -46,10 +30,17 @@ public function __construct( */ public function buildForm(FormBuilderInterface $builder, array $options): void { - $fields = $this->customFieldModel->fetchCustomFieldsForObject($options['customObject']); - $choices = []; + $customObject = $this->customObjectModel->fetchEntity($options['customObjectId']); + $fields = $this->customFieldModel->fetchCustomFieldsForObject($customObject); + $choices = []; + foreach ($fields as $field) { - $choices[$field->getLabel()] = $field->getId(); + $choices[$field->getLabel()] = $field->getId(); + $optionAttr[$field->getLabel()] = [ + 'data-operators' => json_encode($field->getTypeObject()->getOperatorOptions()), + 'data-options' => json_encode($field->getChoices()), + 'data-field-type' => $field->getType(), + ]; } $builder->add( @@ -62,16 +53,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'attr' => [ 'class' => 'form-control', ], - 'choice_attr' => array_map( - function ($field) { - return [ - 'data-operators' => json_encode($field->getTypeObject()->getOperatorOptions()), - 'data-options' => json_encode($field->getChoices()), - 'data-field-type' => $field->getType(), - ]; - }, - $fields - ), + 'choice_attr' => $optionAttr ?? [], ] ); @@ -110,7 +92,7 @@ function ($field) { $builder->add( 'customObjectId', HiddenType::class, - ['data' => $options['customObject']->getId()] + ['data' => $options['customObjectId']] ); } @@ -119,6 +101,6 @@ function ($field) { */ public function configureOptions(OptionsResolver $resolver): void { - $resolver->setRequired(['customObject']); + $resolver->setRequired(['customObjectId']); } } diff --git a/Form/Type/CustomFieldType.php b/Form/Type/CustomFieldType.php index 3fbfd7778..765abbdf3 100644 --- a/Form/Type/CustomFieldType.php +++ b/Form/Type/CustomFieldType.php @@ -26,48 +26,15 @@ class CustomFieldType extends AbstractType { - /** - * @var CustomObjectRepository - */ - private $customObjectRepository; - - /** - * @var CustomFieldTypeProvider - */ - private $customFieldTypeProvider; - - /** - * @var ParamsToStringTransformer - */ - private $paramsToStringTransformer; - - /** - * @var OptionsToStringTransformer - */ - private $optionsToStringTransformer; - - /** - * @var CustomFieldFactory - */ - private $customFieldFactory; - - /** - * @var bool - */ - private $isCustomObjectForm; + private bool $isCustomObjectForm; public function __construct( - CustomObjectRepository $customObjectRepository, - CustomFieldTypeProvider $customFieldTypeProvider, - ParamsToStringTransformer $paramsToStringTransformer, - OptionsToStringTransformer $optionsToStringTransformer, - CustomFieldFactory $customFieldFactory + private CustomObjectRepository $customObjectRepository, + private CustomFieldTypeProvider $customFieldTypeProvider, + private ParamsToStringTransformer $paramsToStringTransformer, + private OptionsToStringTransformer $optionsToStringTransformer, + private CustomFieldFactory $customFieldFactory ) { - $this->customObjectRepository = $customObjectRepository; - $this->customFieldTypeProvider = $customFieldTypeProvider; - $this->paramsToStringTransformer = $paramsToStringTransformer; - $this->optionsToStringTransformer = $optionsToStringTransformer; - $this->customFieldFactory = $customFieldFactory; } /** @@ -128,8 +95,8 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setDefaults( [ 'data_class' => CustomField::class, - 'empty_data' => function (FormInterface $form) { - $type = $form->get('type')->getData(); + 'empty_data' => function (FormInterface $form): CustomField { + $type = $form->get('type')->getData(); $customObject = $form->get('customObject')->getData(); return $this->customFieldFactory->create($type, $customObject); @@ -199,8 +166,8 @@ private function buildModalFormFields(FormBuilderInterface $builder, array $opti $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event): void { /** @var CustomField $customField */ $customField = $event->getData(); - $form = $event->getForm(); - $hasChoices = $customField->getTypeObject()->hasChoices(); + $form = $event->getForm(); + $hasChoices = $customField->getTypeObject()->hasChoices(); $this->createDefaultValueInput($form, $customField); @@ -260,7 +227,7 @@ private function buildModalFormFields(FormBuilderInterface $builder, array $opti ] ); - $builder->setAction($options['action']); + $builder->setAction($options['action'] ?? ''); } /** @@ -270,9 +237,9 @@ private function buildModalFormFields(FormBuilderInterface $builder, array $opti private function buildPanelFormFields(FormBuilderInterface $builder): void { $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event): void { - /** @var CustomField $customField */ + /** @var ?CustomField $customField */ $customField = $event->getData(); - $form = $event->getForm(); + $form = $event->getForm(); if (!$customField) { // Custom field is new without data fetched from DB @@ -368,7 +335,7 @@ private function recreateDefaultValueBeforePost(FormBuilderInterface $builder): // Set proper type object when creating new custom field /** @var CustomField $customField */ $customField = $event->getData(); - $form = $event->getForm(); + $form = $event->getForm(); if (!$customField->getTypeObject() && $customField->getType()) { $customField->setTypeObject($this->customFieldTypeProvider->getType($customField->getType())); diff --git a/Form/Type/CustomFieldValueType.php b/Form/Type/CustomFieldValueType.php index 10051667c..fe6dab7eb 100644 --- a/Form/Type/CustomFieldValueType.php +++ b/Form/Type/CustomFieldValueType.php @@ -34,7 +34,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void try { $viewTransformer = $customField->getTypeObject()->createViewTransformer(); $formField->addViewTransformer($viewTransformer); - } catch (UndefinedTransformerException $e) { + } catch (UndefinedTransformerException) { } $builder->add($formField); diff --git a/Form/Type/CustomObjectType.php b/Form/Type/CustomObjectType.php index 2308a7f28..b5a991662 100644 --- a/Form/Type/CustomObjectType.php +++ b/Form/Type/CustomObjectType.php @@ -26,26 +26,11 @@ class CustomObjectType extends AbstractType { - /** - * @var EntityManager - */ - private $entityManager; - - /** - * @var CustomFieldTypeProvider - */ - private $customFieldTypeProvider; - - /** - * @var CustomObjectRepository - */ - private $customObjectRepository; - - public function __construct(EntityManager $entityManager, CustomFieldTypeProvider $customFieldTypeProvider, CustomObjectRepository $customObjectRepository) - { - $this->entityManager = $entityManager; - $this->customFieldTypeProvider = $customFieldTypeProvider; - $this->customObjectRepository = $customObjectRepository; + public function __construct( + private EntityManager $entityManager, + private CustomFieldTypeProvider $customFieldTypeProvider, + private CustomObjectRepository $customObjectRepository + ) { } /** @@ -205,10 +190,6 @@ function (FormEvent $event): void { $customObject = $event->getData(); $customFields = $customObject->getCustomFields(); - if (empty($customFields)) { - return; - } - /** @var CustomField $customField */ foreach ($customFields as $customField) { if (!$customField->getTypeObject()) { diff --git a/Form/Validator/Constraints/AllowUniqueIdentifierValidator.php b/Form/Validator/Constraints/AllowUniqueIdentifierValidator.php index a26d3f7b0..7d24fb6bb 100644 --- a/Form/Validator/Constraints/AllowUniqueIdentifierValidator.php +++ b/Form/Validator/Constraints/AllowUniqueIdentifierValidator.php @@ -11,11 +11,8 @@ class AllowUniqueIdentifierValidator extends ConstraintValidator { - private CustomItemModel $customItemModel; - - public function __construct(CustomItemModel $customItemModel) + public function __construct(private CustomItemModel $customItemModel) { - $this->customItemModel = $customItemModel; } /** diff --git a/Form/Validator/Constraints/CustomObjectTypeValuesValidator.php b/Form/Validator/Constraints/CustomObjectTypeValuesValidator.php index ca780b840..91aa1774d 100644 --- a/Form/Validator/Constraints/CustomObjectTypeValuesValidator.php +++ b/Form/Validator/Constraints/CustomObjectTypeValuesValidator.php @@ -13,7 +13,7 @@ class CustomObjectTypeValuesValidator extends ConstraintValidator /** * @param CustomObject $customObject */ - public function validate($customObject, Constraint $constraint) + public function validate($customObject, Constraint $constraint): void { if (CustomObject::TYPE_RELATIONSHIP === $customObject->getType()) { if (null === $customObject->getMasterObject()) { diff --git a/Helper/LockFlashMessageHelper.php b/Helper/LockFlashMessageHelper.php index 6962791ff..322f34dad 100644 --- a/Helper/LockFlashMessageHelper.php +++ b/Helper/LockFlashMessageHelper.php @@ -7,40 +7,16 @@ use Mautic\CoreBundle\Helper\CoreParametersHelper; use Mautic\CoreBundle\Service\FlashBag; use Symfony\Component\Routing\Router; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class LockFlashMessageHelper { - /** - * @var CoreParametersHelper - */ - private $coreParametersHelper; - - /** - * @var TranslatorInterface - */ - private $translator; - - /** - * @var FlashBag - */ - private $flashBag; - - /** - * @var Router - */ - private $router; - public function __construct( - CoreParametersHelper $coreParametersHelper, - TranslatorInterface $translator, - FlashBag $flashBag, - Router $router + private CoreParametersHelper $coreParametersHelper, + private TranslatorInterface $translator, + private FlashBag $flashBag, + private Router $router ) { - $this->coreParametersHelper = $coreParametersHelper; - $this->translator = $translator; - $this->flashBag = $flashBag; - $this->router = $router; } /** diff --git a/Helper/QueryBuilderManipulatorTrait.php b/Helper/QueryBuilderManipulatorTrait.php index 0b7d6f386..eba753f15 100644 --- a/Helper/QueryBuilderManipulatorTrait.php +++ b/Helper/QueryBuilderManipulatorTrait.php @@ -4,6 +4,8 @@ namespace MauticPlugin\CustomObjectsBundle\Helper; +use Doctrine\DBAL\ArrayParameterType; +use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Query\QueryBuilder; use MauticPlugin\CustomObjectsBundle\Segment\Query\UnionQueryContainer; @@ -18,7 +20,7 @@ trait QueryBuilderManipulatorTrait private function copyParams($fromQueryBuilder, QueryBuilder $toQueryBuilder): void { foreach ($fromQueryBuilder->getParameters() as $key => $value) { - $paramType = is_array($value) ? $toQueryBuilder->getConnection()::PARAM_STR_ARRAY : null; + $paramType = is_array($value) ? ArrayParameterType::STRING : ParameterType::STRING; $toQueryBuilder->setParameter($key, $value, $paramType); } } diff --git a/Helper/QueryFilterFactory.php b/Helper/QueryFilterFactory.php index b8290adb5..89f4a20fc 100644 --- a/Helper/QueryFilterFactory.php +++ b/Helper/QueryFilterFactory.php @@ -14,48 +14,15 @@ class QueryFilterFactory { - /** - * @var EntityManager - */ - private $entityManager; - - /** - * @var CustomFieldTypeProvider - */ - private $fieldTypeProvider; - - /** - * @var UnionQueryContainer|null - */ - private $unionQueryContainer; - - /** - * @var CustomFieldRepository - */ - private $customFieldRepository; - - /** - * @var Calculator - */ - private $calculator; - - /** - * @var int - */ - private $itemRelationLevelLimit; + private ?UnionQueryContainer $unionQueryContainer = null; public function __construct( - EntityManager $entityManager, - CustomFieldTypeProvider $fieldTypeProvider, - CustomFieldRepository $customFieldRepository, - Calculator $calculator, - int $itemRelationLevelLimit + private EntityManager $entityManager, + private CustomFieldTypeProvider $fieldTypeProvider, + private CustomFieldRepository $customFieldRepository, + private Calculator $calculator, + private int $itemRelationLevelLimit ) { - $this->entityManager = $entityManager; - $this->fieldTypeProvider = $fieldTypeProvider; - $this->customFieldRepository = $customFieldRepository; - $this->calculator = $calculator; - $this->itemRelationLevelLimit = $itemRelationLevelLimit; } public function createQuery( @@ -164,4 +131,14 @@ private function createMultilevelQueries(string $alias, int $segmentFilterFieldI $this->unionQueryContainer->add($qb); } } + + public function getCustomFieldTypeById(int $segmentFilterFieldId): string + { + return $this->customFieldRepository->getCustomFieldTypeById($segmentFilterFieldId); + } + + public function getTableNameFromType(string $segmentFilterFieldType): string + { + return $this->fieldTypeProvider->getType($segmentFilterFieldType)->getTableName(); + } } diff --git a/Helper/QueryFilterFactory/Calculator.php b/Helper/QueryFilterFactory/Calculator.php index a634bef2a..c79575693 100644 --- a/Helper/QueryFilterFactory/Calculator.php +++ b/Helper/QueryFilterFactory/Calculator.php @@ -12,29 +12,19 @@ class Calculator private const COLUMN_SUFFIX_LOWER = 'lower'; private const COLUMN_SUFFIX_HIGHER = 'higher'; - /** - * @var int - */ - private $level; + private ?int $level = null; /** * Matrix ciphers - joins per query. - * - * @var int */ - private $cipherCount; + private ?int $cipherCount = null; /** * Number of union queries to be generated. - * - * @var int */ - private $totalQueryCountPerLevel; + private float|int|null $totalQueryCountPerLevel = null; - /** - * @var string - */ - private $matrix; + private ?string $matrix = null; /** * Reset counter with new level. diff --git a/Helper/QueryFilterHelper.php b/Helper/QueryFilterHelper.php index 171901f06..d5ba3d24c 100644 --- a/Helper/QueryFilterHelper.php +++ b/Helper/QueryFilterHelper.php @@ -4,13 +4,13 @@ namespace MauticPlugin\CustomObjectsBundle\Helper; -use Doctrine\DBAL\Connection; +use Doctrine\DBAL\ArrayParameterType; +use Doctrine\DBAL\Query\Expression\CompositeExpression; use Doctrine\ORM\EntityManager; use Mautic\LeadBundle\Segment\ContactSegmentFilter; -use Mautic\LeadBundle\Segment\Query\Expression\CompositeExpression; use Mautic\LeadBundle\Segment\Query\QueryBuilder as SegmentQueryBuilder; +use Mautic\LeadBundle\Segment\RandomParameterName; use MauticPlugin\CustomObjectsBundle\Exception\InvalidArgumentException; -use MauticPlugin\CustomObjectsBundle\Provider\CustomFieldTypeProvider; use MauticPlugin\CustomObjectsBundle\Repository\DbalQueryTrait; use MauticPlugin\CustomObjectsBundle\Segment\Query\UnionQueryContainer; @@ -18,40 +18,20 @@ class QueryFilterHelper { use DbalQueryTrait; - /** - * @var EntityManager - */ - private $entityManager; - - /** - * @var QueryFilterFactory - */ - private $queryFilterFactory; - - /** - * @var CustomFieldTypeProvider - */ - private $fieldTypeProvider; - - /** - * @var int - */ - private $itemRelationLevelLimit; - public function __construct( - EntityManager $entityManager, - QueryFilterFactory $queryFilterFactory + private EntityManager $entityManager, + private QueryFilterFactory $queryFilterFactory, + private RandomParameterName $randomParameterNameService ) { - $this->entityManager = $entityManager; - $this->queryFilterFactory = $queryFilterFactory; } public function createValueQuery( string $alias, - ContactSegmentFilter $segmentFilter + ContactSegmentFilter $segmentFilter, + bool $filterAlreadyNegated = false ): UnionQueryContainer { $unionQueryContainer = $this->queryFilterFactory->createQuery($alias, $segmentFilter); - $this->addCustomFieldValueExpressionFromSegmentFilter($unionQueryContainer, $alias, $segmentFilter); + $this->addCustomFieldValueExpressionFromSegmentFilter($unionQueryContainer, $alias, $segmentFilter, $filterAlreadyNegated); return $unionQueryContainer; } @@ -88,17 +68,27 @@ public function addContactIdRestriction(SegmentQueryBuilder $queryBuilder, strin public function addCustomFieldValueExpressionFromSegmentFilter( UnionQueryContainer $unionQueryContainer, string $tableAlias, - ContactSegmentFilter $filter + ContactSegmentFilter $filter, + bool $filterAlreadyNegated = false ): void { + $filterValue = $filter->getParameterValue(); foreach ($unionQueryContainer as $segmentQueryBuilder) { - $expression = $this->getCustomValueValueExpression($segmentQueryBuilder, $tableAlias, $filter->getOperator()); + $valueParameter = $this->randomParameterNameService->generateRandomParameterName(); + $expression = $this->getCustomValueValueExpression( + $segmentQueryBuilder, + $tableAlias, + $filter, + $valueParameter, + $filterAlreadyNegated, + $filterValue + ); $this->addOperatorExpression( $segmentQueryBuilder, - $tableAlias, $expression, $filter->getOperator(), - $filter->getParameterValue() + $filterValue, + $valueParameter ); } } @@ -109,8 +99,9 @@ public function addCustomObjectNameExpression( string $operator, ?string $value ): void { - $expression = $this->getCustomObjectNameExpression($queryBuilder, $tableAlias, $operator); - $this->addOperatorExpression($queryBuilder, $tableAlias, $expression, $operator, $value); + $valueParameter = $this->randomParameterNameService->generateRandomParameterName(); + $expression = $this->getCustomObjectNameExpression($queryBuilder, $tableAlias, $operator, $valueParameter); + $this->addOperatorExpression($queryBuilder, $expression, $operator, $value, $valueParameter); } /** @@ -119,10 +110,10 @@ public function addCustomObjectNameExpression( */ private function addOperatorExpression( SegmentQueryBuilder $segmentQueryBuilder, - string $tableAlias, $expression, string $operator, - $value + $value, + string $valueParameter ): void { $valueType = null; @@ -134,12 +125,11 @@ private function addOperatorExpression( case 'notIn': case 'multiselect': case 'in': - $valueType = Connection::PARAM_STR_ARRAY; - $valueParameter = $tableAlias.'_value_value'; - + $valueType = ArrayParameterType::STRING; + $segmentQueryBuilder->setParameter($valueParameter, $value, $valueType); break; default: - $valueParameter = $tableAlias.'_value_value'; + $segmentQueryBuilder->setParameter($valueParameter, $value, $valueType); } switch ($operator) { @@ -147,76 +137,108 @@ private function addOperatorExpression( break; default: $segmentQueryBuilder->andWhere($expression); - break; } - - if (isset($valueParameter)) { - $segmentQueryBuilder->setParameter($valueParameter, $value, $valueType); - } } /** * Form the logical expression needed to limit the CustomValue's value for given operator. * + * @param mixed $filterParameterValue + * * @return CompositeExpression|string */ - private function getCustomValueValueExpression(SegmentQueryBuilder $customQuery, string $tableAlias, string $operator) - { + private function getCustomValueValueExpression( + SegmentQueryBuilder $customQuery, + string $tableAlias, + ContactSegmentFilter $filter, + string $valueParameter, + bool $alreadyNegated = false, + $filterParameterValue = null + ) { + $operator = $filter->getOperator(); + if ($alreadyNegated) { + switch ($operator) { + case 'empty': + $operator = 'notEmpty'; + break; + case 'neq': + $operator = 'eq'; + break; + case '!between': + case 'notBetween': + $operator = 'between'; + break; + } + } + switch ($operator) { case 'empty': $expression = $customQuery->expr()->orX( $customQuery->expr()->isNull($tableAlias.'_value.value'), - $customQuery->expr()->eq($tableAlias.'_value.value', $customQuery->expr()->literal('')) ); - + if ($filter->doesColumnSupportEmptyValue()) { + $expression->add( + $customQuery->expr()->eq($tableAlias.'_value.value', $customQuery->expr()->literal('')) + ); + } break; case 'notEmpty': - $expression = $customQuery->expr()->andX( + $expression = $customQuery->expr()->and( $customQuery->expr()->isNotNull($tableAlias.'_value.value'), - $customQuery->expr()->neq($tableAlias.'_value.value', $customQuery->expr()->literal('')) ); + if ($filter->doesColumnSupportEmptyValue()) { + $expression->add( + $customQuery->expr()->neq($tableAlias.'_value.value', $customQuery->expr()->literal('')) + ); + } break; case 'notIn': case '!multiselect': case 'in': case 'multiselect': - $valueParameter = $tableAlias.'_value_value'; $expression = $customQuery->expr()->in( $tableAlias.'_value.value', - ":${valueParameter}" + ":{$valueParameter}" ); break; case 'neq': - $valueParameter = $tableAlias.'_value_value'; - $expression = $customQuery->expr()->orX( - $customQuery->expr()->neq($tableAlias.'_value.value', ":${valueParameter}"), + $expression = $customQuery->expr()->or( + $customQuery->expr()->neq($tableAlias.'_value.value', ":{$valueParameter}"), $customQuery->expr()->isNull($tableAlias.'_value.value') ); break; case 'contains': - $valueParameter = $tableAlias.'_value_value'; - $expression = $customQuery->expr()->like($tableAlias.'_value.value', "%:{$valueParameter}%"); break; case 'notLike': - $valueParameter = $tableAlias.'_value_value'; - - $expression = $customQuery->expr()->orX( + $expression = $customQuery->expr()->or( $customQuery->expr()->isNull($tableAlias.'_value.value'), - $customQuery->expr()->like($tableAlias.'_value.value', ":${valueParameter}") + $customQuery->expr()->like($tableAlias.'_value.value', ":{$valueParameter}") ); break; + case 'between': + case 'notBetween': + if (is_array($filterParameterValue)) { + $expression = $customQuery->expr()->{$operator}( + $tableAlias.'_value.value', + array_map(function (mixed $val) use ($customQuery): mixed { + return is_numeric($val) && intval($val) === $val ? + $val : $customQuery->expr()->literal($val); + }, array_values($filterParameterValue)) + ); + break; + } + // no break default: - $valueParameter = $tableAlias.'_value_value'; $expression = $customQuery->expr()->{$operator}( $tableAlias.'_value.value', - ":${valueParameter}" + ":{$valueParameter}" ); } @@ -228,58 +250,38 @@ private function getCustomValueValueExpression(SegmentQueryBuilder $customQuery, * * @return CompositeExpression|string */ - private function getCustomObjectNameExpression(SegmentQueryBuilder $customQuery, string $tableAlias, string $operator) - { - switch ($operator) { - case 'empty': - $expression = $customQuery->expr()->orX( - $customQuery->expr()->isNull($tableAlias.'_item.name'), - $customQuery->expr()->eq($tableAlias.'_item.name', $customQuery->expr()->literal('')) - ); - - break; - case 'notEmpty': - $expression = $customQuery->expr()->andX( - $customQuery->expr()->isNotNull($tableAlias.'_item.name'), - $customQuery->expr()->neq($tableAlias.'_item.name', $customQuery->expr()->literal('')) - ); - - break; - case 'notIn': - case 'in': - $valueParameter = $tableAlias.'_value_value'; - $expression = $customQuery->expr()->in( - $tableAlias.'_item.name', - ":${valueParameter}" - ); - - break; - case 'neq': - $valueParameter = $tableAlias.'_value_value'; - $expression = $customQuery->expr()->orX( - $customQuery->expr()->eq($tableAlias.'_item.name', ":${valueParameter}"), - $customQuery->expr()->isNull($tableAlias.'_item.name') - ); - - break; - case 'notLike': - $valueParameter = $tableAlias.'_value_value'; - - $expression = $customQuery->expr()->orX( - $customQuery->expr()->isNull($tableAlias.'_item.name'), - $customQuery->expr()->like($tableAlias.'_item.name', ":${valueParameter}") - ); - - break; - default: - $valueParameter = $tableAlias.'_value_value'; - $expression = $customQuery->expr()->{$operator}( - $tableAlias.'_item.name', - ":${valueParameter}" - ); - } - - return $expression; + private function getCustomObjectNameExpression( + SegmentQueryBuilder $customQuery, + string $tableAlias, + string $operator, + string $valueParameter + ) { + return match ($operator) { + 'empty' => $customQuery->expr()->or( + $customQuery->expr()->isNull($tableAlias.'_item.name'), + $customQuery->expr()->eq($tableAlias.'_item.name', $customQuery->expr()->literal('')) + ), + 'notEmpty' => $customQuery->expr()->and( + $customQuery->expr()->isNotNull($tableAlias.'_item.name'), + $customQuery->expr()->neq($tableAlias.'_item.name', $customQuery->expr()->literal('')) + ), + 'notIn', 'in' => $customQuery->expr()->in( + $tableAlias.'_item.name', + ":{$valueParameter}" + ), + 'neq' => $customQuery->expr()->orX( + $customQuery->expr()->eq($tableAlias.'_item.name', ':'.$valueParameter), + $customQuery->expr()->isNull($tableAlias.'_item.name') + ), + 'notLike' => $customQuery->expr()->or( + $customQuery->expr()->isNull($tableAlias.'_item.name'), + $customQuery->expr()->like($tableAlias.'_item.name', ":{$valueParameter}") + ), + default => $customQuery->expr()->{$operator}( + $tableAlias.'_item.name', + ":{$valueParameter}" + ), + }; } /** @@ -313,4 +315,130 @@ private function getBasicItemQueryBuilder(SegmentQueryBuilder $queryBuilder, str return $customFieldQueryBuilder; } + + public function createMergeFilterQuery( + ContactSegmentFilter $segmentFilter, + string $leadsTableAlias + ): SegmentQueryBuilder { + $customItemXrefContactAlias = 'cix'; + $qb = new SegmentQueryBuilder($this->entityManager->getConnection()); + $qb->select('1') + ->from(MAUTIC_TABLE_PREFIX.'custom_item_xref_contact', $customItemXrefContactAlias) + ->where($qb->expr()->eq($customItemXrefContactAlias.'.contact_id', $leadsTableAlias.'.id')); + + $joinedAlias = []; + + foreach ($segmentFilter->contactSegmentFilterCrate->getMergedProperty() as $filter) { + $segmentFilterFieldId = (int) $filter['field']; + $segmentFilterFieldType = $filter['type'] ?: $this->queryFilterFactory + ->getCustomFieldTypeById($segmentFilterFieldId); + $dataTable = $this->queryFilterFactory->getTableNameFromType($segmentFilterFieldType); + $segmentMergedFilter = $segmentFilter; + $segmentFilterFieldOperator = (string) $filter['operator']; + + $alias = $customItemXrefContactAlias.'_'.$segmentFilterFieldId.'_'.$filter['type']; + $aliasValue = $alias.'_value'; + $isCmoFilter = $filter['cmo_filter'] ?? false; + $cinAlias = 'cin_'.$segmentFilterFieldId; + $cinAliasItem = $cinAlias.'_item'; + $valueParameter = $this->randomParameterNameService->generateRandomParameterName(); + + if ($isCmoFilter && !in_array($cinAliasItem, $joinedAlias, true)) { + $this->joinMergeCustomItem($qb, $customItemXrefContactAlias, $cinAliasItem, $segmentFilterFieldId); + $joinedAlias[] = $cinAliasItem; + } elseif (!in_array($aliasValue, $joinedAlias, true)) { + $this->joinMergeCustomField( + $qb, + $customItemXrefContactAlias, + $dataTable, + $aliasValue, + $segmentFilterFieldId + ); + $joinedAlias[] = $aliasValue; + } + + $this->addOperatorExpression( + $qb, + $this->getMergeExpression( + $isCmoFilter, + $qb, + $cinAlias, + $alias, + $segmentMergedFilter, + $valueParameter + ), + $segmentFilterFieldOperator, + $filter['filter_value'], + $valueParameter + ); + } + + return $qb; + } + + private function joinMergeCustomItem( + SegmentQueryBuilder $qb, + string $customItemXrefContactAlias, + string $cinAliasItem, + int $segmentFilterFieldId + ): void { + $qb->leftJoin( + $customItemXrefContactAlias, + MAUTIC_TABLE_PREFIX.'custom_item', + $cinAliasItem, + "$customItemXrefContactAlias.custom_item_id = $cinAliasItem.id" + ); + $qb->andWhere($qb->expr()->eq($cinAliasItem.'.custom_object_id', $segmentFilterFieldId)); + } + + private function joinMergeCustomField( + SegmentQueryBuilder $qb, + string $customItemXrefContactAlias, + string $dataTable, + string $aliasValue, + int $segmentFilterFieldId + ): void { + $qb->innerJoin( + $customItemXrefContactAlias, + MAUTIC_TABLE_PREFIX.$dataTable, + $aliasValue, + "$aliasValue.custom_item_id = $customItemXrefContactAlias.custom_item_id AND " + ."$aliasValue.custom_field_id = $segmentFilterFieldId" + ); + } + + /** + * @phpstan-ignore-next-line + * + * @return CompositeExpression|string + */ + private function getMergeExpression( + bool $isCmoFilter, + SegmentQueryBuilder $qb, + string $cinAlias, + string $alias, + ContactSegmentFilter $filter, + string $valueParameter + ) { + $segmentFilterFieldOperator = $filter->getOperator(); + if ($isCmoFilter) { + $expression = $this->getCustomObjectNameExpression( + $qb, + $cinAlias, + $segmentFilterFieldOperator, + $valueParameter + ); + } else { + $expression = $this->getCustomValueValueExpression( + $qb, + $alias, + $filter, + $valueParameter, + false, + $filter->getParameterValue() + ); + } + + return $expression; + } } diff --git a/Helper/TokenFormatter.php b/Helper/TokenFormatter.php index af5379670..62bd37eee 100644 --- a/Helper/TokenFormatter.php +++ b/Helper/TokenFormatter.php @@ -117,16 +117,15 @@ private function htmlList(array $values, string $tag): string foreach ($values as $item) { $list .= '
  • '.$item.'
  • '; } - $list .= ""; - return $list; + return $list.""; } private function removeEmptyValues(array $values): array { return array_filter( $values, - function ($value) { + function ($value): bool { return '' !== trim($value); } ); diff --git a/Helper/TokenParser.php b/Helper/TokenParser.php index c7e4d845b..f97d67f9c 100644 --- a/Helper/TokenParser.php +++ b/Helper/TokenParser.php @@ -27,7 +27,7 @@ public function findTokens(string $content): ArrayCollection try { $this->extractAliases($parts[0], $token); - } catch (\LengthException $e) { + } catch (\LengthException) { // Invalid token, pretend like we did not see it. continue; } @@ -109,7 +109,7 @@ private function getPartsDividedByPipe(string $tokenDataRaw): array private function trimArrayElements(array $array): array { return array_map( - function ($part) { + function ($part): string { return trim($part); }, $array diff --git a/Migrations/Version_0_0_1.php b/Migrations/Version_0_0_1.php index 5b0310033..6a25021ae 100644 --- a/Migrations/Version_0_0_1.php +++ b/Migrations/Version_0_0_1.php @@ -10,10 +10,7 @@ class Version_0_0_1 extends AbstractMigration { - /** - * @var string - */ - private $table = 'custom_object'; + private string $table = 'custom_object'; /** * {@inheritdoc} @@ -22,7 +19,7 @@ protected function isApplicable(Schema $schema): bool { try { return !$schema->getTable($this->concatPrefix($this->table))->hasColumn('description'); - } catch (SchemaException $e) { + } catch (SchemaException) { return false; } } diff --git a/Migrations/Version_0_0_11.php b/Migrations/Version_0_0_11.php index caaaaf385..078e95a01 100644 --- a/Migrations/Version_0_0_11.php +++ b/Migrations/Version_0_0_11.php @@ -5,16 +5,13 @@ namespace MauticPlugin\CustomObjectsBundle\Migrations; use Doctrine\DBAL\Schema\Schema; -use Mautic\CoreBundle\Exception\SchemaException; +use Doctrine\DBAL\Schema\SchemaException; use Mautic\IntegrationsBundle\Migration\AbstractMigration; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; class Version_0_0_11 extends AbstractMigration { - /** - * @var string - */ - private $table = 'custom_object'; + private string $table = 'custom_object'; /** * {@inheritdoc} @@ -24,9 +21,9 @@ protected function isApplicable(Schema $schema): bool $tableCustomObject = $this->concatPrefix($this->table); try { - return !$schema->getTable($tableCustomObject)->hasColumn('type') || - !$schema->getTable($tableCustomObject)->hasColumn('master_object'); - } catch (SchemaException $e) { + return !$schema->getTable($tableCustomObject)->hasColumn('type') + || !$schema->getTable($tableCustomObject)->hasColumn('master_object'); + } catch (SchemaException) { return false; } } diff --git a/Migrations/Version_0_0_13.php b/Migrations/Version_0_0_13.php index 5766ef58e..adcbf34e6 100644 --- a/Migrations/Version_0_0_13.php +++ b/Migrations/Version_0_0_13.php @@ -17,7 +17,7 @@ protected function isApplicable(Schema $schema): bool { try { return !$schema->getTable($this->concatPrefix('custom_object'))->hasColumn('relationship_object'); - } catch (SchemaException $e) { + } catch (SchemaException) { return false; } } diff --git a/Migrations/Version_0_0_14.php b/Migrations/Version_0_0_14.php index 918a3c1f6..4df17e9f2 100644 --- a/Migrations/Version_0_0_14.php +++ b/Migrations/Version_0_0_14.php @@ -17,7 +17,7 @@ protected function isApplicable(Schema $schema): bool { try { return !$schema->getTable($this->concatPrefix('custom_field'))->hasColumn('show_in_custom_object_detail_list'); - } catch (SchemaException $e) { + } catch (SchemaException) { return false; } } diff --git a/Migrations/Version_0_0_15.php b/Migrations/Version_0_0_15.php index 4514feb44..da930ccf1 100644 --- a/Migrations/Version_0_0_15.php +++ b/Migrations/Version_0_0_15.php @@ -14,7 +14,7 @@ protected function isApplicable(Schema $schema): bool { try { return $schema->getTable($this->concatPrefix('custom_object'))->hasColumn('relationship'); - } catch (SchemaException $e) { + } catch (SchemaException) { return false; } } diff --git a/Migrations/Version_0_0_16.php b/Migrations/Version_0_0_16.php index 17af16cf6..e9279848c 100644 --- a/Migrations/Version_0_0_16.php +++ b/Migrations/Version_0_0_16.php @@ -5,7 +5,7 @@ namespace MauticPlugin\CustomObjectsBundle\Migrations; use Doctrine\DBAL\Schema\Schema; -use Mautic\CoreBundle\Exception\SchemaException; +use Doctrine\DBAL\Schema\SchemaException; use Mautic\IntegrationsBundle\Migration\AbstractMigration; class Version_0_0_16 extends AbstractMigration @@ -16,9 +16,9 @@ protected function isApplicable(Schema $schema): bool $table = $schema->getTable($tableName); try { - return $table->hasColumn('required') && - null === $table->getColumn('required')->getDefault(); - } catch (SchemaException $e) { + return $table->hasColumn('required') + && null === $table->getColumn('required')->getDefault(); + } catch (SchemaException) { return false; } } diff --git a/Migrations/Version_0_0_17.php b/Migrations/Version_0_0_17.php index 531ea816d..e21757262 100644 --- a/Migrations/Version_0_0_17.php +++ b/Migrations/Version_0_0_17.php @@ -10,15 +10,14 @@ class Version_0_0_17 extends AbstractMigration { - /** @var Schema */ - private $schema; + private ?Schema $schema = null; protected function isApplicable(Schema $schema): bool { $this->schema = $schema; try { return !$this->schema->getTable($this->concatPrefix('custom_object'))->hasForeignKey('FK_CO_RELATIONSHIP_OBJECT'); - } catch (SchemaException $e) { + } catch (SchemaException) { return false; } } diff --git a/Migrations/Version_0_0_18.php b/Migrations/Version_0_0_18.php index 1c389680c..453eb5223 100644 --- a/Migrations/Version_0_0_18.php +++ b/Migrations/Version_0_0_18.php @@ -10,15 +10,14 @@ class Version_0_0_18 extends AbstractMigration { - /** @var Schema */ - private $schema; + private ?Schema $schema = null; protected function isApplicable(Schema $schema): bool { $this->schema = $schema; try { return !$this->schema->getTable($this->concatPrefix('custom_object'))->hasForeignKey('FK_CO_MASTER_OBJECT'); - } catch (SchemaException $e) { + } catch (SchemaException) { return false; } } diff --git a/Migrations/Version_0_0_19.php b/Migrations/Version_0_0_19.php index a76f762da..c91718737 100644 --- a/Migrations/Version_0_0_19.php +++ b/Migrations/Version_0_0_19.php @@ -13,8 +13,7 @@ class Version_0_0_19 extends AbstractMigration { public const FOREIGN_KEY_TO_DELETE = '/^FK_\d+594D0CC2$/'; - /** @var Schema */ - private $schema; + private ?Schema $schema = null; protected function isApplicable(Schema $schema): bool { diff --git a/Migrations/Version_0_0_2.php b/Migrations/Version_0_0_2.php index 0bcd7419b..a8d7169a5 100644 --- a/Migrations/Version_0_0_2.php +++ b/Migrations/Version_0_0_2.php @@ -9,10 +9,7 @@ class Version_0_0_2 extends AbstractMigration { - /** - * @var string - */ - private $table = 'custom_item_xref_custom_item'; + private string $table = 'custom_item_xref_custom_item'; /** * {@inheritdoc} diff --git a/Migrations/Version_0_0_21.php b/Migrations/Version_0_0_21.php index 6a7ca6b7f..e1316fe40 100644 --- a/Migrations/Version_0_0_21.php +++ b/Migrations/Version_0_0_21.php @@ -18,7 +18,7 @@ protected function isApplicable(Schema $schema): bool try { return !$schema->getTable($tableCustomObject)->hasColumn('is_unique_identifier'); - } catch (SchemaException $e) { + } catch (SchemaException) { return false; } } diff --git a/Migrations/Version_0_0_27.php b/Migrations/Version_0_0_27.php index d9feb6cc2..d153caa85 100644 --- a/Migrations/Version_0_0_27.php +++ b/Migrations/Version_0_0_27.php @@ -18,7 +18,7 @@ protected function isApplicable(Schema $schema): bool try { return !$schema->getTable($tableCustomItem)->hasColumn('unique_hash'); - } catch (SchemaException $e) { + } catch (SchemaException) { return false; } } diff --git a/Migrations/Version_0_0_3.php b/Migrations/Version_0_0_3.php index 709b7de35..59490da38 100644 --- a/Migrations/Version_0_0_3.php +++ b/Migrations/Version_0_0_3.php @@ -9,10 +9,7 @@ class Version_0_0_3 extends AbstractMigration { - /** - * @var string - */ - private $table = 'custom_field_option'; + private string $table = 'custom_field_option'; /** * {@inheritdoc} diff --git a/Migrations/Version_0_0_4.php b/Migrations/Version_0_0_4.php index 79be54015..b00d65ee1 100644 --- a/Migrations/Version_0_0_4.php +++ b/Migrations/Version_0_0_4.php @@ -9,10 +9,7 @@ class Version_0_0_4 extends AbstractMigration { - /** - * @var string - */ - private $table = 'custom_field_value_option'; + private string $table = 'custom_field_value_option'; /** * {@inheritdoc} diff --git a/Migrations/Version_0_0_5.php b/Migrations/Version_0_0_5.php index 623de5f4f..beeffe5d6 100644 --- a/Migrations/Version_0_0_5.php +++ b/Migrations/Version_0_0_5.php @@ -10,10 +10,7 @@ class Version_0_0_5 extends AbstractMigration { - /** - * @var string - */ - private $table = 'custom_field_value_option'; + private string $table = 'custom_field_value_option'; /** * {@inheritdoc} @@ -22,7 +19,7 @@ protected function isApplicable(Schema $schema): bool { try { return $schema->getTable($this->concatPrefix($this->table))->hasColumn('option_id'); - } catch (SchemaException $e) { + } catch (SchemaException) { return false; } } diff --git a/Migrations/Version_0_0_6.php b/Migrations/Version_0_0_6.php index 4a0ec4dcf..e7a759f1d 100644 --- a/Migrations/Version_0_0_6.php +++ b/Migrations/Version_0_0_6.php @@ -10,10 +10,7 @@ class Version_0_0_6 extends AbstractMigration { - /** - * @var string - */ - private $table = 'custom_field_option'; + private string $table = 'custom_field_option'; /** * {@inheritdoc} @@ -22,7 +19,7 @@ protected function isApplicable(Schema $schema): bool { try { return $schema->getTable($this->concatPrefix($this->table))->hasColumn('id'); - } catch (SchemaException $e) { + } catch (SchemaException) { return false; } } diff --git a/Migrations/Version_0_0_7.php b/Migrations/Version_0_0_7.php index 007d95c91..4577047fc 100644 --- a/Migrations/Version_0_0_7.php +++ b/Migrations/Version_0_0_7.php @@ -10,10 +10,7 @@ class Version_0_0_7 extends AbstractMigration { - /** - * @var string - */ - private $table = 'custom_field_option'; + private string $table = 'custom_field_option'; /** * {@inheritdoc} @@ -22,7 +19,7 @@ protected function isApplicable(Schema $schema): bool { try { return !$schema->getTable($this->concatPrefix($this->table))->hasColumn('option_order'); - } catch (SchemaException $e) { + } catch (SchemaException) { return false; } } diff --git a/Migrations/Version_0_0_8.php b/Migrations/Version_0_0_8.php index 94af2463e..a4e3cd478 100644 --- a/Migrations/Version_0_0_8.php +++ b/Migrations/Version_0_0_8.php @@ -10,10 +10,7 @@ class Version_0_0_8 extends AbstractMigration { - /** - * @var string - */ - private $table = 'custom_item_xref_custom_item'; + private string $table = 'custom_item_xref_custom_item'; /** * {@inheritdoc} @@ -22,7 +19,7 @@ protected function isApplicable(Schema $schema): bool { try { return $schema->getTable($this->concatPrefix($this->table))->hasColumn('parent_custom_item_id'); - } catch (SchemaException $e) { + } catch (SchemaException) { return false; } } diff --git a/Migrations/Version_0_0_9.php b/Migrations/Version_0_0_9.php index ef82a98e6..bac270f0f 100644 --- a/Migrations/Version_0_0_9.php +++ b/Migrations/Version_0_0_9.php @@ -10,15 +10,9 @@ class Version_0_0_9 extends AbstractMigration { - /** - * @var string - */ - private $tableCustomObject = 'custom_object'; + private string $tableCustomObject = 'custom_object'; - /** - * @var string - */ - private $tableCustomField = 'custom_field'; + private string $tableCustomField = 'custom_field'; /** * {@inheritdoc} @@ -27,7 +21,7 @@ protected function isApplicable(Schema $schema): bool { try { return !$schema->getTable($this->concatPrefix($this->tableCustomObject))->hasColumn('alias'); - } catch (SchemaException $e) { + } catch (SchemaException) { return false; } } diff --git a/Model/CustomFieldModel.php b/Model/CustomFieldModel.php index 960cf3ed0..20ce79eef 100644 --- a/Model/CustomFieldModel.php +++ b/Model/CustomFieldModel.php @@ -4,38 +4,40 @@ namespace MauticPlugin\CustomObjectsBundle\Model; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Tools\Pagination\Paginator; use Mautic\CoreBundle\Entity\CommonRepository; +use Mautic\CoreBundle\Helper\CoreParametersHelper; use Mautic\CoreBundle\Helper\DateTimeHelper; use Mautic\CoreBundle\Helper\UserHelper; use Mautic\CoreBundle\Model\FormModel; +use Mautic\CoreBundle\Security\Permissions\CorePermissions; +use Mautic\CoreBundle\Translation\Translator; use MauticPlugin\CustomObjectsBundle\Entity\CustomField; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; use MauticPlugin\CustomObjectsBundle\Exception\ForbiddenException; use MauticPlugin\CustomObjectsBundle\Exception\NotFoundException; use MauticPlugin\CustomObjectsBundle\Provider\CustomFieldPermissionProvider; use MauticPlugin\CustomObjectsBundle\Repository\CustomFieldRepository; +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; class CustomFieldModel extends FormModel { - /** - * @var CustomFieldRepository - */ - private $customFieldRepository; - - /** - * @var CustomFieldPermissionProvider - */ - private $permissionProvider; - public function __construct( - CustomFieldRepository $customFieldRepository, - CustomFieldPermissionProvider $permissionProvider, - UserHelper $userHelper + EntityManagerInterface $em, + CorePermissions $security, + EventDispatcherInterface $dispatcher, + UrlGeneratorInterface $router, + Translator $translator, + UserHelper $userHelper, + LoggerInterface $logger, + CoreParametersHelper $coreParametersHelper, + private CustomFieldRepository $customFieldRepository, + private CustomFieldPermissionProvider $permissionProvider, ) { - $this->customFieldRepository = $customFieldRepository; - $this->permissionProvider = $permissionProvider; - $this->userHelper = $userHelper; + parent::__construct($em, $security, $dispatcher, $router, $translator, $userHelper, $logger, $coreParametersHelper); } public function setMetadata(CustomField $entity): CustomField @@ -140,7 +142,7 @@ private function sanitizeAlias(CustomField $entity): CustomField if (empty($dirtyAlias)) { $dirtyAlias = $entity->getName(); } - $cleanAlias = $this->cleanAlias($dirtyAlias, '', false, '-'); + $cleanAlias = $this->cleanAlias($dirtyAlias, '', 0, '-'); $entity->setAlias($cleanAlias); return $entity; @@ -177,7 +179,7 @@ private function addCreatorLimit(array $args): array { try { $this->permissionProvider->isGranted('viewother'); - } catch (ForbiddenException $e) { + } catch (ForbiddenException) { if (!isset($args['filter'])) { $args['filter'] = []; } diff --git a/Model/CustomFieldOptionModel.php b/Model/CustomFieldOptionModel.php index 51bd105de..c259bfcab 100644 --- a/Model/CustomFieldOptionModel.php +++ b/Model/CustomFieldOptionModel.php @@ -8,18 +8,9 @@ class CustomFieldOptionModel { - /** - * @var EntityManager - */ - private $entityManager; - - /** - * CustomFieldOptionModel constructor. - */ public function __construct( - EntityManager $entityManager + private EntityManager $entityManager ) { - $this->entityManager = $entityManager; } /** diff --git a/Model/CustomFieldValueModel.php b/Model/CustomFieldValueModel.php index e10b92081..1bc2325b7 100644 --- a/Model/CustomFieldValueModel.php +++ b/Model/CustomFieldValueModel.php @@ -18,22 +18,10 @@ class CustomFieldValueModel { - /** - * @var EntityManager - */ - private $entityManager; - - /** - * @var ValidatorInterface - */ - private $validator; - public function __construct( - EntityManager $entityManager, - ValidatorInterface $validator + private EntityManager $entityManager, + private ValidatorInterface $validator ) { - $this->entityManager = $entityManager; - $this->validator = $validator; } /** @@ -119,7 +107,7 @@ public function getItemsListData(Collection $customFields, array $customItems): return null; } - $columns = $customFields->map(function (CustomField $customField) { + $columns = $customFields->map(function (CustomField $customField): ?string { return $customField->getLabel(); }); $data = $this->buildItemsListData($customFields->toArray(), $customItems); @@ -192,9 +180,7 @@ private function fetchValues(Collection $queries): ArrayCollection $query = implode(' UNION ALL ', $queries->toArray()); $statement = $this->entityManager->getConnection()->prepare($query); - $statement->execute(); - - return new ArrayCollection($statement->fetchAll()); + return new ArrayCollection($statement->executeQuery()->fetchAllAssociative()); } private function buildQueriesForUnion(CustomItem $customItem, Collection $customFields): Collection @@ -226,7 +212,7 @@ private function buildItemsListData(array $customFields, array $customItems): ar $result = $this->fetchItemsListData($customFields, $customItems); $result = $this->transformItemsListDataResult($result); - return array_reduce($customItems, function (array $data, CustomItem $customItem) use ($customFields, $result) { + return array_reduce($customItems, function (array $data, CustomItem $customItem) use ($customFields, $result): array { $fields = []; foreach ($customFields as $customField) { @@ -252,7 +238,7 @@ private function buildItemsListData(array $customFields, array $customItems): ar private function fetchItemsListData(array $customFields, array $customItems): array { // create a map [tableName] = [fieldId, fieldId, ...] for creating queries - $tableToCustomFieldIds = array_reduce($customFields, function (array $tables, CustomField $customField) { + $tableToCustomFieldIds = array_reduce($customFields, function (array $tables, CustomField $customField): array { $tableName = $customField->getTypeObject()->getPrefixedTableName(); if (!isset($tables[$tableName])) { @@ -276,7 +262,7 @@ private function fetchItemsListData(array $customFields, array $customItems): ar }, array_keys($tableToCustomFieldIds)); // extract item IDs - $itemIds = array_map(function (CustomItem $customItem) { + $itemIds = array_map(function (CustomItem $customItem): int { return $customItem->getId(); }, $customItems); @@ -288,7 +274,7 @@ private function fetchItemsListData(array $customFields, array $customItems): ar $types[$table] = Connection::PARAM_INT_ARRAY; } - return $this->entityManager->getConnection()->fetchAll(implode(' UNION ALL ', $queries), $params, $types); + return $this->entityManager->getConnection()->fetchAllAssociative(implode(' UNION ALL ', $queries), $params, $types); } /** @@ -297,8 +283,8 @@ private function fetchItemsListData(array $customFields, array $customItems): ar */ private function transformItemsListDataResult(array $result): array { - return array_reduce($result, function (array $result, array $row) { - $itemId = $row['custom_item_id']; + return array_reduce($result, function (array $result, array $row): array { + $itemId = $row['custom_item_id']; $fieldId = $row['custom_field_id']; if (!isset($result[$itemId])) { diff --git a/Model/CustomItemExportSchedulerModel.php b/Model/CustomItemExportSchedulerModel.php index bc09d399a..e13b353f8 100644 --- a/Model/CustomItemExportSchedulerModel.php +++ b/Model/CustomItemExportSchedulerModel.php @@ -4,12 +4,14 @@ namespace MauticPlugin\CustomObjectsBundle\Model; -use DateTimeImmutable; -use DateTimeZone; +use Doctrine\ORM\EntityManagerInterface; +use Mautic\CoreBundle\Helper\CoreParametersHelper; use Mautic\CoreBundle\Helper\ExportHelper; +use Mautic\CoreBundle\Helper\UserHelper; use Mautic\CoreBundle\Model\AbstractCommonModel; +use Mautic\CoreBundle\Security\Permissions\CorePermissions; +use Mautic\CoreBundle\Translation\Translator; use Mautic\EmailBundle\Helper\MailHelper; -use MauticPlugin\CustomObjectsBundle\CustomItemEvents; use MauticPlugin\CustomObjectsBundle\Entity\CustomField; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Entity\CustomItemExportScheduler; @@ -18,9 +20,11 @@ use MauticPlugin\CustomObjectsBundle\Repository\CustomItemExportSchedulerRepository; use MauticPlugin\CustomObjectsBundle\Repository\CustomItemRepository; use MauticPlugin\CustomObjectsBundle\Repository\CustomItemXrefContactRepository; +use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; class CustomItemExportSchedulerModel extends AbstractCommonModel { @@ -28,38 +32,25 @@ class CustomItemExportSchedulerModel extends AbstractCommonModel private const CUSTOM_ITEM_LIMIT = 200; private const CONTACT_LIMIT = 5000; - private ExportHelper $exportHelper; - - private MailHelper $mailHelper; - - private CustomItemRouteProvider $customItemRouteProvider; - - private CustomFieldValueModel $customFieldValueModel; - - private CustomItemXrefContactRepository $customItemXrefContactRepository; - - private CustomItemRepository $customItemRepository; - - private EventDispatcherInterface $eventDispatcher; - private string $filePath; public function __construct( - ExportHelper $exportHelper, - MailHelper $mailHelper, - CustomFieldValueModel $customFieldValueModel, - CustomItemRouteProvider $customItemRouteProvider, - CustomItemXrefContactRepository $customItemXrefContactRepository, - CustomItemRepository $customItemRepository, - EventDispatcherInterface $eventDispatcher + EntityManagerInterface $em, + CorePermissions $security, + EventDispatcherInterface $dispatcher, + UrlGeneratorInterface $router, + Translator $translator, + UserHelper $userHelper, + LoggerInterface $logger, + CoreParametersHelper $coreParametersHelper, + private ExportHelper $exportHelper, + private MailHelper $mailHelper, + private CustomFieldValueModel $customFieldValueModel, + private CustomItemRouteProvider $customItemRouteProvider, + private CustomItemXrefContactRepository $customItemXrefContactRepository, + private CustomItemRepository $customItemRepository, ) { - $this->exportHelper = $exportHelper; - $this->mailHelper = $mailHelper; - $this->customFieldValueModel = $customFieldValueModel; - $this->customItemRouteProvider = $customItemRouteProvider; - $this->customItemXrefContactRepository = $customItemXrefContactRepository; - $this->customItemRepository = $customItemRepository; - $this->eventDispatcher = $eventDispatcher; + parent::__construct($em, $security, $dispatcher, $router, $translator, $userHelper, $logger, $coreParametersHelper); } public function getRepository(): CustomItemExportSchedulerRepository @@ -79,7 +70,7 @@ public function saveEntity(int $customObjectId): CustomItemExportScheduler $customItemExportScheduler = new CustomItemExportScheduler(); $customItemExportScheduler ->setUser($this->userHelper->getUser()) - ->setScheduledDateTime(new DateTimeImmutable('now', new DateTimeZone('UTC'))) + ->setScheduledDateTime(new \DateTimeImmutable('now', new \DateTimeZone('UTC'))) ->setCustomObjectId($customObjectId); $this->em->persist($customItemExportScheduler); @@ -93,7 +84,7 @@ public function processDataAndGetExportFilePath(CustomItemExportScheduler $custo $scheduledDateTime = $customItemExportScheduler->getScheduledDateTime(); $fileName = 'custom_items_export_'.$scheduledDateTime->format(self::EXPORT_FILE_NAME_DATE_FORMAT).'.csv'; - $filePath = $this->exportHelper->getValidExportFileName($fileName, 'custom_item_export_dir'); + $filePath = $this->coreParametersHelper->get('custom_item_export_dir').'/'.$fileName; $this->filePath = $filePath; @@ -167,20 +158,12 @@ private function addCustomItemsToCsvFile(array $customFields, CustomObject $cust foreach ($customFields as $customField) { $fieldValue = $listData->getFields($customItem->getId())[$customField->getId()]->getValue(); - switch ($customField->getType()) { - case 'date': - $value = $fieldValue instanceof \DateTimeInterface ? $fieldValue->format('Y-m-d') : $fieldValue; - break; - - case 'datetime': - $value = $fieldValue instanceof \DateTimeInterface ? $fieldValue->format('Y-m-d H:i:s') : $fieldValue; - break; - - case 'multiselect': $value = is_array($fieldValue) ? implode(',', $fieldValue) : $fieldValue; - break; - - default: $value = $fieldValue; - } + $value = match ($customField->getType()) { + 'date' => $fieldValue instanceof \DateTimeInterface ? $fieldValue->format('Y-m-d') : $fieldValue, + 'datetime' => $fieldValue instanceof \DateTimeInterface ? $fieldValue->format('Y-m-d H:i:s') : $fieldValue, + 'multiselect' => is_array($fieldValue) ? implode(',', $fieldValue) : $fieldValue, + default => $fieldValue, + }; $rowData[] = $value; } @@ -206,10 +189,6 @@ private function addCustomItemsToCsvFile(array $customFields, CustomObject $cust $rowData = $savedRow; $rowData[] = implode(',', $results); - if ($this->eventDispatcher->hasListeners(CustomItemEvents::ON_PROCESSING_FILE)) { - $this->eventDispatcher->dispatch(CustomItemEvents::ON_PROCESSING_FILE); - } - fputcsv($handler, $rowData); $customItemAdded = true; } diff --git a/Model/CustomItemImportModel.php b/Model/CustomItemImportModel.php index 64d1d6266..10836f344 100644 --- a/Model/CustomItemImportModel.php +++ b/Model/CustomItemImportModel.php @@ -4,40 +4,39 @@ namespace MauticPlugin\CustomObjectsBundle\Model; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; +use Mautic\CoreBundle\Helper\CoreParametersHelper; +use Mautic\CoreBundle\Helper\UserHelper; use Mautic\CoreBundle\Model\FormModel; -use Mautic\CoreBundle\Templating\Helper\FormatterHelper; +use Mautic\CoreBundle\Security\Permissions\CorePermissions; +use Mautic\CoreBundle\Translation\Translator; +use Mautic\CoreBundle\Twig\Helper\FormatterHelper; use Mautic\LeadBundle\Entity\Import; +use Mautic\LeadBundle\Entity\Lead; use Mautic\UserBundle\Entity\User; +use MauticPlugin\CustomObjectsBundle\DTO\ImportLogDTO; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; use MauticPlugin\CustomObjectsBundle\Exception\NotFoundException; +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; class CustomItemImportModel extends FormModel { - /** - * @var EntityManager - */ - private $entityManager; - - /** - * @var CustomItemModel - */ - private $customItemModel; - - /** - * @var FormatterHelper - */ - private $formatterHelper; - public function __construct( - EntityManager $entityManager, - CustomItemModel $customItemModel, - FormatterHelper $formatterHelper + EntityManagerInterface $em, + CorePermissions $security, + EventDispatcherInterface $dispatcher, + UrlGeneratorInterface $router, + Translator $translator, + UserHelper $userHelper, + LoggerInterface $logger, + CoreParametersHelper $coreParametersHelper, + private CustomItemModel $customItemModel, + private FormatterHelper $formatterHelper, ) { - $this->entityManager = $entityManager; - $this->customItemModel = $customItemModel; - $this->formatterHelper = $formatterHelper; + parent::__construct($em, $security, $dispatcher, $router, $translator, $userHelper, $logger, $coreParametersHelper); } /** @@ -45,7 +44,7 @@ public function __construct( * * @return bool updated = true, inserted = false */ - public function import(Import $import, array $rowData, CustomObject $customObject): bool + public function import(Import $import, array $rowData, CustomObject $customObject, ImportLogDTO $importLogDto = null): bool { $matchedFields = $import->getMatchedFields(); $customItem = $this->getCustomItem($import, $customObject, $rowData); @@ -80,7 +79,7 @@ public function import(Import $import, array $rowData, CustomObject $customObjec try { $customFieldValue = $customItem->findCustomFieldValueForFieldId((int) $customFieldId); - } catch (NotFoundException $e) { + } catch (NotFoundException) { $customFieldValue = $customItem->createNewCustomFieldValueByFieldId((int) $customFieldId, $csvValue); } @@ -94,7 +93,7 @@ public function import(Import $import, array $rowData, CustomObject $customObjec $merged = true; } - $this->linkContacts($customItem, $contactIds); + $this->linkContacts($customItem, $contactIds, $importLogDto); return $merged; } @@ -102,14 +101,25 @@ public function import(Import $import, array $rowData, CustomObject $customObjec /** * @param int[] $contactIds */ - private function linkContacts(CustomItem $customItem, array $contactIds): CustomItem + private function linkContacts(CustomItem $customItem, array $contactIds, ?ImportLogDTO $importLogDto): void { foreach ($contactIds as $contactId) { - $xref = $this->customItemModel->linkEntity($customItem, 'contact', $contactId); + $leadRepository = $this->em->getRepository(Lead::class); + if (method_exists($leadRepository, 'exists') && !$leadRepository->exists((string) $contactId)) { + if ($importLogDto) { + $importLogDto->addWarning( + $this->translator->trans('custom.item.import.invalid.contactid.for.link', [ + '%contactId%' => $contactId, + '%customItemId%' => $customItem->getId(), + ]) + ); + } + continue; + } + + $xref = $this->customItemModel->linkEntity($customItem, 'contact', (int) $contactId); $customItem->addContactReference($xref); } - - return $customItem; } private function setOwner(Import $import, CustomItem $customItem): CustomItem @@ -118,7 +128,7 @@ private function setOwner(Import $import, CustomItem $customItem): CustomItem if ($owner) { /** @var User $user */ - $user = $this->entityManager->find(User::class, $owner); + $user = $this->em->find(User::class, $owner); $customItem->setCreatedBy($user); } @@ -143,7 +153,7 @@ private function getCustomItem(Import $import, CustomObject $customObject, array try { $customItem = $this->customItemModel->fetchEntity((int) $rowData[$idKey]); $customItem = $this->customItemModel->populateCustomFields($customItem); - } catch (NotFoundException $e) { + } catch (NotFoundException) { } } diff --git a/Model/CustomItemModel.php b/Model/CustomItemModel.php index 626db817f..b1625c77e 100644 --- a/Model/CustomItemModel.php +++ b/Model/CustomItemModel.php @@ -5,13 +5,16 @@ namespace MauticPlugin\CustomObjectsBundle\Model; use Doctrine\DBAL\Query\QueryBuilder as DbalQueryBuilder; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\QueryBuilder; use Mautic\CoreBundle\Doctrine\Helper\FulltextKeyword; use Mautic\CoreBundle\Entity\CommonRepository; +use Mautic\CoreBundle\Helper\CoreParametersHelper; use Mautic\CoreBundle\Helper\DateTimeHelper; use Mautic\CoreBundle\Helper\UserHelper; use Mautic\CoreBundle\Model\FormModel; +use Mautic\CoreBundle\Security\Permissions\CorePermissions; +use Mautic\CoreBundle\Translation\Translator; use MauticPlugin\CustomObjectsBundle\CustomItemEvents; use MauticPlugin\CustomObjectsBundle\DTO\CustomItemFieldListData; use MauticPlugin\CustomObjectsBundle\DTO\TableConfig; @@ -31,53 +34,28 @@ use MauticPlugin\CustomObjectsBundle\Exception\NotFoundException; use MauticPlugin\CustomObjectsBundle\Provider\CustomItemPermissionProvider; use MauticPlugin\CustomObjectsBundle\Repository\CustomItemRepository; +use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Validator\Validator\ValidatorInterface; -use UnexpectedValueException; class CustomItemModel extends FormModel { - /** - * @var EntityManager - */ - private $entityManager; - - /** - * @var CustomItemRepository - */ - private $customItemRepository; - - /** - * @var CustomItemPermissionProvider - */ - private $permissionProvider; - - /** - * @var CustomFieldValueModel - */ - private $customFieldValueModel; - - /** - * @var ValidatorInterface - */ - private $validator; - public function __construct( - EntityManager $entityManager, - CustomItemRepository $customItemRepository, - CustomItemPermissionProvider $permissionProvider, - UserHelper $userHelper, - CustomFieldValueModel $customFieldValueModel, + EntityManagerInterface $em, + CorePermissions $security, EventDispatcherInterface $dispatcher, - ValidatorInterface $validator + UrlGeneratorInterface $router, + Translator $translator, + UserHelper $userHelper, + LoggerInterface $logger, + CoreParametersHelper $coreParametersHelper, + private CustomItemRepository $customItemRepository, + private CustomItemPermissionProvider $permissionProvider, + private CustomFieldValueModel $customFieldValueModel, + private ValidatorInterface $validator, ) { - $this->entityManager = $entityManager; - $this->customItemRepository = $customItemRepository; - $this->permissionProvider = $permissionProvider; - $this->userHelper = $userHelper; - $this->customFieldValueModel = $customFieldValueModel; - $this->dispatcher = $dispatcher; - $this->validator = $validator; + parent::__construct($em, $security, $dispatcher, $router, $translator, $userHelper, $logger, $coreParametersHelper); } public function save(CustomItem $customItem, bool $dryRun = false): CustomItem @@ -102,18 +80,18 @@ public function save(CustomItem $customItem, bool $dryRun = false): CustomItem throw new InvalidValueException($errors->get(0)->getMessage()); } - $this->dispatcher->dispatch(CustomItemEvents::ON_CUSTOM_ITEM_PRE_SAVE, new CustomItemEvent($customItem, $customItem->isNew())); + $this->dispatcher->dispatch(new CustomItemEvent($customItem, $customItem->isNew()), CustomItemEvents::ON_CUSTOM_ITEM_PRE_SAVE); if (!$dryRun) { if ($customItem->isNew()) { // Custom item is new so we need to upsert it to atomically find whether it exists based on unique fields or not. - $this->entityManager->detach($customItem); + $this->em->detach($customItem); $this->customItemRepository->upsert($customItem); // We need to re-attach the entity to the entity manager so that it can be saved by the rest of the code. $customFieldValues = $customItem->getCustomFieldValues(); - $hasBeenUpdated = $customItem->hasBeenUpdated(); - $hasBeenInserted = $customItem->hasBeenInserted(); + $hasBeenUpdated = $customItem->hasBeenUpdated(); + $hasBeenInserted = $customItem->hasBeenInserted(); $customItem = $this->fetchEntity($customItem->getId()); $customItem->setHasBeenUpdated($hasBeenUpdated); @@ -124,8 +102,8 @@ public function save(CustomItem $customItem, bool $dryRun = false): CustomItem $customItem->addCustomFieldValue($customFieldValue); } } else { - $this->entityManager->persist($customItem); - $this->entityManager->flush(); + $this->em->persist($customItem); + $this->em->flush(); } $customItem->getCustomFieldValues()->map( @@ -134,7 +112,7 @@ public function save(CustomItem $customItem, bool $dryRun = false): CustomItem $customItem->recordCustomFieldValueChanges(); - $this->dispatcher->dispatch(CustomItemEvents::ON_CUSTOM_ITEM_POST_SAVE, new CustomItemEvent($customItem, $customItem->isNew())); + $this->dispatcher->dispatch(new CustomItemEvent($customItem, $customItem->isNew()), CustomItemEvents::ON_CUSTOM_ITEM_POST_SAVE); } return $customItem; @@ -157,54 +135,54 @@ public function unlockEntity($entity, $extra = null): void } /** - * @throws UnexpectedValueException + * @throws \UnexpectedValueException */ public function linkEntity(CustomItem $customItem, string $entityType, int $entityId): CustomItemXrefInterface { $event = new CustomItemXrefEntityDiscoveryEvent($customItem, $entityType, $entityId); - $this->dispatcher->dispatch(CustomItemEvents::ON_CUSTOM_ITEM_LINK_ENTITY_DISCOVERY, $event); + $this->dispatcher->dispatch($event, CustomItemEvents::ON_CUSTOM_ITEM_LINK_ENTITY_DISCOVERY); if (!$event->getXrefEntity() instanceof CustomItemXrefInterface) { - throw new UnexpectedValueException("Entity {$entityType} was not able to be linked to {$customItem->getName()} ({$customItem->getId()})"); + throw new \UnexpectedValueException("Entity {$entityType} was not able to be linked to {$customItem->getName()} ({$customItem->getId()})"); } - $this->dispatcher->dispatch(CustomItemEvents::ON_CUSTOM_ITEM_LINK_ENTITY, new CustomItemXrefEntityEvent($event->getXrefEntity())); + $this->dispatcher->dispatch(new CustomItemXrefEntityEvent($event->getXrefEntity()), CustomItemEvents::ON_CUSTOM_ITEM_LINK_ENTITY); return $event->getXrefEntity(); } /** - * @throws UnexpectedValueException + * @throws \UnexpectedValueException */ public function unlinkEntity(CustomItem $customItem, string $entityType, int $entityId): CustomItemXrefInterface { $event = new CustomItemXrefEntityDiscoveryEvent($customItem, $entityType, $entityId); - $this->dispatcher->dispatch(CustomItemEvents::ON_CUSTOM_ITEM_LINK_ENTITY_DISCOVERY, $event); + $this->dispatcher->dispatch($event, CustomItemEvents::ON_CUSTOM_ITEM_LINK_ENTITY_DISCOVERY); if (!$event->getXrefEntity() instanceof CustomItemXrefInterface) { - throw new UnexpectedValueException("Entity {$entityType} was not able to be unlinked from {$customItem->getName()} ({$customItem->getId()})"); + throw new \UnexpectedValueException("Entity {$entityType} was not able to be unlinked from {$customItem->getName()} ({$customItem->getId()})"); } - $this->dispatcher->dispatch(CustomItemEvents::ON_CUSTOM_ITEM_UNLINK_ENTITY, new CustomItemXrefEntityEvent($event->getXrefEntity())); + $this->dispatcher->dispatch(new CustomItemXrefEntityEvent($event->getXrefEntity()), CustomItemEvents::ON_CUSTOM_ITEM_UNLINK_ENTITY); return $event->getXrefEntity(); } public function delete(CustomItem $customItem): void { - //take note of ID before doctrine wipes it out + // take note of ID before doctrine wipes it out $id = $customItem->getId(); $event = new CustomItemEvent($customItem); - $this->dispatcher->dispatch(CustomItemEvents::ON_CUSTOM_ITEM_PRE_DELETE, $event); + $this->dispatcher->dispatch($event, CustomItemEvents::ON_CUSTOM_ITEM_PRE_DELETE); - $this->entityManager->remove($customItem); - $this->entityManager->flush(); + $this->em->remove($customItem); + $this->em->flush(); - //set the id for use in events + // set the id for use in events $customItem->deletedId = $id; - $this->dispatcher->dispatch(CustomItemEvents::ON_CUSTOM_ITEM_POST_DELETE, $event); + $this->dispatcher->dispatch($event, CustomItemEvents::ON_CUSTOM_ITEM_POST_DELETE); } /** @@ -232,8 +210,8 @@ public function getTableData(TableConfig $tableConfig): array $queryBuilder = $this->createListOrmQueryBuilder($tableConfig); $this->dispatcher->dispatch( - CustomItemEvents::ON_CUSTOM_ITEM_LIST_ORM_QUERY, - new CustomItemListQueryEvent($queryBuilder, $tableConfig) + new CustomItemListQueryEvent($queryBuilder, $tableConfig), + CustomItemEvents::ON_CUSTOM_ITEM_LIST_ORM_QUERY ); return $queryBuilder->getQuery()->getResult(); @@ -247,11 +225,11 @@ public function getArrayTableData(TableConfig $tableConfig): array $queryBuilder = $this->createListDbalQueryBuilder($tableConfig); $this->dispatcher->dispatch( - CustomItemEvents::ON_CUSTOM_ITEM_LIST_DBAL_QUERY, - new CustomItemListDbalQueryEvent($queryBuilder, $tableConfig) + new CustomItemListDbalQueryEvent($queryBuilder, $tableConfig), + CustomItemEvents::ON_CUSTOM_ITEM_LIST_DBAL_QUERY ); - return $queryBuilder->execute()->fetchAll(); + return $queryBuilder->execute()->fetchAllAssociative(); } public function getCountForTable(TableConfig $tableConfig): int @@ -263,8 +241,8 @@ public function getCountForTable(TableConfig $tableConfig): int $queryBuilder->resetDQLPart('orderBy'); $this->dispatcher->dispatch( - CustomItemEvents::ON_CUSTOM_ITEM_LIST_ORM_QUERY, - new CustomItemListQueryEvent($queryBuilder, $tableConfig) + new CustomItemListQueryEvent($queryBuilder, $tableConfig), + CustomItemEvents::ON_CUSTOM_ITEM_LIST_ORM_QUERY ); return (int) $queryBuilder->getQuery()->getSingleScalarResult(); @@ -280,8 +258,8 @@ public function getLookupData(TableConfig $tableConfig): array $queryBuilder->select("{$rootAlias}.name as value, {$rootAlias}.id"); $this->dispatcher->dispatch( - CustomItemEvents::ON_CUSTOM_ITEM_LOOKUP_QUERY, - new CustomItemListQueryEvent($queryBuilder, $tableConfig) + new CustomItemListQueryEvent($queryBuilder, $tableConfig), + CustomItemEvents::ON_CUSTOM_ITEM_LOOKUP_QUERY ); $rows = $queryBuilder->getQuery()->getArrayResult(); @@ -316,17 +294,11 @@ public function populateCustomFields(CustomItem $customItem): CustomItem */ public function getFieldListData(CustomObject $customObject, array $customItems, string $filterEntityType): ?CustomItemFieldListData { - switch ($filterEntityType) { - case 'customItem': - $customFields = $customObject->getFieldsShowInCustomObjectDetailList(); - break; - case 'contact': - $customFields = $customObject->getFieldsShowInContactDetailList(); - break; - default: - $customFields = $customObject->getPublishedFields(); - break; - } + $customFields = match ($filterEntityType) { + 'customItem' => $customObject->getFieldsShowInCustomObjectDetailList(), + 'contact' => $customObject->getFieldsShowInContactDetailList(), + default => $customObject->getPublishedFields(), + }; return $this->customFieldValueModel->getItemsListData($customFields, $customItems); } @@ -351,7 +323,7 @@ public function getPermissionBase(): string } /** - * @throws UnexpectedValueException + * @throws \UnexpectedValueException */ private function createListOrmQueryBuilder(TableConfig $tableConfig): QueryBuilder { @@ -359,7 +331,7 @@ private function createListOrmQueryBuilder(TableConfig $tableConfig): QueryBuild $customObjectId = $tableConfig->getParameter('customObjectId'); $search = $tableConfig->getParameter('search'); - $queryBuilder = $this->entityManager->createQueryBuilder(); + $queryBuilder = $this->em->createQueryBuilder(); $queryBuilder = $tableConfig->configureOrmQueryBuilder($queryBuilder); $queryBuilder->select(CustomItem::TABLE_ALIAS); @@ -375,14 +347,14 @@ private function createListOrmQueryBuilder(TableConfig $tableConfig): QueryBuild } /** - * @throws UnexpectedValueException + * @throws \UnexpectedValueException */ private function createListDbalQueryBuilder(TableConfig $tableConfig): DbalQueryBuilder { $this->validateTableConfig($tableConfig); $customObjectId = $tableConfig->getParameter('customObjectId'); - $queryBuilder = $this->entityManager->getConnection()->createQueryBuilder(); + $queryBuilder = $this->em->getConnection()->createQueryBuilder(); $queryBuilder = $tableConfig->configureDbalQueryBuilder($queryBuilder); $queryBuilder->select(CustomItem::TABLE_ALIAS.'.*'); @@ -394,12 +366,12 @@ private function createListDbalQueryBuilder(TableConfig $tableConfig): DbalQuery } /** - * @throws UnexpectedValueException + * @throws \UnexpectedValueException */ private function validateTableConfig(TableConfig $tableConfig): void { if (empty($tableConfig->getParameter('customObjectId'))) { - throw new UnexpectedValueException("customObjectId cannot be empty. It's required for permission management"); + throw new \UnexpectedValueException("customObjectId cannot be empty. It's required for permission management"); } } @@ -421,7 +393,7 @@ private function applyOwnerFilter($queryBuilder, int $customObjectId) try { $this->permissionProvider->isGranted('viewother', $customObjectId); - } catch (ForbiddenException $e) { + } catch (ForbiddenException) { $queryBuilder->andWhere(CustomItem::TABLE_ALIAS.'.createdBy', $user->getId()); } @@ -430,12 +402,12 @@ private function applyOwnerFilter($queryBuilder, int $customObjectId) private function applySearchFilter(QueryBuilder $queryBuilder, string $search): void { - $valueTextBuilder = $this->entityManager->createQueryBuilder(); + $valueTextBuilder = $this->em->createQueryBuilder(); $valueTextBuilder->select('IDENTITY(ValueText.customItem)'); $valueTextBuilder->from(CustomFieldValueText::class, 'ValueText'); $valueTextBuilder->andWhere('MATCH (ValueText.value) AGAINST (:search BOOLEAN) > 0'); - $valueOptionBuilder = $this->entityManager->createQueryBuilder(); + $valueOptionBuilder = $this->em->createQueryBuilder(); $valueOptionBuilder->select('IDENTITY(ValueOption.customItem)'); $valueOptionBuilder->from(CustomFieldValueOption::class, 'ValueOption'); $valueOptionBuilder->andWhere('MATCH (ValueOption.value) AGAINST (:search BOOLEAN) > 0'); diff --git a/Model/CustomItemXrefContactModel.php b/Model/CustomItemXrefContactModel.php index 6d9f378d5..9ae36f3a2 100644 --- a/Model/CustomItemXrefContactModel.php +++ b/Model/CustomItemXrefContactModel.php @@ -4,39 +4,23 @@ namespace MauticPlugin\CustomObjectsBundle\Model; -use DateTime; -use Doctrine\ORM\EntityManager; use Mautic\CoreBundle\Helper\Chart\ChartQuery; use Mautic\CoreBundle\Helper\Chart\LineChart; use Mautic\CoreBundle\Model\FormModel; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; -use Symfony\Component\Translation\TranslatorInterface; class CustomItemXrefContactModel extends FormModel { - /** - * @var EntityManager - */ - private $entityManager; - - public function __construct( - EntityManager $entityManager, - TranslatorInterface $translator - ) { - $this->entityManager = $entityManager; - $this->translator = $translator; - } - /** * @return mixed[] */ public function getLinksLineChartData( - DateTime $from, - DateTime $to, + \DateTime $from, + \DateTime $to, CustomItem $customItem ): array { $chart = new LineChart(null, $from, $to); - $query = new ChartQuery($this->entityManager->getConnection(), $from, $to); + $query = new ChartQuery($this->em->getConnection(), $from, $to); $links = $query->fetchTimeData( 'custom_item_xref_contact', 'date_added', diff --git a/Model/CustomObjectModel.php b/Model/CustomObjectModel.php index fd6d1eed0..04de8371b 100644 --- a/Model/CustomObjectModel.php +++ b/Model/CustomObjectModel.php @@ -4,16 +4,18 @@ namespace MauticPlugin\CustomObjectsBundle\Model; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\Tools\Pagination\Paginator; use Mautic\CoreBundle\Entity\CommonRepository; use Mautic\CoreBundle\Helper\Chart\ChartQuery; use Mautic\CoreBundle\Helper\Chart\LineChart; +use Mautic\CoreBundle\Helper\CoreParametersHelper; use Mautic\CoreBundle\Helper\DateTimeHelper; use Mautic\CoreBundle\Helper\UserHelper; use Mautic\CoreBundle\Model\FormModel; -use Mautic\LeadBundle\Model\ListModel; +use Mautic\CoreBundle\Security\Permissions\CorePermissions; +use Mautic\CoreBundle\Translation\Translator; use MauticPlugin\CustomObjectsBundle\CustomObjectEvents; use MauticPlugin\CustomObjectsBundle\DTO\TableConfig; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; @@ -23,51 +25,26 @@ use MauticPlugin\CustomObjectsBundle\Exception\NotFoundException; use MauticPlugin\CustomObjectsBundle\Provider\CustomObjectPermissionProvider; use MauticPlugin\CustomObjectsBundle\Repository\CustomObjectRepository; +use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; class CustomObjectModel extends FormModel { - /** - * @var EntityManager - */ - private $entityManager; - - /** - * @var CustomObjectRepository - */ - private $customObjectRepository; - - /** - * @var CustomObjectPermissionProvider - */ - private $permissionProvider; - - /** - * @var CustomFieldModel - */ - private $customFieldModel; - - /** - * @var ListModel - */ - private $listModel; - public function __construct( - EntityManager $entityManager, - CustomObjectRepository $customObjectRepository, - CustomObjectPermissionProvider $permissionProvider, - UserHelper $userHelper, - CustomFieldModel $customFieldModel, + EntityManagerInterface $em, + CorePermissions $security, EventDispatcherInterface $dispatcher, - ListModel $listModel + UrlGeneratorInterface $router, + Translator $translator, + UserHelper $userHelper, + LoggerInterface $logger, + CoreParametersHelper $coreParametersHelper, + private CustomObjectRepository $customObjectRepository, + private CustomObjectPermissionProvider $permissionProvider, + private CustomFieldModel $customFieldModel, ) { - $this->entityManager = $entityManager; - $this->customObjectRepository = $customObjectRepository; - $this->permissionProvider = $permissionProvider; - $this->userHelper = $userHelper; - $this->customFieldModel = $customFieldModel; - $this->dispatcher = $dispatcher; - $this->listModel = $listModel; + parent::__construct($em, $security, $dispatcher, $router, $translator, $userHelper, $logger, $coreParametersHelper); } public function save(CustomObject $customObject): CustomObject @@ -97,12 +74,12 @@ public function save(CustomObject $customObject): CustomObject $this->setCustomFieldsMetadata($customObject); - $this->dispatcher->dispatch(CustomObjectEvents::ON_CUSTOM_OBJECT_PRE_SAVE, $event); + $this->dispatcher->dispatch($event, CustomObjectEvents::ON_CUSTOM_OBJECT_PRE_SAVE); - $this->entityManager->persist($customObject); - $this->entityManager->flush(); + $this->em->persist($customObject); + $this->em->flush(); - $this->dispatcher->dispatch(CustomObjectEvents::ON_CUSTOM_OBJECT_POST_SAVE, $event); + $this->dispatcher->dispatch($event, CustomObjectEvents::ON_CUSTOM_OBJECT_POST_SAVE); return $customObject; } @@ -112,14 +89,14 @@ public function delete(CustomObject $customObject): void // Take note of ID before doctrine wipes it out $id = $customObject->getId(); $event = new CustomObjectEvent($customObject); - $this->dispatcher->dispatch(CustomObjectEvents::ON_CUSTOM_OBJECT_PRE_DELETE, $event); + $this->dispatcher->dispatch($event, CustomObjectEvents::ON_CUSTOM_OBJECT_PRE_DELETE); - $this->entityManager->remove($customObject); - $this->entityManager->flush(); + $this->em->remove($customObject); + $this->em->flush(); // Set the id for use in events $customObject->deletedId = $id; - $this->dispatcher->dispatch(CustomObjectEvents::ON_CUSTOM_OBJECT_POST_DELETE, $event); + $this->dispatcher->dispatch($event, CustomObjectEvents::ON_CUSTOM_OBJECT_POST_DELETE); } /** @@ -211,7 +188,7 @@ public function removeCustomFieldById(CustomObject $customObject, int $customFie foreach ($customObject->getCustomFields() as $customField) { if ($customField->getId() === $customFieldId) { $customObject->removeCustomField($customField); - if ($this->entityManager->contains($customField)) { + if ($this->em->contains($customField)) { // We need to ensure that field exists when cloning CO with deleted fields $this->customFieldModel->deleteEntity($customField); } @@ -241,7 +218,7 @@ public function getPermissionBase(): string public function getItemsLineChartData(\DateTime $from, \DateTime $to, CustomObject $customObject): array { $chart = new LineChart(null, $from, $to); - $query = new ChartQuery($this->entityManager->getConnection(), $from, $to); + $query = new ChartQuery($this->em->getConnection(), $from, $to); $items = $query->fetchTimeData('custom_item', 'date_added', ['custom_object_id' => $customObject->getId()]); $chart->setDataset($this->translator->trans('custom.object.created.items'), $items); @@ -250,7 +227,7 @@ public function getItemsLineChartData(\DateTime $from, \DateTime $to, CustomObje private function createListQueryBuilder(TableConfig $tableConfig): QueryBuilder { - $queryBuilder = $this->entityManager->createQueryBuilder(); + $queryBuilder = $this->em->createQueryBuilder(); $queryBuilder = $tableConfig->configureOrmQueryBuilder($queryBuilder); $queryBuilder->select(CustomObject::TABLE_ALIAS); $queryBuilder->from(CustomObject::class, CustomObject::TABLE_ALIAS); @@ -271,7 +248,7 @@ private function sanitizeAlias(CustomObject $entity): CustomObject if (empty($dirtyAlias)) { $dirtyAlias = $entity->getName(); } - $cleanAlias = $this->cleanAlias($dirtyAlias, '', false, '-'); + $cleanAlias = $this->cleanAlias($dirtyAlias, '', 0, '-'); $entity->setAlias($cleanAlias); return $entity; @@ -313,7 +290,7 @@ private function addCreatorLimit(array $args): array try { $this->permissionProvider->isGranted('viewother'); - } catch (ForbiddenException $e) { + } catch (ForbiddenException) { if (!isset($args['filter'])) { $args['filter'] = []; } @@ -339,7 +316,7 @@ private function applyOwnerFilter(QueryBuilder $queryBuilder): QueryBuilder { try { $this->permissionProvider->isGranted('viewother'); - } catch (ForbiddenException $e) { + } catch (ForbiddenException) { $queryBuilder->andWhere(CustomObject::TABLE_ALIAS.'.createdBy', $this->userHelper->getUser()->getId()); } @@ -363,7 +340,7 @@ public function getMasterCustomObjects(): array { return array_filter( $this->fetchAllPublishedEntities(), - function ($item) { + function ($item): bool { $type = $item->getType(); return CustomObject::TYPE_MASTER === $type || null === $type; diff --git a/Provider/AbstractPermissionProvider.php b/Provider/AbstractPermissionProvider.php index 680b239b5..723687d40 100644 --- a/Provider/AbstractPermissionProvider.php +++ b/Provider/AbstractPermissionProvider.php @@ -12,14 +12,8 @@ abstract class AbstractPermissionProvider { public const BASE = 'undefined'; - /** - * @var CorePermissions - */ - private $corePermissions; - - public function __construct(CorePermissions $corePermissions) + public function __construct(private CorePermissions $corePermissions) { - $this->corePermissions = $corePermissions; } /** @@ -40,7 +34,7 @@ public function hasEntityAccess(string $permission, FormEntity $entity): void if (!$this->corePermissions->hasEntityAccess(static::BASE.$permission.'own', static::BASE.$permission.'other', $entity->getCreatedBy())) { $entityId = method_exists($entity, 'getId') ? $entity->getId() : null; - throw new ForbiddenException($permission, get_class($entity), $entityId); + throw new ForbiddenException($permission, $entity::class, $entityId); } } diff --git a/Provider/ConfigProvider.php b/Provider/ConfigProvider.php index 94b5e8f0c..62549c52b 100644 --- a/Provider/ConfigProvider.php +++ b/Provider/ConfigProvider.php @@ -14,14 +14,10 @@ class ConfigProvider public const CONFIG_PARAM_ENABLED = 'custom_objects_enabled'; public const CONFIG_PARAM_ITEM_VALUE_TO_CONTACT_RELATION_LIMIT = 'custom_object_item_value_to_contact_relation_limit'; - /** - * @var CoreParametersHelper - */ - private $coreParametersHelper; + public const CONFIG_PARAM_ITEM_VALUE_TO_CONTACT_RELATION_DEFAULT_LIMIT = 3; - public function __construct(CoreParametersHelper $coreParametersHelper) + public function __construct(private CoreParametersHelper $coreParametersHelper) { - $this->coreParametersHelper = $coreParametersHelper; } /** @@ -31,4 +27,14 @@ public function pluginIsEnabled(): bool { return (bool) $this->coreParametersHelper->get(self::CONFIG_PARAM_ENABLED, true); } + + public function isCustomObjectMergeFilterEnabled(): bool + { + return $this->coreParametersHelper->get('custom_object_merge_filter', false) + && (0 === (int) $this->coreParametersHelper->get( + self::CONFIG_PARAM_ITEM_VALUE_TO_CONTACT_RELATION_LIMIT, + self::CONFIG_PARAM_ITEM_VALUE_TO_CONTACT_RELATION_DEFAULT_LIMIT + ) + ); + } } diff --git a/Provider/CustomFieldRouteProvider.php b/Provider/CustomFieldRouteProvider.php index 3463ee768..8ee50516c 100644 --- a/Provider/CustomFieldRouteProvider.php +++ b/Provider/CustomFieldRouteProvider.php @@ -12,14 +12,8 @@ class CustomFieldRouteProvider public const ROUTE_SAVE = 'mautic_custom_field_save'; - /** - * @var RouterInterface - */ - private $router; - - public function __construct(RouterInterface $router) + public function __construct(private RouterInterface $router) { - $this->router = $router; } public function buildSaveRoute(string $fieldType, ?int $id = null, ?int $objectId = null, ?int $panelCount = null, ?int $panelId = null): string diff --git a/Provider/CustomFieldTypeProvider.php b/Provider/CustomFieldTypeProvider.php index 57569fe38..45e1cf916 100644 --- a/Provider/CustomFieldTypeProvider.php +++ b/Provider/CustomFieldTypeProvider.php @@ -13,7 +13,7 @@ class CustomFieldTypeProvider /** * @var CustomFieldTypeInterface[] */ - private $customFieldTypes = []; + private array $customFieldTypes = []; /** * Builds the list of custom field type objects. diff --git a/Provider/CustomItemPermissionProvider.php b/Provider/CustomItemPermissionProvider.php index c756e1da8..b681524c4 100644 --- a/Provider/CustomItemPermissionProvider.php +++ b/Provider/CustomItemPermissionProvider.php @@ -11,14 +11,8 @@ class CustomItemPermissionProvider { - /** - * @var CorePermissions - */ - private $corePermissions; - - public function __construct(CorePermissions $corePermissions) + public function __construct(private CorePermissions $corePermissions) { - $this->corePermissions = $corePermissions; } /** diff --git a/Provider/CustomItemRouteProvider.php b/Provider/CustomItemRouteProvider.php index 9ad8c09d2..3010b86c7 100644 --- a/Provider/CustomItemRouteProvider.php +++ b/Provider/CustomItemRouteProvider.php @@ -51,14 +51,8 @@ class CustomItemRouteProvider public const ROUTE_CONTACT_LIST = 'mautic_custom_item_contacts'; - /** - * @var RouterInterface - */ - private $router; - - public function __construct(RouterInterface $router) + public function __construct(private RouterInterface $router) { - $this->router = $router; } public function buildListRoute(int $objectId, int $page = 1, string $filterEntityType = null, int $filterEntityId = null, array $parameters = []): string diff --git a/Provider/CustomObjectRouteProvider.php b/Provider/CustomObjectRouteProvider.php index 954ecd293..63aa4ae6a 100644 --- a/Provider/CustomObjectRouteProvider.php +++ b/Provider/CustomObjectRouteProvider.php @@ -26,14 +26,8 @@ class CustomObjectRouteProvider public const ROUTE_LINK = 'mautic_custom_object_link'; - /** - * @var RouterInterface - */ - private $router; - - public function __construct(RouterInterface $router) + public function __construct(private RouterInterface $router) { - $this->router = $router; } public function buildListRoute(int $page = 1): string @@ -56,9 +50,6 @@ public function buildNewRoute(): string return $this->router->generate(static::ROUTE_NEW); } - /** - * @param int $id - */ public function buildEditRoute(?int $id = null): string { return $this->router->generate(static::ROUTE_EDIT, ['objectId' => $id]); diff --git a/Provider/SessionProvider.php b/Provider/SessionProvider.php index f06c91d36..e6790c6e1 100644 --- a/Provider/SessionProvider.php +++ b/Provider/SessionProvider.php @@ -33,26 +33,8 @@ class SessionProvider */ private const KEY_FILTER = 'filter'; - /** - * @var Session - */ - private $session; - - /** - * @var int - */ - private $defaultPageLimit; - - /** - * @var string - */ - private $namespace; - - public function __construct(Session $session, string $namespace, int $defaultPageLimit) + public function __construct(private Session $session, private string $namespace, private int $defaultPageLimit) { - $this->session = $session; - $this->namespace = $namespace; - $this->defaultPageLimit = $defaultPageLimit; } public function getNamespace(): string diff --git a/Provider/SessionProviderFactory.php b/Provider/SessionProviderFactory.php index 63a302484..7bbdb5e16 100644 --- a/Provider/SessionProviderFactory.php +++ b/Provider/SessionProviderFactory.php @@ -9,20 +9,8 @@ class SessionProviderFactory { - /** - * @var Session - */ - private $session; - - /** - * @var CoreParametersHelper - */ - private $coreParametersHelper; - - public function __construct(Session $session, CoreParametersHelper $coreParametersHelper) + public function __construct(private Session $session, private CoreParametersHelper $coreParametersHelper) { - $this->session = $session; - $this->coreParametersHelper = $coreParametersHelper; } public function createObjectProvider(): SessionProvider diff --git a/README.md b/README.md index 972c611a5..3cdf2dd66 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,12 @@ You'll be able to - filter Segments by values in the Custom Objects - create Campaign conditions based on the values in the Custom Objects +## Workflow Update + +Until Github Actions' CI/CD are in place, we request to developers to: +1. Merge their unreviewed and unapproved PRs to `development` branch. +2. Merge their reviewed and approved PRs to `beta` branch. + ## Glossary - `Custom Field` represents one piece of information. Example: Price, Description, Color @@ -48,6 +54,21 @@ See [Wiki](https://github.com/acquia/mc-cs-plugin-custom-objects/wiki) The plugin has currently test coverage of 91%. Each new PR must be covered by tests to be considered to be merged. To run the tests execute `composer test -- --filter CustomObjects` from the Mautic root dir. +## Static Analysis + +PHPSTAN is used for static analysis. Here is how to run it locally from the Mautic's root dir: +``` +bin/phpstan --configuration=plugins/CustomObjectsBundle/phpstan.neon +``` + +This plugin has its own PHPSTAN configuration because there is too big tech debt pile already and so it must have its own PHPSTAN baseline file. + +The tech debt is visible in the phpstan-baseline.neon file and can be regenerated with: +``` +bin/phpstan --configuration=plugins/CustomObjectsBundle/phpstan.neon --generate-baseline=plugins/CustomObjectsBundle/phpstan-baseline.neon && sed -i 's/plugins\/CustomObjectsBundle\//g' plugins/CustomObjectsBundle/phpstan-neon.php +``` +Please do not add more tech debt on this pile. Fix all the new PHPSTAN errors and possibly some old ones with your code changes. + ## License Copyright (C) 2022 Acquia, Inc. diff --git a/Report/ReportColumnsBuilder.php b/Report/ReportColumnsBuilder.php index 12e403f94..1b131b6b3 100644 --- a/Report/ReportColumnsBuilder.php +++ b/Report/ReportColumnsBuilder.php @@ -14,14 +14,9 @@ class ReportColumnsBuilder public const DEFAULT_COLUMN_TYPE = 'string'; /** - * @var CustomObject + * @var mixed[] */ - private $customObject; - - /** - * @var array - */ - private $columns = []; + private array $columns = []; /** * @var callable @@ -37,9 +32,8 @@ class ReportColumnsBuilder 'datetime' => 'datetime', ]; - public function __construct(CustomObject $customObject) + public function __construct(private CustomObject $customObject) { - $this->customObject = $customObject; } private function buildColumns(): void diff --git a/Repository/CustomCommonRepository.php b/Repository/CustomCommonRepository.php new file mode 100644 index 000000000..8d7c30e2b --- /dev/null +++ b/Repository/CustomCommonRepository.php @@ -0,0 +1,18 @@ +where(CustomItem::TABLE_ALIAS.'.customObject = :customObjectId'); $queryBuilder->setParameter('customObjectId', $customObjectId); $queryBuilder->setMaxResults(1); + return (int) $queryBuilder->getQuery()->getSingleScalarResult(); } diff --git a/Repository/CustomItemXrefContactRepository.php b/Repository/CustomItemXrefContactRepository.php index 8297ed6c8..34d491e63 100644 --- a/Repository/CustomItemXrefContactRepository.php +++ b/Repository/CustomItemXrefContactRepository.php @@ -4,14 +4,13 @@ namespace MauticPlugin\CustomObjectsBundle\Repository; -use Mautic\CoreBundle\Entity\CommonRepository; use Mautic\LeadBundle\Entity\Lead; use MauticPlugin\CustomObjectsBundle\DTO\TableConfig; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Entity\CustomItemXrefContact; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; -class CustomItemXrefContactRepository extends CommonRepository +class CustomItemXrefContactRepository extends CustomCommonRepository { /** * @return int[] diff --git a/Repository/CustomItemXrefCustomItemRepository.php b/Repository/CustomItemXrefCustomItemRepository.php index 079fc568d..bd058b92b 100644 --- a/Repository/CustomItemXrefCustomItemRepository.php +++ b/Repository/CustomItemXrefCustomItemRepository.php @@ -4,10 +4,9 @@ namespace MauticPlugin\CustomObjectsBundle\Repository; -use Mautic\CoreBundle\Entity\CommonRepository; use MauticPlugin\CustomObjectsBundle\Entity\CustomItemXrefCustomItem; -class CustomItemXrefCustomItemRepository extends CommonRepository +class CustomItemXrefCustomItemRepository extends CustomCommonRepository { public function deleteAllLinksForCustomItem(int $customItemId): void { diff --git a/Repository/CustomObjectRepository.php b/Repository/CustomObjectRepository.php index a9fa7b3a2..10592e27d 100644 --- a/Repository/CustomObjectRepository.php +++ b/Repository/CustomObjectRepository.php @@ -6,11 +6,10 @@ use Doctrine\ORM\Query\Expr\Orx; use Doctrine\ORM\QueryBuilder; -use Mautic\CoreBundle\Entity\CommonRepository; use Mautic\LeadBundle\Entity\LeadList; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; -class CustomObjectRepository extends CommonRepository +class CustomObjectRepository extends CustomCommonRepository { public function checkAliasExists(string $alias, ?int $id = null): bool { @@ -102,7 +101,7 @@ private function buildSegmentFilterForCustomObjectFields(CustomObject $customObj { $alias = 'cmo_'.$customObject->getId(); $aliasLength = mb_strlen($alias); - $like = "%;s:5:\"field\";s:${aliasLength}:\"{$alias}\";%"; + $like = "%;s:5:\"field\";s:{$aliasLength}:\"{$alias}\";%"; $filterExpression->add( $queryBuilder->expr()->like('l.filters', $queryBuilder->expr()->literal($like)) @@ -112,7 +111,7 @@ private function buildSegmentFilterForCustomObjectFields(CustomObject $customObj foreach ($customObject->getCustomFields() as $customField) { $alias = 'cmf_'.$customField->getId(); $aliasLength = mb_strlen($alias); - $like = "%;s:5:\"field\";s:${aliasLength}:\"{$alias}\";%"; + $like = "%;s:5:\"field\";s:{$aliasLength}:\"{$alias}\";%"; $filterExpression->add( $queryBuilder->expr()->like('l.filters', $queryBuilder->expr()->literal($like)) ); diff --git a/Repository/DbalQueryTrait.php b/Repository/DbalQueryTrait.php index 84ff8c72f..09a13e9d5 100644 --- a/Repository/DbalQueryTrait.php +++ b/Repository/DbalQueryTrait.php @@ -6,6 +6,7 @@ use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\Query\QueryBuilder; +use Doctrine\DBAL\Result; trait DbalQueryTrait { @@ -14,11 +15,11 @@ trait DbalQueryTrait * * @throws \UnexpectedValueException */ - private function executeSelect(QueryBuilder $queryBuilder): Statement + private function executeSelect(QueryBuilder $queryBuilder): Result|Statement { $statement = $queryBuilder->execute(); - if ($statement instanceof Statement) { + if ($statement instanceof Result || $statement instanceof Statement) { return $statement; } diff --git a/Resources/views/CustomField/_detail_left_section.html.twig b/Resources/views/CustomField/_detail_left_section.html.twig new file mode 100644 index 000000000..9908463b5 --- /dev/null +++ b/Resources/views/CustomField/_detail_left_section.html.twig @@ -0,0 +1,25 @@ + +
    +
    + +
    +
    +
    +
    {{ item.type }}
    +
    +
    + {{ include('@MauticCore/Helper/publishstatus_badge.html.twig', { + entity: item + }) }} +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/Resources/views/CustomField/_detail_right_section.html.twig b/Resources/views/CustomField/_detail_right_section.html.twig new file mode 100644 index 000000000..8eedccc78 --- /dev/null +++ b/Resources/views/CustomField/_detail_right_section.html.twig @@ -0,0 +1,23 @@ + +
    + +
    +
    +
    + {{ 'mautic.webhook.webhook_url'|trans }} +
    +
    +
    +
    +
    + +
    + + + {{ include('@MauticCore/Helper/recentactivity.html.twig', { + logs: logs + }) }} +
    +
    + +
    \ No newline at end of file diff --git a/Resources/views/CustomField/detail.html.twig b/Resources/views/CustomField/detail.html.twig new file mode 100644 index 000000000..ec6a6e8bc --- /dev/null +++ b/Resources/views/CustomField/detail.html.twig @@ -0,0 +1,19 @@ +{% extends '@MauticCore/Default/content.html.twig.html.twig' %} + +{% block mauticContent %}customField{% endblock %} + +{% block headerTitle %} + {{ item.getName() }} +{% endblock %} + +{% block actions %} + {{ include('@MauticCore/Helper/page_actions.html.twig', { 'item': item }) }} +{% endblock %} + +{% block content %} + +
    + {{ include('@CustomObjects/CustomField/_detail_left_section.html.twig') }} + {{ include('@CustomObjects/CustomField/_detail_right_section.html.twig', {'logs': logs}) }} +
    +{% endblock %} \ No newline at end of file diff --git a/Resources/views/CustomField/form.html.twig b/Resources/views/CustomField/form.html.twig new file mode 100644 index 000000000..dd1d6ed5d --- /dev/null +++ b/Resources/views/CustomField/form.html.twig @@ -0,0 +1,97 @@ +{% set title = customField.id ? customField.label : customField.typeObject.name %} +{% set showProperties = form.options is defined or customField.typeObject.usePlaceholder() %} + +{% block content %} +
    +
    +

    {{ title }}

    +
    + + {{ form_start(form) }} +
    + + +
    +
    + +
    +
    + {{ form_row(form.label) }} +
    +
    + {{ form_row(form.showInCustomObjectDetailList) }} +
    +
    + +
    +
    + {{ form_row(form.alias) }} +
    +
    + {{ form_row(form.showInContactDetailList) }} +
    +
    + +
    +
    + {{ form_row(form.defaultValue) }} +
    +
    + {{ form_row(form.isUniqueIdentifier) }} +
    +
    + +
    + +
    +
    +
    + {{ form_row(form.required) }} +
    +
    +
    + + {% if showProperties %} +
    +
    + {% if form.options is defined %} +
    + {{ form_row(form.options) }} +
    + {% endif %} +
    +
    + {% if customField.typeObject.usePlaceholder %} +
    + {{ form_row(form.params.placeholder) }} +
    + {% endif %} +
    +
    + {% endif %} +
    +
    + + {{ form_rest(form) }} + {{ form_end(form) }} + +
    +{% endblock %} \ No newline at end of file diff --git a/Resources/views/CustomField/value.html.twig b/Resources/views/CustomField/value.html.twig new file mode 100644 index 000000000..b6193f571 --- /dev/null +++ b/Resources/views/CustomField/value.html.twig @@ -0,0 +1,15 @@ +{% set customFieldType = fieldValue.customField.type %} +{% set fieldTypes = ['select', 'multiselect'] %} + +{% if fieldValue.getValue() is instanceof('DateTimeInterface') %} + {% set date = 'date' == customFieldType ? dateToDate(fieldValue.getValue()) : dateToFull(fieldValue.getValue()) %} + {{ date }} +{% elseif customFieldType in fieldTypes %} +{# TODO: Transform to string #} +{# {{ '%s'|format(fieldValue.getCustomField().getTypeObject()|escape)|raw }}#} + {{ '%s'|format(fieldValue.getValue()|first|escape)|raw }} +{% elseif fieldValue.getValue() is iterable %} + {{ fieldValue.getValue()|join(', ') }} +{% else %} + {{ '%s'|format(fieldValue.getValue()|escape)|raw }} +{% endif %} \ No newline at end of file diff --git a/Resources/views/CustomItem/_detail_left_section.html.twig b/Resources/views/CustomItem/_detail_left_section.html.twig new file mode 100644 index 000000000..f511c0db6 --- /dev/null +++ b/Resources/views/CustomItem/_detail_left_section.html.twig @@ -0,0 +1,112 @@ + +
    +
    + +
    +
    +
    +
    + {% set nameSingular = item.getCustomObject().getNameSingular() %} + {{ '%s'|format(nameSingular|escape)|raw }} +
    +
    + {# TODO: Check if this block is needed #} +
    + {{ include('@MauticCore/Helper/publishstatus_badge.html.twig', { + entity: item + }) }} +
    +
    +
    + +
    +
    +
    + + + {{ include('@MauticCore/Helper/details.html.twig', { + entity: item + }) }} + {% for fieldValue in item.getCustomFieldValues() %} + + + + + {% endfor %} + +
    {{ '%s'|format(fieldValue.getCustomField().getName()|escape)|raw }} + {{ include('@CustomObjects/CustomField/value.html.twig', { + fieldValue: fieldValue + }) }} +
    +
    +
    +
    +
    + + +
    + + + + +
    +
    +
    +
    +
    +
    +
    + + {{ 'custom.item.links.in.time'|trans }} +
    +
    +
    + {{ include('@MauticCore/Helper/graph_dateselect.html.twig', { + dateRangeForm: dateRangeForm, + class: 'pull-right' + }) }} +
    +
    +
    + {{ include('@MauticCore/Helper/chart.html.twig', { + chartData: stats, + chartType: 'line', + chartHeight: 300 + }) }} +
    +
    +
    +
    +
    + {{ customContent('details.stats.graph.below', mauticTemplateVars is defined ? mauticTemplateVars : []) }} +
    + + + + + + +
    +
    + {{ contacts|raw }} +
    + {{ customContent('tabs.content', mauticTemplateVars|default({'mauticTemplate': '@CustomObjects/CustomItem/detail.html.twig', 'item': item}), '@CustomObjects/CustomItem/detail.html.twig') }} +
    + +
    \ No newline at end of file diff --git a/Resources/views/CustomItem/_detail_right_section.html.twig b/Resources/views/CustomItem/_detail_right_section.html.twig new file mode 100644 index 000000000..02d22b0ba --- /dev/null +++ b/Resources/views/CustomItem/_detail_right_section.html.twig @@ -0,0 +1,6 @@ + +
    + + {{ include('@MauticCore/Helper/recentactivity.html.twig', {'logs': logs}) }} +
    + \ No newline at end of file diff --git a/Resources/views/CustomItem/_list.html.twig b/Resources/views/CustomItem/_list.html.twig new file mode 100644 index 000000000..fd8544e24 --- /dev/null +++ b/Resources/views/CustomItem/_list.html.twig @@ -0,0 +1,96 @@ +{% set tableAlias = constant('MauticPlugin\\CustomObjectsBundle\\Entity\\CustomItem::TABLE_ALIAS') %} +{% set routeView = constant('MauticPlugin\\CustomObjectsBundle\\Provider\\CustomItemRouteProvider::ROUTE_VIEW') %} +{% set routeList = constant('MauticPlugin\\CustomObjectsBundle\\Provider\\CustomItemRouteProvider::ROUTE_LIST') %} + +{% set routerSelf = path(routeList, { + 'objectId': customObject.getId(), + 'filterEntityId': filterEntityId, + 'filterEntityType': filterEntityType, + 'lookup': lookup, + 'tmpl': 'list', +}) %} + +{% if items|length %} +
    + + + + {{- include('@MauticCore/Helper/tableheader.html.twig', { + 'checkall' : 'true', + 'target' : target, + 'langVar' : 'custom.item', + 'routeBase' : 'custom_item', + 'baseUrl' : routerSelf + }) -}} + {{- include('@MauticCore/Helper/tableheader.html.twig', { + 'sessionVar' : sessionVar, + 'orderBy' : tableAlias~'.name', + 'text' : 'mautic.core.name', + 'class' : 'col-custom_item_name', + 'baseUrl' : routerSelf, + 'target' : target + }) -}} + {{- include('@MauticCore/Helper/tableheader.html.twig', { + 'sessionVar' : sessionVar, + 'orderBy' : tableAlias~'.id', + 'text' : 'mautic.core.id', + 'default' : true, + 'baseUrl' : routerSelf, + 'target' : target + }) -}} + + {% if fieldData is not empty %} + {% for columnLabel in fieldData.getColumnLabels() %} + {{- include('@MauticCore/Helper/tableheader.html.twig', { 'text' : columnLabel }) -}} + {% endfor %} + {% endif %} + + + + {% for item in items %} + + + + + {% if fieldData is not empty %} + {% for fieldValue in fieldData.getFields(item.getId()) %} + + {% endfor %} + {% endif %} + + {% endfor %} + +
    + {{- include('@MauticCore/Helper/list_actions.html.twig', { 'item' : item }) -}} + +
    + {{ filterEntityId is empty ? include('@MauticCore/Helper/publishstatus_icon.html.twig', { 'item' : item, 'model' : 'custom.item' }) : '' }} + + {{ item.getName() }} + +
    +
    + {{ item.getId() }} + + {{- include('@CustomObjects/CustomField/value.html.twig', { 'fieldValue' : fieldValue }) -}} +
    +
    + +{% else %} + {{- include('@MauticCore/Helper/noresults.html.twig', { 'tip' : lookup ? 'custom.item.link.noresults.tip' : 'custom.object.noresults.tip' }) -}} +{% endif %} diff --git a/Resources/views/CustomItem/detail.html.twig b/Resources/views/CustomItem/detail.html.twig new file mode 100644 index 000000000..dc1910a28 --- /dev/null +++ b/Resources/views/CustomItem/detail.html.twig @@ -0,0 +1,27 @@ +{% extends '@MauticCore/Default/content.html.twig' %} + +{% block mauticContent %}customItem{% endblock %} + +{% block headerTitle %} + {{ item.getName() }} +{% endblock %} + +{% block actions %} + {{ include('@MauticCore/Helper/page_actions.html.twig', { 'item': item }) }} +{% endblock %} + +{% block publishStatus %} + {{- include('@MauticCore/Helper/publishstatus_badge.html.twig', {'entity' : item}) -}} +{% endblock %} + +{% block content %} +
    + {{ include('@CustomObjects/CustomItem/_detail_left_section.html.twig', { + 'entity': item, + 'dateRangeForm': dateRangeForm, + 'chartData': stats, + 'mauticTemplateVars': mauticTemplateVars is defined ? mauticTemplateVars : {} + }) }} + {{ include('@CustomObjects/CustomItem/_detail_right_section.html.twig', {'logs': logs}) }} +
    +{% endblock %} diff --git a/Resources/views/CustomItem/form.html.twig b/Resources/views/CustomItem/form.html.twig new file mode 100644 index 000000000..c23ff9e88 --- /dev/null +++ b/Resources/views/CustomItem/form.html.twig @@ -0,0 +1,56 @@ +{% extends '@MauticCore/Default/content.html.twig' %} + +{% block mauticContent %}customItem{% endblock %} + +{% block headerTitle %} + {% if entity.getId() is empty %} + {{ 'custom.item.new'|trans({'%object%' : customObject.getNameSingular()}) }} + {% else %} + {{ 'custom.item.edit'|trans({'%object%' : customObject.getNameSingular(), '%item%' : entity.getName()}) }} + {% endif %} +{% endblock %} + +{% block content %} + {% set typeRelationship = constant('MauticPlugin\\CustomObjectsBundle\\Entity\\CustomObject::TYPE_RELATIONSHIP') %} + {% set hideCategories = typeRelationship == customObject.getType() ? 'hide' : null %} + {% set fields = form.children %} + + {{ form_start(form) }} + +
    + +
    +
    +
    +
    + {%- if form.name is defined %}{{ form_row(form.name) }}{% endif %} + {{ form_row(form.custom_field_values) }} + {{ form_row(form.contact_id) }} +
    + {% if customObject.getRelationshipObject() is not empty and form.contact_id.vars.value is not empty %} +
    +
    +
    +

    + {{ 'custom.item.new'|trans({'%object%' : customObject.getRelationshipObject().getNameSingular()}) }} +

    +
    +
    + {{ form_row(fields, 'child_custom_field_values', template) }} +{# {{ formRowIfExists(fields, 'child_custom_field_values', template) }}#} +
    +
    +
    + {% endif %} +
    +
    +
    +
    +
    + {{ form_row(form.category) }} + {{ form_row(form.isPublished) }} +
    +
    +
    + {{ form_end(form) }} +{% endblock %} \ No newline at end of file diff --git a/Resources/views/CustomItem/list.html.twig b/Resources/views/CustomItem/list.html.twig new file mode 100644 index 000000000..88711f763 --- /dev/null +++ b/Resources/views/CustomItem/list.html.twig @@ -0,0 +1,37 @@ +{% set isIndex = tmpl == 'index' ? true : false %} +{% set tmpl = 'list' %} +{% set fieldData = fieldData ?? null %} +{% set target = '#'~namespace %} + +{% extends isIndex ? '@MauticCore/Default/content.html.twig' : '@MauticCore/Default/raw_output.html.twig' %} + +{% block mauticContent %}customItem{% endblock %} + +{% block headerTitle %} + {{ customObject.getName() }} +{% endblock %} + +{% block actions %} + {{ include('@MauticCore/Helper/page_actions.html.twig') }} +{% endblock %} + +{% block content %} +
    + {% if isIndex %} +
    + {{ include('@MauticCore/Helper/list_toolbar.html.twig', { + 'searchValue': searchValue, + 'action': currentRoute, + 'target': '#'~namespace, + 'overlayDisabled': lookup + }) }} + +
    + {{ include('@CustomObjects/CustomItem/_list.html.twig') }} +
    +
    + {% else %} + {{ include('@CustomObjects/CustomItem/_list.html.twig') }} + {% endif %} +
    +{% endblock %} \ No newline at end of file diff --git a/Resources/views/CustomObject/Form/Panel/_field.html.twig b/Resources/views/CustomObject/Form/Panel/_field.html.twig new file mode 100644 index 000000000..397e59bc0 --- /dev/null +++ b/Resources/views/CustomObject/Form/Panel/_field.html.twig @@ -0,0 +1,47 @@ +{% set customFieldEntity = customField.vars.data %} +{#{% set customField.vars.index = customField.vars.name %}#} +{% set order = customField.vars.value.getOrder() %} +{#{{ dump(app.request.) }}#} +{# TODO !!!!!!!!!!!! Handle deleted objects#} +{#{% set requestCustomObject = app.request.post('custom_object') %}#} +{#{% set displayStyle = requestCustomObject['customFields'][order]['deleted'] is empty ? '' : 'style="display:none;"' %}#} +{% set displayStyle = '' %} +{% set panelId = panelId is empty ? customField.vars.value.getOrder()|number_format : panelId %} +{% set routeForm = constant('MauticPlugin\\CustomObjectsBundle\\Provider\\CustomFieldRouteProvider::ROUTE_FORM') %} + +
    +
    + + + + + +
    + +
    +
    +
    + {{ form_row(customField.defaultValue) }} +
    +
    +
    +
    + {{ form_rest(customField) }} +
    + +
    \ No newline at end of file diff --git a/Resources/views/CustomObject/Form/Panel/checkbox_group.html.twig b/Resources/views/CustomObject/Form/Panel/checkbox_group.html.twig new file mode 100644 index 000000000..e226dbc02 --- /dev/null +++ b/Resources/views/CustomObject/Form/Panel/checkbox_group.html.twig @@ -0,0 +1 @@ +{% extends '@CustomObjects/CustomObject/Form\\Panel\\_field.html.twig' %} diff --git a/Resources/views/CustomObject/Form/Panel/country.html.twig b/Resources/views/CustomObject/Form/Panel/country.html.twig new file mode 100644 index 000000000..e226dbc02 --- /dev/null +++ b/Resources/views/CustomObject/Form/Panel/country.html.twig @@ -0,0 +1 @@ +{% extends '@CustomObjects/CustomObject/Form\\Panel\\_field.html.twig' %} diff --git a/Resources/views/CustomObject/Form/Panel/date.html.twig b/Resources/views/CustomObject/Form/Panel/date.html.twig new file mode 100644 index 000000000..e226dbc02 --- /dev/null +++ b/Resources/views/CustomObject/Form/Panel/date.html.twig @@ -0,0 +1 @@ +{% extends '@CustomObjects/CustomObject/Form\\Panel\\_field.html.twig' %} diff --git a/Resources/views/CustomObject/Form/Panel/datetime.html.twig b/Resources/views/CustomObject/Form/Panel/datetime.html.twig new file mode 100644 index 000000000..e226dbc02 --- /dev/null +++ b/Resources/views/CustomObject/Form/Panel/datetime.html.twig @@ -0,0 +1 @@ +{% extends '@CustomObjects/CustomObject/Form\\Panel\\_field.html.twig' %} diff --git a/Resources/views/CustomObject/Form/Panel/email.html.twig b/Resources/views/CustomObject/Form/Panel/email.html.twig new file mode 100644 index 000000000..e226dbc02 --- /dev/null +++ b/Resources/views/CustomObject/Form/Panel/email.html.twig @@ -0,0 +1 @@ +{% extends '@CustomObjects/CustomObject/Form\\Panel\\_field.html.twig' %} diff --git a/Resources/views/CustomObject/Form/Panel/hidden.html.twig b/Resources/views/CustomObject/Form/Panel/hidden.html.twig new file mode 100644 index 000000000..e226dbc02 --- /dev/null +++ b/Resources/views/CustomObject/Form/Panel/hidden.html.twig @@ -0,0 +1 @@ +{% extends '@CustomObjects/CustomObject/Form\\Panel\\_field.html.twig' %} diff --git a/Resources/views/CustomObject/Form/Panel/html_area.html.twig b/Resources/views/CustomObject/Form/Panel/html_area.html.twig new file mode 100644 index 000000000..e226dbc02 --- /dev/null +++ b/Resources/views/CustomObject/Form/Panel/html_area.html.twig @@ -0,0 +1 @@ +{% extends '@CustomObjects/CustomObject/Form\\Panel\\_field.html.twig' %} diff --git a/Resources/views/CustomObject/Form/Panel/int.html.twig b/Resources/views/CustomObject/Form/Panel/int.html.twig new file mode 100644 index 000000000..e226dbc02 --- /dev/null +++ b/Resources/views/CustomObject/Form/Panel/int.html.twig @@ -0,0 +1 @@ +{% extends '@CustomObjects/CustomObject/Form\\Panel\\_field.html.twig' %} diff --git a/Resources/views/CustomObject/Form/Panel/multiselect.html.twig b/Resources/views/CustomObject/Form/Panel/multiselect.html.twig new file mode 100644 index 000000000..e226dbc02 --- /dev/null +++ b/Resources/views/CustomObject/Form/Panel/multiselect.html.twig @@ -0,0 +1 @@ +{% extends '@CustomObjects/CustomObject/Form\\Panel\\_field.html.twig' %} diff --git a/Resources/views/CustomObject/Form/Panel/phone.html.twig b/Resources/views/CustomObject/Form/Panel/phone.html.twig new file mode 100644 index 000000000..e226dbc02 --- /dev/null +++ b/Resources/views/CustomObject/Form/Panel/phone.html.twig @@ -0,0 +1 @@ +{% extends '@CustomObjects/CustomObject/Form\\Panel\\_field.html.twig' %} diff --git a/Resources/views/CustomObject/Form/Panel/radio_group.html.twig b/Resources/views/CustomObject/Form/Panel/radio_group.html.twig new file mode 100644 index 000000000..e226dbc02 --- /dev/null +++ b/Resources/views/CustomObject/Form/Panel/radio_group.html.twig @@ -0,0 +1 @@ +{% extends '@CustomObjects/CustomObject/Form\\Panel\\_field.html.twig' %} diff --git a/Resources/views/CustomObject/Form/Panel/select.html.twig b/Resources/views/CustomObject/Form/Panel/select.html.twig new file mode 100644 index 000000000..e226dbc02 --- /dev/null +++ b/Resources/views/CustomObject/Form/Panel/select.html.twig @@ -0,0 +1 @@ +{% extends '@CustomObjects/CustomObject/Form\\Panel\\_field.html.twig' %} diff --git a/Resources/views/CustomObject/Form/Panel/text.html.twig b/Resources/views/CustomObject/Form/Panel/text.html.twig new file mode 100644 index 000000000..e226dbc02 --- /dev/null +++ b/Resources/views/CustomObject/Form/Panel/text.html.twig @@ -0,0 +1 @@ +{% extends '@CustomObjects/CustomObject/Form\\Panel\\_field.html.twig' %} diff --git a/Resources/views/CustomObject/Form/Panel/textarea.html.twig b/Resources/views/CustomObject/Form/Panel/textarea.html.twig new file mode 100644 index 000000000..8e26a3a45 --- /dev/null +++ b/Resources/views/CustomObject/Form/Panel/textarea.html.twig @@ -0,0 +1 @@ +{% extends '@CustomObjects/CustomObject/Form\\Panel\\_field.html.twig' %} \ No newline at end of file diff --git a/Resources/views/CustomObject/Form/Panel/url.html.twig b/Resources/views/CustomObject/Form/Panel/url.html.twig new file mode 100644 index 000000000..e226dbc02 --- /dev/null +++ b/Resources/views/CustomObject/Form/Panel/url.html.twig @@ -0,0 +1 @@ +{% extends '@CustomObjects/CustomObject/Form\\Panel\\_field.html.twig' %} diff --git a/Resources/views/CustomObject/_detail_left_section.html.twig b/Resources/views/CustomObject/_detail_left_section.html.twig new file mode 100644 index 000000000..8b1654671 --- /dev/null +++ b/Resources/views/CustomObject/_detail_left_section.html.twig @@ -0,0 +1,110 @@ + +
    +
    + +
    +
    +
    +
    +
    +
    + + + +
    +
    +
    + + + {{ include('@MauticCore/Helper/details.html.twig', {'entity': customObject}) }} + +
    +
    +
    +
    + +
    + + +
    + + + + +
    +
    +
    +
    +
    +
    +
    + + {{ 'custom.item.links.in.time'|trans }} +
    +
    +
    + {{ include('@MauticCore/Helper/graph_dateselect.html.twig', {'dateRangeForm': dateRangeForm, 'class': 'pull-right'}) }} +
    +
    +
    + {{ include('@MauticCore/Helper/chart.html.twig', {'chartData': chartData, 'chartType': 'line', 'chartHeight': 300}) }} +
    +
    +
    +
    +
    + {{- customContent('details.stats.graph.below', mauticTemplateVars|default({})) -}} + + + + +
    + +
    + + +
    +
      + {% for field in customObject.getCustomFields() %} +
    • +
      +
      +

      + {% set isRequired = field.isRequired() ? true : false %} + {% set requiredTitle = isRequired ? 'mautic.core.required' : 'mautic.core.not_required' %} + {% set requiredClass = isRequired ? 'check' : 'times' %} + + +

      +
      +
      +
      {{ field.getLabel() }}
      +
      +
      + {{ field.getTypeObject().getName() }} +
      +
      +
    • + {% endfor %} +
    +
    + +
    +
    \ No newline at end of file diff --git a/Resources/views/CustomObject/_detail_right_section.html.twig b/Resources/views/CustomObject/_detail_right_section.html.twig new file mode 100644 index 000000000..02d22b0ba --- /dev/null +++ b/Resources/views/CustomObject/_detail_right_section.html.twig @@ -0,0 +1,6 @@ + +
    + + {{ include('@MauticCore/Helper/recentactivity.html.twig', {'logs': logs}) }} +
    + \ No newline at end of file diff --git a/Resources/views/CustomObject/_form-fields.html.twig b/Resources/views/CustomObject/_form-fields.html.twig new file mode 100644 index 000000000..87f649c65 --- /dev/null +++ b/Resources/views/CustomObject/_form-fields.html.twig @@ -0,0 +1,19 @@ +{% set customFields = form.children['customFields'].getIterator().getArrayCopy() %} + +{% for customField in customFields %} + {% set customFieldEntity = customField.vars.data %} + + {% if customFieldEntity.getId() not in deletedFields %} + {{- include( + '@CustomObjects/CustomObject/Form\\Panel\\'~customFieldEntity.getType()~'.html.twig', + { + 'customField': customField, + 'customObject': customObject, + 'panelId': panelId ?? null, + + }) + -}} + {% endif %} +{% endfor %} + +{% do form.children['customFields'].setRendered() %} \ No newline at end of file diff --git a/Resources/views/CustomObject/_list.html.twig b/Resources/views/CustomObject/_list.html.twig new file mode 100644 index 000000000..1d6766b03 --- /dev/null +++ b/Resources/views/CustomObject/_list.html.twig @@ -0,0 +1,74 @@ +{% set tableAlias = constant('MauticPlugin\\CustomObjectsBundle\\Entity\\CustomObject::TABLE_ALIAS') %} +{% set routeView = constant('MauticPlugin\\CustomObjectsBundle\\Provider\\CustomObjectRouteProvider::ROUTE_VIEW') %} +{% set routeList = constant('MauticPlugin\\CustomObjectsBundle\\Provider\\CustomObjectRouteProvider::ROUTE_LIST') %} + +{% if items|length > 0 %} +
    + + + + {{ include('@MauticCore/Helper/tableheader.html.twig', { + 'checkall': 'true', + 'target': '#custom-objects-table', + 'langVar': 'custom.object', + 'routeBase': 'custom_object', + 'routeBase': 'form' + }) }} + + {{ include('@MauticCore/Helper/tableheader.html.twig', { + 'sessionVar': sessionVar, + 'orderBy': tableAlias~'.namePlural', + 'text': 'mautic.core.name', + 'class': 'col-custom_object_-name' + }) }} + + {{ include('@MauticCore/Helper/tableheader.html.twig', { + 'sessionVar': sessionVar, + 'orderBy': tableAlias~'.id', + 'text': 'mautic.core.id', + 'default': true + }) }} + + + + {% for item in items %} + + + + + + {% endfor %} + +
    + {{- include('@MauticCore/Helper/list_actions.html.twig', { 'item': item }) -}} + +
    + {{- include('@MauticCore/Helper/publishstatus_icon.html.twig', + {'item' : item, 'model' : 'custom.object'}) -}} + + {{ item.name }} + +{# #} +{# {{ item.getName() }}#} +{# #} +
    + {% if item.description %} +
    + {{ item.description|purify }} +
    + {% endif %} +
    {{ item.id }}
    +
    + +{% else %} + {{ include('@MauticCore/Helper/noresults.html.twig', {'tip': 'custom.object.noresults.tip'}) }} +{% endif %} diff --git a/Resources/views/CustomObject/detail.html.twig b/Resources/views/CustomObject/detail.html.twig new file mode 100644 index 000000000..80ebb9534 --- /dev/null +++ b/Resources/views/CustomObject/detail.html.twig @@ -0,0 +1,27 @@ +{% extends '@MauticCore/Default/content.html.twig' %} + +{% block mauticContent %}customObject{% endblock %} + +{% block headerTitle %} + {{ customObject.getNameSingular() }} +{% endblock %} + +{% block actions %} + {{ include('@MauticCore/Helper/page_actions.html.twig', { 'item': customObject}) }} +{% endblock %} + +{% block publishStatus %} + {{- include('@MauticCore/Helper/publishstatus_badge.html.twig', {'entity' : customObject}) -}} +{% endblock %} + +{% block content %} +
    + {{ include('@CustomObjects/CustomObject/_detail_left_section.html.twig', { + 'entity': customObject, + 'dateRangeForm': dateRangeForm, + 'chartData': stats, + 'mauticTemplateVars': mauticTemplateVars is defined ? mauticTemplateVars : {} + }) }} + {{ include('@CustomObjects/CustomObject/_detail_right_section.html.twig', {'logs': logs}) }} +
    +{% endblock %} \ No newline at end of file diff --git a/Resources/views/CustomObject/form.html.twig b/Resources/views/CustomObject/form.html.twig new file mode 100644 index 000000000..d630e8246 --- /dev/null +++ b/Resources/views/CustomObject/form.html.twig @@ -0,0 +1,98 @@ +{% extends '@MauticCore/Default/content.html.twig' %} + +{% block mauticContent %}customObject{% endblock %} + +{% block headerTitle %} + {% if customObject.getId() %} + {{ 'custom.object.edit'|trans({'%name%' : customObject.getName()|trans}) }} + {% else %} + {% trans %}custom.object.new{% endtrans %} + {% endif %} +{% endblock %} + +{% block content %} + {{ form_start(form) }} +
    + +
    +
    +
    + + + +
    +
    +
    +
    + {{ form_row(form.nameSingular) }} + {{ form_row(form.namePlural) }} +
    +
    + {{ form_row(form.alias) }} +
    +
    +
    +
    + {{ form_row(form.description) }} +
    +
    +
    + +
    + {{- include('@MauticForm/Builder/_style.html.twig') -}} +
    +
    +
    + +
    +
    +
    + {{- include('@CustomObjects/CustomObject/_form-fields.html.twig') -}} +
    + {% if 0 == customFields|length %} +
    +

    {{ 'mautic.form.form.addfield'|trans }}

    +
    + {% endif %} +
    +
    +
    +
    +
    +
    +
    +
    + {{ form_row(form.type) }} + {{ form_row(form.masterObject) }} + {{ form_row(form.category) }} + {{ form_row(form.isPublished) }} +
    +
    +
    + {{ form_end(form) }} +{% endblock %} + +{% block modal %} + {{ include('@MauticCore/Helper/modal.html.twig', { + 'id': 'objectFieldModal', + 'header': false, + 'footerButtons': true, + }) }} +{% endblock %} \ No newline at end of file diff --git a/Resources/views/CustomObject/list.html.twig b/Resources/views/CustomObject/list.html.twig new file mode 100644 index 000000000..6cb28b6ba --- /dev/null +++ b/Resources/views/CustomObject/list.html.twig @@ -0,0 +1,27 @@ +{% set isIndex = tmpl == 'index' ? true : false %} +{% set tmpl = 'list' %} + +{% extends isIndex ? '@MauticCore/Default/content.html.twig' : '@MauticCore/Default/raw_output.html.twig' %} + +{% block mauticContent %}customObject{% endblock %} + +{% block headerTitle %} + {{ 'custom.object.title'|trans }} +{% endblock %} + +{% block actions %} + {{ include('@MauticCore/Helper/page_actions.html.twig') }} +{% endblock %} + +{% block content %} + {% if isIndex %} +
    + {{ include('@MauticCore/Helper/list_toolbar.html.twig') }} +
    ! + {{ include('@CustomObjects/CustomObject/_list.html.twig') }} +
    +
    + {% else %} + {{ include('@CustomObjects/CustomObject/_list.html.twig') }} + {% endif %} +{% endblock %} \ No newline at end of file diff --git a/Views/FormTheme/FieldValueCondition/campaign_condition_field_value_widget.html.php b/Resources/views/FormTheme/FieldValueCondition/campaign_condition_field_value_widget.html.twig similarity index 56% rename from Views/FormTheme/FieldValueCondition/campaign_condition_field_value_widget.html.php rename to Resources/views/FormTheme/FieldValueCondition/campaign_condition_field_value_widget.html.twig index 3c1b71b88..35c606a32 100644 --- a/Views/FormTheme/FieldValueCondition/campaign_condition_field_value_widget.html.php +++ b/Resources/views/FormTheme/FieldValueCondition/campaign_condition_field_value_widget.html.twig @@ -3,13 +3,13 @@ ?>
    - row($form['field']); ?> + {{ form_row(field) }}
    - row($form['operator']); ?> + {{ form_row(operator) }}
    - row($form['value']); ?> + {{ form_row(value) }}
    diff --git a/Resources/views/SubscribedEvents/Tab/content.html.twig b/Resources/views/SubscribedEvents/Tab/content.html.twig new file mode 100644 index 000000000..702c12c7f --- /dev/null +++ b/Resources/views/SubscribedEvents/Tab/content.html.twig @@ -0,0 +1,49 @@ +
    +
    +
    + {{ include('@MauticCore/Helper/search.html.twig', { + 'searchValue': searchValue, + 'action': searchRoute, + 'searchId': searchId, + 'target': '#'~namespace, + 'searchHelp': '' + }) }} +
    + +
    +
    + Loading... +
    +
    + + + + \ No newline at end of file diff --git a/Resources/views/SubscribedEvents/Tab/link.html.twig b/Resources/views/SubscribedEvents/Tab/link.html.twig new file mode 100644 index 000000000..304c26ac0 --- /dev/null +++ b/Resources/views/SubscribedEvents/Tab/link.html.twig @@ -0,0 +1,11 @@ +
  • + + {% if count is defined %} + + {{ count }} + + {% endif %} + + {{ title|trans }} + +
  • \ No newline at end of file diff --git a/Resources/views/SubscribedEvents/Tab/modal.html.twig b/Resources/views/SubscribedEvents/Tab/modal.html.twig new file mode 100644 index 000000000..70c836855 --- /dev/null +++ b/Resources/views/SubscribedEvents/Tab/modal.html.twig @@ -0,0 +1,6 @@ +{% block modal %} + {{ include('@MauticCore/Helper/modal.html.twig', { + 'id': 'customItemLookupModal', + 'size': 'xl' + }) }} +{% endblock %} \ No newline at end of file diff --git a/Resources/views/SubscribedEvents/Timeline/link.html.twig b/Resources/views/SubscribedEvents/Timeline/link.html.twig new file mode 100644 index 000000000..36efb8b5b --- /dev/null +++ b/Resources/views/SubscribedEvents/Timeline/link.html.twig @@ -0,0 +1,12 @@ +{% set link = event.extra %} + +
    + {% if link.user_id is not empty %} +
    {{ 'mautic.core.createdby'|trans }}
    +
    + + {{ link.user_name }} + +
    + {% endif %} +
    diff --git a/Security/Permissions/CustomObjectPermissions.php b/Security/Permissions/CustomObjectPermissions.php index 522d49f91..9c4b1f50e 100644 --- a/Security/Permissions/CustomObjectPermissions.php +++ b/Security/Permissions/CustomObjectPermissions.php @@ -10,27 +10,12 @@ use MauticPlugin\CustomObjectsBundle\Model\CustomObjectModel; use MauticPlugin\CustomObjectsBundle\Provider\ConfigProvider; use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class CustomObjectPermissions extends AbstractPermissions { public const NAME = 'custom_objects'; - /** - * @var CustomObjectModel - */ - private $customObjectModel; - - /** - * @var ConfigProvider - */ - private $configProvider; - - /** - * @var TranslatorInterface - */ - private $translator; - /** * Cached custom objects. * @@ -40,15 +25,11 @@ class CustomObjectPermissions extends AbstractPermissions public function __construct( CoreParametersHelper $coreParametersHelper, - CustomObjectModel $customObjectModel, - ConfigProvider $configProvider, - TranslatorInterface $translator + private CustomObjectModel $customObjectModel, + private ConfigProvider $configProvider, + private TranslatorInterface $translator ) { parent::__construct($coreParametersHelper->all()); - - $this->customObjectModel = $customObjectModel; - $this->configProvider = $configProvider; - $this->translator = $translator; } /** diff --git a/Segment/Query/Filter/CustomFieldFilterQueryBuilder.php b/Segment/Query/Filter/CustomFieldFilterQueryBuilder.php index bc38e0adb..54cdbf167 100644 --- a/Segment/Query/Filter/CustomFieldFilterQueryBuilder.php +++ b/Segment/Query/Filter/CustomFieldFilterQueryBuilder.php @@ -14,23 +14,16 @@ class CustomFieldFilterQueryBuilder extends BaseFilterQueryBuilder { - /** - * @var QueryFilterHelper - */ - private $filterHelper; - public function __construct( RandomParameterName $randomParameterNameService, EventDispatcherInterface $dispatcher, - QueryFilterHelper $filterHelper + private QueryFilterHelper $filterHelper ) { parent::__construct($randomParameterNameService, $dispatcher); - - $this->filterHelper = $filterHelper; } /** {@inheritdoc} */ - public static function getServiceId() + public static function getServiceId(): string { return 'mautic.lead.query.builder.custom_field.value'; } @@ -45,10 +38,7 @@ public function applyQuery(SegmentQueryBuilder $queryBuilder, ContactSegmentFilt $tableAlias = 'cfwq_'.(int) $filter->getField(); - $unionQueryContainer = $this->filterHelper->createValueQuery( - $tableAlias, - $filter - ); + $unionQueryContainer = $this->filterHelper->createValueQuery($tableAlias, $filter, true); foreach ($unionQueryContainer as $segmentQueryBuilder) { $segmentQueryBuilder->andWhere( @@ -56,23 +46,16 @@ public function applyQuery(SegmentQueryBuilder $queryBuilder, ContactSegmentFilt ); } - switch ($filterOperator) { - case 'empty': - case 'neq': - case 'notLike': - case '!multiselect': - $queryBuilder->addLogic( - $queryBuilder->expr()->notExists($unionQueryContainer->getSQL()), - $filter->getGlue() - ); - - break; - default: - $queryBuilder->addLogic( - $queryBuilder->expr()->exists($unionQueryContainer->getSQL()), - $filter->getGlue() - ); - } + match ($filterOperator) { + 'empty', 'neq', 'notLike', '!multiselect', '!between', 'notBetween' => $queryBuilder->addLogic( + $queryBuilder->expr()->notExists($unionQueryContainer->getSQL()), + $filter->getGlue() + ), + default => $queryBuilder->addLogic( + $queryBuilder->expr()->exists($unionQueryContainer->getSQL()), + $filter->getGlue() + ), + }; $queryBuilder->setParameters($unionQueryContainer->getParameters(), $unionQueryContainer->getParameterTypes()); diff --git a/Segment/Query/Filter/CustomItemNameFilterQueryBuilder.php b/Segment/Query/Filter/CustomItemNameFilterQueryBuilder.php index 21d220b7e..d8c184d1f 100644 --- a/Segment/Query/Filter/CustomItemNameFilterQueryBuilder.php +++ b/Segment/Query/Filter/CustomItemNameFilterQueryBuilder.php @@ -17,18 +17,12 @@ class CustomItemNameFilterQueryBuilder extends BaseFilterQueryBuilder { use QueryBuilderManipulatorTrait; - /** - * @var QueryFilterHelper - */ - private $filterHelper; - public function __construct( RandomParameterName $randomParameterNameService, - QueryFilterHelper $filterHelper, + private QueryFilterHelper $filterHelper, EventDispatcherInterface $dispatcher ) { parent::__construct($randomParameterNameService, $dispatcher); - $this->filterHelper = $filterHelper; } public static function getServiceId(): string @@ -64,16 +58,10 @@ public function applyQuery(QueryBuilder $queryBuilder, ContactSegmentFilter $fil $filterQueryBuilder->select($tableAlias.'_contact.contact_id as lead_id'); $filterQueryBuilder->andWhere($leadsTableAlias.'.id = '.$tableAlias.'_contact.contact_id'); - switch ($filter->getOperator()) { - case 'empty': - case 'neq': - case 'notLike': - $queryBuilder->addLogic($queryBuilder->expr()->notExists($filterQueryBuilder->getSQL()), $filter->getGlue()); - - break; - default: - $queryBuilder->addLogic($queryBuilder->expr()->exists($filterQueryBuilder->getSQL()), $filter->getGlue()); - } + match ($filter->getOperator()) { + 'empty', 'neq', 'notLike' => $queryBuilder->addLogic($queryBuilder->expr()->notExists($filterQueryBuilder->getSQL()), $filter->getGlue()), + default => $queryBuilder->addLogic($queryBuilder->expr()->exists($filterQueryBuilder->getSQL()), $filter->getGlue()), + }; $this->copyParams($filterQueryBuilder, $queryBuilder); diff --git a/Segment/Query/Filter/CustomObjectMergedFilterQueryBuilder.php b/Segment/Query/Filter/CustomObjectMergedFilterQueryBuilder.php new file mode 100644 index 000000000..04161419e --- /dev/null +++ b/Segment/Query/Filter/CustomObjectMergedFilterQueryBuilder.php @@ -0,0 +1,38 @@ +getTableAlias(MAUTIC_TABLE_PREFIX.'leads'); + $subQuery = $this->queryFilterHelper->createMergeFilterQuery($filter, $leadsTableAlias); + $queryBuilder->addLogic($queryBuilder->expr()->exists($subQuery->getSQL()), $filter->getGlue()); + $queryBuilder->setParameters($subQuery->getParameters(), $subQuery->getParameterTypes()); + + return $queryBuilder; + } +} diff --git a/Segment/Query/Filter/QueryFilterFactory.php b/Segment/Query/Filter/QueryFilterFactory.php index 4907b3aa4..084c42854 100644 --- a/Segment/Query/Filter/QueryFilterFactory.php +++ b/Segment/Query/Filter/QueryFilterFactory.php @@ -13,22 +13,10 @@ class QueryFilterFactory { - /** - * @var ContactSegmentFilterFactory - */ - private $contactSegmentFilterFactory; - - /** - * @var QueryFilterHelper - */ - private $queryFilterHelper; - public function __construct( - ContactSegmentFilterFactory $filterFactory, - QueryFilterHelper $queryFilterHelper + private ContactSegmentFilterFactory $contactSegmentFilterFactory, + private QueryFilterHelper $queryFilterHelper ) { - $this->contactSegmentFilterFactory = $filterFactory; - $this->queryFilterHelper = $queryFilterHelper; } /** diff --git a/Segment/Query/UnionQueryContainer.php b/Segment/Query/UnionQueryContainer.php index 19f833ddc..55db816a5 100644 --- a/Segment/Query/UnionQueryContainer.php +++ b/Segment/Query/UnionQueryContainer.php @@ -17,29 +17,24 @@ class UnionQueryContainer implements \Iterator /** * @var SegmentQueryBuilder[] */ - private $queries = []; + private array $queries = []; /** - * @var array + * @var mixed[] */ - private $parameters = []; + private array $parameters = []; /** - * @var array + * @var mixed[] */ - private $parameterTypes = []; + private array $parameterTypes = []; - /** - * @var int - */ - private $position = 0; + private int $position = 0; /** * Whether parameters needs to be rebuild. - * - * @var bool */ - private $needsRebuild = false; + private bool $needsRebuild = false; public function add(SegmentQueryBuilder $queryBuilder): void { diff --git a/Serializer/ApiNormalizer.php b/Serializer/ApiNormalizer.php index 25ced4e37..c9f2b991f 100644 --- a/Serializer/ApiNormalizer.php +++ b/Serializer/ApiNormalizer.php @@ -20,16 +20,6 @@ final class ApiNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface { - /** - * @var CustomFieldTypeProvider - */ - private $customFieldTypeProvider; - - /** - * @var CustomItemModel - */ - private $customItemModel; - /** * @var NormalizerInterface */ @@ -40,22 +30,19 @@ final class ApiNormalizer implements NormalizerInterface, DenormalizerInterface, */ private $iriConverter; - /** - * @var EntityManager - */ - private $em; - - public function __construct(NormalizerInterface $decorated, CustomFieldTypeProvider $customFieldTypeProvider, CustomItemModel $customItemModel, IriConverterInterface $iriConverter, EntityManager $em) + public function __construct( + NormalizerInterface $decorated, + private CustomFieldTypeProvider $customFieldTypeProvider, + private CustomItemModel $customItemModel, + IriConverterInterface $iriConverter, + private EntityManager $em) { if (!$decorated instanceof DenormalizerInterface) { throw new InvalidArgumentException(sprintf('The decorated normalizer must implement the %s.', DenormalizerInterface::class)); } $this->decorated = $decorated; - $this->customFieldTypeProvider = $customFieldTypeProvider; - $this->customItemModel = $customItemModel; $this->iriConverter = $iriConverter; - $this->em = $em; } public function supportsNormalization($data, $format = null) @@ -98,7 +85,7 @@ public function denormalize($data, $class, $format = null, array $context = []) return $this->decorated->denormalize($data, $class, $format, $context); } - public function setSerializer(SerializerInterface $serializer) + public function setSerializer(SerializerInterface $serializer): void { if ($this->decorated instanceof SerializerAwareInterface) { $this->decorated->setSerializer($serializer); diff --git a/Tests/Functional/ApiPlatform/AbstractApiPlatformFunctionalTest.php b/Tests/Functional/ApiPlatform/AbstractApiPlatformFunctionalTest.php index d15f1e75a..85a994a01 100644 --- a/Tests/Functional/ApiPlatform/AbstractApiPlatformFunctionalTest.php +++ b/Tests/Functional/ApiPlatform/AbstractApiPlatformFunctionalTest.php @@ -6,7 +6,6 @@ use Mautic\CoreBundle\Test\MauticMysqlTestCase; use Mautic\UserBundle\Entity\Permission; use Mautic\UserBundle\Entity\User; -use ReflectionClass; use Symfony\Component\HttpFoundation\Response; abstract class AbstractApiPlatformFunctionalTest extends MauticMysqlTestCase @@ -58,7 +57,7 @@ protected function setPermission(User $user, string $permission, array $permissi $this->em->flush(); // reset in-memory permission cache - $property = (new ReflectionClass(CorePermissions::class))->getProperty('grantedPermissions'); + $property = (new \ReflectionClass(CorePermissions::class))->getProperty('grantedPermissions'); $property->setAccessible(true); $property->setValue(self::$container->get('mautic.security'), []); } @@ -78,6 +77,14 @@ protected function updateEntity(string $createdId, array $payload): Response return $this->requestEntity('PUT', $createdId, $payload); } + /** + * @param array $payload + */ + protected function patchEntity(string $createdId, array $payload): Response + { + return $this->requestEntity('PATCH', $createdId, $payload); + } + protected function deleteEntity(string $createdId): Response { return $this->requestEntity('DELETE', $createdId); @@ -85,7 +92,7 @@ protected function deleteEntity(string $createdId): Response protected function requestEntity(string $method, string $path, $payload = null): Response { - $server = ['CONTENT_TYPE' => 'application/ld+json', 'HTTP_ACCEPT' => 'application/ld+json']; + $server = ['CONTENT_TYPE' => 'PATCH' == $method ? 'application/merge-patch+json' : 'application/ld+json', 'HTTP_ACCEPT' => 'application/ld+json']; $this->client->request($method, $path, [], [], $server, $payload ? json_encode($payload) : null); return $this->client->getResponse(); diff --git a/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php b/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php index 6179a2543..5d6a8f24b 100644 --- a/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php +++ b/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php @@ -85,7 +85,7 @@ private function getCreatePayload(string $customObject): array 'string1', 'string2', ], - 'isPublished' => false, + 'isPublished' => false, 'isUniqueIdentifier' => false, ]; } @@ -102,7 +102,7 @@ private function getEditPayload(): array 'string1', 'string2', ], - 'isPublished' => true, + 'isPublished' => true, 'isUniqueIdentifier' => true, ]; } @@ -116,41 +116,41 @@ private function getCRUDProvider(): array { return [ 'all_ok' => [ - ['viewown', 'viewother', 'editown', 'editother', 'create', 'deleteown', 'deleteother', 'publishown', 'publishother'], - Response::HTTP_CREATED, - Response::HTTP_OK, - 'New Custom Field', - Response::HTTP_OK, - 'Edited Custom Field', - Response::HTTP_NO_CONTENT, - ], + ['viewown', 'viewother', 'editown', 'editother', 'create', 'deleteown', 'deleteother', 'publishown', 'publishother'], + Response::HTTP_CREATED, + Response::HTTP_OK, + 'New Custom Field', + Response::HTTP_OK, + 'Edited Custom Field', + Response::HTTP_NO_CONTENT, + ], 'no_delete' => [ - ['viewown', 'viewother', 'editown', 'editother', 'create', 'publishown', 'publishother'], - Response::HTTP_CREATED, - Response::HTTP_OK, - 'New Custom Field', - Response::HTTP_OK, - 'Edited Custom Field', - Response::HTTP_FORBIDDEN, - ], + ['viewown', 'viewother', 'editown', 'editother', 'create', 'publishown', 'publishother'], + Response::HTTP_CREATED, + Response::HTTP_OK, + 'New Custom Field', + Response::HTTP_OK, + 'Edited Custom Field', + Response::HTTP_FORBIDDEN, + ], 'no_update' => [ - ['viewown', 'viewother', 'create', 'deleteown', 'deleteother', 'publishown', 'publishother'], - Response::HTTP_CREATED, - Response::HTTP_OK, - 'New Custom Field', - Response::HTTP_FORBIDDEN, - null, - Response::HTTP_NO_CONTENT, - ], + ['viewown', 'viewother', 'create', 'deleteown', 'deleteother', 'publishown', 'publishother'], + Response::HTTP_CREATED, + Response::HTTP_OK, + 'New Custom Field', + Response::HTTP_FORBIDDEN, + null, + Response::HTTP_NO_CONTENT, + ], 'no_create' => [ - ['viewown', 'viewother', 'editown', 'editother', 'deleteown', 'deleteother', 'publishown', 'publishother'], - Response::HTTP_FORBIDDEN, - '', - null, - '', - null, - '', - ], + ['viewown', 'viewother', 'editown', 'editother', 'deleteown', 'deleteother', 'publishown', 'publishother'], + Response::HTTP_FORBIDDEN, + '', + null, + '', + null, + '', + ], ]; } diff --git a/Tests/Functional/ApiPlatform/CustomFieldOptionFunctionalTest.php b/Tests/Functional/ApiPlatform/CustomFieldOptionFunctionalTest.php index 81d331717..daea1f0b4 100644 --- a/Tests/Functional/ApiPlatform/CustomFieldOptionFunctionalTest.php +++ b/Tests/Functional/ApiPlatform/CustomFieldOptionFunctionalTest.php @@ -9,7 +9,7 @@ use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; use MauticPlugin\CustomObjectsBundle\Helper\CsvHelper; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; final class CustomFieldOptionFunctionalTest extends AbstractApiPlatformFunctionalTest { @@ -126,41 +126,41 @@ private function getCRUDProvider(): array { return [ 'all_ok' => [ - ['viewown', 'viewother', 'editown', 'editother', 'create', 'deleteown', 'deleteother', 'publishown', 'publishother'], - Response::HTTP_CREATED, - Response::HTTP_OK, - 'New Custom Field Option', - Response::HTTP_OK, - 'Edited Custom Field Option', - Response::HTTP_NO_CONTENT, - ], + ['viewown', 'viewother', 'editown', 'editother', 'create', 'deleteown', 'deleteother', 'publishown', 'publishother'], + Response::HTTP_CREATED, + Response::HTTP_OK, + 'New Custom Field Option', + Response::HTTP_OK, + 'Edited Custom Field Option', + Response::HTTP_NO_CONTENT, + ], 'no_delete' => [ - ['viewown', 'viewother', 'editown', 'editother', 'create', 'publishown', 'publishother'], - Response::HTTP_CREATED, - Response::HTTP_OK, - 'New Custom Field Option', - Response::HTTP_OK, - 'Edited Custom Field Option', - Response::HTTP_FORBIDDEN, - ], + ['viewown', 'viewother', 'editown', 'editother', 'create', 'publishown', 'publishother'], + Response::HTTP_CREATED, + Response::HTTP_OK, + 'New Custom Field Option', + Response::HTTP_OK, + 'Edited Custom Field Option', + Response::HTTP_FORBIDDEN, + ], 'no_update' => [ - ['viewown', 'viewother', 'create', 'deleteown', 'deleteother', 'publishown', 'publishother'], - Response::HTTP_CREATED, - Response::HTTP_OK, - 'New Custom Field Option', - Response::HTTP_FORBIDDEN, - null, - Response::HTTP_NO_CONTENT, - ], + ['viewown', 'viewother', 'create', 'deleteown', 'deleteother', 'publishown', 'publishother'], + Response::HTTP_CREATED, + Response::HTTP_OK, + 'New Custom Field Option', + Response::HTTP_FORBIDDEN, + null, + Response::HTTP_NO_CONTENT, + ], 'no_create' => [ - ['viewown', 'viewother', 'editown', 'editother', 'deleteown', 'deleteother', 'publishown', 'publishother'], - Response::HTTP_FORBIDDEN, - '', - null, - '', - null, - '', - ], + ['viewown', 'viewother', 'editown', 'editother', 'deleteown', 'deleteother', 'publishown', 'publishother'], + Response::HTTP_FORBIDDEN, + '', + null, + '', + null, + '', + ], ]; } } diff --git a/Tests/Functional/ApiPlatform/CustomItemFunctionalTest.php b/Tests/Functional/ApiPlatform/CustomItemFunctionalTest.php index 68066f97f..9c04b5e54 100644 --- a/Tests/Functional/ApiPlatform/CustomItemFunctionalTest.php +++ b/Tests/Functional/ApiPlatform/CustomItemFunctionalTest.php @@ -7,157 +7,239 @@ use Mautic\LeadBundle\Provider\FilterOperatorProviderInterface; use MauticPlugin\CustomObjectsBundle\CustomFieldType\TextType; use MauticPlugin\CustomObjectsBundle\Entity\CustomField; +use MauticPlugin\CustomObjectsBundle\Entity\CustomFieldValueText; +use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; +use MauticPlugin\CustomObjectsBundle\Model\CustomItemModel; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; final class CustomItemFunctionalTest extends AbstractApiPlatformFunctionalTest { - public function testCustomItemCRUD(): void + private CustomItemModel $customItemModel; + + public function setUp(): void + { + $this->configParams['custom_objects_enabled'] = true; + + parent::setUp(); + + $customItemModel = $this->getContainer()->get('mautic.custom.model.item'); + \assert($customItemModel instanceof CustomItemModel); + + $this->customItemModel = $customItemModel; + } + + /** + * @dataProvider getCustomItemsDataProvider + * + * @param array $permissions + */ + public function testGetCustomItem(array $permissions, int $expectedResponse): void + { + $customItem = $this->createCustomItem($permissions); + $response = $this->retrieveEntity('/api/v2/custom_items/'.$customItem->getId()); + $json = json_decode($response->getContent(), true); + + self::assertEquals($expectedResponse, $response->getStatusCode()); + + if (Response::HTTP_FORBIDDEN == $expectedResponse) { + $this->assertAccessForbiddenContent($json); + + return; + } + + $this->assertSuccessContent($json, $customItem); + } + + /** + * @return iterable + */ + public function getCustomItemsDataProvider(): iterable + { + yield [['viewother'], Response::HTTP_OK]; + + yield [['editother'], Response::HTTP_OK]; + + yield [['deleteother'], Response::HTTP_OK]; + + yield [['publishother'], Response::HTTP_OK]; + + yield [[], Response::HTTP_FORBIDDEN]; + + yield [['viewown', 'editown', 'create', 'deleteown', 'publishown'], Response::HTTP_FORBIDDEN]; + } + + /** + * @dataProvider postCustomItemsDataProvider + * + * @param array $permissions + */ + public function testPostCustomItem(array $permissions, int $expectedResponse): void { $customObject = $this->createCustomObject(); $category = $this->createCategory(); $customField = $this->createCustomField($customObject); + $user = $this->getUser(); + + $this->setPermission($user, 'custom_objects:'.$customObject->getId(), $permissions); + + $response = $this->createEntity('custom_items', [ + 'name' => 'Custom Item', + 'customObject' => '/api/v2/custom_objects/'.$customObject->getId(), + 'language' => 'en', + 'category' => '/api/v2/categories/'.$category->getId(), + 'fieldValues' => [ + [ + 'id' => '/api/v2/custom_fields/'.$customField->getId(), + 'value' => 'value', + ], + ], + ]); + $json = json_decode($response->getContent(), true); + + self::assertEquals($expectedResponse, $response->getStatusCode()); + + if (Response::HTTP_FORBIDDEN == $expectedResponse) { + $this->assertAccessForbiddenContent($json); - foreach ($this->getCRUDProvider() as $parameters) { - $this->runTestCustomItemCRUD(...array_merge([$customObject, $category, $customField], $parameters)); + return; } + + $this->em->clear(); + $customItem = $this->em->getRepository(CustomItem::class)->find($json['id']); + $this->customItemModel->populateCustomFields($customItem); + $this->assertSuccessContent($json, $customItem); } /** - * @throws \Doctrine\ORM\ORMException + * @return iterable */ - private function runTestCustomItemCRUD( - CustomObject $customObject, - Category $category, - CustomField $customField, - array $permissions, - string $httpCreated, - string $httpRetrieved, - ?string $retrievedAlias, - ?string $retrievedVariable, - string $httpUpdated, - ?string $updatedAlias, - ?string $updatedVariable, - string $httpDeleted - ): void { - // USER - $user = $this->getUser(); - // PERMISSION - $this->setPermission($user, 'custom_objects:'.$customObject->getId(), $permissions); - // CREATE - $payloadCreate = $this->getCreatePayload($customObject, $category, $customField); - $clientCreateResponse = $this->createEntity('custom_items', $payloadCreate); - $this->assertEquals($httpCreated, $clientCreateResponse->getStatusCode()); - if (Response::HTTP_FORBIDDEN === $clientCreateResponse->getStatusCode()) { + public function postCustomItemsDataProvider(): iterable + { + yield [['create'], Response::HTTP_CREATED]; + + yield [[], Response::HTTP_FORBIDDEN]; + + yield [['viewown', 'viewother', 'editown', 'editother', 'deleteown', 'deleteother', 'publishown', 'publishother'], Response::HTTP_FORBIDDEN]; + } + + /** + * @dataProvider putCustomItemsDataProvider + * + * @param array $permissions + */ + public function testPutCustomItem(array $permissions, int $expectedResponse): void + { + $customItem = $this->createCustomItem($permissions); + $response = $this->updateEntity('/api/v2/custom_items/'.$customItem->getId(), [ + 'name' => 'Custom Item Edited', + 'fieldValues' => [ + [ + 'id' => '/api/v2/custom_fields/'.$customItem->getCustomObject()->getCustomFields()->first()->getId(), + 'value' => 'test3', + ], + ], + ]); + $json = json_decode($response->getContent(), true); + + self::assertEquals($expectedResponse, $response->getStatusCode()); + + if (Response::HTTP_FORBIDDEN == $expectedResponse) { + $this->assertAccessForbiddenContent($json); + return; } - // GET ID OF ENTITY - $createdId = json_decode($clientCreateResponse->getContent())->{'@id'}; - // RETRIEVE - $clientRetrieveResponse = $this->retrieveEntity($createdId); - $this->assertEquals($httpRetrieved, $clientRetrieveResponse->getStatusCode()); - if ($retrievedAlias) { - $this->assertEquals($retrievedAlias, json_decode($clientRetrieveResponse->getContent())->name); - $this->assertEquals($retrievedVariable, json_decode($clientRetrieveResponse->getContent(), true)['fieldValues'][0]['value']); - } - // UPDATE - $payloadUpdate = $this->getEditPayload($customField); - $clientUpdateResponse = $this->updateEntity($createdId, $payloadUpdate); - $this->assertEquals($httpUpdated, $clientUpdateResponse->getStatusCode()); - if ($updatedAlias) { - $this->assertEquals($updatedAlias, json_decode($clientUpdateResponse->getContent())->name); - $this->assertEquals($updatedVariable, json_decode($clientUpdateResponse->getContent(), true)['fieldValues'][0]['value']); - } - // DELETE - $clientDeleteResponse = $this->deleteEntity($createdId); - $this->assertEquals($httpDeleted, $clientDeleteResponse->getStatusCode()); + + $this->em->clear(); + $customItem = $this->em->getRepository(CustomItem::class)->find($json['id']); + $this->customItemModel->populateCustomFields($customItem); + $this->assertSuccessContent($json, $customItem); } - private function getCreatePayload(CustomObject $customObject, Category $category, CustomField $customField): array + /** + * @return iterable + */ + public function putCustomItemsDataProvider(): iterable { - return - [ - 'name' => 'Custom Item Created', - 'customObject' => '/api/v2/custom_objects/'.$customObject->getId(), - 'language' => 'en', - 'category' => '/api/v2/categories/'.$category->getId(), - 'fieldValues' => [ - [ - 'id' => '/api/v2/custom_fields/'.$customField->getId(), - 'value' => 'test', - ], - ], - ]; + yield [['editother'], Response::HTTP_OK]; + + yield [['deleteother'], Response::HTTP_OK]; + + yield [[], Response::HTTP_FORBIDDEN]; + + yield [['viewown', 'viewother', 'editown', 'create', 'deleteown', 'publishown', 'publishother'], Response::HTTP_FORBIDDEN]; } - private function getEditPayload($customField): array + /** + * @dataProvider putCustomItemsDataProvider + * + * @param array $permissions + */ + public function testPatchCustomItem(array $permissions, int $expectedResponse): void { - return + $customItem = $this->createCustomItem($permissions); + $response = $this->patchEntity('/api/v2/custom_items/'.$customItem->getId(), [ - 'name' => 'Custom Item Edited', 'fieldValues' => [ [ - 'id' => '/api/v2/custom_fields/'.$customField->getId(), + 'id' => '/api/v2/custom_fields/'.$customItem->getCustomObject()->getCustomFields()->first()->getId(), 'value' => 'test2', ], ], - ]; + ]); + $json = json_decode($response->getContent(), true); + + self::assertEquals($expectedResponse, $response->getStatusCode()); + + if (Response::HTTP_FORBIDDEN == $expectedResponse) { + $this->assertAccessForbiddenContent($json); + + return; + } + + $this->em->clear(); + $customItem = $this->em->getRepository(CustomItem::class)->find($json['id']); + $this->customItemModel->populateCustomFields($customItem); + $this->assertSuccessContent($json, $customItem); } /** - * @see self::testCustomItemCRUD() + * @dataProvider deleteCustomItemsDataProvider * - * @return array|array[] + * @param array $permissions */ - private function getCRUDProvider(): array - { - return [ - 'all_ok' => [ - ['viewown', 'viewother', 'editown', 'editother', 'create', 'deleteown', 'deleteother', 'publishown', 'publishother'], - Response::HTTP_CREATED, - Response::HTTP_OK, - 'Custom Item Created', - 'test', - Response::HTTP_OK, - 'Custom Item Edited', - 'test2', - Response::HTTP_NO_CONTENT, - ], - 'no_delete' => [ - ['viewown', 'viewother', 'editown', 'editother', 'create', 'publishown', 'publishother'], - Response::HTTP_CREATED, - Response::HTTP_OK, - 'Custom Item Created', - 'test', - Response::HTTP_OK, - 'Custom Item Edited', - 'test2', - Response::HTTP_FORBIDDEN, - ], - 'no_update' => [ - ['viewown', 'viewother', 'create', 'deleteown', 'deleteother', 'publishown', 'publishother'], - Response::HTTP_CREATED, - Response::HTTP_OK, - 'Custom Item Created', - 'test', - Response::HTTP_FORBIDDEN, - null, - null, - Response::HTTP_NO_CONTENT, - ], - 'no_create' => [ - ['viewown', 'viewother', 'editown', 'editother', 'deleteown', 'deleteother', 'publishown', 'publishother'], - Response::HTTP_FORBIDDEN, - '', - null, - null, - '', - null, - null, - '', - ], - ]; + public function testDeleteCustomItem(array $permissions, int $expectedResponse): void + { + $customItem = $this->createCustomItem($permissions); + $response = $this->deleteEntity('/api/v2/custom_items/'.$customItem->getId()); + $json = json_decode($response->getContent(), true); + + self::assertEquals($expectedResponse, $response->getStatusCode()); + + if (Response::HTTP_FORBIDDEN == $expectedResponse) { + $this->assertAccessForbiddenContent($json); + + return; + } + + $this->em->clear(); + $customItem = $this->em->getRepository(CustomItem::class)->find($customItem->getId()); + self::assertEquals(Response::HTTP_NO_CONTENT, $response->getStatusCode()); + self::assertNull($json); + self::assertNull($customItem); + } + + /** + * @return iterable + */ + public function deleteCustomItemsDataProvider(): iterable + { + yield [['deleteother'], Response::HTTP_NO_CONTENT]; + + yield [[], Response::HTTP_FORBIDDEN]; + + yield [['viewown', 'viewother', 'editown', 'create', 'deleteown', 'editother', 'publishown', 'publishother'], Response::HTTP_FORBIDDEN]; } private function createCustomObject(): CustomObject @@ -172,6 +254,30 @@ private function createCustomObject(): CustomObject return $customObject; } + /** + * @param array $permissions + */ + private function createCustomItem(array $permissions): CustomItem + { + $customObject = $this->createCustomObject(); + $category = $this->createCategory(); + $customField = $this->createCustomField($customObject); + $customItem = new CustomItem($customObject); + $customItem->setName('Custom Item'); + $customItem->setLanguage('en'); + $customItem->setCategory($category); + $customFieldValue = new CustomFieldValueText($customField, $customItem, 'value'); + $customItem->addCustomFieldValue($customFieldValue); + + $this->em->persist($customItem); + $this->em->flush(); + + $user = $this->getUser(); + $this->setPermission($user, 'custom_objects:'.$customObject->getId(), $permissions); + + return $customItem; + } + private function createCategory(): Category { $category = new Category(); @@ -203,4 +309,35 @@ private function createCustomField(CustomObject $customObject): CustomField return $customField; } + + /** + * @param array $json + */ + private function assertAccessForbiddenContent(array $json): void + { + self::assertEquals($json['@context'], '/api/v2/contexts/Error'); + self::assertEquals($json['@type'], 'hydra:Error'); + self::assertEquals($json['hydra:title'], 'An error occurred'); + self::assertEquals($json['hydra:description'], 'Access Denied.'); + self::assertCount(4, $json); + } + + /** + * @param array $json + */ + private function assertSuccessContent(array $json, CustomItem $customItem): void + { + self::assertEquals($json['@context'], '/api/v2/contexts/custom_items'); + self::assertEquals($json['@id'], '/api/v2/custom_items/'.$customItem->getId()); + self::assertEquals($json['@type'], 'custom_items'); + self::assertEquals($json['id'], $customItem->getId()); + self::assertEquals($json['name'], $customItem->getName()); + self::assertEquals($json['customObject'], '/api/v2/custom_objects/'.$customItem->getCustomObject()->getId()); + self::assertEquals($json['language'], 'en'); + self::assertEquals($json['category'], '/api/v2/categories/'.$customItem->getCategory()->getId()); + self::assertEquals($json['fieldValues'][0]['id'], '/api/v2/custom_fields/'.$customItem->getCustomFieldValues()->first()->getId()); + self::assertEquals($json['fieldValues'][0]['value'], $customItem->getCustomFieldValues()->first()->getValue()); + self::assertCount(9, $json); + self::assertCount(1, $json['fieldValues']); + } } diff --git a/Tests/Functional/ApiPlatform/CustomObjectFunctionalTest.php b/Tests/Functional/ApiPlatform/CustomObjectFunctionalTest.php index bd745f372..2560e189a 100644 --- a/Tests/Functional/ApiPlatform/CustomObjectFunctionalTest.php +++ b/Tests/Functional/ApiPlatform/CustomObjectFunctionalTest.php @@ -45,7 +45,7 @@ public function runTestCustomObjectCRUD( } // UPDATE $payloadUpdate = $this->getEditPayload(); - $clientUpdateResponse = $this->updateEntity($createdId, $payloadUpdate); + $clientUpdateResponse = $this->patchEntity($createdId, $payloadUpdate); $this->assertEquals($httpUpdated, $clientUpdateResponse->getStatusCode()); if ($updatedAlias) { $this->assertEquals($updatedAlias, json_decode($clientUpdateResponse->getContent())->alias); @@ -65,43 +65,43 @@ private function getCreatePayload(): array 'description' => 'string string', 'language' => 'en', 'customFields' => [ - [ - 'label' => 'Test Field 1', - 'alias' => 'customObjectTestField1', - 'type' => 'multiselect', - 'order' => 42, - 'required' => true, - 'defaultValue' => 'one', - 'options' => [ - [ - 'label' => 'one', - 'value' => 'one', - 'order' => 0, - ], - [ - 'label' => 'two', - 'value' => 'two', - 'order' => 1, - ], - ], - 'params' => [ - 'string', + [ + 'label' => 'Test Field 1', + 'alias' => 'customObjectTestField1', + 'type' => 'multiselect', + 'order' => 42, + 'required' => true, + 'defaultValue' => 'one', + 'options' => [ + [ + 'label' => 'one', + 'value' => 'one', + 'order' => 0, ], - 'isPublished' => true, - ], - [ - 'label' => 'Test Field 2', - 'alias' => 'customObjectTestField2', - 'type' => 'text', - 'order' => 43, - 'required' => true, - 'defaultValue' => 'text', - 'params' => [ - 'string', + [ + 'label' => 'two', + 'value' => 'two', + 'order' => 1, ], - 'isPublished' => true, ], + 'params' => [ + 'string', + ], + 'isPublished' => true, ], + [ + 'label' => 'Test Field 2', + 'alias' => 'customObjectTestField2', + 'type' => 'text', + 'order' => 43, + 'required' => true, + 'defaultValue' => 'text', + 'params' => [ + 'string', + ], + 'isPublished' => true, + ], + ], ]; } @@ -126,41 +126,41 @@ private function getCRUDProvider(): array { return [ 'all_ok' => [ - ['viewown', 'viewother', 'editown', 'editother', 'create', 'deleteown', 'deleteother', 'publishown', 'publishother'], - Response::HTTP_CREATED, - Response::HTTP_OK, - 'customObjectTest', - Response::HTTP_OK, - 'customObjectTestEdited', - Response::HTTP_NO_CONTENT, - ], + ['viewown', 'viewother', 'editown', 'editother', 'create', 'deleteown', 'deleteother', 'publishown', 'publishother'], + Response::HTTP_CREATED, + Response::HTTP_OK, + 'customObjectTest', + Response::HTTP_OK, + 'customObjectTestEdited', + Response::HTTP_NO_CONTENT, + ], 'no_delete' => [ - ['viewown', 'viewother', 'editown', 'editother', 'create', 'publishown', 'publishother'], - Response::HTTP_CREATED, - Response::HTTP_OK, - 'customObjectTest', - Response::HTTP_OK, - 'customObjectTestEdited', - Response::HTTP_FORBIDDEN, - ], + ['viewown', 'viewother', 'editown', 'editother', 'create', 'publishown', 'publishother'], + Response::HTTP_CREATED, + Response::HTTP_OK, + 'customObjectTest', + Response::HTTP_OK, + 'customObjectTestEdited', + Response::HTTP_FORBIDDEN, + ], 'no_update' => [ - ['viewown', 'viewother', 'create', 'deleteown', 'deleteother', 'publishown', 'publishother'], - Response::HTTP_CREATED, - Response::HTTP_OK, - 'customObjectTest', - Response::HTTP_FORBIDDEN, - null, - Response::HTTP_NO_CONTENT, - ], + ['viewown', 'viewother', 'create', 'deleteown', 'deleteother', 'publishown', 'publishother'], + Response::HTTP_CREATED, + Response::HTTP_OK, + 'customObjectTest', + Response::HTTP_FORBIDDEN, + null, + Response::HTTP_NO_CONTENT, + ], 'no_create' => [ - ['viewown', 'viewother', 'editown', 'editother', 'deleteown', 'deleteother', 'publishown', 'publishother'], - Response::HTTP_FORBIDDEN, - '', - null, - '', - null, - '', - ], + ['viewown', 'viewother', 'editown', 'editother', 'deleteown', 'deleteother', 'publishown', 'publishother'], + Response::HTTP_FORBIDDEN, + '', + null, + '', + null, + '', + ], ]; } } diff --git a/Tests/Functional/Controller/CustomItemListControllerSearchTest.php b/Tests/Functional/Controller/CustomItemListControllerSearchTest.php index 0f7f7e9cc..6fe0fb257 100644 --- a/Tests/Functional/Controller/CustomItemListControllerSearchTest.php +++ b/Tests/Functional/Controller/CustomItemListControllerSearchTest.php @@ -113,7 +113,7 @@ private function addCustomFieldValue(CustomItem $customItem, AbstractCustomField private function assertFound(CustomObject $customObject, CustomItem $customItem, string $search): void { $crawler = $this->client->request(Request::METHOD_GET, sprintf('/s/custom/object/%s/item?search=%s', $customObject->getId(), $search)); - $tableCrawler = $crawler->filterXPath('//h3[contains(text(), "Devices")]/following::table[1]'); + $tableCrawler = $crawler->filterXPath('//h1[contains(text(), "Devices")]/following::table[1]'); Assert::assertSame(1, $tableCrawler->count()); $rowCrawler = $tableCrawler->filterXPath('.//tbody/tr'); diff --git a/Tests/Functional/Controller/CustomItemListControllerShownFieldTest.php b/Tests/Functional/Controller/CustomItemListControllerShownFieldTest.php index bdf0ee8df..9b5ad02a0 100644 --- a/Tests/Functional/Controller/CustomItemListControllerShownFieldTest.php +++ b/Tests/Functional/Controller/CustomItemListControllerShownFieldTest.php @@ -4,8 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Functional\Controller; -use DateTime; -use InvalidArgumentException; use Mautic\CoreBundle\Test\MauticMysqlTestCase; use Mautic\LeadBundle\Entity\Lead; use MauticPlugin\CustomObjectsBundle\Entity\AbstractCustomFieldValue; @@ -78,7 +76,7 @@ private function assertDetailListDisplaysFields(string $type): void $showInContactDetailList = false; break; default: - throw new InvalidArgumentException(); + throw new \InvalidArgumentException(); break; } @@ -97,8 +95,8 @@ private function assertDetailListDisplaysFields(string $type): void $fieldValueBasset = $this->addCustomFieldValue($customItemAnimal, new CustomFieldValueText($customFieldBreed, $customItemAnimal, 'Basset')); $fieldValueAge = $this->addCustomFieldValue($customItemAnimal, new CustomFieldValueInt($customFieldAge, $customItemAnimal, 5)); - $fieldValueBirthDate = $this->addCustomFieldValue($customItemAnimal, new CustomFieldValueDate($customFieldBirthDate, $customItemAnimal, new DateTime('2015-02-15'))); - $fieldValueInoculation = $this->addCustomFieldValue($customItemAnimal, new CustomFieldValueDateTime($customFieldInoculation, $customItemAnimal, new DateTime('2020-09-15'))); + $fieldValueBirthDate = $this->addCustomFieldValue($customItemAnimal, new CustomFieldValueDate($customFieldBirthDate, $customItemAnimal, new \DateTime('2015-02-15'))); + $fieldValueInoculation = $this->addCustomFieldValue($customItemAnimal, new CustomFieldValueDateTime($customFieldInoculation, $customItemAnimal, new \DateTime('2020-09-15'))); $this->addCustomFieldValue($customItemAnimal, new CustomFieldValueOption($customFieldDiseases, $customItemAnimal, 'fever')); $createXref($customItemAnimal); @@ -108,7 +106,7 @@ private function assertDetailListDisplaysFields(string $type): void $this->em->flush(); $crawler = $this->client->request(Request::METHOD_GET, sprintf('/s/custom/object/%s/item?filterEntityId=%s&filterEntityType=%s', $customObjectAnimal->getId(), $relatedObject->getId(), $type)); - $tableCrawler = $crawler->filterXPath(sprintf('//h3[contains(text(), "%s")]/following::table[1]', $customObjectAnimal->getNameSingular())); + $tableCrawler = $crawler->filterXPath(sprintf('//h1[contains(text(), "%s")]/following::table[1]', $customObjectAnimal->getNameSingular())); Assert::assertSame(1, $tableCrawler->count()); $headRowCrawler = $tableCrawler->filterXPath('.//thead/tr'); diff --git a/Tests/Functional/Controller/CustomItemListControllerXrefTest.php b/Tests/Functional/Controller/CustomItemListControllerXrefTest.php index 0cf538180..9fb8afb1d 100644 --- a/Tests/Functional/Controller/CustomItemListControllerXrefTest.php +++ b/Tests/Functional/Controller/CustomItemListControllerXrefTest.php @@ -67,7 +67,7 @@ private function assertResponse(CustomObject $customObject, CustomItem $customIt $uri = sprintf('/s/custom/object/%s/item?filterEntityId=%s&filterEntityType=%s&lookup=%d', $customObject->getId(), $filterEntityId, $entityType, $lookup); $crawler = $this->client->request(Request::METHOD_GET, $uri); - $tableCrawler = $crawler->filter('table'); + $tableCrawler = $crawler->filter('div[id*="custom-item-"] table'); Assert::assertSame(1, $tableCrawler->count()); $rowCrawler = $tableCrawler->filterXPath('.//tbody/tr'); diff --git a/Tests/Functional/Controller/CustomObject/DeleteControllerTest.php b/Tests/Functional/Controller/CustomObject/DeleteControllerTest.php index a7dd5ecf0..d611be6a6 100644 --- a/Tests/Functional/Controller/CustomObject/DeleteControllerTest.php +++ b/Tests/Functional/Controller/CustomObject/DeleteControllerTest.php @@ -33,8 +33,8 @@ public function testDeleteChildObject() // Open Custom Object listing page verify that both parent and child objects are listed in Custom Objects table. $crawler = $this->client->request(Request::METHOD_GET, '/s/custom/object'); - $this->assertStringContainsString('Products', $crawler->filterXPath('//*[@id="custom-objects-table"]/tbody/tr[1]/td[2]/div/a')->text()); - $this->assertStringContainsString('Electronics', $crawler->filterXPath('//*[@id="custom-objects-table"]/tbody/tr[2]/td[2]/div/a')->text()); + $this->assertStringContainsString('Electronics', $crawler->filterXPath('//*[@id="custom-objects-table"]/tbody/tr[1]/td[2]/div/a')->text()); + $this->assertStringContainsString('Products', $crawler->filterXPath('//*[@id="custom-objects-table"]/tbody/tr[2]/td[2]/div/a')->text()); // Delete the Child Custom Object $this->client->request(Request::METHOD_POST, sprintf('/s/custom/object/delete/%s', $childObject->getId())); diff --git a/Tests/Functional/Controller/CustomObjectFormTest.php b/Tests/Functional/Controller/CustomObjectFormTest.php index 0a887f7bd..32017b8cb 100644 --- a/Tests/Functional/Controller/CustomObjectFormTest.php +++ b/Tests/Functional/Controller/CustomObjectFormTest.php @@ -4,7 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Functional\Controller; -use DateTime; use Mautic\CoreBundle\Test\MauticMysqlTestCase; use MauticPlugin\CustomObjectsBundle\Entity\CustomFieldOption; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; @@ -886,12 +885,12 @@ private function assertCustomObject(array $expected, int $id): void $defaultValue = $customField->getDefaultValue(); switch ($customField->getType()) { case 'date': - $this->assertInstanceOf(DateTime::class, $defaultValue); + $this->assertInstanceOf(\DateTime::class, $defaultValue); $this->assertSame($expectedCf['defaultValue'], $defaultValue->format('Y-m-d')); break; case 'datetime': - $this->assertInstanceOf(DateTime::class, $defaultValue); + $this->assertInstanceOf(\DateTime::class, $defaultValue); $this->assertSame($expectedCf['defaultValue'], $defaultValue->format('Y-m-d H:i')); break; diff --git a/Tests/Functional/DataFixtures/ORM/Data/custom-item-relation-filter-query-builder-fixture-2.yml b/Tests/Functional/DataFixtures/ORM/Data/custom-item-relation-filter-query-builder-fixture-2.yml index 6ea0fc204..73a264473 100644 --- a/Tests/Functional/DataFixtures/ORM/Data/custom-item-relation-filter-query-builder-fixture-2.yml +++ b/Tests/Functional/DataFixtures/ORM/Data/custom-item-relation-filter-query-builder-fixture-2.yml @@ -216,6 +216,7 @@ Mautic\LeadBundle\Entity\LeadList: is_published: true name: 'Price = 1000' alias: 'price-eq-1000' + public_name: 'price-eq-1000' filters: 0: glue : 'and' @@ -233,6 +234,7 @@ Mautic\LeadBundle\Entity\LeadList: is_published: true name: 'Order name = Ordered plug' alias: 'order-plug-name-eq' + public_name: 'order-plug-name-eq' filters: # a:1:{i:0;a:6:{s:4:"glue";s:3:"and";s:5:"field";s:5:"cmo_2";s:6:"object";s:13:"custom_object";s:4:"type";s:4:"text";s:8:"operator";s:1:"=";s:10:"properties";a:1:{s:6:"filter";s:12:"Ordered plug";}}} 0: glue : 'and' @@ -249,6 +251,7 @@ Mautic\LeadBundle\Entity\LeadList: is_published: true name: 'Date < 1990' alias: 'date-lt-1990' + public_name: 'date-lt-1990' filters: # a:1:{i:0;a:6:{s:4:"glue";s:3:"and";s:5:"field";s:5:"cmf_2";s:6:"object";s:13:"custom_object";s:4:"type";s:4:"date";s:8:"operator";s:2:"lt";s:10:"properties";a:1:{s:6:"filter";s:4:"1990";}}} 0: glue : 'and' @@ -265,6 +268,7 @@ Mautic\LeadBundle\Entity\LeadList: is_published: true name: 'DateTime > 1990' alias: 'datetime-gt-1990' + public_name: 'datetime-gt-1990' filters: 0: glue : 'and' @@ -281,6 +285,7 @@ Mautic\LeadBundle\Entity\LeadList: is_published: true name: 'Price > 500' alias: 'price-greater-500' + public_name: 'price-greater-500' filters: # a:1:{i:0;a:6:{s:4:"glue";s:3:"and";s:5:"field";s:5:"cmf_1";s:6:"object";s:13:"custom_object";s:4:"type";s:3:"int";s:8:"operator";s:2:"gt";s:10:"properties";a:1:{s:6:"filter";s:3:"500";}}} 0: glue : 'and' @@ -297,6 +302,7 @@ Mautic\LeadBundle\Entity\LeadList: is_published: true name: 'Price = 500' alias: 'price-eq-500' + public_name: 'price-eq-500' filters: 0: glue : 'and' @@ -313,6 +319,7 @@ Mautic\LeadBundle\Entity\LeadList: is_published: true name: 'Price > 1000' alias: 'price-greater-1000' + public_name: 'price-greater-1000' filters: 0: glue : 'and' @@ -329,6 +336,7 @@ Mautic\LeadBundle\Entity\LeadList: is_published: true name: 'Price <= 1000' alias: 'price-lte-1000' + public_name: 'price-lte-1000' filters: 0: glue : 'and' @@ -345,6 +353,7 @@ Mautic\LeadBundle\Entity\LeadList: is_published: true name: 'Price < 500' alias: 'price-lt-500' + public_name: 'price-lt-500' filters: 0: glue : 'and' @@ -361,6 +370,7 @@ Mautic\LeadBundle\Entity\LeadList: is_published: true name: 'Multiselect = 1' alias: 'option-in-1' + public_name: 'option-in-1' filters: # a:1:{i:0;a:8:{s:6:"object";s:13:"custom_object";s:4:"glue";s:3:"and";s:5:"field";s:5:"cmf_1";s:4:"type";s:11:"multiselect";s:8:"operator";s:2:"in";s:10:"properties";a:1:{s:6:"filter";a:1:{i:0;s:1:"1";}}s:6:"filter";a:1:{i:0;s:1:"1";}s:7:"display";N;}} 0: glue : 'and' @@ -381,6 +391,7 @@ Mautic\LeadBundle\Entity\LeadList: is_published: true name: 'Text = text' alias: 'text-eq-text' + public_name: 'text-eq-tex' filters: 0: glue : 'and' @@ -398,6 +409,7 @@ Mautic\LeadBundle\Entity\LeadList: is_published: true name: 'Combined Price = 1000 and Date = 2020-08-13' alias: 'combined' + public_name: 'combined' filters: 0: glue : 'and' diff --git a/Tests/Functional/DataFixtures/ORM/Data/custom_fields.yml b/Tests/Functional/DataFixtures/ORM/Data/custom_fields.yml index a9c54cf48..ae7da7f5c 100644 --- a/Tests/Functional/DataFixtures/ORM/Data/custom_fields.yml +++ b/Tests/Functional/DataFixtures/ORM/Data/custom_fields.yml @@ -5,7 +5,7 @@ MauticPlugin\CustomObjectsBundle\Entity\CustomField: date_added: '' label: ' Text' alias: 'text_1' - type: 'tect' + type: 'text' custom_field2: custom_object: '@custom_object1' is_published: true @@ -68,4 +68,4 @@ MauticPlugin\CustomObjectsBundle\Entity\CustomField: date_added: '' label: ' Country' alias: 'country_11' - type: 'country' \ No newline at end of file + type: 'country' diff --git a/Tests/Functional/DataFixtures/Traits/CustomObjectsTrait.php b/Tests/Functional/DataFixtures/Traits/CustomObjectsTrait.php index 7d6fe4588..d6f2508ba 100644 --- a/Tests/Functional/DataFixtures/Traits/CustomObjectsTrait.php +++ b/Tests/Functional/DataFixtures/Traits/CustomObjectsTrait.php @@ -65,6 +65,7 @@ public function createCustomItem(ContainerInterface $container, CustomObject $cu /** @var CustomItemModel $customItemModel */ $customItemModel = $container->get('mautic.custom.model.item'); + return $customItemModel->save($customItem); } diff --git a/Tests/Functional/DataFixtures/Traits/FixtureObjectsTrait.php b/Tests/Functional/DataFixtures/Traits/FixtureObjectsTrait.php index b0dac57f3..6bcae7748 100644 --- a/Tests/Functional/DataFixtures/Traits/FixtureObjectsTrait.php +++ b/Tests/Functional/DataFixtures/Traits/FixtureObjectsTrait.php @@ -32,6 +32,8 @@ trait FixtureObjectsTrait */ public function setFixtureObjects(array $objects): void { + $this->skipIfMissingDependency(); + foreach ($objects as $key => $object) { $this->objects[get_class($object)][$key] = $object; $this->entityMap[$key] = get_class($object); @@ -45,6 +47,8 @@ public function setFixtureObjects(array $objects): void */ public function getFixturesByEntityClassName(string $type): array { + $this->skipIfMissingDependency(); + if (!isset($this->objects[$type])) { throw new FixtureNotFoundException('No fixtures of type '.$type.' defined'); } @@ -57,6 +61,8 @@ public function getFixturesByEntityClassName(string $type): array */ public function getFixtureByEntityClassNameAndIndex(string $type, int $index): CommonEntity { + $this->skipIfMissingDependency(); + $fixtures = $this->getFixturesByEntityClassName($type); $fixtures = array_values($fixtures); @@ -75,6 +81,8 @@ public function getFixtureByEntityClassNameAndIndex(string $type, int $index): C */ public function getFixtureById(string $id): UniqueEntityInterface { + $this->skipIfMissingDependency(); + if (!isset($this->entityMap[$id])) { throw new FixtureNotFoundException('No fixture with id "'.$id.'"" defined'); } @@ -87,10 +95,12 @@ public function getFixtureById(string $id): UniqueEntityInterface */ public function getFixturesInUnloadableOrder(): array { + $this->skipIfMissingDependency(); + $entities = []; $orderedKeys = $this->entityMap; - array_reverse($orderedKeys, true); + $orderedKeys = array_reverse($orderedKeys, true); foreach ($orderedKeys as $key => $type) { $entities[$key] = $this->objects[$type][$key]; } @@ -100,6 +110,8 @@ public function getFixturesInUnloadableOrder(): array private function getFixturesDirectory(): string { + $this->skipIfMissingDependency(); + /** @var KernelInterface $kernel */ $kernel = $this->getContainer()->get('kernel'); $pluginDirectory = $kernel->locateResource('@CustomObjectsBundle'); @@ -110,4 +122,11 @@ private function getFixturesDirectory(): string return $pluginDirectory.'/Tests/Functional/DataFixtures/ORM/Data'; } + + private function skipIfMissingDependency(): void + { + if (!self::$container->has('fidry_alice_data_fixtures.loader.doctrine')) { + $this->markTestSkipped('This test requires the theofidry/alice-data-fixtures package'); + } + } } diff --git a/Tests/Functional/EventListener/ApiSubscriberTest.php b/Tests/Functional/EventListener/ApiSubscriberTest.php index 862287795..6b3b2ba9b 100644 --- a/Tests/Functional/EventListener/ApiSubscriberTest.php +++ b/Tests/Functional/EventListener/ApiSubscriberTest.php @@ -347,7 +347,7 @@ public function testCreatingContactWithCustomItemsAndEditAndClearValues(): void $this->assertSame([], $customItemFromResponse['attributes']['multiselect-test-field']); $this->assertSame('', $customItemFromResponse['attributes']['select-test-field']); $this->assertSame('', $customItemFromResponse['attributes']['phone-number-test-field']); - $this->assertSame(null, $customItemFromResponse['attributes']['number-test-field']); + $this->assertSame(0, $customItemFromResponse['attributes']['number-test-field']); $this->assertSame('', $customItemFromResponse['attributes']['hidden-test-field']); $this->assertSame('', $customItemFromResponse['attributes']['email-test-field']); $this->assertSame(null, $customItemFromResponse['attributes']['date-test-field']); diff --git a/Tests/Functional/EventListener/CampaignConditionTest.php b/Tests/Functional/EventListener/CampaignConditionTest.php index f95926bbf..dd464be5e 100644 --- a/Tests/Functional/EventListener/CampaignConditionTest.php +++ b/Tests/Functional/EventListener/CampaignConditionTest.php @@ -5,17 +5,45 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Functional\EventListener; use Mautic\CoreBundle\Test\MauticMysqlTestCase; +use Mautic\CoreBundle\Test\Session\FixedMockFileSessionStorage; use MauticPlugin\CustomObjectsBundle\Entity\CustomField; use MauticPlugin\CustomObjectsBundle\Tests\Functional\DataFixtures\Traits\CustomObjectsTrait; use PHPUnit\Framework\Assert; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Session\Session; +use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; +use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy; class CampaignConditionTest extends MauticMysqlTestCase { use CustomObjectsTrait; + protected function setUp(): void + { + // Disable API just for specific test. + $this->configParams['api_enabled'] = 'testDisabledApi' !== $this->getName(); + + static::getContainer()->set( + 'session', + new Session( + new class() extends FixedMockFileSessionStorage { + } + ) + ); + + parent::setUp(); + } + public function testConditionForm(): void { + $session = self::$container->get('session'); + // @phpstan-ignore-next-line Fixing "cannot serialize anonymous function in \Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage::save() + $session->__construct(new MockArraySessionStorage()); + + $sessionAuthenticationStrategy = self::$container->get('security.authentication.session_strategy'); + // @phpstan-ignore-next-line Prevent clearing CSRF token storage in \Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy::onAuthentication() + $sessionAuthenticationStrategy->__construct(SessionAuthenticationStrategy::MIGRATE); + $customObject = $this->createCustomObjectWithAllFields(self::$container, 'Campaign test object'); $crawler = $this->client->request( Request::METHOD_GET, @@ -57,4 +85,35 @@ public function testConditionForm(): void Assert::assertSame('=', $body['event']['properties']['properties']['operator']); Assert::assertSame('unicorn', $body['event']['properties']['properties']['value']); } + + public function testVerifyDataOperatorAttrIsAvailableForFields(): void + { + $customObject = $this->createCustomObjectWithAllFields(self::$container, 'Campaign test object'); + $crawler = $this->client->request( + Request::METHOD_GET, + 's/campaigns/events/new', + [ + 'campaignId' => 'mautic_041b2a401f680fb0b644654af5ba0892f31f0697', + 'type' => "custom_item.{$customObject->getId()}.fieldvalue", + 'eventType' => 'condition', + 'anchor' => 'leadsource', + 'anchorEventType' => 'source', + ], + [], + $this->createAjaxHeaders() + ); + + Assert::assertTrue($this->client->getResponse()->isOk(), $this->client->getResponse()->getContent()); + + $html = json_decode($this->client->getResponse()->getContent(), true)['newContent']; + + $crawler->addHtmlContent($html); + + $options = $crawler->filter('#campaignevent_properties_field')->filter('option'); // ->attr('data-operators'); + + /** @var \DOMElement $option */ + foreach ($options as $option) { + Assert::assertNotEmpty($option->getAttribute('data-operators')); + } + } } diff --git a/Tests/Functional/EventListener/ContactSubscriberTest.php b/Tests/Functional/EventListener/ContactSubscriberTest.php new file mode 100644 index 000000000..b0e95711a --- /dev/null +++ b/Tests/Functional/EventListener/ContactSubscriberTest.php @@ -0,0 +1,81 @@ +customItemModel = self::$container->get('mautic.custom.model.item'); + $this->contactMerger = self::$container->get('mautic.lead.merger'); + $this->customItemXrefContactRepository = self::$container->get('custom_item.xref.contact.repository'); + } + + public function testMergingContactsWhenLoserHasItemAndWinnerHasNot(): void + { + $winner = $this->createContact('john@doe.email'); + $loser = $this->createContact('anna@muck.email'); + $customObject = $this->createCustomObjectWithAllFields(self::$container, 'Campaign test object'); + $customItem = new CustomItem($customObject); + + $customItem->setName('Campaign test item'); + $customItem = $this->customItemModel->save($customItem); + $this->customItemModel->linkEntity($customItem, 'contact', (int) $loser->getId()); + + $this->contactMerger->merge($winner, $loser); + + Assert::assertCount(0, $this->customItemXrefContactRepository->findBy(['contact' => $loser->getId()])); + Assert::assertCount(1, $this->customItemXrefContactRepository->findBy(['contact' => $winner->getId()])); + } + + public function testMergingContactsWhenLoserHasItemAndWinnerTheSameToo(): void + { + $winner = $this->createContact('john@doe.email'); + $loser = $this->createContact('anna@muck.email'); + $customObject = $this->createCustomObjectWithAllFields(self::$container, 'Campaign test object'); + $customItem = new CustomItem($customObject); + + $customItem->setName('Campaign test item'); + $customItem = $this->customItemModel->save($customItem); + $this->customItemModel->linkEntity($customItem, 'contact', (int) $loser->getId()); + $this->customItemModel->linkEntity($customItem, 'contact', (int) $winner->getId()); + + $this->contactMerger->merge($winner, $loser); + + Assert::assertCount(0, $this->customItemXrefContactRepository->findBy(['contact' => $loser->getId()])); + Assert::assertCount(1, $this->customItemXrefContactRepository->findBy(['contact' => $winner->getId()])); + } + + private function createContact(string $email): Lead + { + /** @var LeadModel $contactModel */ + $contactModel = self::$container->get('mautic.lead.model.lead'); + $contact = new Lead(); + $contact->setEmail($email); + $contactModel->saveEntity($contact); + + return $contact; + } +} diff --git a/Tests/Functional/EventListener/FilterOperatorSubscriberTest.php b/Tests/Functional/EventListener/FilterOperatorSubscriberTest.php index c1f663b32..eeeb646c8 100644 --- a/Tests/Functional/EventListener/FilterOperatorSubscriberTest.php +++ b/Tests/Functional/EventListener/FilterOperatorSubscriberTest.php @@ -4,31 +4,39 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Functional\EventListener; +use Mautic\CoreBundle\Helper\CommandHelper; use Mautic\CoreBundle\Test\MauticMysqlTestCase; use Mautic\LeadBundle\Entity\Lead; +use Mautic\LeadBundle\Entity\LeadField; use Mautic\LeadBundle\Entity\LeadList; use Mautic\LeadBundle\Entity\ListLead; +use MauticPlugin\CustomObjectsBundle\CustomFieldType\CustomFieldTypeInterface; +use MauticPlugin\CustomObjectsBundle\Entity\CustomField; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; +use MauticPlugin\CustomObjectsBundle\Provider\CustomFieldTypeProvider; +use MauticPlugin\CustomObjectsBundle\Tests\ProjectVersionTrait; use Symfony\Component\HttpFoundation\Request; class FilterOperatorSubscriberTest extends MauticMysqlTestCase { - public function testIfNewOperatorNotInCustomObjectsAddedinSegmentFilter() - { - // Create a segment - $segment = new LeadList(); - $segment->setName('Test Segment A'); - $segment->setPublicName('Test Segment A'); - $segment->setAlias('test-segment-a'); + use ProjectVersionTrait; - $this->em->persist($segment); - $this->em->flush(); + /** + * @var CommandHelper + */ + private $commandHelper; - $crawler = $this->client->request(Request::METHOD_GET, '/s/segments/edit/'.$segment->getId()); + protected function setUp(): void + { + parent::setUp(); + $this->commandHelper = static::getContainer()->get('mautic.helper.command'); + } + public function testIfNewOperatorNotInCustomObjectsAddedinSegmentFilter() + { + $crawler = $this->client->request(Request::METHOD_GET, '/s/segments/new/'); $segment_filters = $crawler->filter('#available_segment_filters')->html(); - $this->assertStringContainsString('not in custom objects', $segment_filters); } @@ -62,17 +70,17 @@ public function testIfProperContactsAreAddedinSegmentWithNotInCustomObjectsFilte // 3) create a segment with filter : email > not in custom objects > select custom object $filters = [[ - 'object' => 'lead', - 'glue' => 'and', - 'field' => 'email', - 'type' => 'text', - 'operator' => 'notInCustomObjects', - 'properties' => [ - 'filter' => 'custom-object:'.$customObject->getId().':name', - ], - 'filter' => 'custom-object:'.$customObject->getId().':name', - 'display' => null, - ]]; + 'object' => 'lead', + 'glue' => 'and', + 'field' => 'email', + 'type' => 'text', + 'operator' => 'notInCustomObjects', + 'properties' => [ + 'filter' => 'custom-object:'.$customObject->getId().':name', + ], + 'filter' => 'custom-object:'.$customObject->getId().':name', + 'display' => null, + ]]; $segment = new LeadList(); $segment->setName('Test Segment A'); $segment->setPublicName('Test Segment A'); @@ -82,7 +90,7 @@ public function testIfProperContactsAreAddedinSegmentWithNotInCustomObjectsFilte $this->em->flush(); // 4) run update segment command - $this->runCommand('mautic:segments:update', ['-i' => $segment->getId()]); + $this->commandHelper->runCommand('mautic:segments:update', ['-i' => $segment->getId()]); // 5) fetch segment added contacts $leads = $this->em->getRepository(ListLead::class)->findBy(['list' => $segment->getId()], ['lead' => 'DESC']); @@ -94,4 +102,69 @@ public function testIfProperContactsAreAddedinSegmentWithNotInCustomObjectsFilte $this->assertSame($contact2->getLastname(), $leads[0]->getLead()->getLastname()); $this->assertSame($contact2->getEmail(), $leads[0]->getLead()->getEmail()); } + + public function testCustomObjectSegmentFilterOperatorForDateField(): void + { + if (!$this->isCloudProject()) { + $this->markTestSkipped('As context is not available for segment only in 4.4'); + } + + $leadField = $this->createField('date_field', 'date'); + + $fieldTypeProvider = self::$container->get('custom_field.type.provider'); + \assert($fieldTypeProvider instanceof CustomFieldTypeProvider); + $objectType = $fieldTypeProvider->getType('date'); + $dateField = $this->createCustomField('co_date_field', $objectType); + + $this->createCustomObject('obj', $dateField); + + $this->em->flush(); + $crawler = $this->client->request(Request::METHOD_GET, '/s/segments/new/'); + + $coDateFilterOperators = $crawler + ->filter('#available_segment_filters option[id="available_custom_object_cmf_'.$dateField->getId().'"]') + ->attr('data-field-operators'); + + $leadDateFilterOperators = $crawler + ->filter('#available_segment_filters option[id="available_lead_'.$leadField->getAlias().'"]') + ->attr('data-field-operators'); + + $this->assertSame($coDateFilterOperators, $leadDateFilterOperators); + } + + private function createField(string $alias, string $type): LeadField + { + $field = new LeadField(); + $field->setName($alias); + $field->setAlias($alias); + $field->setType($type); + $this->em->persist($field); + + return $field; + } + + private function createCustomObject(string $alias, ?CustomField $dateField = null): CustomObject + { + $customObject = new CustomObject(); + $customObject->setNameSingular($alias); + $customObject->setNamePlural($alias.'s'); + $customObject->setAlias($alias); + if ($dateField) { + $customObject->addCustomField($dateField); + } + $this->em->persist($customObject); + + return $customObject; + } + + private function createCustomField(string $alias, CustomFieldTypeInterface $objectType): CustomField + { + $dateField = new CustomField(); + $dateField->setTypeObject($objectType); + $dateField->setType($objectType->getKey()); + $dateField->setLabel($alias); + $dateField->setAlias($alias); + + return $dateField; + } } diff --git a/Tests/Functional/EventListener/ImportSubscriberTest.php b/Tests/Functional/EventListener/ImportSubscriberTest.php index 4d3d50278..22bafbb59 100644 --- a/Tests/Functional/EventListener/ImportSubscriberTest.php +++ b/Tests/Functional/EventListener/ImportSubscriberTest.php @@ -4,7 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Functional\EventListener; -use DateTimeImmutable; use Mautic\CoreBundle\Test\MauticMysqlTestCase; use Mautic\LeadBundle\Entity\Import; use Mautic\LeadBundle\Entity\Lead; @@ -24,7 +23,7 @@ use MauticPlugin\CustomObjectsBundle\Repository\CustomFieldRepository; use MauticPlugin\CustomObjectsBundle\Repository\CustomItemRepository; use MauticPlugin\CustomObjectsBundle\Tests\Functional\DataFixtures\Traits\CustomObjectsTrait; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class ImportSubscriberTest extends MauticMysqlTestCase { @@ -62,8 +61,8 @@ public function testImportForAllFieldTypesWithValidValuesAndLinksPlusUpdateToo() ]; $expectedValues = $csvRow; - $expectedValues['datetime'] = new DateTimeImmutable('2019-03-04 12:35:09'); - $expectedValues['date'] = new DateTimeImmutable('2019-03-04 00:00:00'); + $expectedValues['datetime'] = new \DateTimeImmutable('2019-03-04 12:35:09'); + $expectedValues['date'] = new \DateTimeImmutable('2019-03-04 00:00:00'); $expectedValues['multiselect'] = ['option_b', 'option_a']; // Import the custom item @@ -100,8 +99,8 @@ public function testImportForAllFieldTypesWithValidValuesAndLinksPlusUpdateToo() $updateStatus = $this->importCsvRow($customObject, $editCsvRow); $expectedUpdatedValues = $editCsvRow; - $expectedUpdatedValues['datetime'] = new DateTimeImmutable('2019-03-04 12:35:09'); - $expectedUpdatedValues['date'] = new DateTimeImmutable('2019-05-24 00:00:00'); + $expectedUpdatedValues['datetime'] = new \DateTimeImmutable('2019-03-04 12:35:09'); + $expectedUpdatedValues['date'] = new \DateTimeImmutable('2019-05-24 00:00:00'); $expectedUpdatedValues['multiselect'] = ['option_b', 'option_a']; $this->assertTrue($updateStatus); @@ -167,8 +166,8 @@ public function testImportWithDefaultValues(): void ]; $expectedValues = $csvRow; - $expectedValues['datetime'] = new DateTimeImmutable('2019-03-04 12:35:09'); - $expectedValues['date'] = new DateTimeImmutable('2019-06-21 00:00:00'); + $expectedValues['datetime'] = new \DateTimeImmutable('2019-03-04 12:35:09'); + $expectedValues['date'] = new \DateTimeImmutable('2019-06-21 00:00:00'); $expectedValues['multiselect'] = ['option_b']; $expectedValues['text'] = 'A default value'; diff --git a/Tests/Functional/EventListener/TokenSubscriberTest.php b/Tests/Functional/EventListener/TokenSubscriberTest.php index 82b0de65f..e70afafaf 100644 --- a/Tests/Functional/EventListener/TokenSubscriberTest.php +++ b/Tests/Functional/EventListener/TokenSubscriberTest.php @@ -17,6 +17,7 @@ use MauticPlugin\CustomObjectsBundle\Model\CustomItemModel; use MauticPlugin\CustomObjectsBundle\Tests\Functional\DataFixtures\Traits\CustomObjectsTrait; +#[\AllowDynamicProperties] class TokenSubscriberTest extends MauticMysqlTestCase { use CustomObjectsTrait; diff --git a/Tests/Functional/Helper/QueryFilterHelperTest.php b/Tests/Functional/Helper/QueryFilterHelperTest.php index ee61f389c..c890f4183 100644 --- a/Tests/Functional/Helper/QueryFilterHelperTest.php +++ b/Tests/Functional/Helper/QueryFilterHelperTest.php @@ -7,6 +7,7 @@ use Mautic\CoreBundle\Test\MauticMysqlTestCase; use Mautic\LeadBundle\Segment\ContactSegmentFilterFactory; use Mautic\LeadBundle\Segment\Query\QueryBuilder; +use Mautic\LeadBundle\Segment\RandomParameterName; use MauticPlugin\CustomObjectsBundle\Helper\QueryFilterFactory; use MauticPlugin\CustomObjectsBundle\Helper\QueryFilterHelper; use MauticPlugin\CustomObjectsBundle\Provider\CustomFieldTypeProvider; @@ -46,7 +47,8 @@ protected function setUp(): void $customFieldRepository, new QueryFilterFactory\Calculator(), 1 - ) + ), + new RandomParameterName() ); $fixturesDirectory = $this->getFixturesDirectory(); @@ -65,7 +67,7 @@ protected function setUp(): void public function testGetCustomValueValueExpression(): void { $this->assertMatchWhere( - 'test_value.value = :test_value_value', + 'test_value.value = :par0', [ 'glue' => 'and', 'field' => 'cmf_'.$this->getFixtureById('custom_field1')->getId(), @@ -76,18 +78,22 @@ public function testGetCustomValueValueExpression(): void ); $this->assertMatchWhere( - 'test_value.value LIKE :test_value_value', + 'test_value.value LIKE :par1', [ - 'glue' => 'and', - 'field' => 'cmf_'.$this->getFixtureById('custom_field1')->getId(), - 'type' => 'custom_object', - 'operator' => 'like', - 'value' => 'love', + 'glue' => 'and', + 'field' => 'cmf_'.$this->getFixtureById('custom_field1')->getId(), + 'type' => 'custom_object', + 'operator' => 'like', + 'value' => 'love', + 'filter' => '500', + 'properties' => [ + 'filter' => '500', + ], ] ); $this->assertMatchWhere( - '(test_value.value <> :test_value_value) OR (test_value.value IS NULL)', + '(test_value.value <> :par2) OR (test_value.value IS NULL)', [ 'glue' => 'and', 'field' => 'cmf_'.$this->getFixtureById('custom_field1')->getId(), @@ -98,21 +104,190 @@ public function testGetCustomValueValueExpression(): void ); $this->assertMatchWhere( - 'test_value.value > :test_value_value', + 'test_value.value > :par3', [ 'glue' => 'and', 'field' => 'cmf_'.$this->getFixtureById('custom_object_product')->getId(), 'object' => 'custom_object', 'type' => 'int', 'operator' => 'gt', + 'filter' => '500', 'properties' => [ 'filter' => '500', ], ] ); + + $this->assertMatchWhere( + "test_value.value BETWEEN '2024-05-15 00:00:00' AND '2024-05-24 23:59:59'", + [ + 'glue' => 'and', + 'field' => 'cmf_'.$this->getFixtureById('custom_object_product')->getId(), + 'object' => 'custom_object', + 'type' => 'datetime', + 'operator' => 'between', + 'properties' => [ + 'filter' => [ + 'date_from' => 'May 15, 2024', + 'date_to' => 'May 24, 2024', + ], + ], + ] + ); + + $this->assertMatchWhere( + 'test_value.value LIKE :par5', + [ + 'glue' => 'and', + 'field' => 'cmf_'.$this->getFixtureById('custom_field1')->getId(), + 'object' => 'custom_object', + 'type' => 'datetime', + 'operator' => 'like', + 'properties' => [ + 'filter' => '2024', + ], + ] + ); + + $this->assertMatchWhere( + 'test_value.value REGEXP :par6', + [ + 'glue' => 'and', + 'field' => 'cmf_'.$this->getFixtureById('custom_field1')->getId(), + 'object' => 'custom_object', + 'type' => 'datetime', + 'operator' => 'regexp', + 'properties' => [ + 'filter' => '2024', + ], + ] + ); + + $this->assertMatchWhere( + 'test_value.value LIKE :par7', + [ + 'glue' => 'and', + 'field' => 'cmf_'.$this->getFixtureById('custom_field1')->getId(), + 'object' => 'custom_object', + 'type' => 'datetime', + 'operator' => 'startsWith', + 'properties' => [ + 'filter' => '2024', + ], + ] + ); + + $this->assertMatchWhere( + 'test_value.value LIKE :par8', + [ + 'glue' => 'and', + 'field' => 'cmf_'.$this->getFixtureById('custom_field1')->getId(), + 'object' => 'custom_object', + 'type' => 'datetime', + 'operator' => 'endsWith', + 'properties' => [ + 'filter' => '2024', + ], + ] + ); + + $this->assertMatchWhere( + 'test_value.value LIKE :par9', + [ + 'glue' => 'and', + 'field' => 'cmf_'.$this->getFixtureById('custom_field1')->getId(), + 'object' => 'custom_object', + 'type' => 'datetime', + 'operator' => 'contains', + 'properties' => [ + 'filter' => '2024', + ], + ] + ); + + $this->assertMatchWhere( + 'test_value.value IS NULL', + [ + 'glue' => 'and', + 'field' => 'cmf_'.$this->getFixtureById('custom_object_product')->getId(), + 'object' => 'custom_object', + 'type' => 'datetime', + 'operator' => 'empty', + 'properties' => [ + 'filter' => [], + ], + ] + ); + + $this->assertMatchWhere( + 'test_value.value IS NOT NULL', + [ + 'glue' => 'and', + 'field' => 'cmf_'.$this->getFixtureById('custom_object_product')->getId(), + 'object' => 'custom_object', + 'type' => 'datetime', + 'operator' => '!empty', + 'properties' => [ + 'filter' => [], + ], + ] + ); + + $this->assertMatchWhere( + 'test_value.value BETWEEN 0 AND 10', + [ + 'glue' => 'and', + 'field' => 'cmf_'.$this->getFixtureById('custom_object_product')->getId(), + 'object' => 'custom_object', + 'type' => 'int', + 'operator' => 'between', + 'properties' => [ + 'filter' => [ + 'number_from' => 0, + 'number_to' => 10, + ], + ], + ] + ); + + $this->assertMatchWhere( + 'test_value.value >= :pard', + [ + 'glue' => 'and', + 'field' => 'cmf_'.$this->getFixtureById('custom_object_product')->getId(), + 'object' => 'custom_object', + 'type' => 'date', + 'operator' => 'gte', + 'properties' => [ + 'filter' => [ + 'dateTypeMode' => 'absolute', + 'absoluteDate' => 'yesterday', + ], + ], + ], + (new \DateTime('yesterday'))->format('Y-m-d') + ); + + $this->assertMatchWhere( + 'test_value.value <= :pare', + [ + 'glue' => 'and', + 'field' => 'cmf_'.$this->getFixtureById('custom_object_product')->getId(), + 'object' => 'custom_object', + 'type' => 'datetime', + 'operator' => 'lte', + 'properties' => [ + 'filter' => [ + 'dateTypeMode' => 'absolute', + 'absoluteDate' => 'tomorrow', + ], + ], + ], + (new \DateTime('tomorrow'))->format('Y-m-d 23:59:59') + ); } - protected function assertMatchWhere(string $expectedWhere, array $filter): void + protected function assertMatchWhere(string $expectedWhere, array $filter, ?string $expectedValue = null): void { $unionQueryContainer = new UnionQueryContainer(); $qb = new QueryBuilder($this->em->getConnection()); @@ -125,7 +300,12 @@ protected function assertMatchWhere(string $expectedWhere, array $filter): void ); $unionQueryContainer->rewind(); + $whereResponse = (string) $unionQueryContainer->current()->getQueryPart('where'); + $this->assertSame($expectedWhere, $whereResponse); + if ($expectedValue) { + $this->assertSame($expectedValue, current($unionQueryContainer->current()->getParameters())); + } } } diff --git a/Tests/Functional/Segment/Query/Filter/CustomFieldFilterQueryBuilderTest.php b/Tests/Functional/Segment/Query/Filter/CustomFieldFilterQueryBuilderTest.php index 3c501e52d..f94a020d5 100644 --- a/Tests/Functional/Segment/Query/Filter/CustomFieldFilterQueryBuilderTest.php +++ b/Tests/Functional/Segment/Query/Filter/CustomFieldFilterQueryBuilderTest.php @@ -6,6 +6,7 @@ use Mautic\CoreBundle\Test\MauticMysqlTestCase; use Mautic\LeadBundle\Segment\ContactSegmentFilter; +use Mautic\LeadBundle\Segment\ContactSegmentFilterCrate; use Mautic\LeadBundle\Segment\Query\QueryBuilder; use Mautic\LeadBundle\Segment\RandomParameterName; use MauticPlugin\CustomObjectsBundle\Helper\QueryFilterFactory; @@ -24,6 +25,12 @@ class CustomFieldFilterQueryBuilderTest extends MauticMysqlTestCase use FixtureObjectsTrait; use DbalQueryTrait; + protected function setUp(): void + { + $this->configParams['custom_object_merge_filter'] = false; + parent::setUp(); + } + public function testApplyQuery(): void { $fixturesDirectory = $this->getFixturesDirectory(); @@ -54,7 +61,8 @@ public function testApplyQuery(): void $customFieldRepository, new QueryFilterFactory\Calculator(), 1 - ) + ), + new RandomParameterName() ); $queryBuilderService = new CustomFieldFilterQueryBuilder( new RandomParameterName(), @@ -91,12 +99,13 @@ private function createSegmentFilterMock( $filterMock = $this->getMockBuilder(ContactSegmentFilter::class) ->disableOriginalConstructor() ->getMock(); - + $filterMock->contactSegmentFilterCrate = $this->createMock(ContactSegmentFilterCrate::class); $filterMock->method('getType')->willReturn($type); $filterMock->method('getOperator')->willReturn($operator); $filterMock->method('getField')->willReturn((string) $this->getFixtureById($fixtureField)->getId()); $filterMock->method('getParameterValue')->willReturn($value); $filterMock->method('getParameterHolder')->willReturn((string) ':needle'); + $filterMock->method('getGlue')->willReturn($operator); return $filterMock; } diff --git a/Tests/Functional/Segment/Query/Filter/CustomItemNameFilterQueryBuilderTest.php b/Tests/Functional/Segment/Query/Filter/CustomItemNameFilterQueryBuilderTest.php index 2de0bf6a6..666f9409b 100644 --- a/Tests/Functional/Segment/Query/Filter/CustomItemNameFilterQueryBuilderTest.php +++ b/Tests/Functional/Segment/Query/Filter/CustomItemNameFilterQueryBuilderTest.php @@ -59,7 +59,8 @@ public function testApplyQuery(): void $customFieldRepository, new QueryFilterFactory\Calculator(), 1 - ) + ), + new RandomParameterName() ); $queryBuilderService = new CustomItemNameFilterQueryBuilder( new RandomParameterName(), @@ -94,6 +95,7 @@ private function createSegmentFilterMock($value, $type = 'text', $operator = 'eq $filterMock->method('getField')->willReturn((string) $this->getFixtureById($fixtureField)->getId()); $filterMock->method('getParameterValue')->willReturn($value); $filterMock->method('getParameterHolder')->willReturn((string) ':needle'); + $filterMock->method('getGlue')->willReturn($operator); return $filterMock; } diff --git a/Tests/Functional/Segment/Query/Filter/CustomItemRelationQueryBuilderTestCase.php b/Tests/Functional/Segment/Query/Filter/CustomItemRelationQueryBuilderTest.php similarity index 91% rename from Tests/Functional/Segment/Query/Filter/CustomItemRelationQueryBuilderTestCase.php rename to Tests/Functional/Segment/Query/Filter/CustomItemRelationQueryBuilderTest.php index 2f9bdd452..50c4b66bc 100644 --- a/Tests/Functional/Segment/Query/Filter/CustomItemRelationQueryBuilderTestCase.php +++ b/Tests/Functional/Segment/Query/Filter/CustomItemRelationQueryBuilderTest.php @@ -4,7 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Functional\Segment\Query\Filter; -use InvalidArgumentException; use Mautic\CoreBundle\Helper\CoreParametersHelper; use Mautic\CoreBundle\Test\MauticMysqlTestCase; use Mautic\LeadBundle\Entity\LeadList; @@ -13,24 +12,13 @@ use MauticPlugin\CustomObjectsBundle\Provider\ConfigProvider; use MauticPlugin\CustomObjectsBundle\Tests\Functional\DataFixtures\Traits\FixtureObjectsTrait; -class CustomItemRelationQueryBuilderTestCase extends MauticMysqlTestCase +class CustomItemRelationQueryBuilderTest extends MauticMysqlTestCase { use FixtureObjectsTrait; - /** - * @var CoreParametersHelper - */ - private $coreParametersHelper; - - /** - * @var LeadListRepository - */ - private $segmentRepository; - - /** - * @var LeadRepository - */ - private $contactRepository; + private CoreParametersHelper $coreParametersHelper; + private LeadListRepository $segmentRepository; + private LeadRepository $contactRepository; protected function setUp(): void { @@ -173,11 +161,12 @@ private function assertLeadCountBySegmentAlias(int $expectedLeadCount, string $s $segment = $this->segmentRepository->findOneBy(['alias' => $segmentAlias]); if (!$segment) { - throw new InvalidArgumentException("No segment with alias '{$segmentAlias}' found"); + throw new \InvalidArgumentException("No segment with alias '{$segmentAlias}' found"); } - $count = $this->segmentRepository->getLeadCount([$segment->getId()]); - $count = (int) $count[$segment->getId()]; + $count = $this->segmentRepository->getLeadCount($segment->getId()); + $this->assertIsNumeric($count); + $count = (int) $count; $this->assertSame( $expectedLeadCount, @@ -188,7 +177,7 @@ private function assertLeadCountBySegmentAlias(int $expectedLeadCount, string $s private function assertContactIsInSegment(string $contactEmail, string $segmentAlias): void { - $contact = $this->contactRepository->findOneByEmail($contactEmail); + $contact = $this->contactRepository->findOneBy(['email' => $contactEmail]); /** @var LeadList[] $segments */ $segments = $this->segmentRepository->getLeadLists($contact->getId()); diff --git a/Tests/Functional/Segment/Query/Filter/CustomObjectMergedFilterQueryBuilderTest.php b/Tests/Functional/Segment/Query/Filter/CustomObjectMergedFilterQueryBuilderTest.php new file mode 100644 index 000000000..ab051ccb7 --- /dev/null +++ b/Tests/Functional/Segment/Query/Filter/CustomObjectMergedFilterQueryBuilderTest.php @@ -0,0 +1,122 @@ +configParams['custom_object_merge_filter'] = true; + $this->configParams[ConfigProvider::CONFIG_PARAM_ITEM_VALUE_TO_CONTACT_RELATION_LIMIT] = 0; + parent::setUp(); + } + + public function testMergedSegmentFilters(): void + { + $fixturesDirectory = $this->getFixturesDirectory(); + $objects = $this->loadFixtureFiles([ + $fixturesDirectory.'/leads.yml', + $fixturesDirectory.'/custom_objects.yml', + $fixturesDirectory.'/custom_fields.yml', + $fixturesDirectory.'/custom_items.yml', + $fixturesDirectory.'/custom_xref.yml', + $fixturesDirectory.'/custom_values.yml', + ]); + $this->setFixtureObjects($objects); + + $customField = $this->getFixtureById('custom_field1')->getId(); + + $filters = [ + [ + 'glue' => 'and', + 'object' => 'custom_object', + 'type' => 'text', + 'field' => 'cmf_'.$customField, + 'properties' => ['filter' => 'l'], + 'operator' => 'startsWith', + ], + [ + 'glue' => 'and', + 'object' => 'custom_object', + 'type' => 'text', + 'field' => 'cmf_'.$customField, + 'properties' => ['filter' => 'e'], + 'operator' => 'endsWith', + ], + [ + 'object' => 'custom_object', + 'glue' => 'and', + 'field' => 'cmf_'.$customField, + 'type' => 'text', + 'operator' => '!=', + 'properties' => ['filter' => 'some random text'], + 'filter' => 'some random text', + 'display' => null, + ], + ]; + $segment = $this->createSegment($filters); + + $applicationTester = $this->testSymfonyCommand('mautic:segments:update', ['-i' => $segment->getId(), '--env' => 'test']); + Assert::assertSame(0, $applicationTester->getStatusCode()); + Assert::assertStringContainsString('3 total contact(s) to be added in batches of 300', $applicationTester->getDisplay()); + } + + public function testMergedSegmentSingleFilter(): void + { + $fixturesDirectory = $this->getFixturesDirectory(); + $objects = $this->loadFixtureFiles([ + $fixturesDirectory.'/leads.yml', + $fixturesDirectory.'/custom_objects.yml', + $fixturesDirectory.'/custom_fields.yml', + $fixturesDirectory.'/custom_items.yml', + $fixturesDirectory.'/custom_xref.yml', + $fixturesDirectory.'/custom_values.yml', + ]); + $this->setFixtureObjects($objects); + + $customField = $this->getFixtureById('custom_field1')->getId(); + + $filters = [ + [ + 'object' => 'custom_object', + 'glue' => 'and', + 'field' => 'cmf_'.$customField, + 'type' => 'text', + 'operator' => '=', + 'properties' => ['filter' => 'love'], + 'filter' => 'some random text', + 'display' => null, + ], + ]; + $segment = $this->createSegment($filters); + + $applicationTester = $this->testSymfonyCommand('mautic:segments:update', ['-i' => $segment->getId(), '--env' => 'test']); + Assert::assertSame(0, $applicationTester->getStatusCode()); + Assert::assertStringContainsString('3 total contact(s) to be added in batches of 300', $applicationTester->getDisplay()); + } + + /** + * @param mixed[] $filters + */ + private function createSegment(array $filters): LeadList + { + $segment = new LeadList(); + $segment->setFilters($filters); + $segment->setName('Segment A'); + $segment->setAlias('segment-a'); + $this->em->persist($segment); + $this->em->flush(); + + return $segment; + } +} diff --git a/Tests/Functional/Segment/Query/Filter/NegativeOperatorFilterQueryBuilderTest.php b/Tests/Functional/Segment/Query/Filter/NegativeOperatorFilterQueryBuilderTest.php new file mode 100644 index 000000000..06ab327ec --- /dev/null +++ b/Tests/Functional/Segment/Query/Filter/NegativeOperatorFilterQueryBuilderTest.php @@ -0,0 +1,205 @@ +getDataSetAsString(false); + + if ($mergeFilterEnabled && !method_exists(ContactSegmentFilterCrate::class, 'getMergedProperty')) { + $this->markTestSkipped(); + } + + $this->configParams['custom_object_merge_filter'] = $mergeFilterEnabled; + $this->configParams['custom_object_item_value_to_contact_relation_limit'] = $mergeFilterEnabled ? 0 : 3; + + parent::setUp(); + + $this->customItemModel = self::$container->get('mautic.custom.model.item'); + $this->createCustomObjectWithCustomField(); + $this->em->flush(); + } + + /** + * @return iterable + */ + public function dataUseMergeFilter(): iterable + { + yield 'Merge filter enabled' => [true]; + yield 'Merge filter disabled' => [false]; + } + + /** + * @dataProvider dataUseMergeFilter + */ + public function testNotEqualsOperator(bool $mergeFilterEnabled): void + { + $this->createContactAndAttachCustomItem('abc', 'ABC'); + $this->createContactAndAttachCustomItem('xyz', 'XYZ'); + $this->createContactAndAttachCustomItem('empty', ''); + $this->createContact('unlinked'); + + $segment = $this->createAndBuildSegment($this->createFilter('!=', 'abc')); + + $members = $this->em->getRepository(ListLead::class)->findBy(['list' => $segment]); + Assert::assertCount($mergeFilterEnabled ? 2 : 3, $members); + + $firstnames = $this->extractFirstnamesFromSegmentMembers($members); + Assert::assertNotContains('abc', $firstnames); + Assert::assertContains('xyz', $firstnames); + Assert::assertContains('empty', $firstnames); + + if ($mergeFilterEnabled) { + Assert::assertNotContains('unlinked', $firstnames); + } else { + Assert::assertContains('unlinked', $firstnames); + } + } + + /** + * @dataProvider dataUseMergeFilter + */ + public function testEmptyOperator(bool $mergeFilterEnabled): void + { + $this->createContactAndAttachCustomItem('not empty', 'Not empty'); + $this->createContactAndAttachCustomItem('empty', ''); + $this->createContact('unlinked 1'); + $this->createContact('unlinked 2'); + + $segment = $this->createAndBuildSegment($this->createFilter('empty', null)); + + $members = $this->em->getRepository(ListLead::class)->findBy(['list' => $segment]); + Assert::assertCount($mergeFilterEnabled ? 1 : 3, $members); + + $firstnames = $this->extractFirstnamesFromSegmentMembers($members); + Assert::assertNotContains('not empty', $firstnames); + Assert::assertContains('empty', $firstnames); + + if ($mergeFilterEnabled) { + Assert::assertNotContains('unlinked 1', $firstnames); + Assert::assertNotContains('unlinked 2', $firstnames); + } else { + Assert::assertContains('unlinked 1', $firstnames); + Assert::assertContains('unlinked 2', $firstnames); + } + } + + private function createCustomItem(CustomObject $customObject, string $value, string $name): CustomItem + { + $customItem = new CustomItem($customObject); + $customFieldValue = new CustomFieldValueText($this->customField, $customItem, $value); + $customItem->addCustomFieldValue($customFieldValue); + $customItem->setName($name); + $this->em->persist($customItem); + $this->em->persist($customFieldValue); + + return $customItem; + } + + private function createCustomObjectWithCustomField(): void + { + $this->customField = new CustomField(); + $this->customField->setLabel('Field'); + $this->customField->setAlias('field'); + $this->customField->setType('text'); + $this->em->persist($this->customField); + + $this->customObject = new CustomObject(); + $this->customObject->setAlias('Object'); + $this->customObject->setNameSingular('Object'); + $this->customObject->setNamePlural('Objects'); + $this->customObject->addCustomField($this->customField); + $this->customField->setCustomObject($this->customObject); + $this->em->persist($this->customObject); + } + + /** + * @param array $filters + */ + private function createAndBuildSegment(array $filters): LeadList + { + $segment = new LeadList(); + $segment->setName('Segment A'); + $segment->setPublicName('Segment A'); + $segment->setAlias('segment-a'); + $segment->setFilters($filters); + $this->em->persist($segment); + $this->em->flush($segment); + $this->em->clear(); + + $commandTester = $this->testSymfonyCommand(UpdateLeadListsCommand::NAME, ['-i' => $segment->getId()]); + Assert::assertSame(0, $commandTester->getStatusCode(), 'Update lead lists command was not successful'); + + return $segment; + } + + private function createContact(string $firstname): Lead + { + $contact = new Lead(); + $contact->setFirstname($firstname); + $this->em->persist($contact); + + return $contact; + } + + private function createContactAndAttachCustomItem(string $contactFirstname, string $customItemText): void + { + $contact = $this->createContact($contactFirstname); + $this->em->flush(); + + $customItem = $this->createCustomItem($this->customObject, $customItemText, $customItemText); + $this->customItemModel->linkEntity($customItem, 'contact', (int) $contact->getId()); + } + + /** + * @return array + */ + private function createFilter(string $operator, ?string $value): array + { + $filters = [ + [ + 'glue' => 'and', + 'field' => 'cmf_'.$this->customField->getId(), + 'object' => 'custom_object', + 'type' => 'text', + 'operator' => $operator, + 'properties' => [ + 'filter' => $value, + ], + ], + ]; + + return $filters; + } + + /** + * @param array $members + * + * @return array + */ + private function extractFirstnamesFromSegmentMembers(array $members): array + { + return array_map(fn (ListLead $segment) => $segment->getLead()->getFirstname(), $members); + } +} diff --git a/Tests/Functional/Token/EmailTokenTest.php b/Tests/Functional/Token/EmailTokenTest.php index cc6437161..84b7e5297 100644 --- a/Tests/Functional/Token/EmailTokenTest.php +++ b/Tests/Functional/Token/EmailTokenTest.php @@ -16,6 +16,7 @@ use Symfony\Component\DomCrawler\Crawler; use Symfony\Component\HttpFoundation\Request; +#[\AllowDynamicProperties] class EmailTokenTest extends MauticMysqlTestCase { use CustomObjectsTrait; diff --git a/Tests/Functional/Token/EmailWithCustomObjectDynamicContentFunctionalTest.php b/Tests/Functional/Token/EmailWithCustomObjectDynamicContentFunctionalTest.php new file mode 100644 index 000000000..606948748 --- /dev/null +++ b/Tests/Functional/Token/EmailWithCustomObjectDynamicContentFunctionalTest.php @@ -0,0 +1,339 @@ + + */ + private $customItems; + + /** + * @var array + */ + private $customFieldValues; + + protected function setUp(): void + { + parent::setUp(); + + $this->customItemModel = self::$container->get('mautic.custom.model.item'); + $this->customFieldValueModel = self::$container->get('mautic.custom.model.field.value'); + + $this->customObject = $this->createCustomObjectWithAllFields(self::$container, 'Car'); + $this->customItems['nexon'] = new CustomItem($this->customObject); + + $this->customItems['nexon']->setName('Nexon'); + $this->customFieldValueModel->createValuesForItem($this->customItems['nexon']); + + $this->customFieldValues['nexon-text'] = $this->customItems['nexon']->findCustomFieldValueForFieldAlias('text-test-field'); + $this->customFieldValues['nexon-text']->setValue('Tata'); + + $this->customFieldValues['nexon-datetime'] = $this->customItems['nexon']->findCustomFieldValueForFieldAlias('datetime-test-field'); + $this->customFieldValues['nexon-datetime']->setValue('2024-07-01 13:29:43'); + + $this->customFieldValues['nexon-multiselect'] = $this->customItems['nexon']->findCustomFieldValueForFieldAlias('multiselect-test-field'); + $this->customFieldValues['nexon-multiselect']->setValue('option_a'); + + $this->customFieldValues['nexon-select'] = $this->customItems['nexon']->findCustomFieldValueForFieldAlias('select-test-field'); + + $this->customFieldValues['nexon-url'] = $this->customItems['nexon']->findCustomFieldValueForFieldAlias('url-test-field'); + $this->customFieldValues['nexon-url']->setValue('https://test.mautic.fr'); + + $this->customFieldValues['nexon-number'] = $this->customItems['nexon']->findCustomFieldValueForFieldAlias('number-test-field'); + $this->customFieldValues['nexon-number']->setValue(10); + + $this->customItems['nexon'] = $this->customItemModel->save($this->customItems['nexon']); + + $this->customItems['fortuner'] = new CustomItem($this->customObject); + + $this->customItems['fortuner']->setName('Fortuner'); + $this->customFieldValueModel->createValuesForItem($this->customItems['fortuner']); + + $this->customFieldValues['fortuner-text'] = $this->customItems['fortuner']->findCustomFieldValueForFieldAlias('text-test-field'); + $this->customFieldValues['fortuner-text']->setValue('Toyota'); + + $this->customItems['fortuner'] = $this->customItemModel->save($this->customItems['fortuner']); + + $this->customItems['city'] = new CustomItem($this->customObject); + + $this->customItems['city']->setName('City'); + $this->customFieldValueModel->createValuesForItem($this->customItems['city']); + + $this->customFieldValues['city-text'] = $this->customItems['city']->findCustomFieldValueForFieldAlias('text-test-field'); + $this->customFieldValues['city-text']->setValue('Honda'); + + $this->customItems['city'] = $this->customItemModel->save($this->customItems['city']); + } + + public function testDynamicContentEmail(): void + { + foreach ([ + [ + 'nexonlikeurl@acquia.com', + $this->buildDynamicContentArray([ + ['nexon-url', 'tic.f', 'like'], + ]), + 'Custom Object Dynamic Content', + ], + [ + 'nexonselect@acquia.com', + $this->buildDynamicContentArray([ + ['nexon-select', null, 'empty', 'select'], + ]), + 'Custom Object Dynamic Content', + ], + [ + 'nexonmultiselect@acquia.com', + $this->buildDynamicContentArray([ + ['nexon-datetime', null, '!empty', 'datetime'], + ['nexon-number', 12, 'lt', 'number'], + ]), + 'Custom Object Dynamic Content', + ], + [ + 'nexonmultiselect@acquia.com', + $this->buildDynamicContentArray([ + ['nexon-text', 'Tata', '='], + ['nexon-datetime', '2024-07-01 00:00', 'gte', 'datetime'], + ['nexon-multiselect', 'option_a', 'in', 'multiselect'], + ]), + 'Custom Object Dynamic Content', + ], + [ + 'nexondatetime@acquia.com', + $this->buildDynamicContentArray([ + ['nexon-text', 'Tata', '='], + ['nexon-datetime', '2024-07-01', 'gte'], + ]), + 'Custom Object Dynamic Content', + ], + [ + 'nexonequal@acquia.com', + $this->buildDynamicContentArray([ + ['nexon-text', 'Tata', '='], + ]), + 'Custom Object Dynamic Content', + ], + [ + 'nexonnotequal@acquia.com', + $this->buildDynamicContentArray([['nexon-text', 'Toyota', '!=']]), + 'Custom Object Dynamic Content', + ], + [ + 'nexonempty@acquia.com', + $this->buildDynamicContentArray([['nexon-text', '', 'empty']]), + 'Custom Object Dynamic Content', + ], + [ + 'nexonnotempty@acquia.com', + $this->buildDynamicContentArray([['nexon-text', '', '!empty']]), + 'Custom Object Dynamic Content', + ], + [ + 'nexonlike@acquia.com', + $this->buildDynamicContentArray([['nexon-text', 'at', 'like']]), + 'Custom Object Dynamic Content', + ], + [ + 'nexonnotlike@acquia.com', + $this->buildDynamicContentArray([['nexon-text', 'Toyota', '!like']]), + 'Custom Object Dynamic Content', + ], + [ + 'nexonstartsWith@acquia.com', + $this->buildDynamicContentArray([['nexon-text', 'Ta', 'startsWith']]), + 'Custom Object Dynamic Content', + ], + [ + 'nexonendsWith@acquia.com', + $this->buildDynamicContentArray([['nexon-text', 'ta', 'endsWith']]), + 'Custom Object Dynamic Content', + ], + [ + 'nexonendsWith@acquia.com', + $this->buildDynamicContentArray([['nexon-text', 'at', 'contains']]), + 'Custom Object Dynamic Content', + ], + ] as $item) { + $this->emailWithCustomObjectDynamicContent($item[0], $item[1], $item[2]); + } + } + + /** + * @param array $inputs + * + * @return array + */ + private function buildDynamicContentArray(array $inputs): array + { + return [ + [ + 'tokenName' => 'Dynamic Content 1', + 'content' => 'Default Dynamic Content', + 'filters' => [ + [ + 'content' => null, + 'filters' => [ + ], + ], + ], + ], + [ + 'tokenName' => 'Dynamic Content 2', + 'content' => 'Default Dynamic Content', + 'filters' => [ + [ + 'content' => 'Custom Object Dynamic Content', + 'filters' => array_merge( + array_map(function ($input) { + return [ + 'glue' => 'and', + 'field' => 'cmf_'.$this->customFieldValues[$input[0]]->getCustomField()->getId(), + 'object' => 'custom_object', + 'type' => $input[3] ?? 'text', + 'filter' => $input[1], + 'display' => $this->customObject->getName().':'.$this->customFieldValues[$input[0]]->getCustomField()->getLabel(), + 'operator' => $input[2], + ]; + }, $inputs), + [ + [ + 'glue' => 'and', + 'field' => 'email', + 'object' => 'lead', + 'type' => 'email', + 'filter' => null, + 'operator' => '!empty', + ], + ] + ), + ], + ], + ], + ]; + } + + /** + * @param array $dynamicContent + */ + private function emailWithCustomObjectDynamicContent(string $emailAddress, array $dynamicContent, string $assertText): void + { + $lead = $this->createLead($emailAddress); + $email = $this->createEmail(); + $email->setDynamicContent($dynamicContent); + $this->em->persist($email); + $this->em->flush(); + + $this->customItemModel->linkEntity($this->customItems['nexon'], 'contact', (int) $lead->getId()); + $this->customItemModel->linkEntity($this->customItems['fortuner'], 'contact', (int) $lead->getId()); + $this->customItemModel->linkEntity($this->customItems['city'], 'contact', (int) $lead->getId()); + + $this->sendAndAssetText($email, $lead, $assertText); + } + + private function createEmail(bool $publicPreview = true): Email + { + $email = new Email(); + $email->setDateAdded(new \DateTime()); + $email->setName('Email name'); + $email->setSubject('Email subject'); + $email->setTemplate('Blank'); + $email->setPublicPreview($publicPreview); + $email->setCustomHtml('{dynamiccontent="Dynamic Content 2"}'); + $this->em->persist($email); + + return $email; + } + + private function createLead(string $email): Lead + { + $lead = new Lead(); + $lead->setEmail($email); + $this->em->persist($lead); + + return $lead; + } + + private function sendAndAssetText(Email $email, Lead $lead, string $matchText): void + { + /** @var EmailModel $emailModel */ + $emailModel = self::$container->get('mautic.email.model.email'); + $emailModel->sendEmail( + $email, + [ + [ + 'id' => $lead->getId(), + 'email' => $lead->getEmail(), + 'firstname' => $lead->getFirstname(), + 'lastname' => $lead->getLastname(), + ], + ] + ); + + /** @var StatRepository $emailStatRepository */ + $emailStatRepository = $this->em->getRepository(Stat::class); + + /** @var Stat|null $emailStat */ + $emailStat = $emailStatRepository->findOneBy( + [ + 'email' => $email->getId(), + 'lead' => $lead->getId(), + ] + ); + + Assert::assertNotNull($emailStat); + + $crawler = $this->client->request(Request::METHOD_GET, "/email/view/{$emailStat->getTrackingHash()}"); + + $body = $crawler->filter('body'); + + // Remove the tracking tags that are causing troubles with different Mautic configurations. + $body->filter('a,img,div')->each(function (Crawler $crawler) { + foreach ($crawler as $node) { + $node->parentNode->removeChild($node); + } + }); + + Assert::assertStringContainsString( + $matchText, + $body->html() + ); + } +} diff --git a/Tests/Functional/UpsertFunctionalTest.php b/Tests/Functional/UpsertFunctionalTest.php index a8ce1680e..34c0a6546 100644 --- a/Tests/Functional/UpsertFunctionalTest.php +++ b/Tests/Functional/UpsertFunctionalTest.php @@ -9,7 +9,7 @@ use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; use MauticPlugin\CustomObjectsBundle\Tests\Functional\DataFixtures\Traits\CustomObjectsTrait; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class UpsertFunctionalTest extends \Mautic\CoreBundle\Test\MauticMysqlTestCase { diff --git a/Tests/ProjectVersionTrait.php b/Tests/ProjectVersionTrait.php new file mode 100644 index 000000000..9c8a22436 --- /dev/null +++ b/Tests/ProjectVersionTrait.php @@ -0,0 +1,13 @@ +enableProfiler(); + $this->client->enableProfiler(); $commandTester = $this->getCustomItemExportCommandTester(); $this->em->clear(); diff --git a/Tests/Unit/Controller/ControllerTestCase.php b/Tests/Unit/Controller/ControllerTestCase.php index 79e7520d1..59f678768 100644 --- a/Tests/Unit/Controller/ControllerTestCase.php +++ b/Tests/Unit/Controller/ControllerTestCase.php @@ -4,16 +4,19 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller; -use Mautic\CoreBundle\Controller\CommonController; -use Mautic\CoreBundle\Controller\MauticController; +use Doctrine\Persistence\ManagerRegistry; +use Mautic\CoreBundle\Factory\MauticFactory; use Mautic\CoreBundle\Factory\ModelFactory; use Mautic\CoreBundle\Helper\CoreParametersHelper; use Mautic\CoreBundle\Helper\UserHelper; use Mautic\CoreBundle\Model\NotificationModel; use Mautic\CoreBundle\Security\Permissions\CorePermissions; -use Mautic\CoreBundle\Templating\Engine\PhpEngine; -use Symfony\Bundle\FrameworkBundle\Controller\Controller; +use Mautic\CoreBundle\Service\FlashBag; +use Mautic\CoreBundle\Translation\Translator; +use PHPUnit\Framework\MockObject\MockObject; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\HeaderBag; use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\Request; @@ -23,7 +26,6 @@ use Symfony\Component\HttpKernel\HttpKernel; use Symfony\Component\Routing\Router; use Symfony\Component\Routing\RouterInterface; -use Symfony\Component\Translation\TranslatorInterface; use Twig\Environment; /** @@ -33,7 +35,6 @@ */ class ControllerTestCase extends \PHPUnit\Framework\TestCase { - protected $requestStack; protected $request; protected $session; @@ -48,43 +49,98 @@ class ControllerTestCase extends \PHPUnit\Framework\TestCase protected $container; /** - * @var UserHelper + * @var MockObject|UserHelper */ protected $userHelper; - protected function addSymfonyDependencies(Controller $controller): void + /** + * @var MockObject|ManagerRegistry + */ + protected $managerRegistry; + + /** + * @var MockObject|MauticFactory + */ + protected $mauticFactory; + + /** + * @var MockObject|ModelFactory + */ + protected $modelFactory; + + /** + * @var MockObject|CoreParametersHelper + */ + protected $coreParametersHelper; + + /** + * @var MockObject|EventDispatcherInterface + */ + protected $dispatcher; + + /** + * @var MockObject|Translator + */ + protected $translator; + + /** + * @var MockObject|FlashBag + */ + protected $flashBag; + + /** + * @var MockObject|RequestStack + */ + protected $requestStack; + + /** + * @var MockObject|CorePermissions + */ + protected $security; + + protected function setUp(): void + { + parent::setUp(); + + $this->security = $this->createMock(CorePermissions::class); + $this->userHelper = $this->createMock(UserHelper::class); + $this->container = $this->createMock(ContainerInterface::class); + $this->router = $this->createMock(RouterInterface::class); + $this->managerRegistry = $this->createMock(ManagerRegistry::class); + $this->mauticFactory = $this->createMock(MauticFactory::class); + $this->modelFactory = $this->createMock(ModelFactory::class); + $this->coreParametersHelper = $this->createMock(CoreParametersHelper::class); + $this->dispatcher = $this->createMock(EventDispatcherInterface::class); + $this->translator = $this->createMock(Translator::class); + $this->flashBag = $this->createMock(FlashBag::class); + $this->requestStack = $this->createMock(RequestStack::class); + $this->security = $this->createMock(CorePermissions::class); + } + + protected function addSymfonyDependencies(AbstractController $controller): void { $requestStack = empty($this->requestStack) ? $this->createMock(RequestStack::class) : $this->requestStack; $request = empty($this->request) ? $this->createMock(Request::class) : $this->request; $session = empty($this->session) ? $this->createMock(Session::class) : $this->session; + $modelFactory = empty($this->modelFactory) ? $this->createMock(ModelFactory::class) : $this->modelFactory; - $this->container = $this->createMock(ContainerInterface::class); $httpKernel = $this->createMock(HttpKernel::class); $response = $this->createMock(Response::class); - $phpEngine = $this->createMock(PhpEngine::class); - $modelFactory = $this->createMock(ModelFactory::class); + $twig = $this->createMock(Environment::class); $notificationModel = $this->createMock(NotificationModel::class); - $security = $this->createMock(CorePermissions::class); - $translator = $this->createMock(TranslatorInterface::class); - $this->router = $this->createMock(RouterInterface::class); - $this->userHelper = $this->createMock(UserHelper::class); $this->container->method('get')->willReturnMap([ ['request_stack', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $requestStack], ['http_kernel', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $httpKernel], - ['templating', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $phpEngine], ['mautic.model.factory', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $modelFactory], ['session', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $session], - ['mautic.security', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $security], + ['mautic.security', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $this->security], ['router', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $this->router], ['mautic.helper.user', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $this->userHelper], - ['twig', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $this->createMock(Environment::class)], + ['twig', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $twig], ]); - $phpEngine->method('renderResponse')->willReturn($response); - $this->container->method('has')->willReturnMap([ - ['templating', false], // 'templating' will be removed in Symfony 5 ['twig', true], ]); @@ -104,14 +160,5 @@ protected function addSymfonyDependencies(Controller $controller): void $requestStack->method('getCurrentRequest')->willReturn($request); $controller->setContainer($this->container); - - if ($controller instanceof MauticController) { - $controller->setRequest($request); - $controller->setTranslator($translator); - } - - if ($controller instanceof CommonController) { - $controller->setCoreParametersHelper($this->createMock(CoreParametersHelper::class)); - } } } diff --git a/Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php b/Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php index 404cc97d9..533cfb927 100644 --- a/Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php +++ b/Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php @@ -7,17 +7,18 @@ use MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller\ControllerTestCase; use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; abstract class AbstractFieldControllerTest extends ControllerTestCase { - protected function createRequestMock( + protected function createRequestStackMock( $objectId = null, $fieldId = null, $fieldType = null, $panelId = null, $panelCount = null, array $mapExtras = [] - ): Request { + ): RequestStack { $request = $this->createMock(Request::class); $map = [ @@ -39,8 +40,26 @@ protected function createRequestMock( $query = $this->createMock(ParameterBag::class); $query->method('get') ->willReturn($fieldId); + $query->method('all') + ->willReturn($map); $request->query = $query; - return $request; + $post = $this->createMock(ParameterBag::class); + $post->method('get') + ->willReturn($fieldId); + $post->method('all') + ->willReturn($map); + $request->request = $post; + + $request->expects($this->any()) + ->method('duplicate') + ->willReturn($request); + + $requestStack = $this->createMock(RequestStack::class); + $requestStack->expects($this->any()) + ->method('getCurrentRequest') + ->willReturn($request); + + return $requestStack; } } diff --git a/Tests/Unit/Controller/CustomField/FormControllerTest.php b/Tests/Unit/Controller/CustomField/FormControllerTest.php index 6c499705e..b6f5cb629 100644 --- a/Tests/Unit/Controller/CustomField/FormControllerTest.php +++ b/Tests/Unit/Controller/CustomField/FormControllerTest.php @@ -4,6 +4,7 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller\CustomField; +use Mautic\CoreBundle\Security\Permissions\CorePermissions; use MauticPlugin\CustomObjectsBundle\Controller\CustomField\FormController; use MauticPlugin\CustomObjectsBundle\Entity\CustomField; use MauticPlugin\CustomObjectsBundle\Entity\CustomFieldFactory; @@ -16,57 +17,98 @@ use MauticPlugin\CustomObjectsBundle\Provider\CustomFieldPermissionProvider; use MauticPlugin\CustomObjectsBundle\Provider\CustomFieldRouteProvider; use MauticPlugin\CustomObjectsBundle\Provider\CustomObjectRouteProvider; +use PHPUnit\Framework\MockObject\MockObject; use Symfony\Component\Form\FormFactory; use Symfony\Component\Form\FormInterface; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; class FormControllerTest extends AbstractFieldControllerTest { + /** + * @var MockObject|RequestStack + */ + protected $requestStack; + + /** + * @var MockObject|CorePermissions + */ + protected $security; + + /** + * @var MockObject|FormFactory + */ private $formFactory; + + /** + * @var MockObject|CustomFieldModel + */ private $customFieldModel; + + /** + * @var MockObject|CustomFieldFactory + */ private $customFieldFactory; + + /** + * @var MockObject|CustomFieldPermissionProvider + */ private $permissionProvider; + + /** + * @var MockObject|CustomFieldRouteProvider + */ private $fieldRouteProvider; + + /** + * @var MockObject|CustomObjectModel + */ private $customObjectModel; + + /** + * @var MockObject|CustomObjectRouteProvider + */ private $objectRouteProvider; + + /** + * @var MockObject|FormInterface + */ private $form; + + /** + * @var MockObject|FormController + */ private $formController; protected function setUp(): void { parent::setUp(); - $this->formFactory = $this->createMock(FormFactory::class); - $this->customFieldModel = $this->createMock(CustomFieldModel::class); - $this->customFieldFactory = $this->createMock(CustomFieldFactory::class); - $this->permissionProvider = $this->createMock(CustomFieldPermissionProvider::class); - $this->fieldRouteProvider = $this->createMock(CustomFieldRouteProvider::class); - $this->customObjectModel = $this->createMock(CustomObjectModel::class); - $this->objectRouteProvider = $this->createMock(CustomObjectRouteProvider::class); - $this->form = $this->createMock(FormInterface::class); - - $this->formController = new FormController( - $this->formFactory, - $this->customFieldModel, - $this->customFieldFactory, - $this->permissionProvider, - $this->fieldRouteProvider, - $this->customObjectModel, - $this->objectRouteProvider - ); - - $this->addSymfonyDependencies($this->formController); + $this->formFactory = $this->createMock(FormFactory::class); + $this->customFieldModel = $this->createMock(CustomFieldModel::class); + $this->customFieldFactory = $this->createMock(CustomFieldFactory::class); + $this->permissionProvider = $this->createMock(CustomFieldPermissionProvider::class); + $this->fieldRouteProvider = $this->createMock(CustomFieldRouteProvider::class); + $this->customObjectModel = $this->createMock(CustomObjectModel::class); + $this->objectRouteProvider = $this->createMock(CustomObjectRouteProvider::class); + $this->form = $this->createMock(FormInterface::class); } - public function testRenderFormIfCustomFieldNotFound(): void + public function testRenderFormIfCustomFieldNotFoundFormController(): void { - $objectId = 1; - $fieldId = 2; - $fieldType = 'text'; - $panelId = null; - $panelCount = null; - - $request = $this->createRequestMock($objectId, $fieldId, $fieldType, $panelId, $panelCount); + $objectId = 1; + $fieldId = 2; + $fieldType = 'text'; + $panelId = null; + $panelCount = null; + + $this->createFormController( + $objectId, + $fieldId, + $fieldType, + $panelId, + $panelCount + ); $this->customFieldModel->expects($this->once()) ->method('fetchEntity') @@ -75,18 +117,42 @@ public function testRenderFormIfCustomFieldNotFound(): void $this->permissionProvider->expects($this->never()) ->method('canEdit'); - $this->formController->renderFormAction($request); + $this->translator->expects($this->once()) + ->method('trans') + ->with( + 'not found message', + [ + '%url%' => null, + ] + ) + ->willReturn('not found message'); + + $this->formController->renderFormAction( + $this->formFactory, + $this->customFieldModel, + $this->customFieldFactory, + $this->permissionProvider, + $this->fieldRouteProvider, + $this->customObjectModel, + $this->objectRouteProvider + ); } public function testRenderFormIfCustomFieldAccessDenied(): void { - $objectId = 1; - $fieldId = 2; - $fieldType = 'text'; - $panelId = null; - $panelCount = null; - - $request = $this->createRequestMock($objectId, $fieldId, $fieldType, $panelId, $panelCount); + $objectId = 1; + $fieldId = 2; + $fieldType = 'text'; + $panelId = null; + $panelCount = null; + + $this->createFormController( + $objectId, + $fieldId, + $fieldType, + $panelId, + $panelCount + ); $this->customFieldModel->expects($this->once()) ->method('fetchEntity') @@ -97,20 +163,38 @@ public function testRenderFormIfCustomFieldAccessDenied(): void ->method('canEdit') ->will($this->throwException(new ForbiddenException('forbidden message'))); + $this->security->expects($this->once()) + ->method('isAnonymous') + ->willReturn(true); + $this->expectException(AccessDeniedHttpException::class); - $this->formController->renderFormAction($request); + $this->formController->renderFormAction( + $this->formFactory, + $this->customFieldModel, + $this->customFieldFactory, + $this->permissionProvider, + $this->fieldRouteProvider, + $this->customObjectModel, + $this->objectRouteProvider + ); } public function testRenderFormActionEditField(): void { - $objectId = 1; - $fieldId = 2; - $fieldType = 'text'; - $panelId = null; - $panelCount = null; - - $request = $this->createRequestMock($objectId, $fieldId, $fieldType, $panelId, $panelCount); + $objectId = 1; + $fieldId = 2; + $fieldType = 'text'; + $panelId = null; + $panelCount = null; + + $this->createFormController( + $objectId, + $fieldId, + $fieldType, + $panelId, + $panelCount + ); $customObject = new CustomObject(); $this->customObjectModel->expects($this->once()) @@ -138,7 +222,13 @@ public function testRenderFormActionEditField(): void $action = 'action'; $this->fieldRouteProvider->expects($this->once()) ->method('buildSaveRoute') - ->with($fieldType, $fieldId, $customObject->getId(), $panelCount, $panelId) + ->with( + $fieldType, + $fieldId, + $customObject->getId(), + $panelCount, + $panelId + ) ->willReturn($action); $this->formFactory->expects($this->once()) @@ -157,7 +247,15 @@ public function testRenderFormActionEditField(): void ->method('createView') ->willReturn($view); - $this->formController->renderFormAction($request); + $this->formController->renderFormAction( + $this->formFactory, + $this->customFieldModel, + $this->customFieldFactory, + $this->permissionProvider, + $this->fieldRouteProvider, + $this->customObjectModel, + $this->objectRouteProvider + ); } public function testRenderFormActionCreateField(): void @@ -168,7 +266,13 @@ public function testRenderFormActionCreateField(): void $panelId = null; $panelCount = null; - $request = $this->createRequestMock($objectId, $fieldId, $fieldType, $panelId, $panelCount); + $this->createFormController( + $objectId, + $fieldId, + $fieldType, + $panelId, + $panelCount + ); $this->permissionProvider->expects($this->once()) ->method('canCreate'); @@ -209,6 +313,49 @@ public function testRenderFormActionCreateField(): void ->method('createView') ->willReturn($view); - $this->formController->renderFormAction($request); + $this->formController->renderFormAction( + $this->formFactory, + $this->customFieldModel, + $this->customFieldFactory, + $this->permissionProvider, + $this->fieldRouteProvider, + $this->customObjectModel, + $this->objectRouteProvider + ); + } + + private function createFormController( + ?int $objectId, + ?int $fieldId, + string $fieldType, + ?int $panelId = null, + ?int $panelCount = null + ): void { + $this->requestStack = $this->createRequestStackMock( + $objectId, + $fieldId, + $fieldType, + $panelId, + $panelCount + ); + + $this->formController = new FormController( + $this->managerRegistry, + $this->mauticFactory, + $this->modelFactory, + $this->userHelper, + $this->coreParametersHelper, + $this->dispatcher, + $this->translator, + $this->flashBag, + $this->requestStack, + $this->security + ); + + $this->addSymfonyDependencies($this->formController); + + $this->container->get('http_kernel')->expects($this->any()) + ->method('handle') + ->willreturn(null); } } diff --git a/Tests/Unit/Controller/CustomField/SaveControllerTest.php b/Tests/Unit/Controller/CustomField/SaveControllerTest.php index 6c3541738..c9fce0446 100644 --- a/Tests/Unit/Controller/CustomField/SaveControllerTest.php +++ b/Tests/Unit/Controller/CustomField/SaveControllerTest.php @@ -20,12 +20,10 @@ use Symfony\Component\Form\FormFactory; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; -use Symfony\Component\Translation\TranslatorInterface; class SaveControllerTest extends AbstractFieldControllerTest { private $formFactory; - private $translator; private $customFieldModel; private $customFieldFactory; private $permissionProvider; @@ -39,36 +37,29 @@ protected function setUp(): void parent::setUp(); $this->formFactory = $this->createMock(FormFactory::class); - $this->translator = $this->createMock(TranslatorInterface::class); $this->customFieldModel = $this->createMock(CustomFieldModel::class); $this->customFieldFactory = $this->createMock(CustomFieldFactory::class); $this->permissionProvider = $this->createMock(CustomFieldPermissionProvider::class); $this->fieldRouteProvider = $this->createMock(CustomFieldRouteProvider::class); $this->customObjectModel = $this->createMock(CustomObjectModel::class); $this->form = $this->createMock(FormInterface::class); - - $this->saveController = new SaveController( - $this->formFactory, - $this->translator, - $this->customFieldModel, - $this->customFieldFactory, - $this->permissionProvider, - $this->fieldRouteProvider, - $this->customObjectModel - ); - - $this->addSymfonyDependencies($this->saveController); } public function testRenderFormIfCustomFieldNotFound(): void { - $objectId = 1; - $fieldId = 2; - $fieldType = 'text'; - $panelId = null; - $panelCount = null; - - $request = $this->createRequestMock($objectId, $fieldId, $fieldType, $panelId, $panelCount); + $objectId = 1; + $fieldId = 2; + $fieldType = 'text'; + $panelId = null; + $panelCount = null; + + $this->createSaveController( + $objectId, + $fieldId, + $fieldType, + $panelId, + $panelCount + ); $this->customFieldModel->expects($this->once()) ->method('fetchEntity') @@ -77,7 +68,14 @@ public function testRenderFormIfCustomFieldNotFound(): void $this->permissionProvider->expects($this->never()) ->method('canEdit'); - $this->saveController->saveAction($request); + $this->saveController->saveAction( + $this->formFactory, + $this->customFieldModel, + $this->customFieldFactory, + $this->permissionProvider, + $this->fieldRouteProvider, + $this->customObjectModel + ); } public function testRenderFormIfCustomFieldAccessDenied(): void @@ -88,7 +86,13 @@ public function testRenderFormIfCustomFieldAccessDenied(): void $panelId = null; $panelCount = null; - $request = $this->createRequestMock($objectId, $fieldId, $fieldType, $panelId, $panelCount); + $this->createSaveController( + $objectId, + $fieldId, + $fieldType, + $panelId, + $panelCount + ); $this->customFieldModel->expects($this->once()) ->method('fetchEntity') @@ -101,7 +105,14 @@ public function testRenderFormIfCustomFieldAccessDenied(): void $this->expectException(AccessDeniedHttpException::class); - $this->saveController->saveAction($request); + $this->saveController->saveAction( + $this->formFactory, + $this->customFieldModel, + $this->customFieldFactory, + $this->permissionProvider, + $this->fieldRouteProvider, + $this->customObjectModel + ); } public function testSaveActionEdit(): void @@ -112,6 +123,14 @@ public function testSaveActionEdit(): void $panelId = null; $panelCount = null; + $this->createSaveController( + $objectId, + $fieldId, + $fieldType, + $panelId, + $panelCount + ); + $customObject = $this->createMock(CustomObject::class); $customObject->expects($this->once()) ->method('getId') @@ -124,7 +143,15 @@ public function testSaveActionEdit(): void ['custom_field', null, []], ['panelId', null, $panelCount], ]; - $request = $this->createRequestMock($objectId, $fieldId, $fieldType, $panelId, $panelCount, $mapExtras); + + $this->createSaveController( + $objectId, + $fieldId, + $fieldType, + $panelId, + $panelCount, + $mapExtras + ); $this->customObjectModel->expects($this->once()) ->method('fetchEntity') @@ -157,7 +184,7 @@ public function testSaveActionEdit(): void $this->form->expects($this->once()) ->method('handleRequest') - ->with($request); + ->with($this->requestStack->getCurrentRequest()); $this->form->expects($this->once()) ->method('isValid') @@ -181,7 +208,14 @@ public function testSaveActionEdit(): void $customObject->expects($this->once()) ->method('setCustomFields'); - $this->saveController->saveAction($request); + $this->saveController->saveAction( + $this->formFactory, + $this->customFieldModel, + $this->customFieldFactory, + $this->permissionProvider, + $this->fieldRouteProvider, + $this->customObjectModel + ); } public function testSaveActionCreate(): void @@ -192,6 +226,14 @@ public function testSaveActionCreate(): void $panelId = null; $panelCount = null; + $this->createSaveController( + $objectId, + $fieldId, + $fieldType, + $panelId, + $panelCount + ); + $customObject = $this->createMock(CustomObject::class); $customObject->expects($this->once()) ->method('getId') @@ -206,7 +248,15 @@ public function testSaveActionCreate(): void ['panelCount', null, $panelCount], ['custom_field', null, []], ]; - $request = $this->createRequestMock($objectId, $fieldId, $fieldType, $panelId, $panelCount, $mapExtras); + + $this->createSaveController( + $objectId, + $fieldId, + $fieldType, + $panelId, + $panelCount, + $mapExtras + ); $this->customObjectModel->expects($this->once()) ->method('fetchEntity') @@ -239,7 +289,7 @@ public function testSaveActionCreate(): void $this->form->expects($this->once()) ->method('handleRequest') - ->with($request); + ->with($this->requestStack->getCurrentRequest()); $this->form->expects($this->once()) ->method('isValid') @@ -260,7 +310,14 @@ public function testSaveActionCreate(): void $customObject->expects($this->once()) ->method('setCustomFields'); - $this->saveController->saveAction($request); + $this->saveController->saveAction( + $this->formFactory, + $this->customFieldModel, + $this->customFieldFactory, + $this->permissionProvider, + $this->fieldRouteProvider, + $this->customObjectModel + ); } public function testInvalidPost(): void @@ -282,7 +339,15 @@ public function testInvalidPost(): void ['custom_field', null, []], ['custom_field', null, []], ]; - $request = $this->createRequestMock($objectId, $fieldId, $fieldType, $panelId, $panelCount, $mapExtras); + + $this->createSaveController( + $objectId, + $fieldId, + $fieldType, + $panelId, + $panelCount, + $mapExtras + ); $this->customObjectModel->expects($this->once()) ->method('fetchEntity') @@ -311,12 +376,52 @@ public function testInvalidPost(): void $this->form->expects($this->once()) ->method('handleRequest') - ->with($request); + ->with($this->requestStack->getCurrentRequest()); $this->form->expects($this->once()) ->method('isValid') ->willReturn(false); - $this->saveController->saveAction($request); + $this->saveController->saveAction( + $this->formFactory, + $this->customFieldModel, + $this->customFieldFactory, + $this->permissionProvider, + $this->fieldRouteProvider, + $this->customObjectModel + ); + } + + private function createSaveController( + ?int $objectId, + ?int $fieldId, + string $fieldType, + ?int $panelId = null, + ?int $panelCount = null, + array $mapExtras = [] + ): void { + $this->requestStack = $this->createRequestStackMock( + $objectId, + $fieldId, + $fieldType, + $panelId, + $panelCount, + $mapExtras + ); + + $this->saveController = new SaveController( + $this->managerRegistry, + $this->mauticFactory, + $this->modelFactory, + $this->userHelper, + $this->coreParametersHelper, + $this->dispatcher, + $this->translator, + $this->flashBag, + $this->requestStack, + $this->security + ); + + $this->addSymfonyDependencies($this->saveController); } } diff --git a/Tests/Unit/Controller/CustomItem/BatchDeleteControllerTest.php b/Tests/Unit/Controller/CustomItem/BatchDeleteControllerTest.php index 695c88f20..dc4d8cd7d 100644 --- a/Tests/Unit/Controller/CustomItem/BatchDeleteControllerTest.php +++ b/Tests/Unit/Controller/CustomItem/BatchDeleteControllerTest.php @@ -4,6 +4,7 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller\CustomItem; +use Mautic\CoreBundle\Model\NotificationModel; use Mautic\CoreBundle\Service\FlashBag; use MauticPlugin\CustomObjectsBundle\Controller\CustomItem\BatchDeleteController; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; @@ -16,15 +17,16 @@ use MauticPlugin\CustomObjectsBundle\Provider\SessionProviderFactory; use MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller\ControllerTestCase; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\RequestStack; +#[\AllowDynamicProperties] class BatchDeleteControllerTest extends ControllerTestCase { private $customItemModel; private $sessionProvider; - private $flashBag; + private $sessionProviderFactory; private $permissionProvider; private $routeProvider; + private $model; /** * @var BatchDeleteController @@ -35,27 +37,43 @@ protected function setUp(): void { parent::setUp(); - $sessionProviderFactory = $this->createMock(SessionProviderFactory::class); - $this->requestStack = $this->createMock(RequestStack::class); - $this->customItemModel = $this->createMock(CustomItemModel::class); - $this->sessionProvider = $this->createMock(SessionProvider::class); - $this->flashBag = $this->createMock(FlashBag::class); - $this->permissionProvider = $this->createMock(CustomItemPermissionProvider::class); - $this->routeProvider = $this->createMock(CustomItemRouteProvider::class); - $this->request = $this->createMock(Request::class); - $this->batchDeleteController = new BatchDeleteController( + $this->customItemModel = $this->createMock(CustomItemModel::class); + $this->sessionProvider = $this->createMock(SessionProvider::class); + $this->sessionProviderFactory = $this->createMock(SessionProviderFactory::class); + $this->permissionProvider = $this->createMock(CustomItemPermissionProvider::class); + $this->routeProvider = $this->createMock(CustomItemRouteProvider::class); + $this->request = $this->createMock(Request::class); + + $this->requestStack->expects($this->any()) + ->method('getCurrentRequest') + ->willReturn($this->request); + + $this->model = $this->createMock(NotificationModel::class); + $this->modelFactory->expects($this->once()) + ->method('getModel') + ->willReturn($this->model); + + $this->batchDeleteController = new BatchDeleteController( + $this->managerRegistry, + $this->mauticFactory, + $this->modelFactory, + $this->userHelper, + $this->coreParametersHelper, + $this->dispatcher, + $this->translator, + $this->flashBag, $this->requestStack, - $this->customItemModel, - $sessionProviderFactory, - $this->permissionProvider, - $this->routeProvider, - $this->flashBag + $this->security ); $this->addSymfonyDependencies($this->batchDeleteController); $this->request->method('isXmlHttpRequest')->willReturn(true); - $sessionProviderFactory->method('createItemProvider')->willReturn($this->sessionProvider); + $this->sessionProviderFactory->method('createItemProvider')->willReturn($this->sessionProvider); + + $this->model->expects($this->once()) + ->method('getNotificationContent') + ->willReturn([[], 'test', 'test']); } public function testDeleteActionIfCustomItemNotFound(): void @@ -79,7 +97,14 @@ public function testDeleteActionIfCustomItemNotFound(): void ->method('add') ->with('custom.item.error.items.not.found', ['%ids%' => '13,14'], FlashBag::LEVEL_ERROR); - $this->batchDeleteController->deleteAction(33); + $this->batchDeleteController->deleteAction( + $this->customItemModel, + $this->sessionProviderFactory, + $this->permissionProvider, + $this->routeProvider, + $this->flashBag, + 33 + ); } public function testDeleteActionIfCustomItemForbidden(): void @@ -107,7 +132,14 @@ public function testDeleteActionIfCustomItemForbidden(): void ->method('add') ->with('custom.item.error.items.denied', ['%ids%' => '13,14'], FlashBag::LEVEL_ERROR); - $this->batchDeleteController->deleteAction(33); + $this->batchDeleteController->deleteAction( + $this->customItemModel, + $this->sessionProviderFactory, + $this->permissionProvider, + $this->routeProvider, + $this->flashBag, + 33 + ); } public function testDeleteAction(): void @@ -144,6 +176,13 @@ public function testDeleteAction(): void ->method('buildListRoute') ->with(33, 3); - $this->batchDeleteController->deleteAction(33); + $this->batchDeleteController->deleteAction( + $this->customItemModel, + $this->sessionProviderFactory, + $this->permissionProvider, + $this->routeProvider, + $this->flashBag, + 33 + ); } } diff --git a/Tests/Unit/Controller/CustomItem/CancelControllerTest.php b/Tests/Unit/Controller/CustomItem/CancelControllerTest.php index 22f0fd3d0..788cedfc5 100644 --- a/Tests/Unit/Controller/CustomItem/CancelControllerTest.php +++ b/Tests/Unit/Controller/CustomItem/CancelControllerTest.php @@ -12,11 +12,13 @@ use MauticPlugin\CustomObjectsBundle\Provider\SessionProvider; use MauticPlugin\CustomObjectsBundle\Provider\SessionProviderFactory; use MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller\ControllerTestCase; +use Symfony\Component\HttpFoundation\Request; class CancelControllerTest extends ControllerTestCase { private const OBJECT_ID = 33; + private $sessionProviderFactory; private $sessionProvider; private $routeProvider; private $customItemModel; @@ -30,20 +32,32 @@ protected function setUp(): void { parent::setUp(); - $sessionProviderFactory = $this->createMock(SessionProviderFactory::class); - $this->sessionProvider = $this->createMock(SessionProvider::class); - $this->routeProvider = $this->createMock(CustomItemRouteProvider::class); - $this->customItemModel = $this->createMock(CustomItemModel::class); - - $this->cancelController = new CancelController( - $sessionProviderFactory, - $this->routeProvider, - $this->customItemModel + $this->sessionProviderFactory = $this->createMock(SessionProviderFactory::class); + $this->sessionProvider = $this->createMock(SessionProvider::class); + $this->routeProvider = $this->createMock(CustomItemRouteProvider::class); + $this->customItemModel = $this->createMock(CustomItemModel::class); + $this->request = $this->createMock(Request::class); + + $this->requestStack->expects($this->any()) + ->method('getCurrentRequest') + ->willReturn($this->request); + + $this->cancelController = new CancelController( + $this->managerRegistry, + $this->mauticFactory, + $this->modelFactory, + $this->userHelper, + $this->coreParametersHelper, + $this->dispatcher, + $this->translator, + $this->flashBag, + $this->requestStack, + $this->security ); $this->addSymfonyDependencies($this->cancelController); - $sessionProviderFactory->method('createItemProvider')->willReturn($this->sessionProvider); + $this->sessionProviderFactory->method('createItemProvider')->willReturn($this->sessionProvider); } public function testCancelAction(): void @@ -62,7 +76,12 @@ public function testCancelAction(): void ->with(self::OBJECT_ID, $pageNumber) ->willReturn('some/route'); - $this->cancelController->cancelAction(self::OBJECT_ID); + $this->cancelController->cancelAction( + $this->sessionProviderFactory, + $this->routeProvider, + $this->customItemModel, + self::OBJECT_ID + ); } public function testCancelActionWithEntityUnlock(): void @@ -89,6 +108,12 @@ public function testCancelActionWithEntityUnlock(): void ->with(self::OBJECT_ID, $pageNumber) ->willReturn('some/route'); - $this->cancelController->cancelAction(self::OBJECT_ID, $customItemId); + $this->cancelController->cancelAction( + $this->sessionProviderFactory, + $this->routeProvider, + $this->customItemModel, + self::OBJECT_ID, + $customItemId + ); } } diff --git a/Tests/Unit/Controller/CustomItem/DeleteControllerTest.php b/Tests/Unit/Controller/CustomItem/DeleteControllerTest.php index 36b2a7e82..fcb3e8393 100644 --- a/Tests/Unit/Controller/CustomItem/DeleteControllerTest.php +++ b/Tests/Unit/Controller/CustomItem/DeleteControllerTest.php @@ -4,7 +4,7 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller\CustomItem; -use Mautic\CoreBundle\Service\FlashBag; +use Mautic\CoreBundle\Model\NotificationModel; use MauticPlugin\CustomObjectsBundle\Controller\CustomItem\DeleteController; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Exception\ForbiddenException; @@ -15,9 +15,11 @@ use MauticPlugin\CustomObjectsBundle\Provider\SessionProvider; use MauticPlugin\CustomObjectsBundle\Provider\SessionProviderFactory; use MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller\ControllerTestCase; +use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +#[\AllowDynamicProperties] class DeleteControllerTest extends ControllerTestCase { private const OBJECT_ID = 33; @@ -26,7 +28,6 @@ class DeleteControllerTest extends ControllerTestCase private $customItemModel; private $sessionProvider; - private $flashBag; private $permissionProvider; private $routeProvider; @@ -39,26 +40,37 @@ protected function setUp(): void { parent::setUp(); - $sessionProviderFactory = $this->createMock(SessionProviderFactory::class); - $this->customItemModel = $this->createMock(CustomItemModel::class); - $this->sessionProvider = $this->createMock(SessionProvider::class); - $this->flashBag = $this->createMock(FlashBag::class); - $this->permissionProvider = $this->createMock(CustomItemPermissionProvider::class); - $this->routeProvider = $this->createMock(CustomItemRouteProvider::class); - $this->request = $this->createMock(Request::class); - $this->deleteController = new DeleteController( - $this->customItemModel, - $sessionProviderFactory, + $this->sessionProviderFactory = $this->createMock(SessionProviderFactory::class); + $this->customItemModel = $this->createMock(CustomItemModel::class); + $this->sessionProvider = $this->createMock(SessionProvider::class); + $this->permissionProvider = $this->createMock(CustomItemPermissionProvider::class); + $this->routeProvider = $this->createMock(CustomItemRouteProvider::class); + $this->request = $this->createMock(Request::class); + + $this->requestStack->expects($this->any()) + ->method('getCurrentRequest') + ->willReturn($this->request); + + $this->model = $this->createMock(NotificationModel::class); + + $this->deleteController = new DeleteController( + $this->managerRegistry, + $this->mauticFactory, + $this->modelFactory, + $this->userHelper, + $this->coreParametersHelper, + $this->dispatcher, + $this->translator, $this->flashBag, - $this->permissionProvider, - $this->routeProvider + $this->requestStack, + $this->security ); $this->addSymfonyDependencies($this->deleteController); $this->request->method('isXmlHttpRequest')->willReturn(true); $this->request->method('getRequestUri')->willReturn('https://a.b'); - $sessionProviderFactory->method('createItemProvider')->willReturn($this->sessionProvider); + $this->sessionProviderFactory->method('createItemProvider')->willReturn($this->sessionProvider); } public function testDeleteActionIfCustomItemNotFound(): void @@ -73,7 +85,25 @@ public function testDeleteActionIfCustomItemNotFound(): void $this->flashBag->expects($this->never()) ->method('add'); - $this->deleteController->deleteAction(self::OBJECT_ID, self::ITEM_ID); + $this->translator->expects($this->once()) + ->method('trans') + ->willReturn('Item not found message'); + + $post = $this->createMock(ParameterBag::class); + $this->request->request = $post; + $post->expects($this->once()) + ->method('all') + ->willReturn([]); + + $this->deleteController->deleteAction( + $this->customItemModel, + $this->sessionProviderFactory, + $this->flashBag, + $this->permissionProvider, + $this->routeProvider, + self::OBJECT_ID, + self::ITEM_ID + ); } public function testDeleteActionIfCustomItemForbidden(): void @@ -92,9 +122,21 @@ public function testDeleteActionIfCustomItemForbidden(): void $this->flashBag->expects($this->never()) ->method('add'); + $this->security->expects($this->once()) + ->method('isAnonymous') + ->willReturn(true); + $this->expectException(AccessDeniedHttpException::class); - $this->deleteController->deleteAction(self::OBJECT_ID, self::ITEM_ID); + $this->deleteController->deleteAction( + $this->customItemModel, + $this->sessionProviderFactory, + $this->flashBag, + $this->permissionProvider, + $this->routeProvider, + self::OBJECT_ID, + self::ITEM_ID + ); } public function testDeleteAction(): void @@ -124,6 +166,18 @@ public function testDeleteAction(): void ->method('buildListRoute') ->with(self::OBJECT_ID, 3); - $this->deleteController->deleteAction(self::OBJECT_ID, self::ITEM_ID); + $this->modelFactory->expects($this->once()) + ->method('getModel') + ->willReturn($this->model); + + $this->deleteController->deleteAction( + $this->customItemModel, + $this->sessionProviderFactory, + $this->flashBag, + $this->permissionProvider, + $this->routeProvider, + self::OBJECT_ID, + self::ITEM_ID + ); } } diff --git a/Tests/Unit/Controller/CustomItem/FormControllerTest.php b/Tests/Unit/Controller/CustomItem/FormControllerTest.php index 54fd0cb5a..cb98a6de2 100644 --- a/Tests/Unit/Controller/CustomItem/FormControllerTest.php +++ b/Tests/Unit/Controller/CustomItem/FormControllerTest.php @@ -4,6 +4,7 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller\CustomItem; +use Mautic\CoreBundle\Model\NotificationModel; use Mautic\UserBundle\Entity\User; use MauticPlugin\CustomObjectsBundle\Controller\CustomItem\FormController; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; @@ -21,9 +22,11 @@ use PHPUnit\Framework\MockObject\MockObject; use Symfony\Component\Form\FormFactory; use Symfony\Component\Form\FormInterface; +use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +#[\AllowDynamicProperties] class FormControllerTest extends ControllerTestCase { public const OBJECT_ID = 33; @@ -86,23 +89,36 @@ protected function setUp(): void { parent::setUp(); - $this->customItemModel = $this->createMock(CustomItemModel::class); - $this->customObjectModel = $this->createMock(CustomObjectModel::class); - $this->formFactory = $this->createMock(FormFactory::class); - $this->permissionProvider = $this->createMock(CustomItemPermissionProvider::class); - $this->routeProvider = $this->createMock(CustomItemRouteProvider::class); - $this->lockFlashMessageHelper = $this->createMock(LockFlashMessageHelper::class); - $this->request = $this->createMock(Request::class); - $this->customObject = $this->createMock(CustomObject::class); - $this->customItem = $this->createMock(CustomItem::class); - $this->form = $this->createMock(FormInterface::class); - $this->formController = new FormController( - $this->formFactory, - $this->customObjectModel, - $this->customItemModel, - $this->permissionProvider, - $this->routeProvider, - $this->lockFlashMessageHelper + $this->customItemModel = $this->createMock(CustomItemModel::class); + $this->customObjectModel = $this->createMock(CustomObjectModel::class); + $this->formFactory = $this->createMock(FormFactory::class); + $this->permissionProvider = $this->createMock(CustomItemPermissionProvider::class); + $this->routeProvider = $this->createMock(CustomItemRouteProvider::class); + $this->lockFlashMessageHelper = $this->createMock(LockFlashMessageHelper::class); + $this->request = $this->createMock(Request::class); + $this->customObject = $this->createMock(CustomObject::class); + $this->customItem = $this->createMock(CustomItem::class); + $this->form = $this->createMock(FormInterface::class); + $this->model = $this->createMock(NotificationModel::class); + + $userMock = $this->createMock(User::class); + $userMock->method('isAdmin') + ->willReturn(true); + + $this->userHelper->expects($this->any())->method('getUser') + ->willReturn($userMock); + + $this->formController = new FormController( + $this->managerRegistry, + $this->mauticFactory, + $this->modelFactory, + $this->userHelper, + $this->coreParametersHelper, + $this->dispatcher, + $this->translator, + $this->flashBag, + $this->requestStack, + $this->security ); $this->addSymfonyDependencies($this->formController); @@ -133,9 +149,20 @@ public function testNewActionIfForbidden(): void $this->routeProvider->expects($this->never()) ->method('buildNewRoute'); + $this->security->expects($this->once()) + ->method('isAnonymous') + ->willReturn(true); + $this->expectException(AccessDeniedHttpException::class); - $this->formController->newAction(self::OBJECT_ID); + $this->formController->newAction( + $this->formFactory, + $this->routeProvider, + $this->customItemModel, + $this->customObjectModel, + $this->permissionProvider, + self::OBJECT_ID + ); } public function testNewWithRedirectToContactActionIfForbidden(): void @@ -155,7 +182,15 @@ public function testNewWithRedirectToContactActionIfForbidden(): void $this->expectException(AccessDeniedHttpException::class); - $this->formController->newWithRedirectToContactAction(static::OBJECT_ID, static::CONTACT_ID); + $this->formController->newWithRedirectToContactAction( + $this->formFactory, + $this->routeProvider, + $this->customItemModel, + $this->customObjectModel, + $this->permissionProvider, + static::OBJECT_ID, + static::CONTACT_ID + ); } public function testNewAction(): void @@ -178,7 +213,22 @@ public function testNewAction(): void $this->assertRenderFormForItem($this->customItem); - $this->formController->newAction(self::OBJECT_ID); + $this->modelFactory->expects($this->once()) + ->method('getModel') + ->willReturn($this->model); + + $this->modelFactory->expects($this->once()) + ->method('getModel') + ->willReturn($this->model); + + $this->formController->newAction( + $this->formFactory, + $this->routeProvider, + $this->customItemModel, + $this->customObjectModel, + $this->permissionProvider, + self::OBJECT_ID + ); } public function testNewWithRedirectToContactAction(): void @@ -191,7 +241,7 @@ public function getId() }; $customItem = new class($customObject) extends CustomItem { - public function getId() + public function getId(): int { return FormControllerTest::ITEM_ID; } @@ -215,7 +265,19 @@ public function getId() $this->assertRenderFormForItem($customItem, static::CONTACT_ID); - $this->formController->newWithRedirectToContactAction(static::OBJECT_ID, static::CONTACT_ID); + $this->modelFactory->expects($this->once()) + ->method('getModel') + ->willReturn($this->model); + + $this->formController->newWithRedirectToContactAction( + $this->formFactory, + $this->routeProvider, + $this->customItemModel, + $this->customObjectModel, + $this->permissionProvider, + static::OBJECT_ID, + static::CONTACT_ID + ); } public function testNewWithRedirectToContactActionWithChildObject(): void @@ -282,7 +344,19 @@ function ($newCustomItem) { ) ->willReturn($this->form); - $this->formController->newWithRedirectToContactAction(static::OBJECT_ID, static::CONTACT_ID); + $this->modelFactory->expects($this->once()) + ->method('getModel') + ->willReturn($this->model); + + $this->formController->newWithRedirectToContactAction( + $this->formFactory, + $this->routeProvider, + $this->customItemModel, + $this->customObjectModel, + $this->permissionProvider, + static::OBJECT_ID, + static::CONTACT_ID + ); } public function testEditActionIfCustomItemNotFound(): void @@ -294,7 +368,21 @@ public function testEditActionIfCustomItemNotFound(): void $this->routeProvider->expects($this->never()) ->method('buildEditRoute'); - $this->formController->editAction(self::OBJECT_ID, self::ITEM_ID); + $post = $this->createMock(ParameterBag::class); + $this->request->request = $post; + $post->expects($this->once()) + ->method('all') + ->willReturn([]); + + $this->formController->editAction( + $this->formFactory, + $this->routeProvider, + $this->customItemModel, + $this->lockFlashMessageHelper, + $this->permissionProvider, + self::OBJECT_ID, + self::ITEM_ID + ); } public function testEditActionIfCustomItemForbidden(): void @@ -312,7 +400,15 @@ public function testEditActionIfCustomItemForbidden(): void $this->expectException(AccessDeniedHttpException::class); - $this->formController->editAction(self::OBJECT_ID, self::ITEM_ID); + $this->formController->editAction( + $this->formFactory, + $this->routeProvider, + $this->customItemModel, + $this->lockFlashMessageHelper, + $this->permissionProvider, + self::OBJECT_ID, + self::ITEM_ID + ); } public function testEditAction(): void @@ -338,7 +434,19 @@ public function testEditAction(): void $this->assertRenderFormForItem($this->customItem); - $this->formController->editAction(self::OBJECT_ID, self::ITEM_ID); + $this->modelFactory->expects($this->once()) + ->method('getModel') + ->willReturn($this->model); + + $this->formController->editAction( + $this->formFactory, + $this->routeProvider, + $this->customItemModel, + $this->lockFlashMessageHelper, + $this->permissionProvider, + self::OBJECT_ID, + self::ITEM_ID + ); } public function testEditWithRedirectToContactAction(): void @@ -351,7 +459,7 @@ public function getId() }; $customItem = new class($customObject) extends CustomItem { - public function getId() + public function getId(): int { return FormControllerTest::ITEM_ID; } @@ -378,7 +486,20 @@ public function getId() $this->assertRenderFormForItem($customItem, static::CONTACT_ID); - $this->formController->editWithRedirectToContactAction(self::OBJECT_ID, self::ITEM_ID, static::CONTACT_ID); + $this->modelFactory->expects($this->once()) + ->method('getModel') + ->willReturn($this->model); + + $this->formController->editWithRedirectToContactAction( + $this->formFactory, + $this->routeProvider, + $this->customItemModel, + $this->lockFlashMessageHelper, + $this->permissionProvider, + self::OBJECT_ID, + self::ITEM_ID, + static::CONTACT_ID + ); } public function testEditWithRedirectToContactActionWithChildObject(): void @@ -401,7 +522,7 @@ public function getId() }; $customItem = new class($customObject) extends CustomItem { - public function getId() + public function getId(): int { return FormControllerTest::ITEM_ID; } @@ -409,7 +530,7 @@ public function getId() public function findChildCustomItem(): CustomItem { return new class($this->getCustomObject()->getRelationshipObject()) extends CustomItem { - public function getId() + public function getId(): int { return 777; } @@ -452,7 +573,20 @@ function (CustomItem $childCustomItem) { $this->assertRenderFormForItem($customItem, static::CONTACT_ID); - $this->formController->editWithRedirectToContactAction(self::OBJECT_ID, self::ITEM_ID, static::CONTACT_ID); + $this->modelFactory->expects($this->once()) + ->method('getModel') + ->willReturn($this->model); + + $this->formController->editWithRedirectToContactAction( + $this->formFactory, + $this->routeProvider, + $this->customItemModel, + $this->lockFlashMessageHelper, + $this->permissionProvider, + self::OBJECT_ID, + self::ITEM_ID, + static::CONTACT_ID + ); } public function testEditWithRedirectToContactActionIfCustomItemNotFound(): void @@ -464,7 +598,22 @@ public function testEditWithRedirectToContactActionIfCustomItemNotFound(): void $this->routeProvider->expects($this->never()) ->method('buildEditRouteWithRedirectToContact'); - $this->formController->editWithRedirectToContactAction(self::OBJECT_ID, self::ITEM_ID, static::CONTACT_ID); + $post = $this->createMock(ParameterBag::class); + $this->request->request = $post; + $post->expects($this->once()) + ->method('all') + ->willReturn([]); + + $this->formController->editWithRedirectToContactAction( + $this->formFactory, + $this->routeProvider, + $this->customItemModel, + $this->lockFlashMessageHelper, + $this->permissionProvider, + self::OBJECT_ID, + self::ITEM_ID, + static::CONTACT_ID + ); } public function testEditWithRedirectToContactActionIfCustomItemForbidden(): void @@ -482,7 +631,16 @@ public function testEditWithRedirectToContactActionIfCustomItemForbidden(): void $this->expectException(AccessDeniedHttpException::class); - $this->formController->editWithRedirectToContactAction(self::OBJECT_ID, self::ITEM_ID, static::CONTACT_ID); + $this->formController->editWithRedirectToContactAction( + $this->formFactory, + $this->routeProvider, + $this->customItemModel, + $this->lockFlashMessageHelper, + $this->permissionProvider, + self::OBJECT_ID, + self::ITEM_ID, + static::CONTACT_ID + ); } public function testEditWithRedirectToContactActionWhenTheItemIsLocked() @@ -500,21 +658,21 @@ public function testEditWithRedirectToContactActionWhenTheItemIsLocked() ->method('buildEditRouteWithRedirectToContact') ->with(self::OBJECT_ID, self::ITEM_ID, static::CONTACT_ID); - $userMock = $this->createMock(User::class); - $this->userHelper->expects($this->once()) - ->method('getUser') - ->willReturn($userMock); - - $userMock->expects($this->once()) - ->method('isAdmin') - ->willReturn(true); - $this->routeProvider->expects($this->once()) ->method('buildViewRoute') ->with(static::OBJECT_ID, static::ITEM_ID) ->willReturn('https://redirect.url'); - $this->formController->editWithRedirectToContactAction(self::OBJECT_ID, self::ITEM_ID, static::CONTACT_ID); + $this->formController->editWithRedirectToContactAction( + $this->formFactory, + $this->routeProvider, + $this->customItemModel, + $this->lockFlashMessageHelper, + $this->permissionProvider, + self::OBJECT_ID, + self::ITEM_ID, + static::CONTACT_ID + ); } public function testEditActionWhenTheItemIsLocked() @@ -532,21 +690,20 @@ public function testEditActionWhenTheItemIsLocked() ->method('buildEditRoute') ->with(self::OBJECT_ID, self::ITEM_ID); - $userMock = $this->createMock(User::class); - $this->userHelper->expects($this->once()) - ->method('getUser') - ->willReturn($userMock); - - $userMock->expects($this->once()) - ->method('isAdmin') - ->willReturn(true); - $this->routeProvider->expects($this->once()) ->method('buildViewRoute') ->with(static::OBJECT_ID, static::ITEM_ID) ->willReturn('https://redirect.url'); - $this->formController->editAction(self::OBJECT_ID, self::ITEM_ID); + $this->formController->editAction( + $this->formFactory, + $this->routeProvider, + $this->customItemModel, + $this->lockFlashMessageHelper, + $this->permissionProvider, + self::OBJECT_ID, + self::ITEM_ID + ); } public function testCloneAction(): void @@ -567,7 +724,18 @@ public function testCloneAction(): void $this->assertRenderFormForItem($this->customItem); - $this->formController->cloneAction(self::OBJECT_ID, self::ITEM_ID); + $this->modelFactory->expects($this->once()) + ->method('getModel') + ->willReturn($this->model); + + $this->formController->cloneAction( + $this->formFactory, + $this->routeProvider, + $this->customItemModel, + $this->permissionProvider, + self::OBJECT_ID, + self::ITEM_ID + ); } public function testCloneActionIfCustomItemNotFound(): void @@ -579,7 +747,20 @@ public function testCloneActionIfCustomItemNotFound(): void $this->routeProvider->expects($this->never()) ->method('buildCloneRoute'); - $this->formController->cloneAction(self::OBJECT_ID, self::ITEM_ID); + $post = $this->createMock(ParameterBag::class); + $this->request->request = $post; + $post->expects($this->once()) + ->method('all') + ->willReturn([]); + + $this->formController->cloneAction( + $this->formFactory, + $this->routeProvider, + $this->customItemModel, + $this->permissionProvider, + self::OBJECT_ID, + self::ITEM_ID + ); } public function testCloneActionIfCustomItemForbidden(): void @@ -597,7 +778,14 @@ public function testCloneActionIfCustomItemForbidden(): void $this->expectException(AccessDeniedHttpException::class); - $this->formController->cloneAction(self::OBJECT_ID, self::ITEM_ID); + $this->formController->cloneAction( + $this->formFactory, + $this->routeProvider, + $this->customItemModel, + $this->permissionProvider, + self::OBJECT_ID, + self::ITEM_ID + ); } private function assertRenderFormForItem(CustomItem $customItem, ?int $contactId = null): void diff --git a/Tests/Unit/Controller/CustomItem/LinkControllerTest.php b/Tests/Unit/Controller/CustomItem/LinkControllerTest.php index 88b5325ca..f401033ba 100644 --- a/Tests/Unit/Controller/CustomItem/LinkControllerTest.php +++ b/Tests/Unit/Controller/CustomItem/LinkControllerTest.php @@ -4,7 +4,7 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller\CustomItem; -use Doctrine\DBAL\Driver\DriverException; +use Doctrine\DBAL\Driver\Exception as TheDriverException; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; use Mautic\CoreBundle\Service\FlashBag; use MauticPlugin\CustomObjectsBundle\Controller\CustomItem\LinkController; @@ -14,7 +14,6 @@ use MauticPlugin\CustomObjectsBundle\Model\CustomItemModel; use MauticPlugin\CustomObjectsBundle\Provider\CustomItemPermissionProvider; use MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller\ControllerTestCase; -use UnexpectedValueException; class LinkControllerTest extends ControllerTestCase { @@ -25,7 +24,7 @@ class LinkControllerTest extends ControllerTestCase private const ENTITY_TYPE = 'contact'; private $customItemModel; - private $flashBag; + private $permissionProvider; /** @@ -37,15 +36,9 @@ protected function setUp(): void { parent::setUp(); - $this->customItemModel = $this->createMock(CustomItemModel::class); - $this->flashBag = $this->createMock(FlashBag::class); - $this->permissionProvider = $this->createMock(CustomItemPermissionProvider::class); - $this->linkController = new LinkController( - $this->customItemModel, - $this->permissionProvider, - $this->flashBag - ); - + $this->customItemModel = $this->createMock(CustomItemModel::class); + $this->permissionProvider = $this->createMock(CustomItemPermissionProvider::class); + $this->linkController = new LinkController(); $this->addSymfonyDependencies($this->linkController); } @@ -62,7 +55,14 @@ public function testSaveActionIfCustomItemNotFound(): void ->method('add') ->with('Item not found message', [], FlashBag::LEVEL_ERROR); - $this->linkController->saveAction(self::ITEM_ID, self::ENTITY_TYPE, self::ENTITY_ID); + $this->linkController->saveAction( + $this->customItemModel, + $this->permissionProvider, + $this->flashBag, + self::ITEM_ID, + self::ENTITY_TYPE, + self::ENTITY_ID + ); } public function testSaveActionIfCustomItemIsLinkedAlready(): void @@ -72,8 +72,8 @@ public function testSaveActionIfCustomItemIsLinkedAlready(): void ->will( $this->throwException( new UniqueConstraintViolationException( - 'a message', - $this->createMock(DriverException::class) + $this->createMock(TheDriverException::class), + null ) ) ); @@ -89,7 +89,14 @@ public function testSaveActionIfCustomItemIsLinkedAlready(): void FlashBag::LEVEL_ERROR ); - $this->linkController->saveAction(self::ITEM_ID, self::ENTITY_TYPE, self::ENTITY_ID); + $this->linkController->saveAction( + $this->customItemModel, + $this->permissionProvider, + $this->flashBag, + self::ITEM_ID, + self::ENTITY_TYPE, + self::ENTITY_ID + ); } public function testSaveActionIfCustomItemForbidden(): void @@ -106,7 +113,14 @@ public function testSaveActionIfCustomItemForbidden(): void ->method('add') ->with('You do not have permission to edit', [], FlashBag::LEVEL_ERROR); - $this->linkController->saveAction(self::ITEM_ID, self::ENTITY_TYPE, self::ENTITY_ID); + $this->linkController->saveAction( + $this->customItemModel, + $this->permissionProvider, + $this->flashBag, + self::ITEM_ID, + self::ENTITY_TYPE, + self::ENTITY_ID + ); } public function testSaveActionIfCustomItemLinkedToUnknownEntityType(): void @@ -123,13 +137,20 @@ public function testSaveActionIfCustomItemLinkedToUnknownEntityType(): void $this->customItemModel->expects($this->once()) ->method('linkEntity') ->with($customItem, 'unicorn', self::ENTITY_ID) - ->will($this->throwException(new UnexpectedValueException('Entity unicorn cannot be linked to a custom item'))); + ->will($this->throwException(new \UnexpectedValueException('Entity unicorn cannot be linked to a custom item'))); $this->flashBag->expects($this->once()) ->method('add') ->with('Entity unicorn cannot be linked to a custom item', [], FlashBag::LEVEL_ERROR); - $this->linkController->saveAction(self::ITEM_ID, 'unicorn', self::ENTITY_ID); + $this->linkController->saveAction( + $this->customItemModel, + $this->permissionProvider, + $this->flashBag, + self::ITEM_ID, + 'unicorn', + self::ENTITY_ID + ); } public function testSaveAction(): void @@ -147,6 +168,13 @@ public function testSaveAction(): void ->method('linkEntity') ->with($customItem, self::ENTITY_TYPE, self::ENTITY_ID); - $this->linkController->saveAction(self::ITEM_ID, self::ENTITY_TYPE, self::ENTITY_ID); + $this->linkController->saveAction( + $this->customItemModel, + $this->permissionProvider, + $this->flashBag, + self::ITEM_ID, + self::ENTITY_TYPE, + self::ENTITY_ID + ); } } diff --git a/Tests/Unit/Controller/CustomItem/ListControllerTest.php b/Tests/Unit/Controller/CustomItem/ListControllerTest.php index 0484064e2..af5002b1d 100644 --- a/Tests/Unit/Controller/CustomItem/ListControllerTest.php +++ b/Tests/Unit/Controller/CustomItem/ListControllerTest.php @@ -18,9 +18,9 @@ use MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller\ControllerTestCase; use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +#[\AllowDynamicProperties] class ListControllerTest extends ControllerTestCase { private const OBJECT_ID = 33; @@ -32,6 +32,7 @@ class ListControllerTest extends ControllerTestCase private $sessionProvider; private $permissionProvider; private $routeProvider; + private $sessionProviderFactory; /** * @var ListController @@ -42,27 +43,31 @@ protected function setUp(): void { parent::setUp(); - $sessionProviderFactory = $this->createMock(SessionProviderFactory::class); - $this->requestStack = $this->createMock(RequestStack::class); - $this->customItemModel = $this->createMock(CustomItemModel::class); - $this->customObjectModel = $this->createMock(CustomObjectModel::class); - $this->sessionProvider = $this->createMock(SessionProvider::class); - $this->permissionProvider = $this->createMock(CustomItemPermissionProvider::class); - $this->routeProvider = $this->createMock(CustomItemRouteProvider::class); - $this->request = $this->createMock(Request::class); - $this->listController = new ListController( + $this->sessionProviderFactory = $this->createMock(SessionProviderFactory::class); + $this->customItemModel = $this->createMock(CustomItemModel::class); + $this->customObjectModel = $this->createMock(CustomObjectModel::class); + $this->sessionProvider = $this->createMock(SessionProvider::class); + $this->permissionProvider = $this->createMock(CustomItemPermissionProvider::class); + $this->routeProvider = $this->createMock(CustomItemRouteProvider::class); + $this->request = $this->createMock(Request::class); + + $this->listController = new ListController( + $this->managerRegistry, + $this->mauticFactory, + $this->modelFactory, + $this->userHelper, + $this->coreParametersHelper, + $this->dispatcher, + $this->translator, + $this->flashBag, $this->requestStack, - $sessionProviderFactory, - $this->customItemModel, - $this->customObjectModel, - $this->permissionProvider, - $this->routeProvider + $this->security ); $this->addSymfonyDependencies($this->listController); $this->requestStack->method('getCurrentRequest')->willReturn($this->request); - $sessionProviderFactory->method('createItemProvider')->willReturn($this->sessionProvider); + $this->sessionProviderFactory->method('createItemProvider')->willReturn($this->sessionProvider); } public function testListActionIfCustomObjectNotFound(): void @@ -74,7 +79,21 @@ public function testListActionIfCustomObjectNotFound(): void $this->customItemModel->expects($this->never()) ->method('getTableData'); - $this->listController->listAction(self::OBJECT_ID, self::PAGE); + $post = $this->createMock(ParameterBag::class); + $this->request->request = $post; + $post->expects($this->once()) + ->method('all') + ->willReturn([]); + + $this->listController->listAction( + $this->sessionProviderFactory, + $this->customItemModel, + $this->customObjectModel, + $this->permissionProvider, + $this->routeProvider, + self::OBJECT_ID, + self::PAGE + ); } public function testListActionIfForbidden(): void @@ -86,9 +105,21 @@ public function testListActionIfForbidden(): void $this->customObjectModel->expects($this->never()) ->method('fetchEntity'); + $this->security->expects($this->once()) + ->method('isAnonymous') + ->willReturn(true); + $this->expectException(AccessDeniedHttpException::class); - $this->listController->listAction(self::OBJECT_ID, self::PAGE); + $this->listController->listAction( + $this->sessionProviderFactory, + $this->customItemModel, + $this->customObjectModel, + $this->permissionProvider, + $this->routeProvider, + self::OBJECT_ID, + self::PAGE + ); } public function testListAction(): void @@ -148,7 +179,15 @@ public function testListAction(): void ->method('setPageLimit') ->with($pageLimit); - $this->listController->listAction(self::OBJECT_ID, self::PAGE); + $this->listController->listAction( + $this->sessionProviderFactory, + $this->customItemModel, + $this->customObjectModel, + $this->permissionProvider, + $this->routeProvider, + self::OBJECT_ID, + self::PAGE + ); } public function testListActionWithQueryParamAndAjax(): void @@ -225,6 +264,14 @@ public function testListActionWithQueryParamAndAjax(): void ->method('setPageLimit') ->with($pageLimit); - $this->listController->listAction(self::OBJECT_ID, self::PAGE); + $this->listController->listAction( + $this->sessionProviderFactory, + $this->customItemModel, + $this->customObjectModel, + $this->permissionProvider, + $this->routeProvider, + self::OBJECT_ID, + self::PAGE + ); } } diff --git a/Tests/Unit/Controller/CustomItem/LookupControllerTest.php b/Tests/Unit/Controller/CustomItem/LookupControllerTest.php index 5b3de0385..1363d77b3 100644 --- a/Tests/Unit/Controller/CustomItem/LookupControllerTest.php +++ b/Tests/Unit/Controller/CustomItem/LookupControllerTest.php @@ -12,15 +12,14 @@ use MauticPlugin\CustomObjectsBundle\Provider\CustomItemPermissionProvider; use MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller\ControllerTestCase; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\RequestStack; class LookupControllerTest extends ControllerTestCase { private const OBJECT_ID = 22; private $customItemModel; + private $permissionProvider; - private $flashBag; /** * @var LookupController @@ -32,16 +31,9 @@ protected function setUp(): void parent::setUp(); $this->customItemModel = $this->createMock(CustomItemModel::class); - $this->requestStack = $this->createMock(RequestStack::class); $this->permissionProvider = $this->createMock(CustomItemPermissionProvider::class); - $this->flashBag = $this->createMock(FlashBag::class); $this->request = $this->createMock(Request::class); - $this->lookupController = new LookupController( - $this->requestStack, - $this->customItemModel, - $this->permissionProvider, - $this->flashBag - ); + $this->lookupController = new LookupController(); $this->addSymfonyDependencies($this->lookupController); } @@ -59,7 +51,13 @@ public function testListActionIfForbidden(): void $this->customItemModel->expects($this->never()) ->method('getLookupData'); - $this->lookupController->listAction(self::OBJECT_ID); + $this->lookupController->listAction( + $this->request, + $this->customItemModel, + $this->permissionProvider, + $this->flashBag, + self::OBJECT_ID + ); } public function testListAction(): void @@ -85,7 +83,13 @@ public function testListAction(): void return true; })); - $this->lookupController->listAction(self::OBJECT_ID); + $this->lookupController->listAction( + $this->request, + $this->customItemModel, + $this->permissionProvider, + $this->flashBag, + self::OBJECT_ID + ); } public function testListActionForContactEntity(): void @@ -116,6 +120,12 @@ public function testListActionForContactEntity(): void return true; })); - $this->lookupController->listAction(self::OBJECT_ID); + $this->lookupController->listAction( + $this->request, + $this->customItemModel, + $this->permissionProvider, + $this->flashBag, + self::OBJECT_ID + ); } } diff --git a/Tests/Unit/Controller/CustomItem/SaveControllerTest.php b/Tests/Unit/Controller/CustomItem/SaveControllerTest.php index 5f96f67cb..72927327c 100644 --- a/Tests/Unit/Controller/CustomItem/SaveControllerTest.php +++ b/Tests/Unit/Controller/CustomItem/SaveControllerTest.php @@ -4,7 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller\CustomItem; -use Mautic\CoreBundle\Service\FlashBag; use Mautic\UserBundle\Entity\User; use MauticPlugin\CustomObjectsBundle\Controller\CustomItem\SaveController; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; @@ -24,9 +23,9 @@ use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +#[\AllowDynamicProperties] class SaveControllerTest extends ControllerTestCase { public const OBJECT_ID = 33; @@ -50,11 +49,6 @@ class SaveControllerTest extends ControllerTestCase */ private $customObjectModel; - /** - * @var MockObject|FlashBag - */ - private $flashBag; - /** * @var MockObject|CustomItemPermissionProvider */ @@ -89,26 +83,34 @@ protected function setUp(): void { parent::setUp(); - $this->formFactory = $this->createMock(FormFactoryInterface::class); - $this->customItemModel = $this->createMock(CustomItemModel::class); - $this->customObjectModel = $this->createMock(CustomObjectModel::class); - $this->flashBag = $this->createMock(FlashBag::class); - $this->permissionProvider = $this->createMock(CustomItemPermissionProvider::class); - $this->routeProvider = $this->createMock(CustomItemRouteProvider::class); - $this->lockFlashMessageHelper = $this->createMock(LockFlashMessageHelper::class); - $this->requestStack = $this->createMock(RequestStack::class); - $this->request = new Request(); - $this->customItem = $this->createMock(CustomItem::class); - $this->form = $this->createMock(FormInterface::class); - $this->saveController = new SaveController( - $this->requestStack, - $this->formFactory, + $this->formFactory = $this->createMock(FormFactoryInterface::class); + $this->customItemModel = $this->createMock(CustomItemModel::class); + $this->customObjectModel = $this->createMock(CustomObjectModel::class); + $this->permissionProvider = $this->createMock(CustomItemPermissionProvider::class); + $this->routeProvider = $this->createMock(CustomItemRouteProvider::class); + $this->lockFlashMessageHelper = $this->createMock(LockFlashMessageHelper::class); + $this->request = new Request(); + $this->customItem = $this->createMock(CustomItem::class); + $this->form = $this->createMock(FormInterface::class); + + $userMock = $this->createMock(User::class); + $userMock->method('isAdmin') + ->willReturn(true); + + $this->userHelper->expects($this->any())->method('getUser') + ->willReturn($userMock); + + $this->saveController = new SaveController( + $this->managerRegistry, + $this->mauticFactory, + $this->modelFactory, + $this->userHelper, + $this->coreParametersHelper, + $this->dispatcher, + $this->translator, $this->flashBag, - $this->customItemModel, - $this->customObjectModel, - $this->permissionProvider, - $this->routeProvider, - $this->lockFlashMessageHelper + $this->requestStack, + $this->security ); $this->addSymfonyDependencies($this->saveController); @@ -132,7 +134,17 @@ public function testSaveActionIfExistingCustomItemNotFound(): void $this->permissionProvider->expects($this->never()) ->method('canCreate'); - $this->saveController->saveAction(self::OBJECT_ID, self::ITEM_ID); + $this->saveController->saveAction( + $this->formFactory, + $this->flashBag, + $this->customItemModel, + $this->customObjectModel, + $this->permissionProvider, + $this->routeProvider, + $this->lockFlashMessageHelper, + self::OBJECT_ID, + self::ITEM_ID + ); } public function testSaveActionIfExistingCustomItemIsForbidden(): void @@ -150,7 +162,17 @@ public function testSaveActionIfExistingCustomItemIsForbidden(): void $this->expectException(AccessDeniedHttpException::class); - $this->saveController->saveAction(self::OBJECT_ID, self::ITEM_ID); + $this->saveController->saveAction( + $this->formFactory, + $this->flashBag, + $this->customItemModel, + $this->customObjectModel, + $this->permissionProvider, + $this->routeProvider, + $this->lockFlashMessageHelper, + self::OBJECT_ID, + self::ITEM_ID + ); } public function testSaveActionForExistingCustomItemWithValidForm(): void @@ -248,7 +270,17 @@ public function testSaveActionForExistingCustomItemWithValidForm(): void Assert::assertSame(Request::METHOD_GET, $this->request->getMethod()); - $this->saveController->saveAction(self::OBJECT_ID, self::ITEM_ID); + $this->saveController->saveAction( + $this->formFactory, + $this->flashBag, + $this->customItemModel, + $this->customObjectModel, + $this->permissionProvider, + $this->routeProvider, + $this->lockFlashMessageHelper, + self::OBJECT_ID, + self::ITEM_ID + ); } public function testThatSaveActionRedirectToContactViewPageWhenContactIdIsSet(): void @@ -330,7 +362,17 @@ public function testThatSaveActionRedirectToContactViewPageWhenContactIdIsSet(): ->method('generate') ->willReturn('someRedirectUrl'); - $this->saveController->saveAction(self::OBJECT_ID, self::ITEM_ID); + $this->saveController->saveAction( + $this->formFactory, + $this->flashBag, + $this->customItemModel, + $this->customObjectModel, + $this->permissionProvider, + $this->routeProvider, + $this->lockFlashMessageHelper, + self::OBJECT_ID, + self::ITEM_ID + ); } public function testSaveActionIfNewCustomItemIsForbidden(): void @@ -353,7 +395,16 @@ public function testSaveActionIfNewCustomItemIsForbidden(): void $this->expectException(AccessDeniedHttpException::class); - $this->saveController->saveAction(self::OBJECT_ID); + $this->saveController->saveAction( + $this->formFactory, + $this->flashBag, + $this->customItemModel, + $this->customObjectModel, + $this->permissionProvider, + $this->routeProvider, + $this->lockFlashMessageHelper, + self::OBJECT_ID + ); } public function testSaveActionForNewCustomItemWithInvalidForm(): void @@ -404,7 +455,16 @@ public function testSaveActionForNewCustomItemWithInvalidForm(): void $this->customItemModel->expects($this->never()) ->method('save'); - $this->saveController->saveAction(self::OBJECT_ID); + $this->saveController->saveAction( + $this->formFactory, + $this->flashBag, + $this->customItemModel, + $this->customObjectModel, + $this->permissionProvider, + $this->routeProvider, + $this->lockFlashMessageHelper, + self::OBJECT_ID + ); } public function testSaveActionForNewCustomItemWithChildItemWhenInvalidForm(): void @@ -492,7 +552,16 @@ function (CustomItem $customItem) { $this->customItemModel->expects($this->never()) ->method('save'); - $this->saveController->saveAction(self::OBJECT_ID); + $this->saveController->saveAction( + $this->formFactory, + $this->flashBag, + $this->customItemModel, + $this->customObjectModel, + $this->permissionProvider, + $this->routeProvider, + $this->lockFlashMessageHelper, + self::OBJECT_ID + ); } public function testSaveActionWhenTheItemIsLocked(): void @@ -512,21 +581,22 @@ public function testSaveActionWhenTheItemIsLocked(): void ->with($this->customItem) ->willReturn(true); - $userMock = $this->createMock(User::class); - $this->userHelper->expects($this->once()) - ->method('getUser') - ->willReturn($userMock); - - $userMock->expects($this->once()) - ->method('isAdmin') - ->willReturn(true); - $this->routeProvider->expects($this->once()) ->method('buildViewRoute') ->with(static::OBJECT_ID, static::ITEM_ID) ->willReturn('https://redirect.url'); - $this->saveController->saveAction(self::OBJECT_ID, self::ITEM_ID); + $this->saveController->saveAction( + $this->formFactory, + $this->flashBag, + $this->customItemModel, + $this->customObjectModel, + $this->permissionProvider, + $this->routeProvider, + $this->lockFlashMessageHelper, + self::OBJECT_ID, + self::ITEM_ID + ); } public function testThatUserIsGettingRedirectedWhenWeEditCustomItemAndContactIdIsSpecified(): void @@ -621,6 +691,16 @@ public function testThatUserIsGettingRedirectedWhenWeEditCustomItemAndContactIdI Assert::assertSame(Request::METHOD_GET, $this->request->getMethod()); - $this->saveController->saveAction(self::OBJECT_ID, self::ITEM_ID); + $this->saveController->saveAction( + $this->formFactory, + $this->flashBag, + $this->customItemModel, + $this->customObjectModel, + $this->permissionProvider, + $this->routeProvider, + $this->lockFlashMessageHelper, + self::OBJECT_ID, + self::ITEM_ID + ); } } diff --git a/Tests/Unit/Controller/CustomItem/UnlinkControllerTest.php b/Tests/Unit/Controller/CustomItem/UnlinkControllerTest.php index 54376f4ff..c548accf1 100644 --- a/Tests/Unit/Controller/CustomItem/UnlinkControllerTest.php +++ b/Tests/Unit/Controller/CustomItem/UnlinkControllerTest.php @@ -15,7 +15,6 @@ use MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller\ControllerTestCase; use PHPUnit\Framework\Assert; use PHPUnit\Framework\MockObject\MockObject; -use UnexpectedValueException; class UnlinkControllerTest extends ControllerTestCase { @@ -30,11 +29,6 @@ class UnlinkControllerTest extends ControllerTestCase */ private $customItemModel; - /** - * @var MockObject|FlashBag - */ - private $flashBag; - /** * @var MockObject|CustomItemPermissionProvider */ @@ -50,13 +44,8 @@ protected function setUp(): void parent::setUp(); $this->customItemModel = $this->createMock(CustomItemModel::class); - $this->flashBag = $this->createMock(FlashBag::class); $this->permissionProvider = $this->createMock(CustomItemPermissionProvider::class); - $this->unlinkController = new UnlinkController( - $this->customItemModel, - $this->permissionProvider, - $this->flashBag - ); + $this->unlinkController = new UnlinkController(); $this->addSymfonyDependencies($this->unlinkController); } @@ -77,7 +66,14 @@ public function testSaveActionIfCustomItemNotFound(): void $this->customItemModel->expects($this->never()) ->method('unlinkEntity'); - $this->unlinkController->saveAction(self::ITEM_ID, self::ENTITY_TYPE, self::ENTITY_ID); + $this->unlinkController->saveAction( + $this->customItemModel, + $this->permissionProvider, + $this->flashBag, + self::ITEM_ID, + self::ENTITY_TYPE, + self::ENTITY_ID + ); } public function testSaveActionIfForbidden(): void @@ -100,7 +96,14 @@ public function testSaveActionIfForbidden(): void $this->customItemModel->expects($this->never()) ->method('unlinkEntity'); - $this->unlinkController->saveAction(self::ITEM_ID, self::ENTITY_TYPE, self::ENTITY_ID); + $this->unlinkController->saveAction( + $this->customItemModel, + $this->permissionProvider, + $this->flashBag, + self::ITEM_ID, + self::ENTITY_TYPE, + self::ENTITY_ID + ); } public function testSaveActionIfEntityTypeNotFound(): void @@ -111,19 +114,26 @@ public function testSaveActionIfEntityTypeNotFound(): void $this->customItemModel->expects($this->once()) ->method('unlinkEntity') - ->will($this->throwException(new UnexpectedValueException('Entity unicorn cannot be linked to a custom item'))); + ->will($this->throwException(new \UnexpectedValueException('Entity unicorn cannot be linked to a custom item'))); $this->flashBag->expects($this->once()) ->method('add') ->with('Entity unicorn cannot be linked to a custom item', [], FlashBag::LEVEL_ERROR); - $this->unlinkController->saveAction(self::ITEM_ID, 'unicorn', self::ENTITY_ID); + $this->unlinkController->saveAction( + $this->customItemModel, + $this->permissionProvider, + $this->flashBag, + self::ITEM_ID, + 'unicorn', + self::ENTITY_ID + ); } public function testSaveAction(): void { $customItem = new class(new CustomObject()) extends CustomItem { - public function getId() + public function getId(): int { return UnlinkControllerTest::ITEM_ID; } @@ -143,7 +153,14 @@ public function getId() $this->customItemModel->expects($this->never()) ->method('delete'); - $this->unlinkController->saveAction(self::ITEM_ID, self::ENTITY_TYPE, self::ENTITY_ID); + $this->unlinkController->saveAction( + $this->customItemModel, + $this->permissionProvider, + $this->flashBag, + self::ITEM_ID, + self::ENTITY_TYPE, + self::ENTITY_ID + ); } public function testSaveActionWithChildItem(): void @@ -157,7 +174,7 @@ public function testSaveActionWithChildItem(): void $customObject->setRelationshipObject($childCustomObject); $customItem = new class($customObject) extends CustomItem { - public function getId() + public function getId(): int { return UnlinkControllerTest::ITEM_ID; } @@ -190,6 +207,13 @@ function (CustomItem $childCustomItem) use ($childCustomObject) { } )); - $this->unlinkController->saveAction(self::ITEM_ID, self::ENTITY_TYPE, self::ENTITY_ID); + $this->unlinkController->saveAction( + $this->customItemModel, + $this->permissionProvider, + $this->flashBag, + self::ITEM_ID, + self::ENTITY_TYPE, + self::ENTITY_ID + ); } } diff --git a/Tests/Unit/Controller/CustomItem/ViewControllerTest.php b/Tests/Unit/Controller/CustomItem/ViewControllerTest.php index e8ea8b4e1..c2e0ed8df 100644 --- a/Tests/Unit/Controller/CustomItem/ViewControllerTest.php +++ b/Tests/Unit/Controller/CustomItem/ViewControllerTest.php @@ -17,9 +17,11 @@ use MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller\ControllerTestCase; use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\FormInterface; -use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpFoundation\ParameterBag; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +#[\AllowDynamicProperties] class ViewControllerTest extends ControllerTestCase { private const OBJECT_ID = 33; @@ -49,18 +51,25 @@ protected function setUp(): void $this->auditLog = $this->createMock(AuditLogModel::class); $this->permissionProvider = $this->createMock(CustomItemPermissionProvider::class); $this->routeProvider = $this->createMock(CustomItemRouteProvider::class); - $this->requestStack = $this->createMock(RequestStack::class); $this->formFactory = $this->createMock(FormFactoryInterface::class); $this->form = $this->createMock(FormInterface::class); $this->customItem = $this->createMock(CustomItem::class); + $this->request = $this->createMock(Request::class); + $this->requestStack->expects($this->any()) + ->method('getCurrentRequest') + ->willReturn($this->request); + $this->viewController = new ViewController( + $this->managerRegistry, + $this->mauticFactory, + $this->modelFactory, + $this->userHelper, + $this->coreParametersHelper, + $this->dispatcher, + $this->translator, + $this->flashBag, $this->requestStack, - $this->formFactory, - $this->customItemModel, - $this->customItemXrefContactModel, - $this->auditLog, - $this->permissionProvider, - $this->routeProvider + $this->security ); $this->addSymfonyDependencies($this->viewController); @@ -78,7 +87,22 @@ public function testViewActionIfCustomItemNotFound(): void $this->routeProvider->expects($this->never()) ->method('buildViewRoute'); - $this->viewController->viewAction(self::OBJECT_ID, self::ITEM_ID); + $post = $this->createMock(ParameterBag::class); + $this->request->request = $post; + $post->expects($this->once()) + ->method('all') + ->willReturn([]); + + $this->viewController->viewAction( + $this->formFactory, + $this->customItemModel, + $this->customItemXrefContactModel, + $this->auditLog, + $this->permissionProvider, + $this->routeProvider, + self::OBJECT_ID, + self::ITEM_ID + ); } public function testViewActionIfCustomItemForbidden(): void @@ -94,9 +118,22 @@ public function testViewActionIfCustomItemForbidden(): void $this->routeProvider->expects($this->never()) ->method('buildViewRoute'); + $this->security->expects($this->once()) + ->method('isAnonymous') + ->willReturn(true); + $this->expectException(AccessDeniedHttpException::class); - $this->viewController->viewAction(self::OBJECT_ID, self::ITEM_ID); + $this->viewController->viewAction( + $this->formFactory, + $this->customItemModel, + $this->customItemXrefContactModel, + $this->auditLog, + $this->permissionProvider, + $this->routeProvider, + self::OBJECT_ID, + self::ITEM_ID + ); } public function testViewAction(): void @@ -154,6 +191,15 @@ public function testViewAction(): void ->method('getLogForObject') ->with('customItem', self::ITEM_ID, '2019-01-04 10:20:30', 10, 'customObjects'); - $this->viewController->viewAction(self::OBJECT_ID, self::ITEM_ID); + $this->viewController->viewAction( + $this->formFactory, + $this->customItemModel, + $this->customItemXrefContactModel, + $this->auditLog, + $this->permissionProvider, + $this->routeProvider, + self::OBJECT_ID, + self::ITEM_ID + ); } } diff --git a/Tests/Unit/Controller/CustomObject/CancelControllerTest.php b/Tests/Unit/Controller/CustomObject/CancelControllerTest.php index 3e1c8b628..3d6cc3ae7 100644 --- a/Tests/Unit/Controller/CustomObject/CancelControllerTest.php +++ b/Tests/Unit/Controller/CustomObject/CancelControllerTest.php @@ -22,24 +22,32 @@ class CancelControllerTest extends ControllerTestCase * @var CancelController */ private $cancelController; + private $sessionProviderFactory; protected function setUp(): void { parent::setUp(); - $sessionProviderFactory = $this->createMock(SessionProviderFactory::class); - $this->sessionProvider = $this->createMock(SessionProvider::class); - $this->routeProvider = $this->createMock(CustomObjectRouteProvider::class); - $this->customObjectModel = $this->createMock(CustomObjectModel::class); + $this->sessionProviderFactory = $this->createMock(SessionProviderFactory::class); + $this->sessionProvider = $this->createMock(SessionProvider::class); + $this->routeProvider = $this->createMock(CustomObjectRouteProvider::class); + $this->customObjectModel = $this->createMock(CustomObjectModel::class); $this->cancelController = new CancelController( - $sessionProviderFactory, - $this->routeProvider, - $this->customObjectModel + $this->managerRegistry, + $this->mauticFactory, + $this->modelFactory, + $this->userHelper, + $this->coreParametersHelper, + $this->dispatcher, + $this->translator, + $this->flashBag, + $this->requestStack, + $this->security ); $this->addSymfonyDependencies($this->cancelController); - $sessionProviderFactory->method('createObjectProvider')->willReturn($this->sessionProvider); + $this->sessionProviderFactory->method('createObjectProvider')->willReturn($this->sessionProvider); } public function testCancelAction(): void @@ -58,7 +66,12 @@ public function testCancelAction(): void ->with($pageNumber) ->willReturn('some/route'); - $this->cancelController->cancelAction(null); + $this->cancelController->cancelAction( + $this->sessionProviderFactory, + $this->routeProvider, + $this->customObjectModel, + null + ); } public function testCancelActionWithEntityUnlock(): void @@ -85,6 +98,11 @@ public function testCancelActionWithEntityUnlock(): void ->with($pageNumber) ->willReturn('some/route'); - $this->cancelController->cancelAction($customObjectId); + $this->cancelController->cancelAction( + $this->sessionProviderFactory, + $this->routeProvider, + $this->customObjectModel, + $customObjectId + ); } } diff --git a/Tests/Unit/Controller/CustomObject/DeleteControllerTest.php b/Tests/Unit/Controller/CustomObject/DeleteControllerTest.php index e5bb892fd..6004f4c23 100644 --- a/Tests/Unit/Controller/CustomObject/DeleteControllerTest.php +++ b/Tests/Unit/Controller/CustomObject/DeleteControllerTest.php @@ -5,7 +5,6 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller\CustomObject; use Doctrine\Common\Collections\ArrayCollection; -use Mautic\CoreBundle\Service\FlashBag; use Mautic\LeadBundle\Entity\LeadList; use MauticPlugin\CustomObjectsBundle\Controller\CustomObject\DeleteController; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; @@ -17,10 +16,9 @@ use MauticPlugin\CustomObjectsBundle\Provider\SessionProvider; use MauticPlugin\CustomObjectsBundle\Provider\SessionProviderFactory; use MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller\ControllerTestCase; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; -use Symfony\Component\Translation\TranslatorInterface; class DeleteControllerTest extends ControllerTestCase { @@ -28,56 +26,52 @@ class DeleteControllerTest extends ControllerTestCase private $customObjectModel; private $sessionProvider; - private $flashBag; - private $permissionProvider; - /** - * @var EventDispatcherInterface - */ - private $eventDispatcher; + private $permissionProvider; /** * @var DeleteController */ private $deleteController; - /** - * @var TranslatorInterface - */ - private $translator; - /** * @var int */ private $leadListIndex; + private $sessionProviderFactory; protected function setUp(): void { parent::setUp(); - $sessionProviderFactory = $this->createMock(SessionProviderFactory::class); - $this->customObjectModel = $this->createMock(CustomObjectModel::class); - $this->sessionProvider = $this->createMock(SessionProvider::class); - $this->flashBag = $this->createMock(FlashBag::class); - $this->permissionProvider = $this->createMock(CustomObjectPermissionProvider::class); - $this->request = $this->createMock(Request::class); - $this->eventDispatcher = $this->createMock(EventDispatcherInterface::class); + $this->sessionProviderFactory = $this->createMock(SessionProviderFactory::class); + $this->customObjectModel = $this->createMock(CustomObjectModel::class); + $this->sessionProvider = $this->createMock(SessionProvider::class); + $this->permissionProvider = $this->createMock(CustomObjectPermissionProvider::class); + $this->request = $this->createMock(Request::class); + + $this->requestStack->expects($this->any()) + ->method('getCurrentRequest') + ->willReturn($this->request); + $this->deleteController = new DeleteController( - $this->customObjectModel, - $sessionProviderFactory, + $this->managerRegistry, + $this->mauticFactory, + $this->modelFactory, + $this->userHelper, + $this->coreParametersHelper, + $this->dispatcher, + $this->translator, $this->flashBag, - $this->permissionProvider, - $this->eventDispatcher + $this->requestStack, + $this->security ); $this->addSymfonyDependencies($this->deleteController); $this->request->method('isXmlHttpRequest')->willReturn(true); $this->request->method('getRequestUri')->willReturn('https://a.b'); - $sessionProviderFactory->method('createObjectProvider')->willReturn($this->sessionProvider); - - $this->translator = $this->createMock(TranslatorInterface::class); - $this->deleteController->setTranslator($this->translator); + $this->sessionProviderFactory->method('createObjectProvider')->willReturn($this->sessionProvider); $this->leadListIndex = 1; } @@ -94,7 +88,20 @@ public function testDeleteActionIfCustomObjectNotFound(): void $this->flashBag->expects($this->never()) ->method('add'); - $this->deleteController->deleteAction(self::OBJECT_ID); + $post = $this->createMock(ParameterBag::class); + $this->request->request = $post; + $post->expects($this->once()) + ->method('all') + ->willReturn([]); + + $this->deleteController->deleteAction( + $this->sessionProviderFactory, + $this->customObjectModel, + $this->flashBag, + $this->permissionProvider, + $this->dispatcher, + self::OBJECT_ID + ); } public function testDeleteActionIfCustomObjectForbidden(): void @@ -113,9 +120,20 @@ public function testDeleteActionIfCustomObjectForbidden(): void $this->flashBag->expects($this->never()) ->method('add'); + $this->security->expects($this->once()) + ->method('isAnonymous') + ->willReturn(true); + $this->expectException(AccessDeniedHttpException::class); - $this->deleteController->deleteAction(self::OBJECT_ID); + $this->deleteController->deleteAction( + $this->sessionProviderFactory, + $this->customObjectModel, + $this->flashBag, + $this->permissionProvider, + $this->dispatcher, + self::OBJECT_ID + ); } public function testDeleteAction(): void @@ -129,14 +147,21 @@ public function testDeleteAction(): void ->with(self::OBJECT_ID) ->willReturn($customObject); - $this->eventDispatcher->expects($this->once()) + $this->dispatcher->expects($this->once()) ->method('dispatch'); $this->sessionProvider->expects($this->once()) ->method('getPage') ->willReturn(3); - $this->deleteController->deleteAction(self::OBJECT_ID); + $this->deleteController->deleteAction( + $this->sessionProviderFactory, + $this->customObjectModel, + $this->flashBag, + $this->permissionProvider, + $this->dispatcher, + self::OBJECT_ID + ); } public function testThatItDisplaysErrorMessageIfThereAreRelatedSegments(): void @@ -150,7 +175,7 @@ public function testThatItDisplaysErrorMessageIfThereAreRelatedSegments(): void ->with(self::OBJECT_ID) ->willReturn($customObject); - $this->eventDispatcher->expects($this->never()) + $this->dispatcher->expects($this->never()) ->method('dispatch'); $this->flashBag->expects($this->once()) @@ -168,7 +193,14 @@ public function testThatItDisplaysErrorMessageIfThereAreRelatedSegments(): void ->method('checkIfTheCustomObjectIsUsedInSegmentFilters') ->willThrowException($inUseException); - $this->deleteController->deleteAction(self::OBJECT_ID); + $this->deleteController->deleteAction( + $this->sessionProviderFactory, + $this->customObjectModel, + $this->flashBag, + $this->permissionProvider, + $this->dispatcher, + self::OBJECT_ID + ); } private function createSegments(int $quantity): ArrayCollection diff --git a/Tests/Unit/Controller/CustomObject/FormControllerTest.php b/Tests/Unit/Controller/CustomObject/FormControllerTest.php index 2d1fd8943..04b26c651 100644 --- a/Tests/Unit/Controller/CustomObject/FormControllerTest.php +++ b/Tests/Unit/Controller/CustomObject/FormControllerTest.php @@ -4,6 +4,7 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller\CustomObject; +use Mautic\CoreBundle\Model\NotificationModel; use MauticPlugin\CustomObjectsBundle\Controller\CustomObject\FormController; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; use MauticPlugin\CustomObjectsBundle\Exception\ForbiddenException; @@ -18,9 +19,11 @@ use MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller\ControllerTestCase; use Symfony\Component\Form\FormFactory; use Symfony\Component\Form\FormInterface; +use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +#[\AllowDynamicProperties] class FormControllerTest extends ControllerTestCase { private const OBJECT_ID = 33; @@ -54,14 +57,19 @@ protected function setUp(): void $this->request = $this->createMock(Request::class); $this->customObject = $this->createMock(CustomObject::class); $this->form = $this->createMock(FormInterface::class); - $this->formController = new FormController( - $this->formFactory, - $this->customObjectModel, - $this->customFieldModel, - $this->permissionProvider, - $this->routeProvider, - $this->customFieldTypeProvider, - $this->lockFlashMessageHelper + $this->model = $this->createMock(NotificationModel::class); + + $this->formController = new FormController( + $this->managerRegistry, + $this->mauticFactory, + $this->modelFactory, + $this->userHelper, + $this->coreParametersHelper, + $this->dispatcher, + $this->translator, + $this->flashBag, + $this->requestStack, + $this->security ); $this->addSymfonyDependencies($this->formController); @@ -82,7 +90,13 @@ public function testNewActionIfForbidden(): void $this->expectException(AccessDeniedHttpException::class); - $this->formController->newAction(); + $this->formController->newAction( + $this->permissionProvider, + $this->formFactory, + $this->routeProvider, + $this->customFieldTypeProvider, + $this->customFieldModel + ); } public function testNewAction(): void @@ -110,7 +124,21 @@ public function testNewAction(): void ->method('buildSaveRoute') ->willReturn('https://list.items'); - $this->formController->newAction(); + $this->modelFactory->expects($this->once()) + ->method('getModel') + ->willReturn($this->model); + + $this->modelFactory->expects($this->once()) + ->method('getModel') + ->willReturn($this->model); + + $this->formController->newAction( + $this->permissionProvider, + $this->formFactory, + $this->routeProvider, + $this->customFieldTypeProvider, + $this->customFieldModel + ); } public function testEditActionIfCustomObjectNotFound(): void @@ -123,7 +151,22 @@ public function testEditActionIfCustomObjectNotFound(): void $this->routeProvider->expects($this->never()) ->method('buildEditRoute'); - $this->formController->editAction(self::OBJECT_ID); + $post = $this->createMock(ParameterBag::class); + $this->request->request = $post; + $post->expects($this->once()) + ->method('all') + ->willReturn([]); + + $this->formController->editAction( + $this->customObjectModel, + $this->permissionProvider, + $this->lockFlashMessageHelper, + $this->formFactory, + $this->routeProvider, + $this->customFieldTypeProvider, + $this->customFieldModel, + self::OBJECT_ID + ); } public function testEditActionIfCustomObjectForbidden(): void @@ -142,7 +185,16 @@ public function testEditActionIfCustomObjectForbidden(): void $this->expectException(AccessDeniedHttpException::class); - $this->formController->editAction(self::OBJECT_ID); + $this->formController->editAction( + $this->customObjectModel, + $this->permissionProvider, + $this->lockFlashMessageHelper, + $this->formFactory, + $this->routeProvider, + $this->customFieldTypeProvider, + $this->customFieldModel, + self::OBJECT_ID + ); } public function testEditAction(): void @@ -188,7 +240,24 @@ public function testEditAction(): void ->with(self::OBJECT_ID) ->willReturn('https://list.items'); - $this->formController->editAction(self::OBJECT_ID); + $this->modelFactory->expects($this->once()) + ->method('getModel') + ->willReturn($this->model); + + $this->modelFactory->expects($this->once()) + ->method('getModel') + ->willReturn($this->model); + + $this->formController->editAction( + $this->customObjectModel, + $this->permissionProvider, + $this->lockFlashMessageHelper, + $this->formFactory, + $this->routeProvider, + $this->customFieldTypeProvider, + $this->customFieldModel, + self::OBJECT_ID + ); } public function testCloneActionIfCustomObjectNotFound(): void @@ -201,7 +270,21 @@ public function testCloneActionIfCustomObjectNotFound(): void $this->routeProvider->expects($this->never()) ->method('buildCloneRoute'); - $this->formController->cloneAction(self::OBJECT_ID); + $post = $this->createMock(ParameterBag::class); + $this->request->request = $post; + $post->expects($this->once()) + ->method('all') + ->willReturn([]); + + $this->formController->cloneAction( + $this->customObjectModel, + $this->permissionProvider, + $this->formFactory, + $this->routeProvider, + $this->customFieldTypeProvider, + $this->customFieldModel, + self::OBJECT_ID + ); } public function testCloneActionIfCustomObjectForbidden(): void @@ -220,7 +303,15 @@ public function testCloneActionIfCustomObjectForbidden(): void $this->expectException(AccessDeniedHttpException::class); - $this->formController->cloneAction(self::OBJECT_ID); + $this->formController->cloneAction( + $this->customObjectModel, + $this->permissionProvider, + $this->formFactory, + $this->routeProvider, + $this->customFieldTypeProvider, + $this->customFieldModel, + self::OBJECT_ID + ); } public function testCloneAction(): void @@ -252,6 +343,22 @@ public function testCloneAction(): void ->method('buildSaveRoute') ->willReturn('https://list.items'); - $this->formController->cloneAction(self::OBJECT_ID); + $this->modelFactory->expects($this->once()) + ->method('getModel') + ->willReturn($this->model); + + $this->modelFactory->expects($this->once()) + ->method('getModel') + ->willReturn($this->model); + + $this->formController->cloneAction( + $this->customObjectModel, + $this->permissionProvider, + $this->formFactory, + $this->routeProvider, + $this->customFieldTypeProvider, + $this->customFieldModel, + self::OBJECT_ID + ); } } diff --git a/Tests/Unit/Controller/CustomObject/ListControllerTest.php b/Tests/Unit/Controller/CustomObject/ListControllerTest.php index c346ac8bd..0991fa819 100644 --- a/Tests/Unit/Controller/CustomObject/ListControllerTest.php +++ b/Tests/Unit/Controller/CustomObject/ListControllerTest.php @@ -16,9 +16,9 @@ use MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller\ControllerTestCase; use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +#[\AllowDynamicProperties] class ListControllerTest extends ControllerTestCase { private const PAGE = 3; @@ -37,25 +37,29 @@ protected function setUp(): void { parent::setUp(); - $sessionProviderFactory = $this->createMock(SessionProviderFactory::class); - $this->requestStack = $this->createMock(RequestStack::class); - $this->customObjectModel = $this->createMock(CustomObjectModel::class); - $this->sessionProvider = $this->createMock(SessionProvider::class); - $this->permissionProvider = $this->createMock(CustomObjectPermissionProvider::class); - $this->routeProvider = $this->createMock(CustomObjectRouteProvider::class); - $this->request = $this->createMock(Request::class); - $this->listController = new ListController( + $this->sessionProviderFactory = $this->createMock(SessionProviderFactory::class); + $this->customObjectModel = $this->createMock(CustomObjectModel::class); + $this->sessionProvider = $this->createMock(SessionProvider::class); + $this->permissionProvider = $this->createMock(CustomObjectPermissionProvider::class); + $this->routeProvider = $this->createMock(CustomObjectRouteProvider::class); + $this->request = $this->createMock(Request::class); + $this->listController = new ListController( + $this->managerRegistry, + $this->mauticFactory, + $this->modelFactory, + $this->userHelper, + $this->coreParametersHelper, + $this->dispatcher, + $this->translator, + $this->flashBag, $this->requestStack, - $sessionProviderFactory, - $this->customObjectModel, - $this->permissionProvider, - $this->routeProvider + $this->security ); $this->addSymfonyDependencies($this->listController); $this->requestStack->method('getCurrentRequest')->willReturn($this->request); - $sessionProviderFactory->method('createObjectProvider')->willReturn($this->sessionProvider); + $this->sessionProviderFactory->method('createObjectProvider')->willReturn($this->sessionProvider); } public function testListActionIfForbidden(): void @@ -69,7 +73,13 @@ public function testListActionIfForbidden(): void $this->expectException(AccessDeniedHttpException::class); - $this->listController->listAction(self::PAGE); + $this->listController->listAction( + $this->sessionProviderFactory, + $this->customObjectModel, + $this->permissionProvider, + $this->routeProvider, + self::PAGE + ); } public function testListAction(): void @@ -123,7 +133,13 @@ public function testListAction(): void ->method('setPageLimit') ->with($pageLimit); - $this->listController->listAction(self::PAGE); + $this->listController->listAction( + $this->sessionProviderFactory, + $this->customObjectModel, + $this->permissionProvider, + $this->routeProvider, + self::PAGE + ); } public function testListActionWithOrderByQueryParamAndAjax(): void @@ -189,6 +205,16 @@ public function testListActionWithOrderByQueryParamAndAjax(): void ->method('setPageLimit') ->with($pageLimit); - $this->listController->listAction(self::PAGE); + $this->sessionProvider->expects($this->once()) + ->method('setPageLimit') + ->with($pageLimit); + + $this->listController->listAction( + $this->sessionProviderFactory, + $this->customObjectModel, + $this->permissionProvider, + $this->routeProvider, + self::PAGE + ); } } diff --git a/Tests/Unit/Controller/CustomObject/SaveControllerTest.php b/Tests/Unit/Controller/CustomObject/SaveControllerTest.php index a70329db8..543606df1 100644 --- a/Tests/Unit/Controller/CustomObject/SaveControllerTest.php +++ b/Tests/Unit/Controller/CustomObject/SaveControllerTest.php @@ -4,7 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller\CustomObject; -use Mautic\CoreBundle\Service\FlashBag; use MauticPlugin\CustomObjectsBundle\Controller\CustomObject\SaveController; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; use MauticPlugin\CustomObjectsBundle\Exception\ForbiddenException; @@ -23,10 +22,11 @@ use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +#[\AllowDynamicProperties] class SaveControllerTest extends ControllerTestCase { private const OBJECT_ID = 33; @@ -37,7 +37,6 @@ class SaveControllerTest extends ControllerTestCase private $customFieldTypeProvider; private $paramsToStringTransformer; private $optionsToStringTransformer; - private $flashBag; private $permissionProvider; private $routeProvider; private $lockFlashMessageHelper; @@ -56,10 +55,8 @@ protected function setUp(): void $this->formFactory = $this->createMock(FormFactoryInterface::class); $this->customObjectModel = $this->createMock(CustomObjectModel::class); $this->customFieldModel = $this->createMock(CustomFieldModel::class); - $this->flashBag = $this->createMock(FlashBag::class); $this->permissionProvider = $this->createMock(CustomObjectPermissionProvider::class); $this->routeProvider = $this->createMock(CustomObjectRouteProvider::class); - $this->requestStack = $this->createMock(RequestStack::class); $this->customFieldTypeProvider = $this->createMock(CustomFieldTypeProvider::class); $this->paramsToStringTransformer = $this->createMock(ParamsToStringTransformer::class); $this->optionsToStringTransformer = $this->createMock(OptionsToStringTransformer::class); @@ -67,21 +64,25 @@ protected function setUp(): void $this->request = $this->createMock(Request::class); $this->customObject = $this->createMock(CustomObject::class); $this->form = $this->createMock(FormInterface::class); + $this->saveController = new SaveController( - $this->requestStack, + $this->managerRegistry, + $this->mauticFactory, + $this->modelFactory, + $this->userHelper, + $this->coreParametersHelper, + $this->dispatcher, + $this->translator, $this->flashBag, - $this->formFactory, - $this->customObjectModel, - $this->customFieldModel, - $this->permissionProvider, - $this->routeProvider, - $this->customFieldTypeProvider, - $this->paramsToStringTransformer, - $this->optionsToStringTransformer, - $this->lockFlashMessageHelper + $this->requestStack, + $this->security ); $this->addSymfonyDependencies($this->saveController); + + $this->requestStack->expects($this->any()) + ->method('getCurrentRequest') + ->willReturn($this->request); } public function testSaveActionIfExistingCustomObjectNotFound(): void @@ -96,7 +97,25 @@ public function testSaveActionIfExistingCustomObjectNotFound(): void $this->permissionProvider->expects($this->never()) ->method('canCreate'); - $this->saveController->saveAction(self::OBJECT_ID); + $post = $this->createMock(ParameterBag::class); + $this->request->request = $post; + $post->expects($this->once()) + ->method('all') + ->willReturn([]); + + $this->saveController->saveAction( + $this->flashBag, + $this->formFactory, + $this->customObjectModel, + $this->customFieldModel, + $this->permissionProvider, + $this->routeProvider, + $this->customFieldTypeProvider, + $this->paramsToStringTransformer, + $this->optionsToStringTransformer, + $this->lockFlashMessageHelper, + self::OBJECT_ID + ); } public function testSaveActionIfExistingCustomObjectIsForbidden(): void @@ -114,7 +133,19 @@ public function testSaveActionIfExistingCustomObjectIsForbidden(): void $this->expectException(AccessDeniedHttpException::class); - $this->saveController->saveAction(self::OBJECT_ID); + $this->saveController->saveAction( + $this->flashBag, + $this->formFactory, + $this->customObjectModel, + $this->customFieldModel, + $this->permissionProvider, + $this->routeProvider, + $this->customFieldTypeProvider, + $this->paramsToStringTransformer, + $this->optionsToStringTransformer, + $this->lockFlashMessageHelper, + self::OBJECT_ID + ); } public function testSaveActionForExistingCustomObjectWithValidFormClickingApply(): void @@ -196,7 +227,19 @@ public function testSaveActionForExistingCustomObjectWithValidFormClickingApply( ->with('custom_object') ->willReturn([]); - $this->saveController->saveAction(self::OBJECT_ID); + $this->saveController->saveAction( + $this->flashBag, + $this->formFactory, + $this->customObjectModel, + $this->customFieldModel, + $this->permissionProvider, + $this->routeProvider, + $this->customFieldTypeProvider, + $this->paramsToStringTransformer, + $this->optionsToStringTransformer, + $this->lockFlashMessageHelper, + self::OBJECT_ID + ); } public function testSaveActionForExistingCustomObjectWithValidFormClickingSaveAndAjax(): void @@ -298,7 +341,19 @@ public function testSaveActionForExistingCustomObjectWithValidFormClickingSaveAn ->willReturn([]); /** @var JsonResponse $jsonResponse */ - $jsonResponse = $this->saveController->saveAction(self::OBJECT_ID); + $jsonResponse = $this->saveController->saveAction( + $this->flashBag, + $this->formFactory, + $this->customObjectModel, + $this->customFieldModel, + $this->permissionProvider, + $this->routeProvider, + $this->customFieldTypeProvider, + $this->paramsToStringTransformer, + $this->optionsToStringTransformer, + $this->lockFlashMessageHelper, + self::OBJECT_ID + ); $this->assertMatchesRegularExpression('/Redirecting to https:\/\/view.object/', $jsonResponse->getContent()); } @@ -352,6 +407,17 @@ public function testSaveActionForNewCustomObjectWithInvalidForm(): void $this->customFieldTypeProvider->expects($this->once()) ->method('getTypes'); - $this->saveController->saveAction(); + $this->saveController->saveAction( + $this->flashBag, + $this->formFactory, + $this->customObjectModel, + $this->customFieldModel, + $this->permissionProvider, + $this->routeProvider, + $this->customFieldTypeProvider, + $this->paramsToStringTransformer, + $this->optionsToStringTransformer, + $this->lockFlashMessageHelper, + ); } } diff --git a/Tests/Unit/Controller/CustomObject/ViewControllerTest.php b/Tests/Unit/Controller/CustomObject/ViewControllerTest.php index b86f4faee..1e1130358 100644 --- a/Tests/Unit/Controller/CustomObject/ViewControllerTest.php +++ b/Tests/Unit/Controller/CustomObject/ViewControllerTest.php @@ -16,9 +16,12 @@ use MauticPlugin\CustomObjectsBundle\Tests\Unit\Controller\ControllerTestCase; use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\FormInterface; +use Symfony\Component\HttpFoundation\ParameterBag; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +#[\AllowDynamicProperties] class ViewControllerTest extends ControllerTestCase { private const OBJECT_ID = 33; @@ -45,19 +48,29 @@ protected function setUp(): void $this->permissionProvider = $this->createMock(CustomObjectPermissionProvider::class); $this->routeProvider = $this->createMock(CustomObjectRouteProvider::class); $this->requestStack = $this->createMock(RequestStack::class); + $this->request = $this->createMock(Request::class); $this->formFactory = $this->createMock(FormFactoryInterface::class); $this->form = $this->createMock(FormInterface::class); $this->customObject = $this->createMock(CustomObject::class); + $this->viewController = new ViewController( + $this->managerRegistry, + $this->mauticFactory, + $this->modelFactory, + $this->userHelper, + $this->coreParametersHelper, + $this->dispatcher, + $this->translator, + $this->flashBag, $this->requestStack, - $this->formFactory, - $this->customObjectModel, - $this->auditLog, - $this->permissionProvider, - $this->routeProvider + $this->security ); $this->addSymfonyDependencies($this->viewController); + + $this->requestStack->expects($this->any()) + ->method('getCurrentRequest') + ->willReturn($this->request); } public function testViewActionIfCustomObjectNotFound(): void @@ -72,7 +85,20 @@ public function testViewActionIfCustomObjectNotFound(): void $this->routeProvider->expects($this->never()) ->method('buildViewRoute'); - $this->viewController->viewAction(self::OBJECT_ID); + $post = $this->createMock(ParameterBag::class); + $this->request->request = $post; + $post->expects($this->once()) + ->method('all') + ->willReturn([]); + + $this->viewController->viewAction( + $this->formFactory, + $this->customObjectModel, + $this->auditLog, + $this->permissionProvider, + $this->routeProvider, + self::OBJECT_ID + ); } public function testViewActionIfCustomObjectForbidden(): void @@ -88,9 +114,20 @@ public function testViewActionIfCustomObjectForbidden(): void $this->routeProvider->expects($this->never()) ->method('buildViewRoute'); + $this->security->expects($this->once()) + ->method('isAnonymous') + ->willReturn(true); + $this->expectException(AccessDeniedHttpException::class); - $this->viewController->viewAction(self::OBJECT_ID); + $this->viewController->viewAction( + $this->formFactory, + $this->customObjectModel, + $this->auditLog, + $this->permissionProvider, + $this->routeProvider, + self::OBJECT_ID + ); } public function testViewAction(): void @@ -148,6 +185,13 @@ public function testViewAction(): void ->method('getLogForObject') ->with('customObject', self::OBJECT_ID, '2019-01-04 10:20:30', 10, 'customObjects'); - $this->viewController->viewAction(self::OBJECT_ID); + $this->viewController->viewAction( + $this->formFactory, + $this->customObjectModel, + $this->auditLog, + $this->permissionProvider, + $this->routeProvider, + self::OBJECT_ID + ); } } diff --git a/Tests/Unit/CustomFieldType/AbstractCustomFieldTypeTest.php b/Tests/Unit/CustomFieldType/AbstractCustomFieldTypeTest.php index 37a9c8908..31246ecd4 100644 --- a/Tests/Unit/CustomFieldType/AbstractCustomFieldTypeTest.php +++ b/Tests/Unit/CustomFieldType/AbstractCustomFieldTypeTest.php @@ -9,7 +9,7 @@ use MauticPlugin\CustomObjectsBundle\CustomFieldType\EmailType; use MauticPlugin\CustomObjectsBundle\Entity\CustomField; use MauticPlugin\CustomObjectsBundle\Exception\UndefinedTransformerException; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class AbstractCustomFieldTypeTest extends \PHPUnit\Framework\TestCase { @@ -26,8 +26,6 @@ protected function setUp(): void { parent::setUp(); - defined('MAUTIC_TABLE_PREFIX') || define('MAUTIC_TABLE_PREFIX', ''); - $this->translator = $this->createMock(TranslatorInterface::class); $this->customField = $this->createMock(CustomField::class); $this->filterOperatorProvider = $this->createMock(FilterOperatorProviderInterface::class); diff --git a/Tests/Unit/CustomFieldType/AbstractMultivalueTypeTest.php b/Tests/Unit/CustomFieldType/AbstractMultivalueTypeTest.php index d5bae2109..4702d613b 100644 --- a/Tests/Unit/CustomFieldType/AbstractMultivalueTypeTest.php +++ b/Tests/Unit/CustomFieldType/AbstractMultivalueTypeTest.php @@ -16,7 +16,7 @@ use MauticPlugin\CustomObjectsBundle\Exception\NotFoundException; use MauticPlugin\CustomObjectsBundle\Helper\CsvHelper; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class AbstractMultivalueTypeTest extends \PHPUnit\Framework\TestCase { @@ -80,7 +80,7 @@ public function testGetOperators(): void 'in' => [], '!in' => [], 'somethingelse' => [], - ]); + ]); $operators = $this->fieldType->getOperators(); diff --git a/Tests/Unit/CustomFieldType/AbstractTextTypeTest.php b/Tests/Unit/CustomFieldType/AbstractTextTypeTest.php index f57dd097f..1abaedda2 100644 --- a/Tests/Unit/CustomFieldType/AbstractTextTypeTest.php +++ b/Tests/Unit/CustomFieldType/AbstractTextTypeTest.php @@ -10,7 +10,7 @@ use MauticPlugin\CustomObjectsBundle\Entity\CustomFieldValueText; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use Symfony\Component\Form\Extension\Core\Type\TextType; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class AbstractTextTypeTest extends \PHPUnit\Framework\TestCase { diff --git a/Tests/Unit/CustomFieldType/CountryTypeTest.php b/Tests/Unit/CustomFieldType/CountryTypeTest.php index 5b76ce15f..674115143 100644 --- a/Tests/Unit/CustomFieldType/CountryTypeTest.php +++ b/Tests/Unit/CustomFieldType/CountryTypeTest.php @@ -8,7 +8,7 @@ use MauticPlugin\CustomObjectsBundle\CustomFieldType\CountryType; use MauticPlugin\CustomObjectsBundle\Entity\CustomFieldValueText; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class CountryTypeTest extends \PHPUnit\Framework\TestCase { diff --git a/Tests/Unit/CustomFieldType/DataTransformer/DateTimeAtomTransformerTest.php b/Tests/Unit/CustomFieldType/DataTransformer/DateTimeAtomTransformerTest.php index 7faebafad..90dec29af 100644 --- a/Tests/Unit/CustomFieldType/DataTransformer/DateTimeAtomTransformerTest.php +++ b/Tests/Unit/CustomFieldType/DataTransformer/DateTimeAtomTransformerTest.php @@ -4,7 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\CustomFieldType\DataTransformer; -use DateTime; use MauticPlugin\CustomObjectsBundle\CustomFieldType\DataTransformer\DateTimeAtomTransformer; class DateTimeAtomTransformerTest extends \PHPUnit\Framework\TestCase @@ -12,7 +11,7 @@ class DateTimeAtomTransformerTest extends \PHPUnit\Framework\TestCase public function test(): void { $date = '2019-05-30T13:45:04+00:00'; - $datetime = new DateTime($date); + $datetime = new \DateTime($date); $format = DATE_ATOM; $transformer = new DateTimeAtomTransformer(); diff --git a/Tests/Unit/CustomFieldType/DateTimeTypeTest.php b/Tests/Unit/CustomFieldType/DateTimeTypeTest.php index f9ecf679d..3f4f92227 100644 --- a/Tests/Unit/CustomFieldType/DateTimeTypeTest.php +++ b/Tests/Unit/CustomFieldType/DateTimeTypeTest.php @@ -13,7 +13,7 @@ use MauticPlugin\CustomObjectsBundle\Entity\CustomFieldValueDateTime; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Exception\InvalidValueException; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class DateTimeTypeTest extends \PHPUnit\Framework\TestCase { diff --git a/Tests/Unit/CustomFieldType/DateTypeTest.php b/Tests/Unit/CustomFieldType/DateTypeTest.php index 2458f4ba7..b18ebed52 100644 --- a/Tests/Unit/CustomFieldType/DateTypeTest.php +++ b/Tests/Unit/CustomFieldType/DateTypeTest.php @@ -12,7 +12,7 @@ use MauticPlugin\CustomObjectsBundle\Entity\CustomFieldValueDate; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Exception\InvalidValueException; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class DateTypeTest extends \PHPUnit\Framework\TestCase { diff --git a/Tests/Unit/CustomFieldType/EmailTypeTest.php b/Tests/Unit/CustomFieldType/EmailTypeTest.php index 94f9f347f..25138fc92 100644 --- a/Tests/Unit/CustomFieldType/EmailTypeTest.php +++ b/Tests/Unit/CustomFieldType/EmailTypeTest.php @@ -7,7 +7,7 @@ use Mautic\LeadBundle\Provider\FilterOperatorProviderInterface; use MauticPlugin\CustomObjectsBundle\CustomFieldType\EmailType; use MauticPlugin\CustomObjectsBundle\Entity\CustomField; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class EmailTypeTest extends \PHPUnit\Framework\TestCase { diff --git a/Tests/Unit/CustomFieldType/IntTypeTest.php b/Tests/Unit/CustomFieldType/IntTypeTest.php index 92f21ca1b..8273c63ec 100644 --- a/Tests/Unit/CustomFieldType/IntTypeTest.php +++ b/Tests/Unit/CustomFieldType/IntTypeTest.php @@ -9,7 +9,7 @@ use MauticPlugin\CustomObjectsBundle\Entity\CustomField; use MauticPlugin\CustomObjectsBundle\Entity\CustomFieldValueInt; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class IntTypeTest extends \PHPUnit\Framework\TestCase { diff --git a/Tests/Unit/CustomFieldType/MultiselectTypeTest.php b/Tests/Unit/CustomFieldType/MultiselectTypeTest.php index 5df503b17..7c02fe404 100644 --- a/Tests/Unit/CustomFieldType/MultiselectTypeTest.php +++ b/Tests/Unit/CustomFieldType/MultiselectTypeTest.php @@ -7,7 +7,7 @@ use Mautic\LeadBundle\Provider\FilterOperatorProviderInterface; use MauticPlugin\CustomObjectsBundle\CustomFieldType\MultiselectType; use MauticPlugin\CustomObjectsBundle\Helper\CsvHelper; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class MultiselectTypeTest extends \PHPUnit\Framework\TestCase { diff --git a/Tests/Unit/CustomFieldType/PhoneTypeTest.php b/Tests/Unit/CustomFieldType/PhoneTypeTest.php index 941baf036..eb090d12f 100644 --- a/Tests/Unit/CustomFieldType/PhoneTypeTest.php +++ b/Tests/Unit/CustomFieldType/PhoneTypeTest.php @@ -7,7 +7,7 @@ use Mautic\LeadBundle\Provider\FilterOperatorProviderInterface; use MauticPlugin\CustomObjectsBundle\CustomFieldType\PhoneType; use MauticPlugin\CustomObjectsBundle\Entity\CustomField; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class PhoneTypeTest extends \PHPUnit\Framework\TestCase { diff --git a/Tests/Unit/CustomFieldType/SelectTypeTest.php b/Tests/Unit/CustomFieldType/SelectTypeTest.php index a1096a022..ae118df29 100644 --- a/Tests/Unit/CustomFieldType/SelectTypeTest.php +++ b/Tests/Unit/CustomFieldType/SelectTypeTest.php @@ -11,7 +11,7 @@ use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Exception\NotFoundException; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class SelectTypeTest extends \PHPUnit\Framework\TestCase { @@ -60,7 +60,7 @@ public function testGetOperators(): void '=' => [], '!=' => [], 'somethingelse' => [], - ]); + ]); $operators = $this->fieldType->getOperators(); diff --git a/Tests/Unit/CustomFieldType/UrlTypeTest.php b/Tests/Unit/CustomFieldType/UrlTypeTest.php index fdaa75929..1a617c73f 100644 --- a/Tests/Unit/CustomFieldType/UrlTypeTest.php +++ b/Tests/Unit/CustomFieldType/UrlTypeTest.php @@ -7,7 +7,7 @@ use Mautic\LeadBundle\Provider\FilterOperatorProviderInterface; use MauticPlugin\CustomObjectsBundle\CustomFieldType\UrlType; use MauticPlugin\CustomObjectsBundle\Entity\CustomField; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class UrlTypeTest extends \PHPUnit\Framework\TestCase { diff --git a/Tests/Unit/CustomObjectTestCase.php b/Tests/Unit/CustomObjectTestCase.php index 39809599a..d31014eaf 100644 --- a/Tests/Unit/CustomObjectTestCase.php +++ b/Tests/Unit/CustomObjectTestCase.php @@ -4,8 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit; -use DateTimeImmutable; -use DateTimeZone; use Mautic\CoreBundle\Test\MauticMysqlTestCase; use Mautic\LeadBundle\Entity\Lead; use Mautic\UserBundle\Entity\User; @@ -62,7 +60,7 @@ protected function createContact(string $firstName = 'name', string $lastName = protected function createCustomItemExportScheduleEntity(CustomObject $customObject): CustomItemExportScheduler { $customItemExportScheduler = new CustomItemExportScheduler(); - $customItemExportScheduler->setScheduledDateTime(new DateTimeImmutable('now', new DateTimeZone('UTC'))); + $customItemExportScheduler->setScheduledDateTime(new \DateTimeImmutable('now', new \DateTimeZone('UTC'))); $customItemExportScheduler->setUser($this->em->getRepository(User::class)->find(1)); $customItemExportScheduler->setCustomObjectId((int) $customObject->getId()); diff --git a/Tests/Unit/Entity/CustomFieldTest.php b/Tests/Unit/Entity/CustomFieldTest.php index cc44dd05d..4e9f3a9b8 100644 --- a/Tests/Unit/Entity/CustomFieldTest.php +++ b/Tests/Unit/Entity/CustomFieldTest.php @@ -19,13 +19,13 @@ use MauticPlugin\CustomObjectsBundle\Form\Validator\Constraints\AllowUniqueIdentifier; use MauticPlugin\CustomObjectsBundle\Helper\CsvHelper; use Symfony\Component\Form\DataTransformerInterface; -use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Validator\Constraints\Callback; use Symfony\Component\Validator\Constraints\Length; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Violation\ConstraintViolationBuilderInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class CustomFieldTest extends \PHPUnit\Framework\TestCase { @@ -282,8 +282,8 @@ public function testGetChoices(): void ); $this->assertSame([ - 'Option A label' => 'option_a_value', - 'Option B label' => 'option_b_value', + 'Option A label' => 'option_a_value', + 'Option B label' => 'option_b_value', ], $customField->getChoices()); } @@ -316,6 +316,22 @@ public function testValueToLabel(): void $this->assertSame('Option B', $customField->valueToLabel('option_b')); } + public function testValueToLabelWithInteger(): void + { + $customField = new CustomField(); + $optionB = new CustomFieldOption(); + $optionB->setLabel('1'); + $optionB->setValue('1'); + $customField->addOption($optionB); + $customField->setTypeObject( + new SelectType( + $this->createMock(TranslatorInterface::class), + $this->createMock(FilterOperatorProviderInterface::class) + ) + ); + $this->assertSame('1', $customField->valueToLabel('1')); + } + public function testValueToLabelIfOptionNotFound(): void { $customField = new CustomField(); diff --git a/Tests/Unit/Entity/CustomItemTest.php b/Tests/Unit/Entity/CustomItemTest.php index 87215858e..8d5358402 100644 --- a/Tests/Unit/Entity/CustomItemTest.php +++ b/Tests/Unit/Entity/CustomItemTest.php @@ -15,7 +15,7 @@ use MauticPlugin\CustomObjectsBundle\Entity\CustomItemXrefCustomItem; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; use MauticPlugin\CustomObjectsBundle\Exception\NotFoundException; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class CustomItemTest extends \PHPUnit\Framework\TestCase { diff --git a/Tests/Unit/Entity/CustomItemXrefCompanyTest.php b/Tests/Unit/Entity/CustomItemXrefCompanyTest.php index 4d035037e..86c789b32 100644 --- a/Tests/Unit/Entity/CustomItemXrefCompanyTest.php +++ b/Tests/Unit/Entity/CustomItemXrefCompanyTest.php @@ -4,7 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\Entity; -use DateTimeImmutable; use Mautic\LeadBundle\Entity\Company; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Entity\CustomItemXrefCompany; @@ -15,7 +14,7 @@ public function testGetters(): void { $customItem = $this->createMock(CustomItem::class); $company = $this->createMock(Company::class); - $dateAdded = new DateTimeImmutable('2019-03-04 12:34:56'); + $dateAdded = new \DateTimeImmutable('2019-03-04 12:34:56'); $xref = new CustomItemXrefCompany( $customItem, $company, diff --git a/Tests/Unit/Entity/CustomItemXrefContactTest.php b/Tests/Unit/Entity/CustomItemXrefContactTest.php index 3f9c3e9de..483896a0f 100644 --- a/Tests/Unit/Entity/CustomItemXrefContactTest.php +++ b/Tests/Unit/Entity/CustomItemXrefContactTest.php @@ -4,7 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\Entity; -use DateTimeImmutable; use Mautic\LeadBundle\Entity\Lead; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Entity\CustomItemXrefContact; @@ -15,7 +14,7 @@ public function testGetters(): void { $customItem = $this->createMock(CustomItem::class); $contact = $this->createMock(Lead::class); - $dateAdded = new DateTimeImmutable('2019-03-04 12:34:56'); + $dateAdded = new \DateTimeImmutable('2019-03-04 12:34:56'); $xref = new CustomItemXrefContact( $customItem, $contact, diff --git a/Tests/Unit/Entity/CustomItemXrefCustomItemTest.php b/Tests/Unit/Entity/CustomItemXrefCustomItemTest.php index 92140d119..b000bb451 100644 --- a/Tests/Unit/Entity/CustomItemXrefCustomItemTest.php +++ b/Tests/Unit/Entity/CustomItemXrefCustomItemTest.php @@ -4,10 +4,8 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\Entity; -use DateTimeImmutable; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Entity\CustomItemXrefCustomItem; -use UnexpectedValueException; class CustomItemXrefCustomItemTest extends \PHPUnit\Framework\TestCase { @@ -15,7 +13,7 @@ public function testGettersIfCustomItemAIsLower(): void { $customItemA = $this->createMock(CustomItem::class); $customItemB = $this->createMock(CustomItem::class); - $dateAdded = new DateTimeImmutable('2019-03-04 12:34:56'); + $dateAdded = new \DateTimeImmutable('2019-03-04 12:34:56'); $customItemA->method('getId')->willReturn(33); $customItemB->method('getId')->willReturn(55); @@ -37,7 +35,7 @@ public function testGettersIfCustomItemBIsLower(): void { $customItemA = $this->createMock(CustomItem::class); $customItemB = $this->createMock(CustomItem::class); - $dateAdded = new DateTimeImmutable('2019-03-04 12:34:56'); + $dateAdded = new \DateTimeImmutable('2019-03-04 12:34:56'); $customItemA->method('getId')->willReturn(55); $customItemB->method('getId')->willReturn(33); @@ -57,12 +55,12 @@ public function testGettersIfCustomItemsAreEqual(): void { $customItemA = $this->createMock(CustomItem::class); $customItemB = $this->createMock(CustomItem::class); - $dateAdded = new DateTimeImmutable('2019-03-04 12:34:56'); + $dateAdded = new \DateTimeImmutable('2019-03-04 12:34:56'); $customItemA->method('getId')->willReturn(55); $customItemB->method('getId')->willReturn(55); - $this->expectException(UnexpectedValueException::class); + $this->expectException(\UnexpectedValueException::class); new CustomItemXrefCustomItem( $customItemA, diff --git a/Tests/Unit/EventListener/ApiSubscriberTest.php b/Tests/Unit/EventListener/ApiSubscriberTest.php index 711d0179e..6674a23f7 100644 --- a/Tests/Unit/EventListener/ApiSubscriberTest.php +++ b/Tests/Unit/EventListener/ApiSubscriberTest.php @@ -4,7 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\EventListener; -use InvalidArgumentException; use Mautic\ApiBundle\Event\ApiEntityEvent; use Mautic\LeadBundle\Entity\Lead; use Mautic\LeadBundle\Provider\FilterOperatorProviderInterface; @@ -21,10 +20,18 @@ use MauticPlugin\CustomObjectsBundle\Provider\ConfigProvider; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class ApiSubscriberTest extends \PHPUnit\Framework\TestCase { + private const CONTROLLER_METHODS = [ + 'newEntityAction', + 'newEntitiesAction', + 'editEntityAction', + 'editEntitiesAction', + ]; + private const CONTROLLER_CLASS = 'Mautic\LeadBundle\Controller\Api\LeadApiController'; + private $configProvider; private $customObjectModel; @@ -48,7 +55,7 @@ protected function setUp(): void $this->customObjectModel = $this->createMock(CustomObjectModel::class); $this->customItemModel = $this->createMock(CustomItemModel::class); $this->apiEntityEvent = $this->createMock(ApiEntityEvent::class); - $this->request = $this->createMock(Request::class); + $this->request = new Request(); $this->apiSubscriber = new ApiSubscriber( $this->configProvider, $this->customObjectModel, @@ -74,7 +81,23 @@ public function testPluginDisabled(): void $this->apiSubscriber->validateCustomObjectsInContactRequest($this->apiEntityEvent); } - public function testGetCustomObjectsFromContactCreateRequestForUnsupportedApiEndpoint(): void + /** + * @return iterable + */ + public function dataGetCustomObjectsFromContactCreateRequestForUnsupportedApiEndpoint(): iterable + { + foreach (self::CONTROLLER_METHODS as $method) { + yield ['Mautic\UnknownBundle\Controller\Api\UnknownController::'.$method]; + } + + yield [self::CONTROLLER_CLASS.'::unknownAction']; + yield [self::CONTROLLER_CLASS.'::unknownMethod']; + } + + /** + * @dataProvider dataGetCustomObjectsFromContactCreateRequestForUnsupportedApiEndpoint + */ + public function testGetCustomObjectsFromContactCreateRequestForUnsupportedApiEndpoint(string $controller): void { $this->configProvider->expects($this->once()) ->method('pluginIsEnabled') @@ -82,9 +105,19 @@ public function testGetCustomObjectsFromContactCreateRequestForUnsupportedApiEnd $this->apiEntityEvent->expects($this->once()) ->method('getEntityRequestParameters') - ->willReturn([]); + ->willReturn([ + 'email' => 'john@doe.email', + 'customObjects' => [ + 'data' => [ + [ + 'alias' => 'object-1-alias', + 'data' => [[]], + ], + ], + ], + ]); - $this->request->method('getPathInfo')->willReturn('/api/unicorn'); + $this->setControllerToRequest($controller); $this->apiEntityEvent->expects($this->never()) ->method('getEntity'); @@ -98,7 +131,7 @@ public function testGetCustomObjectsFromContactCreateRequestWithoutCustomObjects ->method('pluginIsEnabled') ->willReturn(true); - $this->request->method('getPathInfo')->willReturn('/api/contacts/new'); + $this->setControllerToRequest(); $this->apiEntityEvent->expects($this->once()) ->method('getEntityRequestParameters') @@ -110,13 +143,26 @@ public function testGetCustomObjectsFromContactCreateRequestWithoutCustomObjects $this->apiSubscriber->validateCustomObjectsInContactRequest($this->apiEntityEvent); } - public function testValidateCustomObjectsInContactRequestWhenCustomObjectNotFoundByAlias(): void + /** + * @return iterable + */ + public function dataValidateCustomObjectsInContactRequestWhenCustomObjectNotFoundByAlias(): iterable + { + foreach (self::CONTROLLER_METHODS as $method) { + yield [self::CONTROLLER_CLASS.'::'.$method]; + } + } + + /** + * @dataProvider dataValidateCustomObjectsInContactRequestWhenCustomObjectNotFoundByAlias + */ + public function testValidateCustomObjectsInContactRequestWhenCustomObjectNotFoundByAlias(string $controller): void { $this->configProvider->expects($this->once()) ->method('pluginIsEnabled') ->willReturn(true); - $this->request->method('getPathInfo')->willReturn('/api/contacts/new'); + $this->setControllerToRequest($controller); $this->apiEntityEvent->expects($this->once()) ->method('getEntityRequestParameters') @@ -152,7 +198,7 @@ public function testValidateCustomObjectsInContactRequestWhenCustomObjectNotFoun ->method('pluginIsEnabled') ->willReturn(true); - $this->request->method('getPathInfo')->willReturn('/api/contacts/new'); + $this->setControllerToRequest(); $this->apiEntityEvent->expects($this->once()) ->method('getEntityRequestParameters') @@ -188,7 +234,7 @@ public function testValidateCustomObjectsInContactRequestWhenCustomObjectDoesNot ->method('pluginIsEnabled') ->willReturn(true); - $this->request->method('getPathInfo')->willReturn('/api/contacts/new'); + $this->setControllerToRequest(); $this->apiEntityEvent->expects($this->once()) ->method('getEntityRequestParameters') @@ -207,7 +253,7 @@ public function testValidateCustomObjectsInContactRequestWhenCustomObjectDoesNot ->method('getEntity') ->willReturn(new Lead()); - $this->expectException(InvalidArgumentException::class); + $this->expectException(\InvalidArgumentException::class); $this->expectExceptionCode(Response::HTTP_BAD_REQUEST); $this->apiSubscriber->validateCustomObjectsInContactRequest($this->apiEntityEvent); } @@ -218,7 +264,7 @@ public function testValidateCustomObjectsInContactRequestWhenCustomItemNotFound( ->method('pluginIsEnabled') ->willReturn(true); - $this->request->method('getPathInfo')->willReturn('/api/contacts/new'); + $this->setControllerToRequest(); $this->apiEntityEvent->expects($this->once()) ->method('getEntityRequestParameters') @@ -261,7 +307,7 @@ public function testValidateCustomObjectsInContactRequestForCustomItemEdit(): vo ->method('pluginIsEnabled') ->willReturn(true); - $this->request->method('getPathInfo')->willReturn('/api/contacts/new'); + $this->setControllerToRequest(); $this->apiEntityEvent->expects($this->once()) ->method('getEntityRequestParameters') @@ -342,7 +388,7 @@ public function testSaveCustomObjectsInContactRequestForNewCustomItem(): void ->method('pluginIsEnabled') ->willReturn(true); - $this->request->method('getPathInfo')->willReturn('/api/contacts/new'); + $this->setControllerToRequest(); $this->apiEntityEvent->expects($this->once()) ->method('getEntityRequestParameters') @@ -408,7 +454,7 @@ public function testSaveCustomObjectsInContactRequestForNewCustomItem(): void ->method('save') ->with($this->callback(function (CustomItem $customItem) { $this->assertSame('Test Item', $customItem->getName()); - $skuValue = $customItem->findCustomFieldValueForFieldAlias('sku'); + $skuValue = $customItem->findCustomFieldValueForFieldAlias('sku'); $priceValue = $customItem->findCustomFieldValueForFieldAlias('price'); $this->assertSame('d2345f', $skuValue->getValue()); $this->assertSame(237, $priceValue->getValue()); @@ -418,4 +464,9 @@ public function testSaveCustomObjectsInContactRequestForNewCustomItem(): void $this->apiSubscriber->saveCustomObjectsInContactRequest($this->apiEntityEvent); } + + private function setControllerToRequest(string $controller = self::CONTROLLER_CLASS.'::'.self::CONTROLLER_METHODS[0]): void + { + $this->request->attributes->set('_controller', $controller); + } } diff --git a/Tests/Unit/EventListener/AssetsSubscriberTest.php b/Tests/Unit/EventListener/AssetsSubscriberTest.php index ec20fc3c9..f76d4cf60 100644 --- a/Tests/Unit/EventListener/AssetsSubscriberTest.php +++ b/Tests/Unit/EventListener/AssetsSubscriberTest.php @@ -4,19 +4,24 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\EventListener; -use Mautic\CoreBundle\Templating\Helper\AssetsHelper; +use Mautic\CoreBundle\Helper\CoreParametersHelper; +use Mautic\CoreBundle\Twig\Helper\AssetsHelper; use MauticPlugin\CustomObjectsBundle\EventListener\AssetsSubscriber; use MauticPlugin\CustomObjectsBundle\Provider\ConfigProvider; +use Symfony\Component\Asset\Packages; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\Event\RequestEvent; class AssetsSubscriberTest extends \PHPUnit\Framework\TestCase { + private $packages; + + private $coreParametersHelper; private $assetsHelper; private $configProvider; - private $getResponseEvent; + private $requestEvent; private $request; @@ -26,11 +31,16 @@ protected function setUp(): void { parent::setUp(); - $this->assetsHelper = $this->createMock(AssetsHelper::class); - $this->configProvider = $this->createMock(ConfigProvider::class); - $this->getResponseEvent = $this->createMock(GetResponseEvent::class); - $this->request = $this->createMock(Request::class); - $this->assetsSubscriber = new AssetsSubscriber($this->assetsHelper, $this->configProvider); + $this->packages = $this->createMock(Packages::class); + $this->coreParametersHelper = $this->createMock(CoreParametersHelper::class); + $this->assetsHelper = new AssetsHelper( + $this->packages, + $this->coreParametersHelper + ); + $this->configProvider = $this->createMock(ConfigProvider::class); + $this->requestEvent = $this->createMock(RequestEvent::class); + $this->request = $this->createMock(Request::class); + $this->assetsSubscriber = new AssetsSubscriber($this->assetsHelper, $this->configProvider); } public function testPluginDisabled(): void @@ -39,13 +49,10 @@ public function testPluginDisabled(): void ->method('pluginIsEnabled') ->willReturn(false); - $this->getResponseEvent->expects($this->never()) - ->method('isMasterRequest'); - - $this->assetsHelper->expects($this->never()) - ->method('addStylesheet'); + $this->requestEvent->expects($this->never()) + ->method('isMainRequest'); - $this->assetsSubscriber->loadAssets($this->getResponseEvent); + $this->assetsSubscriber->loadAssets($this->requestEvent); } public function testPluginEnabledOnPublicPage(): void @@ -54,11 +61,11 @@ public function testPluginEnabledOnPublicPage(): void ->method('pluginIsEnabled') ->willReturn(true); - $this->getResponseEvent->expects($this->once()) - ->method('isMasterRequest') + $this->requestEvent->expects($this->once()) + ->method('isMainRequest') ->willReturn(true); - $this->getResponseEvent->expects($this->once()) + $this->requestEvent->expects($this->once()) ->method('getRequest') ->willReturn($this->request); @@ -66,10 +73,7 @@ public function testPluginEnabledOnPublicPage(): void ->method('getPathInfo') ->willReturn('/email/unsubscribe/5c9f4105548a6783784018'); - $this->assetsHelper->expects($this->never()) - ->method('addStylesheet'); - - $this->assetsSubscriber->loadAssets($this->getResponseEvent); + $this->assetsSubscriber->loadAssets($this->requestEvent); } public function testPluginEnabled(): void @@ -78,11 +82,11 @@ public function testPluginEnabled(): void ->method('pluginIsEnabled') ->willReturn(true); - $this->getResponseEvent->expects($this->once()) - ->method('isMasterRequest') + $this->requestEvent->expects($this->once()) + ->method('isMainRequest') ->willReturn(true); - $this->getResponseEvent->expects($this->once()) + $this->requestEvent->expects($this->once()) ->method('getRequest') ->willReturn($this->request); @@ -90,9 +94,6 @@ public function testPluginEnabled(): void ->method('getPathInfo') ->willReturn('/s/dashboard'); - $this->assetsHelper->expects($this->once()) - ->method('addStylesheet'); - - $this->assetsSubscriber->loadAssets($this->getResponseEvent); + $this->assetsSubscriber->loadAssets($this->requestEvent); } } diff --git a/Tests/Unit/EventListener/CampaignSubscriberTest.php b/Tests/Unit/EventListener/CampaignSubscriberTest.php index 5f9c65ee1..c609fe7c8 100644 --- a/Tests/Unit/EventListener/CampaignSubscriberTest.php +++ b/Tests/Unit/EventListener/CampaignSubscriberTest.php @@ -7,6 +7,7 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\DBAL\Connection; use Doctrine\DBAL\Query\QueryBuilder; +use Doctrine\DBAL\Result; use Doctrine\DBAL\Statement; use Mautic\CampaignBundle\Event\CampaignBuilderEvent; use Mautic\CampaignBundle\Event\CampaignExecutionEvent; @@ -26,7 +27,7 @@ use MauticPlugin\CustomObjectsBundle\Provider\ConfigProvider; use MauticPlugin\CustomObjectsBundle\Segment\Query\Filter\QueryFilterFactory; use PHPUnit\Framework\TestCase; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class CampaignSubscriberTest extends TestCase { @@ -52,6 +53,7 @@ class CampaignSubscriberTest extends TestCase private $queryBuilder; private $segmentQueryBuilder; private $statement; + private $result; /** * @var CampaignSubscriber @@ -61,9 +63,6 @@ class CampaignSubscriberTest extends TestCase protected function setUp(): void { parent::setUp(); - defined('MAUTIC_TABLE_PREFIX') || define('MAUTIC_TABLE_PREFIX', ''); - - defined('MAUTIC_TABLE_PREFIX') || define('MAUTIC_TABLE_PREFIX', ''); $this->customFieldModel = $this->createMock(CustomFieldModel::class); $this->customObjectModel = $this->createMock(CustomObjectModel::class); @@ -81,6 +80,7 @@ protected function setUp(): void $this->queryBuilder = $this->createMock(QueryBuilder::class); $this->segmentQueryBuilder = $this->createMock(SegmentQueryBuilder::class); $this->statement = $this->createMock(Statement::class); + $this->result = $this->createMock(Result::class); $this->campaignSubscriber = new CampaignSubscriber( $this->customFieldModel, $this->customObjectModel, @@ -380,7 +380,7 @@ public function testOnCampaignTriggerConditionWhenItemNotFound(): void $this->queryBuilder->expects($this->once()) ->method('execute') - ->willReturn($this->statement); + ->willReturn($this->result); $this->queryFilterFactory->expects($this->once()) ->method('configureQueryBuilderFromSegmentFilter') @@ -413,8 +413,8 @@ public function testOnCampaignTriggerConditionWhenItemNotFound(): void ->method('fetchEntity') ->willReturn($this->customField); - $this->statement->expects($this->once()) - ->method('fetchColumn') + $this->result->expects($this->once()) + ->method('fetchOne') ->willReturn(false); $this->campaignExecutionEvent->expects($this->once()) @@ -436,7 +436,7 @@ public function testOnCampaignTriggerCondition(): void $this->queryBuilder->expects($this->once()) ->method('execute') - ->willReturn($this->statement); + ->willReturn($this->result); $this->queryFilterFactory->expects($this->once()) ->method('configureQueryBuilderFromSegmentFilter') @@ -473,8 +473,8 @@ public function testOnCampaignTriggerCondition(): void ->method('setChannel') ->with('customItem', 4344); - $this->statement->expects($this->once()) - ->method('fetchColumn') + $this->result->expects($this->once()) + ->method('fetchOne') ->willReturn('4344'); $this->campaignExecutionEvent->expects($this->once()) diff --git a/Tests/Unit/EventListener/ContactSubscriberTest.php b/Tests/Unit/EventListener/ContactSubscriberTest.php index 80718dbb6..ed935dd7a 100644 --- a/Tests/Unit/EventListener/ContactSubscriberTest.php +++ b/Tests/Unit/EventListener/ContactSubscriberTest.php @@ -16,7 +16,9 @@ use MauticPlugin\CustomObjectsBundle\Model\CustomItemModel; use MauticPlugin\CustomObjectsBundle\Provider\ConfigProvider; use MauticPlugin\CustomObjectsBundle\Provider\CustomItemRouteProvider; -use Symfony\Component\Translation\TranslatorInterface; +use MauticPlugin\CustomObjectsBundle\Repository\CustomItemXrefContactRepository; +use PHPUnit\Framework\MockObject\MockObject; +use Symfony\Contracts\Translation\TranslatorInterface; class ContactSubscriberTest extends \PHPUnit\Framework\TestCase { @@ -28,6 +30,11 @@ class ContactSubscriberTest extends \PHPUnit\Framework\TestCase private $leadTimelineEvent; private $leadEventLogRepo; + /** + * @var MockObject&CustomItemXrefContactRepository + */ + private MockObject $ciXcontactRepo; + /** * @var ContactSubscriber */ @@ -44,12 +51,14 @@ protected function setUp(): void $this->configProvider = $this->createMock(ConfigProvider::class); $this->leadTimelineEvent = $this->createMock(LeadTimelineEvent::class); $this->leadEventLogRepo = $this->createMock(LeadEventLogRepository::class); + $this->ciXcontactRepo = $this->createMock(CustomItemXrefContactRepository::class); $this->subscriber = new ContactSubscriber( $this->entityManager, $this->translator, $this->routeProvider, $this->customItemModel, - $this->configProvider + $this->configProvider, + $this->ciXcontactRepo ); } @@ -176,7 +185,7 @@ public function testPluginEnabledOnPublicPageWhenItemFound(): void 'id' => 444, ], 'contactId' => 333, - 'contentTemplate' => 'CustomObjectsBundle:SubscribedEvents\Timeline:link.html.php', + 'contentTemplate' => '@CustomObjects/SubscribedEvents/Timeline/link.html.twig', ]); $this->subscriber->onTimelineGenerate($this->leadTimelineEvent); @@ -273,7 +282,7 @@ public function testPluginEnabledOnPublicPageWhenItemNotFound(): void 'id' => 444, ], 'contactId' => 333, - 'contentTemplate' => 'CustomObjectsBundle:SubscribedEvents\Timeline:link.html.php', + 'contentTemplate' => '@CustomObjects/SubscribedEvents/Timeline/link.html.twig', ]); $this->subscriber->onTimelineGenerate($this->leadTimelineEvent); diff --git a/Tests/Unit/EventListener/ContactTabSubscriberTest.php b/Tests/Unit/EventListener/ContactTabSubscriberTest.php index 62499bc83..30d945723 100644 --- a/Tests/Unit/EventListener/ContactTabSubscriberTest.php +++ b/Tests/Unit/EventListener/ContactTabSubscriberTest.php @@ -17,7 +17,7 @@ use MauticPlugin\CustomObjectsBundle\Repository\CustomItemRepository; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class ContactTabSubscriberTest extends TestCase { @@ -123,8 +123,8 @@ public function testForTabsContext(): void ->method('checkContext') ->willReturnMap( [ - ['MauticLeadBundle:Lead:lead.html.php', 'tabs', true], - ['MauticLeadBundle:Lead:lead.html.php', 'tabs.content', false], + ['@MauticLead/Lead/lead.html.twig', 'tabs', true], + ['@MauticLead/Lead/lead.html.twig', 'tabs.content', false], ] ); @@ -136,7 +136,7 @@ public function testForTabsContext(): void ->method('addTemplate') ->withConsecutive( [ - 'CustomObjectsBundle:SubscribedEvents/Tab:link.html.php', + '@CustomObjects/SubscribedEvents/Tab/link.html.twig', [ 'count' => 13, 'title' => 'Object A', @@ -144,7 +144,7 @@ public function testForTabsContext(): void ], ], [ - 'CustomObjectsBundle:SubscribedEvents/Tab:modal.html.php', + '@CustomObjects/SubscribedEvents/Tab/modal.html.twig', ] ); @@ -176,8 +176,8 @@ public function testForTabContentsContext(): void ->method('checkContext') ->willReturnMap( [ - ['MauticLeadBundle:Lead:lead.html.php', 'tabs', false], - ['MauticLeadBundle:Lead:lead.html.php', 'tabs.content', true], + ['@MauticLead/Lead/lead.html.twig', 'tabs', false], + ['@MauticLead/Lead/lead.html.twig', 'tabs.content', true], ] ); @@ -218,7 +218,7 @@ public function testForTabContentsContext(): void $this->customContentEvent->expects($this->once()) ->method('addTemplate') ->with( - 'CustomObjectsBundle:SubscribedEvents/Tab:content.html.php', + '@CustomObjects/SubscribedEvents/Tab/content.html.twig', [ 'customObjectId' => 555, 'currentEntityId' => 45, diff --git a/Tests/Unit/EventListener/CustomFieldPostLoadSubscriberTest.php b/Tests/Unit/EventListener/CustomFieldPostLoadSubscriberTest.php index e250adfcd..abdb79f33 100644 --- a/Tests/Unit/EventListener/CustomFieldPostLoadSubscriberTest.php +++ b/Tests/Unit/EventListener/CustomFieldPostLoadSubscriberTest.php @@ -12,7 +12,7 @@ use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; use MauticPlugin\CustomObjectsBundle\EventListener\CustomFieldPostLoadSubscriber; use MauticPlugin\CustomObjectsBundle\Provider\CustomFieldTypeProvider; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class CustomFieldPostLoadSubscriberTest extends \PHPUnit\Framework\TestCase { diff --git a/Tests/Unit/EventListener/CustomItemButtonSubscriberTest.php b/Tests/Unit/EventListener/CustomItemButtonSubscriberTest.php index ed44bf1a0..093fed29d 100644 --- a/Tests/Unit/EventListener/CustomItemButtonSubscriberTest.php +++ b/Tests/Unit/EventListener/CustomItemButtonSubscriberTest.php @@ -15,7 +15,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class CustomItemButtonSubscriberTest extends TestCase { diff --git a/Tests/Unit/EventListener/CustomItemPostSaveSubscriberTest.php b/Tests/Unit/EventListener/CustomItemPostSaveSubscriberTest.php index f28cc0113..b1a1e38ed 100644 --- a/Tests/Unit/EventListener/CustomItemPostSaveSubscriberTest.php +++ b/Tests/Unit/EventListener/CustomItemPostSaveSubscriberTest.php @@ -4,7 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\EventListener; -use Exception; use MauticPlugin\CustomObjectsBundle\CustomItemEvents; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; @@ -33,7 +32,7 @@ public function __construct() public function fetchEntity(int $id): CustomItem { - throw new Exception('This should not have been called.'); + throw new \Exception('This should not have been called.'); } }; @@ -60,7 +59,7 @@ public function __construct() $subscriber->postSave($event); - // No actual assertions made, we're just ensuring an exception is not thrown. + // No actual assertions made, we're just ensuring an \Exception is not thrown. $this->addToAssertionCount(1); } @@ -74,7 +73,7 @@ public function __construct() public function fetchEntity(int $id): CustomItem { - throw new Exception('This should not have been called.'); + throw new \Exception('This should not have been called.'); } }; @@ -101,7 +100,7 @@ public function __construct() $subscriber->postSave($event); - // No actual assertions made, we're just ensuring an exception is not thrown. + // No actual assertions made, we're just ensuring an \Exception is not thrown. $this->addToAssertionCount(1); } } diff --git a/Tests/Unit/EventListener/CustomItemTabSubscriberTest.php b/Tests/Unit/EventListener/CustomItemTabSubscriberTest.php index 2e4e7bb5e..fea8001e9 100644 --- a/Tests/Unit/EventListener/CustomItemTabSubscriberTest.php +++ b/Tests/Unit/EventListener/CustomItemTabSubscriberTest.php @@ -15,7 +15,7 @@ use MauticPlugin\CustomObjectsBundle\Repository\CustomItemRepository; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class CustomItemTabSubscriberTest extends TestCase { @@ -105,8 +105,8 @@ public function testForTabsContext(): void $this->customContentEvent ->method('checkContext') ->withConsecutive( - ['CustomObjectsBundle:CustomItem:detail.html.php', 'tabs'], - ['CustomObjectsBundle:CustomItem:detail.html.php', 'tabs.content'] + ['@CustomObjects/CustomItem/detail.html.twig', 'tabs'], + ['@CustomObjects/CustomItem/detail.html.twig', 'tabs.content'] ) ->willReturnOnConsecutiveCalls(true, false); @@ -118,7 +118,7 @@ public function testForTabsContext(): void ->method('addTemplate') ->withConsecutive( [ - 'CustomObjectsBundle:SubscribedEvents/Tab:link.html.php', + '@CustomObjects/SubscribedEvents/Tab/link.html.twig', [ 'count' => 13, 'title' => 'Object A', @@ -126,7 +126,7 @@ public function testForTabsContext(): void ], ], [ - 'CustomObjectsBundle:SubscribedEvents/Tab:modal.html.php', + '@CustomObjects/SubscribedEvents/Tab/modal.html.twig', ] ); @@ -158,8 +158,8 @@ public function testForTabsContextWhenTheCustomItemMatchesCustomObject(): void $this->customContentEvent ->method('checkContext') ->withConsecutive( - ['CustomObjectsBundle:CustomItem:detail.html.php', 'tabs'], - ['CustomObjectsBundle:CustomItem:detail.html.php', 'tabs.content'] + ['@CustomObjects/CustomItem/detail.html.twig', 'tabs'], + ['@CustomObjects/CustomItem/detail.html.twig', 'tabs.content'] ) ->willReturn(true, false); @@ -169,7 +169,7 @@ public function testForTabsContextWhenTheCustomItemMatchesCustomObject(): void $this->customContentEvent->expects($this->once()) ->method('addTemplate') - ->with('CustomObjectsBundle:SubscribedEvents/Tab:modal.html.php'); + ->with('@CustomObjects/SubscribedEvents/Tab/modal.html.twig'); $this->customObjectModel->expects($this->once()) ->method('getMasterCustomObjects') @@ -194,8 +194,8 @@ public function testForTabContentsContext(): void $this->customContentEvent ->method('checkContext') ->withConsecutive( - ['CustomObjectsBundle:CustomItem:detail.html.php', 'tabs'], - ['CustomObjectsBundle:CustomItem:detail.html.php', 'tabs.content'] + ['@CustomObjects/CustomItem/detail.html.twig', 'tabs'], + ['@CustomObjects/CustomItem/detail.html.twig', 'tabs.content'] ) ->willReturn(false, true); @@ -236,7 +236,7 @@ public function testForTabContentsContext(): void $this->customContentEvent->expects($this->once()) ->method('addTemplate') ->with( - 'CustomObjectsBundle:SubscribedEvents/Tab:content.html.php', + '@CustomObjects/SubscribedEvents/Tab/content.html.twig', [ 'customObjectId' => 555, 'currentEntityId' => 45, diff --git a/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php b/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php index 585817fbb..ec7bf22d0 100644 --- a/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php +++ b/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php @@ -72,8 +72,6 @@ protected function setUp(): void { parent::setUp(); - defined('MAUTIC_TABLE_PREFIX') || define('MAUTIC_TABLE_PREFIX', ''); - $this->entityManager = $this->createMock(EntityManager::class); $this->queryBuilder = $this->createMock(QueryBuilder::class); $this->queryBuilderDbal = $this->createMock(DbalQueryBuilder::class); diff --git a/Tests/Unit/EventListener/CustomObjectButtonSubscriberTest.php b/Tests/Unit/EventListener/CustomObjectButtonSubscriberTest.php index 3f1b0738f..83b3fce2d 100644 --- a/Tests/Unit/EventListener/CustomObjectButtonSubscriberTest.php +++ b/Tests/Unit/EventListener/CustomObjectButtonSubscriberTest.php @@ -12,7 +12,7 @@ use MauticPlugin\CustomObjectsBundle\Provider\CustomItemRouteProvider; use MauticPlugin\CustomObjectsBundle\Provider\CustomObjectPermissionProvider; use MauticPlugin\CustomObjectsBundle\Provider\CustomObjectRouteProvider; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class CustomObjectButtonSubscriberTest extends \PHPUnit\Framework\TestCase { diff --git a/Tests/Unit/EventListener/CustomObjectPostSaveSubscriberTest.php b/Tests/Unit/EventListener/CustomObjectPostSaveSubscriberTest.php index 5fb8f36fe..5422c7ea3 100644 --- a/Tests/Unit/EventListener/CustomObjectPostSaveSubscriberTest.php +++ b/Tests/Unit/EventListener/CustomObjectPostSaveSubscriberTest.php @@ -4,7 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\EventListener; -use Exception; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; use MauticPlugin\CustomObjectsBundle\Event\CustomObjectEvent; use MauticPlugin\CustomObjectsBundle\EventListener\CustomObjectPostSaveSubscriber; @@ -53,7 +52,7 @@ public function __construct() public function saveEntity($entity, $unlock = true): void { - throw new Exception('Should not have been called.'); + throw new \Exception('Should not have been called.'); } }; @@ -65,7 +64,7 @@ public function saveEntity($entity, $unlock = true): void $subscriber->postSave($event); - // Asserting that the exception is not thrown + // Asserting that the \Exception is not thrown $this->addToAssertionCount(1); } } diff --git a/Tests/Unit/EventListener/DynamicContentSubscriberTest.php b/Tests/Unit/EventListener/DynamicContentSubscriberTest.php index 147c95aab..6f28959d0 100644 --- a/Tests/Unit/EventListener/DynamicContentSubscriberTest.php +++ b/Tests/Unit/EventListener/DynamicContentSubscriberTest.php @@ -4,6 +4,7 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\EventListener; +use Doctrine\DBAL\Result; use Doctrine\DBAL\Statement; use Mautic\DynamicContentBundle\Event\ContactFiltersEvaluateEvent; use Mautic\LeadBundle\Entity\Lead; @@ -86,8 +87,6 @@ public function testFiltersNotEvaluatedIfEventMarkedEvaluated(): void public function testFiltersInsertedIntoEvent(): void { - defined('MAUTIC_TABLE_PREFIX') || define('MAUTIC_TABLE_PREFIX', ''); - $this->configProviderMock->expects($this->once())->method('pluginIsEnabled')->willReturn(true); $this->queryFilterFactory->expects($this->exactly(2)) @@ -120,11 +119,15 @@ public function testFiltersInsertedIntoEvent(): void $event = $this->buildEventWithFilters(); $event->setIsEvaluated(false); - $this->queryBuilderMock->expects($this->once())->method('execute')->willReturn($this->statementMock); + $result = $this->createMock(Result::class); + + $this->queryBuilderMock->expects($this->once()) + ->method('execute') + ->willReturn($result); $this->loggerMock ->expects($this->never()) - ->method('addError'); + ->method('error'); $this->dynamicContentSubscriber->evaluateFilters($event); } diff --git a/Tests/Unit/EventListener/FilterOperatorSubscriberTest.php b/Tests/Unit/EventListener/FilterOperatorSubscriberTest.php index 3afb8ca20..7be7eaf23 100644 --- a/Tests/Unit/EventListener/FilterOperatorSubscriberTest.php +++ b/Tests/Unit/EventListener/FilterOperatorSubscriberTest.php @@ -13,7 +13,7 @@ use MauticPlugin\CustomObjectsBundle\Model\CustomObjectModel; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormInterface; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; final class FilterOperatorSubscriberTest extends \PHPUnit\Framework\TestCase { @@ -29,7 +29,6 @@ final class FilterOperatorSubscriberTest extends \PHPUnit\Framework\TestCase protected function setUp(): void { - defined('MAUTIC_TABLE_PREFIX') || define('MAUTIC_TABLE_PREFIX', getenv('MAUTIC_DB_PREFIX') ?: ''); $this->customObjectModelMock = $this->createMock(CustomObjectModel::class); $this->filterOperatorSubscriber = new FilterOperatorSubscriber($this->customObjectModelMock); } diff --git a/Tests/Unit/EventListener/ImportSubscriberTest.php b/Tests/Unit/EventListener/ImportSubscriberTest.php index 9f50f200a..664c97541 100644 --- a/Tests/Unit/EventListener/ImportSubscriberTest.php +++ b/Tests/Unit/EventListener/ImportSubscriberTest.php @@ -21,7 +21,7 @@ use MauticPlugin\CustomObjectsBundle\Provider\CustomItemPermissionProvider; use MauticPlugin\CustomObjectsBundle\Repository\CustomFieldRepository; use Symfony\Component\Form\Form; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class ImportSubscriberTest extends \PHPUnit\Framework\TestCase { diff --git a/Tests/Unit/EventListener/MenuSubscriberTest.php b/Tests/Unit/EventListener/MenuSubscriberTest.php index fd2566aba..39e46569c 100644 --- a/Tests/Unit/EventListener/MenuSubscriberTest.php +++ b/Tests/Unit/EventListener/MenuSubscriberTest.php @@ -10,7 +10,6 @@ use MauticPlugin\CustomObjectsBundle\Model\CustomObjectModel; use MauticPlugin\CustomObjectsBundle\Provider\ConfigProvider; use MauticPlugin\CustomObjectsBundle\Provider\CustomItemRouteProvider; -use MauticPlugin\CustomObjectsBundle\Provider\CustomObjectRouteProvider; use PHPUnit\Framework\TestCase; class MenuSubscriberTest extends TestCase @@ -155,18 +154,7 @@ public function testAdminMenu(): void ->method('fetchAllPublishedEntities'); $this->menuEvent->expects($this->once()) - ->method('addMenuItems') - ->willReturn([ - 'priority' => 61, - 'items' => [ - 'custom.object.config.menu.title' => [ - 'id' => CustomObjectRouteProvider::ROUTE_LIST, - 'route' => CustomObjectRouteProvider::ROUTE_LIST, - 'access' => 'custom_objects:custom_objects:view', - 'iconClass' => 'fa-list-alt', - ], - ], - ]); + ->method('addMenuItems'); $this->menuSubscriber->onBuildMenu($this->menuEvent); } diff --git a/Tests/Unit/EventListener/ReportSubscriberTest.php b/Tests/Unit/EventListener/ReportSubscriberTest.php index 5dc053f93..ae8a2742f 100644 --- a/Tests/Unit/EventListener/ReportSubscriberTest.php +++ b/Tests/Unit/EventListener/ReportSubscriberTest.php @@ -25,7 +25,8 @@ use MauticPlugin\CustomObjectsBundle\Repository\CustomObjectRepository; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class ReportSubscriberTest extends TestCase { @@ -84,6 +85,11 @@ class ReportSubscriberTest extends TestCase */ private $connection; + /** + * @var MockObject|EventDispatcherInterface + */ + private $dispatcher; + /** * @var ReportHelper */ @@ -91,12 +97,11 @@ class ReportSubscriberTest extends TestCase protected function setUp(): void { - defined('MAUTIC_TABLE_PREFIX') || define('MAUTIC_TABLE_PREFIX', getenv('MAUTIC_DB_PREFIX') ?: ''); - $this->customObjectRepository = $this->createMock(CustomObjectRepository::class); $this->fieldsBuilder = $this->createMock(FieldsBuilder::class); $this->companyReportData = $this->createMock(CompanyReportData::class); - $this->reportHelper = new ReportHelper(); + $this->dispatcher = $this->createMock(EventDispatcherInterface::class); + $this->reportHelper = new ReportHelper($this->dispatcher); $this->translatorInterface = $this->createMock(TranslatorInterface::class); $this->reportSubscriber = new ReportSubscriber($this->customObjectRepository, $this->fieldsBuilder, $this->companyReportData, $this->reportHelper, $this->translatorInterface); $this->reportBuilderEvent = $this->createMock(ReportBuilderEvent::class); diff --git a/Tests/Unit/EventListener/SegmentFiltersChoicesGenerateSubscriberTest.php b/Tests/Unit/EventListener/SegmentFiltersChoicesGenerateSubscriberTest.php index 7f38fc534..cb5d41985 100644 --- a/Tests/Unit/EventListener/SegmentFiltersChoicesGenerateSubscriberTest.php +++ b/Tests/Unit/EventListener/SegmentFiltersChoicesGenerateSubscriberTest.php @@ -7,8 +7,14 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Criteria; use Mautic\LeadBundle\Event\LeadListFiltersChoicesEvent; +use Mautic\LeadBundle\Event\OverrideOperatorLabelEvent; +use Mautic\LeadBundle\Event\TypeOperatorsEvent; use Mautic\LeadBundle\LeadEvents; use Mautic\LeadBundle\Provider\FilterOperatorProviderInterface; +use Mautic\LeadBundle\Provider\TypeOperatorProvider; +use Mautic\LeadBundle\Provider\TypeOperatorProviderInterface; +use Mautic\LeadBundle\Segment\OperatorOptions; +use MauticPlugin\CustomObjectsBundle\CustomFieldType\DateType; use MauticPlugin\CustomObjectsBundle\CustomFieldType\IntType; use MauticPlugin\CustomObjectsBundle\Entity\CustomField; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; @@ -16,12 +22,16 @@ use MauticPlugin\CustomObjectsBundle\Provider\ConfigProvider; use MauticPlugin\CustomObjectsBundle\Provider\CustomFieldTypeProvider; use MauticPlugin\CustomObjectsBundle\Repository\CustomObjectRepository; +use MauticPlugin\CustomObjectsBundle\Tests\ProjectVersionTrait; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class SegmentFiltersChoicesGenerateSubscriberTest extends TestCase { + use ProjectVersionTrait; + /** * @var CustomObjectRepository|MockObject */ @@ -52,6 +62,16 @@ class SegmentFiltersChoicesGenerateSubscriberTest extends TestCase */ private $filterOperatorProvider; + /** + * @var TypeOperatorProviderInterface|MockObject + */ + private $typeOperatorProvider; + + /** + * @var EventDispatcherInterface|MockObject + */ + private $dispatcher; + public function setUp(): void { parent::setUp(); @@ -61,17 +81,27 @@ public function setUp(): void $this->configProvider = $this->createMock(ConfigProvider::class); $this->fieldTypeProvider = $this->createMock(CustomFieldTypeProvider::class); $this->filterOperatorProvider = $this->createMock(FilterOperatorProviderInterface::class); + $this->dispatcher = $this->createMock(EventDispatcherInterface::class); + $this->typeOperatorProvider = new TypeOperatorProvider( + $this->dispatcher, + $this->filterOperatorProvider + ); $this->subscriber = new SegmentFiltersChoicesGenerateSubscriber( $this->customObjectRepository, $this->translator, $this->configProvider, - $this->fieldTypeProvider + $this->fieldTypeProvider, + $this->typeOperatorProvider ); } public function testOnGenerateSegmentFilters(): void { + if (!$this->isCloudProject()) { + $this->markTestSkipped('Undefined index: default on TypeOperatorProvider.php:61 in 4.4'); + } + $customObject = new CustomObject(); $customObject->setId(1); $customObject->setNameSingular('Product'); @@ -98,116 +128,119 @@ public function testOnGenerateSegmentFilters(): void $allOperators = [ '=' => [ - 'label' => 'equals', - 'expr' => 'eq', - 'negate_expr' => 'neq', - ], + 'label' => 'equals', + 'expr' => 'eq', + 'negate_expr' => 'neq', + ], '!=' => [ - 'label' => 'not equal', - 'expr' => 'neq', - 'negate_expr' => 'eq', - ], + 'label' => 'not equal', + 'expr' => 'neq', + 'negate_expr' => 'eq', + ], 'gt' => [ - 'label' => 'greater than', - 'expr' => 'gt', - 'negate_expr' => 'lt', - ], + 'label' => 'greater than', + 'expr' => 'gt', + 'negate_expr' => 'lt', + ], 'gte' => [ - 'label' => 'greater than or equal', - 'expr' => 'gte', - 'negate_expr' => 'lt', - ], + 'label' => 'greater than or equal', + 'expr' => 'gte', + 'negate_expr' => 'lt', + ], 'lt' => [ - 'label' => 'less than', - 'expr' => 'lt', - 'negate_expr' => 'gt', - ], + 'label' => 'less than', + 'expr' => 'lt', + 'negate_expr' => 'gt', + ], 'lte' => [ - 'label' => 'less than or equal', - 'expr' => 'lte', - 'negate_expr' => 'gt', - ], + 'label' => 'less than or equal', + 'expr' => 'lte', + 'negate_expr' => 'gt', + ], 'empty' => [ - 'label' => 'empty', - 'expr' => 'empty', - 'negate_expr' => 'notEmpty', - ], + 'label' => 'empty', + 'expr' => 'empty', + 'negate_expr' => 'notEmpty', + ], '!empty' => [ - 'label' => 'not empty', - 'expr' => 'notEmpty', - 'negate_expr' => 'empty', - ], + 'label' => 'not empty', + 'expr' => 'notEmpty', + 'negate_expr' => 'empty', + ], 'like' => [ - 'label' => 'like', - 'expr' => 'like', - 'negate_expr' => 'notLike', - ], + 'label' => 'like', + 'expr' => 'like', + 'negate_expr' => 'notLike', + ], '!like' => [ - 'label' => 'not like', - 'expr' => 'notLike', - 'negate_expr' => 'like', - ], + 'label' => 'not like', + 'expr' => 'notLike', + 'negate_expr' => 'like', + ], 'between' => [ - 'label' => 'between', - 'expr' => 'between', - 'negate_expr' => 'notBetween', - 'hide' => true, - ], + 'label' => 'between', + 'expr' => 'between', + 'negate_expr' => 'notBetween', + ], '!between' => [ - 'label' => 'not between', - 'expr' => 'notBetween', - 'negate_expr' => 'between', - 'hide' => true, - ], + 'label' => 'not between', + 'expr' => 'notBetween', + 'negate_expr' => 'between', + ], 'in' => [ - 'label' => 'including', - 'expr' => 'in', - 'negate_expr' => 'notIn', - ], + 'label' => 'including', + 'expr' => 'in', + 'negate_expr' => 'notIn', + ], '!in' => [ - 'label' => 'excluding', - 'expr' => 'notIn', - 'negate_expr' => 'in', - ], + 'label' => 'excluding', + 'expr' => 'notIn', + 'negate_expr' => 'in', + ], 'regexp' => [ - 'label' => 'regexp', - 'expr' => 'regexp', - 'negate_expr' => 'notRegexp', - ], + 'label' => 'regexp', + 'expr' => 'regexp', + 'negate_expr' => 'notRegexp', + ], '!regexp' => [ - 'label' => 'not regexp', - 'expr' => 'notRegexp', - 'negate_expr' => 'regexp', - ], + 'label' => 'not regexp', + 'expr' => 'notRegexp', + 'negate_expr' => 'regexp', + ], 'date' => [ - 'label' => 'date', - 'expr' => 'date', - 'negate_expr' => 'date', - 'hide' => true, - ], + 'label' => 'date', + 'expr' => 'date', + 'negate_expr' => 'date', + 'hide' => true, + ], 'startsWith' => [ - 'label' => 'starts with', - 'expr' => 'startsWith', - 'negate_expr' => 'startsWith', - ], + 'label' => 'starts with', + 'expr' => 'startsWith', + 'negate_expr' => 'startsWith', + ], 'endsWith' => [ - 'label' => 'ends with', - 'expr' => 'endsWith', - 'negate_expr' => 'endsWith', - ], + 'label' => 'ends with', + 'expr' => 'endsWith', + 'negate_expr' => 'endsWith', + ], 'contains' => [ - 'label' => 'contains', - 'expr' => 'contains', - 'negate_expr' => 'contains', - ], + 'label' => 'contains', + 'expr' => 'contains', + 'negate_expr' => 'contains', + ], 'withinCustomObjects' => [ - 'label' => 'within custom objects', - 'expr' => 'withinCustomObjects', - 'negate_expr' => 'notWithinCustomObjects', - ], + 'label' => 'within custom objects', + 'expr' => 'withinCustomObjects', + 'negate_expr' => 'notWithinCustomObjects', + ], + ]; + + $betweenOperators = [ + 'between' => 'between', + 'not between' => '!between', ]; - $fieldOperators = [ + $fieldOperators = array_merge([ 'equals' => '=', 'not equal' => '!=', 'greater than' => 'gt', @@ -216,6 +249,136 @@ public function testOnGenerateSegmentFilters(): void 'less than or equal' => 'lte', 'empty' => 'empty', 'not empty' => '!empty', + ], $betweenOperators); + + $event = new LeadListFiltersChoicesEvent([], [], $this->translator); + + $this->configProvider->expects($this->once()) + ->method('pluginIsEnabled') + ->willReturn(true); + + $this->fieldTypeProvider->expects($this->once()) + ->method('getKeyTypeMapping') + ->willReturn($keyTypeMapping); + + $this->customObjectRepository->expects($this->once()) + ->method('matching') + ->with($criteria) + ->willReturn(new ArrayCollection([$customObject])); + + $translationsKeys = [ + ['custom.item.name.label'], + ['mautic.lead.list.form.operator.equals'], + ['mautic.lead.list.form.operator.notequals'], + ['mautic.lead.list.form.operator.isempty'], + ['mautic.lead.list.form.operator.isnotempty'], + ['mautic.lead.list.form.operator.islike'], + ['mautic.lead.list.form.operator.isnotlike'], + ['mautic.lead.list.form.operator.regexp'], + ['mautic.lead.list.form.operator.notregexp'], + ['mautic.core.operator.starts.with'], + ['mautic.core.operator.ends.with'], + ['mautic.core.operator.contains'], + ['mautic.lead.list.form.operator.equals'], + ['mautic.lead.list.form.operator.notequals'], + ['mautic.lead.list.form.operator.greaterthan'], + ['mautic.lead.list.form.operator.greaterthanequals'], + ['mautic.lead.list.form.operator.lessthan'], + ['mautic.lead.list.form.operator.lessthanequals'], + ['mautic.lead.list.form.operator.isempty'], + ['mautic.lead.list.form.operator.isnotempty'], + ['mautic.lead.list.form.operator.islike'], + ['mautic.lead.list.form.operator.isnotlike'], + ['mautic.lead.list.form.operator.between'], + ['mautic.lead.list.form.operator.notbetween'], + ['mautic.lead.list.form.operator.regexp'], + ['mautic.lead.list.form.operator.notregexp'], + ['mautic.core.operator.starts.with'], + ['mautic.core.operator.ends.with'], + ['mautic.core.operator.contains'], + ]; + + $translations = [ + 'Mobile', + 'equals', + 'not equal', + 'empty', + 'not empty', + 'like', + 'not like', + 'regexp', + 'not regexp', + 'starts with', + 'ends with', + 'contains', + 'equals', + 'not equal', + 'greater than', + 'greater than or equal', + 'less than', + 'less than or equal', + 'empty', + 'not empty', + 'like', + 'not like', + 'between', + 'not between', + 'regexp', + 'not regexp', + 'starts with', + 'ends with', + 'contains', + ]; + + $this->translator + ->method('trans') + ->withConsecutive(...$translationsKeys) + ->willReturn(...$translations); + + $this->filterOperatorProvider->expects($this->any()) + ->method('getAllOperators') + ->willReturn($allOperators); + + $this->subscriber->onGenerateSegmentFilters($event); + + $choices = $event->getChoices(); + $this->assertIsArray($choices); + $this->assertArrayHasKey('custom_object', $choices); + $this->assertArrayHasKey('cmo_1', $choices['custom_object']); + $this->assertArrayHasKey('cmf_1', $choices['custom_object']); + $this->assertSame('Products Mobile', $choices['custom_object']['cmo_1']['label']); + $this->assertSame('Products : Price', $choices['custom_object']['cmf_1']['label']); + $this->assertSame($fieldOperators, $choices['custom_object']['cmf_1']['operators']); + } + + public function testOnGenerateSegmentFiltersForDate(): void + { + if (!$this->isCloudProject()) { + $this->markTestSkipped('OVERRIDE_OPERATOR_LABEL_FOR_FIELD_TYPE event is not present in 4.4'); + } + + $customObject = new CustomObject(); + $customObject->setId(1); + $customObject->setNameSingular('Product'); + $customObject->setNamePlural('Products'); + $customObject->setIsPublished(true); + + $dateType = new DateType($this->translator, $this->filterOperatorProvider); + $dateCustomField = new CustomField(); + $dateCustomField->setId(2); + $dateCustomField->setType('date'); + $dateCustomField->setTypeObject($dateType); + $dateCustomField->setLabel('Purchase Date'); + $dateCustomField->setAlias('purchase_date'); + + $customObject->addCustomField($dateCustomField); + + $criteria = new Criteria(Criteria::expr()->eq('isPublished', 1)); + + $keyTypeMapping = [ + 'custom.field.type.text' => 'text', + 'custom.field.type.date' => 'date', + 'custom.field.type.hidden' => 'hidden', ]; $event = new LeadListFiltersChoicesEvent([], [], $this->translator); @@ -237,66 +400,94 @@ public function testOnGenerateSegmentFilters(): void ->method('trans') ->withConsecutive( ['custom.item.name.label'], - ['mautic.lead.list.form.operator.equals'], - ['mautic.lead.list.form.operator.notequals'], - ['mautic.lead.list.form.operator.isempty'], - ['mautic.lead.list.form.operator.isnotempty'], - ['mautic.lead.list.form.operator.islike'], - ['mautic.lead.list.form.operator.isnotlike'], - ['mautic.lead.list.form.operator.regexp'], - ['mautic.lead.list.form.operator.notregexp'], - ['mautic.core.operator.starts.with'], - ['mautic.core.operator.ends.with'], - ['mautic.core.operator.contains'], - ['mautic.lead.list.form.operator.equals'], - ['mautic.lead.list.form.operator.notequals'], - ['mautic.lead.list.form.operator.greaterthan'], - ['mautic.lead.list.form.operator.greaterthanequals'], - ['mautic.lead.list.form.operator.lessthan'], - ['mautic.lead.list.form.operator.lessthanequals'], - ['mautic.lead.list.form.operator.isempty'], - ['mautic.lead.list.form.operator.isnotempty'], - ['mautic.lead.list.form.operator.islike'], - ['mautic.lead.list.form.operator.isnotlike'], - ['mautic.lead.list.form.operator.regexp'], - ['mautic.lead.list.form.operator.notregexp'], - ['mautic.core.operator.starts.with'], - ['mautic.core.operator.ends.with'], - ['mautic.core.operator.contains'] ) ->willReturn( - 'Mobile', - 'equals', - 'not equal', - 'empty', - 'not empty', - 'like', - 'not like', - 'regexp', - 'not regexp', - 'starts with', - 'ends with', - 'contains', - 'equals', - 'not equal', - 'greater than', - 'greater than or equal', - 'less than', - 'less than or equal', - 'empty', - 'not empty', - 'like', - 'not like', - 'regexp', - 'not regexp', - 'starts with', - 'ends with', - 'contains' + 'Mobile' ); $this->filterOperatorProvider->expects($this->once()) ->method('getAllOperators') - ->willReturn($allOperators); + ->willReturn([ + OperatorOptions::GREATER_THAN => [ + 'label' => 'grater than', + 'expr' => 'gt', + 'negate_expr' => 'lt', + ], + OperatorOptions::GREATER_THAN_OR_EQUAL => [ + 'label' => 'grater than or equal', + 'expr' => 'gte', + 'negate_expr' => 'lt', + ], + OperatorOptions::LESS_THAN => [ + 'label' => 'less than', + 'expr' => 'lt', + 'negagte_expr' => 'gt', + ], + OperatorOptions::LESS_THAN_OR_EQUAL => [ + 'label' => 'less than or equal', + 'expr' => 'lte', + 'negate_expr' => 'gt', + ], + ]); + + $this->dispatcher->expects($this->exactly(3)) + ->method('dispatch') + ->withConsecutive( + [ + LeadEvents::COLLECT_OPERATORS_FOR_FIELD_TYPE, + $this->callback(function (TypeOperatorsEvent $event) { + // Emulate a subscriber. + $event->setOperatorsForFieldType('date', [ + 'include' => [ + OperatorOptions::GREATER_THAN, + OperatorOptions::GREATER_THAN_OR_EQUAL, + OperatorOptions::LESS_THAN, + OperatorOptions::LESS_THAN_OR_EQUAL, + ], + ]); + + $event->setOperatorsForFieldType('text', [ + 'include' => [ + OperatorOptions::GREATER_THAN, + OperatorOptions::GREATER_THAN_OR_EQUAL, + OperatorOptions::LESS_THAN, + OperatorOptions::LESS_THAN_OR_EQUAL, + ], + ]); + + return true; + }), + ], + [ + LeadEvents::OVERRIDE_OPERATOR_LABEL_FOR_FIELD_TYPE, + $this->callback(function (OverrideOperatorLabelEvent $event) { + // Emulate a subscriber. + $event->setTypeOperatorsChoices( + [ + 'Greater Than' => OperatorOptions::GREATER_THAN, + ] + ); + + return true; + }), + ], + [ + LeadEvents::OVERRIDE_OPERATOR_LABEL_FOR_FIELD_TYPE, + $this->callback(function (OverrideOperatorLabelEvent $event) { + // Emulate a subscriber. + $event->setTypeOperatorsChoices( + [ + 'After' => OperatorOptions::GREATER_THAN, + 'After (Including day)' => OperatorOptions::GREATER_THAN_OR_EQUAL, + 'Before' => OperatorOptions::LESS_THAN, + 'Before (Including day)' => OperatorOptions::LESS_THAN_OR_EQUAL, + ] + ); + + return true; + }), + ], + ); $this->subscriber->onGenerateSegmentFilters($event); @@ -304,10 +495,18 @@ public function testOnGenerateSegmentFilters(): void $this->assertIsArray($choices); $this->assertArrayHasKey('custom_object', $choices); $this->assertArrayHasKey('cmo_1', $choices['custom_object']); - $this->assertArrayHasKey('cmf_1', $choices['custom_object']); + $this->assertArrayHasKey('cmf_2', $choices['custom_object']); $this->assertSame('Products Mobile', $choices['custom_object']['cmo_1']['label']); - $this->assertSame('Products : Price', $choices['custom_object']['cmf_1']['label']); - $this->assertSame($fieldOperators, $choices['custom_object']['cmf_1']['operators']); + $this->assertSame('Products : Purchase Date', $choices['custom_object']['cmf_2']['label']); + $this->assertSame( + [ + 'After' => OperatorOptions::GREATER_THAN, + 'After (Including day)' => OperatorOptions::GREATER_THAN_OR_EQUAL, + 'Before' => OperatorOptions::LESS_THAN, + 'Before (Including day)' => OperatorOptions::LESS_THAN_OR_EQUAL, + ], + $choices['custom_object']['cmf_2']['operators'] + ); } public function testGetSubscribedEvents(): void diff --git a/Tests/Unit/EventListener/SerializerSubscriberTest.php b/Tests/Unit/EventListener/SerializerSubscriberTest.php index 5f607ce93..3e154b68c 100644 --- a/Tests/Unit/EventListener/SerializerSubscriberTest.php +++ b/Tests/Unit/EventListener/SerializerSubscriberTest.php @@ -27,7 +27,7 @@ use MauticPlugin\CustomObjectsBundle\Repository\CustomItemXrefContactRepository; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class SerializerSubscriberTest extends \PHPUnit\Framework\TestCase { diff --git a/Tests/Unit/EventListener/TokenSubscriberTest.php b/Tests/Unit/EventListener/TokenSubscriberTest.php index 62f2821be..296d881f7 100644 --- a/Tests/Unit/EventListener/TokenSubscriberTest.php +++ b/Tests/Unit/EventListener/TokenSubscriberTest.php @@ -7,6 +7,7 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\DBAL\Query\QueryBuilder; use Mautic\CampaignBundle\Entity\Campaign; +use Mautic\CampaignBundle\Entity\Event; use Mautic\CampaignBundle\Event\CampaignEvent; use Mautic\CampaignBundle\Model\EventModel; use Mautic\CoreBundle\Event\BuilderEvent; @@ -29,6 +30,7 @@ use MauticPlugin\CustomObjectsBundle\Helper\QueryFilterHelper; use MauticPlugin\CustomObjectsBundle\Helper\TokenFormatter; use MauticPlugin\CustomObjectsBundle\Helper\TokenParser; +use MauticPlugin\CustomObjectsBundle\Model\CustomFieldModel; use MauticPlugin\CustomObjectsBundle\Model\CustomItemModel; use MauticPlugin\CustomObjectsBundle\Model\CustomObjectModel; use MauticPlugin\CustomObjectsBundle\Provider\ConfigProvider; @@ -36,7 +38,7 @@ use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\EventDispatcher\EventDispatcher; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class TokenSubscriberTest extends TestCase { @@ -65,6 +67,11 @@ class TokenSubscriberTest extends TestCase */ private $customItemModel; + /** + * @var CustomFieldModel|MockObject + */ + private $customFieldModel; + /** * @var TokenParser|MockObject */ @@ -114,6 +121,7 @@ protected function setUp(): void $this->queryFilterFactory = $this->createMock(QueryFilterFactory::class); $this->customObjectModel = $this->createMock(CustomObjectModel::class); $this->customItemModel = $this->createMock(CustomItemModel::class); + $this->customFieldModel = $this->createMock(CustomFieldModel::class); $this->tokenParser = $this->createMock(TokenParser::class); $this->eventModel = $this->createMock(EventModel::class); $this->eventDispatcher = $this->createMock(EventDispatcher::class); @@ -124,10 +132,12 @@ protected function setUp(): void $this->queryFilterFactory, $this->customObjectModel, $this->customItemModel, + $this->customFieldModel, $this->tokenParser, $this->eventModel, $this->eventDispatcher, - $this->tokenFormatter + $this->tokenFormatter, + 15 ); $this->builderEvent = $this->createMock(BuilderEvent::class); @@ -143,6 +153,7 @@ public function testGetSubscribedEvents(): void EmailEvents::EMAIL_ON_SEND => ['decodeTokens', 0], EmailEvents::EMAIL_ON_DISPLAY => ['decodeTokens', 0], CustomItemEvents::ON_CUSTOM_ITEM_LIST_DBAL_QUERY => ['onListQuery', -1], + EmailEvents::TOKEN_REPLACEMENT => ['onTokenReplacement', 100], ], TokenSubscriber::getSubscribedEvents() ); @@ -786,7 +797,7 @@ public function testOnListQueryForSegmentFilterWithCampaignEmailWhenNoSegmentExi $this->constructWithDependencies(); $queryBuilder = $this->createMock(QueryBuilder::class); - $campaignEvent = $this->createMock(CampaignEvent::class); + $campaignEvent = $this->createMock(Event::class); $token = $this->tokenParser->findTokens('{custom-object=product:sku | where=segment-filter |order=latest|limit=1 | default=No thing}')->current(); $campaign = $this->createMock(Campaign::class); @@ -844,10 +855,12 @@ private function constructWithDependencies(): void $this->queryFilterFactory, $this->customObjectModel, $this->customItemModel, + $this->customFieldModel, $this->tokenParser, $this->eventModel, $this->eventDispatcher, - new TokenFormatter() + new TokenFormatter(), + 15 ); } } diff --git a/Tests/Unit/Form/Type/CampaignConditionFieldValueTypeTest.php b/Tests/Unit/Form/Type/CampaignConditionFieldValueTypeTest.php index c8df0e30e..8288c7e93 100644 --- a/Tests/Unit/Form/Type/CampaignConditionFieldValueTypeTest.php +++ b/Tests/Unit/Form/Type/CampaignConditionFieldValueTypeTest.php @@ -10,6 +10,7 @@ use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; use MauticPlugin\CustomObjectsBundle\Form\Type\CampaignConditionFieldValueType; use MauticPlugin\CustomObjectsBundle\Model\CustomFieldModel; +use MauticPlugin\CustomObjectsBundle\Model\CustomObjectModel; use MauticPlugin\CustomObjectsBundle\Provider\CustomItemRouteProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -19,7 +20,7 @@ use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormConfigBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; final class CampaignConditionFieldValueTypeTest extends TestCase { @@ -28,6 +29,11 @@ final class CampaignConditionFieldValueTypeTest extends TestCase */ private $customFieldModelMock; + /** + * @var MockObject|CustomObjectModel + */ + private $customObjectModelMock; + /** * @var MockObject|CustomItemRouteProvider */ @@ -48,10 +54,12 @@ protected function setUp(): void parent::setUp(); $this->customFieldModelMock = $this->createMock(CustomFieldModel::class); + $this->customObjectModelMock = $this->createMock(CustomObjectModel::class); $this->customItemRouterMock = $this->createMock(CustomItemRouteProvider::class); $this->translatorMock = $this->createMock(TranslatorInterface::class); $this->campaignConditionFieldValueType = new CampaignConditionFieldValueType( $this->customFieldModelMock, + $this->customObjectModelMock, $this->customItemRouterMock, $this->translatorMock ); @@ -80,6 +88,11 @@ public function testBuildForm(): void $customField->setTypeObject(new IntType($this->translatorMock, $filterOperatorProviderInterfaceMock)); $customFields = [42 => $customField]; + $this->customObjectModelMock + ->expects(self::once()) + ->method('fetchEntity') + ->with($customObject->getId()) + ->willReturn($customObject); $this->customFieldModelMock ->expects(self::once()) ->method('fetchCustomFieldsForObject') @@ -102,7 +115,7 @@ public function testBuildForm(): void 'class' => 'form-control', ], 'choice_attr' => [ - 42 => [ + 'Cheese' => [ 'data-operators' => '{"=":"a","!=":"b"}', 'data-options' => '[]', 'data-field-type' => 'int', @@ -139,8 +152,8 @@ public function testBuildForm(): void ] ); $options = [ - 'customObject' => $customObject, - 'data' => [ + 'customObjectId' => $customObject->getId(), + 'data' => [ 'field' => 42, ], ]; @@ -160,7 +173,7 @@ public function testConfigureOptions() $resolver ->expects(self::once()) ->method('setRequired') - ->with(['customObject']); + ->with(['customObjectId']); $this->campaignConditionFieldValueType->configureOptions($resolver); } diff --git a/Tests/Unit/Form/Type/CustomFieldTypeTest.php b/Tests/Unit/Form/Type/CustomFieldTypeTest.php index 789229922..37b3e389a 100644 --- a/Tests/Unit/Form/Type/CustomFieldTypeTest.php +++ b/Tests/Unit/Form/Type/CustomFieldTypeTest.php @@ -4,7 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\Form\Type; -use Mautic\CoreBundle\Form\Type\FormButtonsType; use Mautic\CoreBundle\Form\Type\YesNoButtonGroupType; use MauticPlugin\CustomObjectsBundle\Entity\CustomField; use MauticPlugin\CustomObjectsBundle\Entity\CustomFieldFactory; @@ -66,6 +65,7 @@ public function testBuildModalFormFields(): void { $options['data'] = $this->customField; $options['custom_object_form'] = ''; + $options['action'] = ''; $this->formBuilder->expects($this->once()) ->method('addModelTransFormer') @@ -160,9 +160,9 @@ public function testBuildModalFormFields(): void 'label' => 'custom.field.is_unique_identifier.label', 'attr' => [ 'data-toggle-button' => true, - 'tooltip' => 'custom.field.help.is_unique_identifier' + 'tooltip' => 'custom.field.help.is_unique_identifier', ], - ] + ], ] ); diff --git a/Tests/Unit/Form/Validator/AllowUniqueIdentifierTest.php b/Tests/Unit/Form/Validator/AllowUniqueIdentifierTest.php index c5271f759..90a44a140 100644 --- a/Tests/Unit/Form/Validator/AllowUniqueIdentifierTest.php +++ b/Tests/Unit/Form/Validator/AllowUniqueIdentifierTest.php @@ -27,4 +27,4 @@ public function testGetTargets(): void { $this->assertSame(AllowUniqueIdentifier::CLASS_CONSTRAINT, $this->constraint->getTargets()); } -} \ No newline at end of file +} diff --git a/Tests/Unit/Form/Validator/AllowUniqueIdentifierValidatorTest.php b/Tests/Unit/Form/Validator/AllowUniqueIdentifierValidatorTest.php index c276abae4..e4ce50e8f 100644 --- a/Tests/Unit/Form/Validator/AllowUniqueIdentifierValidatorTest.php +++ b/Tests/Unit/Form/Validator/AllowUniqueIdentifierValidatorTest.php @@ -4,9 +4,7 @@ use MauticPlugin\CustomObjectsBundle\Entity\CustomField; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; -use MauticPlugin\CustomObjectsBundle\Form\Validator\Constraints\AllowUniqueIdentifier; use MauticPlugin\CustomObjectsBundle\Form\Validator\Constraints\AllowUniqueIdentifierValidator; -use MauticPlugin\CustomObjectsBundle\Model\CustomFieldModel; use MauticPlugin\CustomObjectsBundle\Model\CustomItemModel; use MauticPlugin\CustomObjectsBundle\Repository\CustomItemRepository; use PHPUnit\Framework\MockObject\MockObject; @@ -105,6 +103,10 @@ public function testAllowIsUniqueIdentifierInvalid(): void ->method('addViolation'); /** @phpstan-ignore-next-line */ + $this->constraint->method('__get') + ->with('message') + ->willReturn('custom.field.allow.unique_identifier.invalid'); + $message = $this->constraint->message; $this->context->expects($this->once()) ->method('buildViolation') diff --git a/Tests/Unit/Form/Validator/CustomObjectTypeValuesValidatorTest.php b/Tests/Unit/Form/Validator/CustomObjectTypeValuesValidatorTest.php index 63f1943a2..78e83912f 100644 --- a/Tests/Unit/Form/Validator/CustomObjectTypeValuesValidatorTest.php +++ b/Tests/Unit/Form/Validator/CustomObjectTypeValuesValidatorTest.php @@ -86,6 +86,10 @@ public function testValidateNoCustomObject() $violationBuilder->expects($this->once()) ->method('addViolation'); + $this->constraint->method('__get') + ->with('missingMasterObject') + ->willReturn("Objects of type 'Relationship' must select a master object."); + $this->context->expects($this->once()) ->method('buildViolation') ->with($this->constraint->missingMasterObject) diff --git a/Tests/Unit/Helper/LockFlashMessageHelperTest.php b/Tests/Unit/Helper/LockFlashMessageHelperTest.php index 9d6d1bd40..ea1d8aae8 100644 --- a/Tests/Unit/Helper/LockFlashMessageHelperTest.php +++ b/Tests/Unit/Helper/LockFlashMessageHelperTest.php @@ -10,7 +10,7 @@ use MauticPlugin\CustomObjectsBundle\Helper\LockFlashMessageHelper; use PHPUnit\Framework\TestCase; use Symfony\Component\Routing\Router; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class LockFlashMessageHelperTest extends TestCase { @@ -76,7 +76,7 @@ public function testAddFlash(): void $checkedOut ->method('format') ->withConsecutive([$dateFormat1], [$dateFormat2], [$dateFormat3]) - ->willReturnOnConsecutiveCalls(1, 2, 3); + ->willReturnOnConsecutiveCalls('1', '2', '3'); $flashBag->expects($this->once()) ->method('add') diff --git a/Tests/Unit/Helper/QueryFilterFactoryTest.php b/Tests/Unit/Helper/QueryFilterFactoryTest.php index 9ff200554..603795971 100644 --- a/Tests/Unit/Helper/QueryFilterFactoryTest.php +++ b/Tests/Unit/Helper/QueryFilterFactoryTest.php @@ -26,14 +26,12 @@ class QueryFilterFactoryTest extends TestCase */ private $segmentFilter; - private string $prefix = ''; + private ?string $prefix = ''; public function setUp(): void { parent::setUp(); - defined('MAUTIC_TABLE_PREFIX') || define('MAUTIC_TABLE_PREFIX', '___'); - $this->prefix = MAUTIC_TABLE_PREFIX; $this->segmentFilter = $this->createMock(ContactSegmentFilter::class); @@ -199,6 +197,7 @@ private function trimSpacesAndLinebreaks(string $string): string { // Remove line breaks $string = preg_replace('/[\r\n]+/', ' ', $string); + // Remove multi-spaces return preg_replace('!\s+!', ' ', $string); } diff --git a/Tests/Unit/Helper/QueryFilterHelperTest.php b/Tests/Unit/Helper/QueryFilterHelperTest.php index b1da3be6c..1fd415595 100644 --- a/Tests/Unit/Helper/QueryFilterHelperTest.php +++ b/Tests/Unit/Helper/QueryFilterHelperTest.php @@ -8,6 +8,7 @@ use Doctrine\ORM\EntityManager; use Mautic\LeadBundle\Segment\Query\Expression\ExpressionBuilder; use Mautic\LeadBundle\Segment\Query\QueryBuilder; +use Mautic\LeadBundle\Segment\RandomParameterName; use MauticPlugin\CustomObjectsBundle\Helper\QueryFilterFactory; use MauticPlugin\CustomObjectsBundle\Helper\QueryFilterHelper; use MauticPlugin\CustomObjectsBundle\Provider\CustomFieldTypeProvider; @@ -49,7 +50,8 @@ protected function setUp(): void $this->createMock(CustomFieldRepository::class), new QueryFilterFactory\Calculator(), 1 - ) + ), + new RandomParameterName() ); $this->queryBuilder = $this->createMock(QueryBuilder::class); $this->expressionBuilder = $this->createMock(ExpressionBuilder::class); @@ -78,7 +80,7 @@ public function testAddCustomObjectNameExpression(): void $this->queryBuilder ->expects($this->any()) ->method('setParameter') - ->with('test_value_value', 'acquia', null); + ->with('par0', 'acquia', null); $this->queryFilterHelper ->addCustomObjectNameExpression($this->queryBuilder, 'test', 'eq', 'acquia'); diff --git a/Tests/Unit/Model/CustomFieldOptionModelTest.php b/Tests/Unit/Model/CustomFieldOptionModelTest.php index 719d7c1f6..15ee572c6 100644 --- a/Tests/Unit/Model/CustomFieldOptionModelTest.php +++ b/Tests/Unit/Model/CustomFieldOptionModelTest.php @@ -24,8 +24,6 @@ protected function setUp(): void { parent::setUp(); - defined('MAUTIC_TABLE_PREFIX') || define('MAUTIC_TABLE_PREFIX', ''); - $this->entityManager = $this->createMock(EntityManager::class); $this->connection = $this->createMock(Connection::class); $this->queryBuilder = $this->createMock(QueryBuilder::class); diff --git a/Tests/Unit/Model/CustomFieldValueModelTest.php b/Tests/Unit/Model/CustomFieldValueModelTest.php index ea70cf92d..4996f40c9 100644 --- a/Tests/Unit/Model/CustomFieldValueModelTest.php +++ b/Tests/Unit/Model/CustomFieldValueModelTest.php @@ -7,6 +7,7 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\DBAL\Connection; use Doctrine\DBAL\Query\QueryBuilder; +use Doctrine\DBAL\Result; use Doctrine\DBAL\Statement; use Doctrine\ORM\AbstractQuery; use Doctrine\ORM\EntityManager; @@ -18,9 +19,9 @@ use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; use MauticPlugin\CustomObjectsBundle\Model\CustomFieldValueModel; -use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Validator\ConstraintViolationListInterface; use Symfony\Component\Validator\Validator\ValidatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class CustomFieldValueModelTest extends \PHPUnit\Framework\TestCase { @@ -41,8 +42,6 @@ protected function setUp(): void { parent::setUp(); - defined('MAUTIC_TABLE_PREFIX') || define('MAUTIC_TABLE_PREFIX', ''); - $this->customObject = $this->createMock(CustomObject::class); $this->customItem = $this->createMock(CustomItem::class); $this->customField = $this->createMock(CustomField::class); @@ -66,7 +65,7 @@ public function testGetValuesForItemIfItemDoesNotHaveId(): void { $customFields = new ArrayCollection([$this->customField]); - $this->customItem->expects($this->once()) + $this->customItem->expects($this->any()) ->method('getCustomObject') ->willReturn($this->customObject); @@ -177,11 +176,14 @@ public function testGetValuesForItemIfItemHasId(): void ->with('THE TEXT FIELD SQL QUERY UNION ALL THE NUMBER FIELD SQL QUERY') ->willReturn($this->statement); - $this->statement->expects($this->once()) - ->method('execute'); + $result = $this->createMock(Result::class); $this->statement->expects($this->once()) - ->method('fetchAll') + ->method('executeQuery') + ->willReturn($result); + + $result->expects($this->once()) + ->method('fetchAllAssociative') ->willReturn([[ 'custom_field_id' => 44, 'custom_item_id' => 33, @@ -248,7 +250,7 @@ public function testSaveForExistingCustomItem(): void $this->customItem->expects($this->exactly(2)) ->method('getId') - ->willReturn(null); + ->willReturn(0); $this->entityManager->expects($this->once()) ->method('persist') diff --git a/Tests/Unit/Model/CustomItemImportModelTest.php b/Tests/Unit/Model/CustomItemImportModelTest.php index 17aca122e..8ef2eeaa1 100644 --- a/Tests/Unit/Model/CustomItemImportModelTest.php +++ b/Tests/Unit/Model/CustomItemImportModelTest.php @@ -6,12 +6,20 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\EntityManager; -use Mautic\CoreBundle\Templating\Helper\FormatterHelper; +use Mautic\CoreBundle\Helper\CoreParametersHelper; +use Mautic\CoreBundle\Helper\UserHelper; +use Mautic\CoreBundle\Security\Permissions\CorePermissions; +use Mautic\CoreBundle\Translation\Translator; +use Mautic\CoreBundle\Twig\Helper\DateHelper; +use Mautic\CoreBundle\Twig\Helper\FormatterHelper; use Mautic\LeadBundle\Entity\Import; +use Mautic\LeadBundle\Entity\Lead; +use Mautic\LeadBundle\Entity\LeadRepository; use Mautic\LeadBundle\Provider\FilterOperatorProviderInterface; use Mautic\UserBundle\Entity\User; use MauticPlugin\CustomObjectsBundle\CustomFieldType\DateTimeType; use MauticPlugin\CustomObjectsBundle\CustomFieldType\TextareaType; +use MauticPlugin\CustomObjectsBundle\DTO\ImportLogDTO; use MauticPlugin\CustomObjectsBundle\Entity\CustomField; use MauticPlugin\CustomObjectsBundle\Entity\CustomFieldValueInterface; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; @@ -20,7 +28,9 @@ use MauticPlugin\CustomObjectsBundle\Model\CustomItemImportModel; use MauticPlugin\CustomObjectsBundle\Model\CustomItemModel; use PHPUnit\Framework\MockObject\MockObject; -use Symfony\Component\Translation\TranslatorInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; class CustomItemImportModelTest extends \PHPUnit\Framework\TestCase { @@ -54,14 +64,48 @@ class CustomItemImportModelTest extends \PHPUnit\Framework\TestCase private $entityManager; /** - * @var MockObject|CustomItemModel + * @var MockObject|CorePermissions */ - private $customItemModel; + private $security; + + /** + * @var MockObject|EventDispatcherInterface + */ + private $dispatcher; + + /** + * @var MockObject|UrlGeneratorInterface + */ + private $router; + + /** + * @var MockObject|Translator + */ + private $translator; + + /** + * @var MockObject|UserHelper + */ + private $userHelper; + + /** + * @var MockObject|LoggerInterface + */ + private $logger; + + /** + * @var MockObject|CoreParametersHelper + */ + private $coreParametersHelper; + + private DateHelper $dateHelper; /** - * @var MockObject|FormatterHelper + * @var MockObject|CustomItemModel */ - private $formatterHelper; + private $customItemModel; + + private FormatterHelper $formatterHelper; /** * @var MockObject|CustomField @@ -93,23 +137,51 @@ protected function setUp(): void $this->import = $this->createMock(Import::class); $this->customItemModel = $this->createMock(CustomItemModel::class); $this->entityManager = $this->createMock(EntityManager::class); - $this->formatterHelper = $this->createMock(FormatterHelper::class); + $this->security = $this->createMock(CorePermissions::class); + $this->dispatcher = $this->createMock(EventDispatcherInterface::class); + $this->router = $this->createMock(UrlGeneratorInterface::class); + $this->translator = $this->createMock(Translator::class); + $this->userHelper = $this->createMock(UserHelper::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->coreParametersHelper = $this->createMock(CoreParametersHelper::class); + + $this->dateHelper = new DateHelper( + 'F j, Y g:i a T', + 'D, M d', + 'F j, Y', + 'g:i a', + $this->translator, + $this->coreParametersHelper, + ); + + $this->formatterHelper = new FormatterHelper( + $this->dateHelper, + $this->translator, + ); $this->filterOperatorProvider = $this->createMock(FilterOperatorProviderInterface::class); $this->customItemImportModel = new CustomItemImportModel( $this->entityManager, + $this->security, + $this->dispatcher, + $this->router, + $this->translator, + $this->userHelper, + $this->logger, + $this->coreParametersHelper, $this->customItemModel, $this->formatterHelper ); - /** @var TranslatorInterface $translator */ - $translator = $this->createMock(TranslatorInterface::class); - - $textareaType = new TextareaType($translator, $this->filterOperatorProvider); - $dateTimeType = new DateTimeType($translator, $this->filterOperatorProvider); + $textareaType = new TextareaType($this->translator, $this->filterOperatorProvider); + $dateTimeType = new DateTimeType($this->translator, $this->filterOperatorProvider); $this->descriptionField->method('getId')->willReturn(33); $this->descriptionField->method('getTypeObject')->willReturn($textareaType); $this->dateField->method('getId')->willReturn(34); $this->dateField->method('getTypeObject')->willReturn($dateTimeType); + + if (!method_exists(LeadRepository::class, 'exists')) { + $this->markTestSkipped(); + } } public function testImportForCreated(): void @@ -121,11 +193,6 @@ public function testImportForCreated(): void $this->customItemModel->expects($this->never()) ->method('fetchEntity'); - $this->formatterHelper->expects($this->once()) - ->method('simpleCsvToArray') - ->with('3262739,3262738,3262737') - ->willReturn([3262739, 3262738, 3262737]); - $this->customObject->expects($this->exactly(3)) ->method('getCustomFields') ->willReturn(new ArrayCollection([$this->descriptionField, $this->dateField])); @@ -149,6 +216,12 @@ public function testImportForCreated(): void })) ->willReturn($customItem); + $leadRepository = $this->createMock(LeadRepository::class); + $this->entityManager->expects($this->any()) + ->method('getRepository') + ->with(Lead::class) + ->willReturn($leadRepository); + $this->assertSame( false, $this->customItemImportModel->import($this->import, self::ROW_DATA, $this->customObject) @@ -161,11 +234,6 @@ public function testImportForCreatedWhenObjectHasNoFields(): void ->method('getMatchedFields') ->willReturn(self::MAPPED_FIELDS); - $this->formatterHelper->expects($this->once()) - ->method('simpleCsvToArray') - ->with('3262739,3262738,3262737') - ->willReturn([3262739, 3262738, 3262737]); - $this->customObject->expects($this->exactly(1)) ->method('getCustomFields') ->willReturn([]); @@ -218,11 +286,6 @@ public function testImportForUpdatedWithSetOwner(): void ->with(User::class, 222) ->willReturn(222); - $this->formatterHelper->expects($this->once()) - ->method('simpleCsvToArray') - ->with('3262739,3262738,3262737') - ->willReturn([3262739, 3262738, 3262737]); - $this->customItemModel->expects($this->exactly(3)) ->method('linkEntity') ->withConsecutive( @@ -236,6 +299,16 @@ public function testImportForUpdatedWithSetOwner(): void ->with($customItem) ->willReturn($customItem); + $leadRepository = $this->createMock(LeadRepository::class); + $leadRepository->expects($this->atLeast(3)) + ->method('exists') + ->willReturn(true); + + $this->entityManager->expects($this->any()) + ->method('getRepository') + ->with(Lead::class) + ->willReturn($leadRepository); + $this->customItemImportModel->import($this->import, $rowData, $this->customObject); } @@ -247,6 +320,53 @@ public function testImportForUpdatedWhenItemNotFound(): void $rowData['id'] = '555'; $customItem = $this->createMock(CustomItem::class); + $this->import->expects($this->exactly(2)) + ->method('getMatchedFields') + ->willReturn($mappedFields); + + $this->customObject->expects($this->exactly(3)) + ->method('getCustomFields') + ->willReturn(new ArrayCollection([$this->descriptionField, $this->dateField])); + + $this->customItemModel->expects($this->once()) + ->method('fetchEntity') + ->with(555) + ->will($this->throwException(new NotFoundException())); + + $this->customItemModel->expects($this->exactly(3)) + ->method('linkEntity') + ->withConsecutive( + [$customItem, 'contact', 3262739], + [$customItem, 'contact', 3262738], + [$customItem, 'contact', 3262737] + ); + + $this->customItemModel->expects($this->once()) + ->method('save') + ->with($this->isInstanceOf(CustomItem::class)) + ->willReturn($customItem); + + $leadRepository = $this->createMock(LeadRepository::class); + $leadRepository->expects($this->atLeast(3)) + ->method('exists') + ->willReturn(true); + + $this->entityManager->expects($this->any()) + ->method('getRepository') + ->with(Lead::class) + ->willReturn($leadRepository); + + $this->customItemImportModel->import($this->import, $rowData, $this->customObject); + } + + public function testImportWithLinkContactWhenGivenContactIdIsInvalid(): void + { + $mappedFields = self::MAPPED_FIELDS; + $rowData = self::ROW_DATA; + $mappedFields['id'] = 'customItemId'; + $rowData['id'] = '555'; + $customItem = $this->createMock(CustomItem::class); + $this->import->expects($this->exactly(2)) ->method('getMatchedFields') ->willReturn($mappedFields); @@ -265,7 +385,7 @@ public function testImportForUpdatedWhenItemNotFound(): void ->with('3262739,3262738,3262737') ->willReturn([3262739, 3262738, 3262737]); - $this->customItemModel->expects($this->exactly(3)) + $this->customItemModel->expects($this->exactly(1)) ->method('linkEntity') ->withConsecutive( [$customItem, 'contact', 3262739], @@ -278,6 +398,26 @@ public function testImportForUpdatedWhenItemNotFound(): void ->with($this->isInstanceOf(CustomItem::class)) ->willReturn($customItem); - $this->customItemImportModel->import($this->import, $rowData, $this->customObject); + $leadRepository = $this->createMock(LeadRepository::class); + $leadRepository->expects($this->atLeast(3)) + ->method('exists') + ->willReturnOnConsecutiveCalls(true, false, false); + + $this->entityManager->expects($this->any()) + ->method('getRepository') + ->with(Lead::class) + ->willReturn($leadRepository); + + $translator = $this->createMock(TranslatorInterface::class); + $translator->expects($this->any()) + ->method('trans') + ->willReturn('test warning'); + + $this->customItemImportModel->setTranslator($translator); + + $importLogDto = new ImportLogDTO(); + $this->customItemImportModel->import($this->import, $rowData, $this->customObject, $importLogDto); + + $this->assertTrue($importLogDto->hasWarning()); } } diff --git a/Tests/Unit/Model/CustomItemModelTest.php b/Tests/Unit/Model/CustomItemModelTest.php index fe8d9887f..bb01109c5 100644 --- a/Tests/Unit/Model/CustomItemModelTest.php +++ b/Tests/Unit/Model/CustomItemModelTest.php @@ -7,12 +7,16 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\DBAL\Connection; use Doctrine\DBAL\Query\QueryBuilder as DbalQueryBuilder; +use Doctrine\DBAL\Result; use Doctrine\DBAL\Statement; use Doctrine\ORM\AbstractQuery; use Doctrine\ORM\EntityManager; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; +use Mautic\CoreBundle\Helper\CoreParametersHelper; use Mautic\CoreBundle\Helper\UserHelper; +use Mautic\CoreBundle\Security\Permissions\CorePermissions; +use Mautic\CoreBundle\Translation\Translator; use Mautic\UserBundle\Entity\User; use MauticPlugin\CustomObjectsBundle\CustomItemEvents; use MauticPlugin\CustomObjectsBundle\DTO\TableConfig; @@ -29,11 +33,13 @@ use MauticPlugin\CustomObjectsBundle\Model\CustomItemModel; use MauticPlugin\CustomObjectsBundle\Provider\CustomItemPermissionProvider; use MauticPlugin\CustomObjectsBundle\Repository\CustomItemRepository; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Validator\ConstraintViolationListInterface; use Symfony\Component\Validator\Validator\ValidatorInterface; -use UnexpectedValueException; class CustomItemModelTest extends TestCase { @@ -72,15 +78,44 @@ class CustomItemModelTest extends TestCase */ private $customItemModel; + /** + * @var CorePermissions|MockObject + */ + private $security; + + /** + * @var UrlGeneratorInterface|MockObject + */ + private $router; + + /** + * @var Translator|MockObject + */ + private $translator; + + /** + * @var LoggerInterface|MockObject + */ + private $logger; + + /** + * @var CoreParametersHelper|MockObject + */ + private $coreParametersHelper; + protected function setUp(): void { parent::setUp(); - defined('MAUTIC_TABLE_PREFIX') || define('MAUTIC_TABLE_PREFIX', getenv('MAUTIC_DB_PREFIX') ?: ''); - $this->customItem = $this->createMock(CustomItem::class); $this->user = $this->createMock(User::class); $this->entityManager = $this->createMock(EntityManager::class); + $this->security = $this->createMock(CorePermissions::class); + $this->router = $this->createMock(UrlGeneratorInterface::class); + $this->translator = $this->createMock(Translator::class); + $this->userHelper = $this->createMock(UserHelper::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->coreParametersHelper = $this->createMock(CoreParametersHelper::class); $this->queryBuilder = $this->createMock(QueryBuilder::class); $this->dbalQueryBuilder = $this->createMock(DbalQueryBuilder::class); $this->statement = $this->createMock(Statement::class); @@ -95,11 +130,16 @@ protected function setUp(): void $this->violationList = $this->createMock(ConstraintViolationListInterface::class); $this->customItemModel = new CustomItemModel( $this->entityManager, + $this->security, + $this->dispatcher, + $this->router, + $this->translator, + $this->userHelper, + $this->logger, + $this->coreParametersHelper, $this->customItemRepository, $this->customItemPermissionProvider, - $this->userHelper, $this->customFieldValueModel, - $this->dispatcher, $this->validator ); @@ -127,13 +167,13 @@ public function testSaveNew(): void $this->customItem->expects($this->never())->method('recordCustomFieldValueChanges'); $this->dispatcher->method('dispatch') ->withConsecutive( - [CustomItemEvents::ON_CUSTOM_ITEM_PRE_SAVE, $this->isInstanceOf(CustomItemEvent::class)], - [CustomItemEvents::ON_CUSTOM_ITEM_POST_SAVE, $this->isInstanceOf(CustomItemEvent::class)] + [$this->isInstanceOf(CustomItemEvent::class), CustomItemEvents::ON_CUSTOM_ITEM_PRE_SAVE], + [$this->isInstanceOf(CustomItemEvent::class), CustomItemEvents::ON_CUSTOM_ITEM_POST_SAVE] ); $this->customItemRepository->expects($this->once())->method('upsert')->with($this->customItem); $this->validator->expects($this->once())->method('validate')->with($this->customItem)->willReturn($this->violationList); - $this->expectException(NotFoundException::class); //since the fetchEntity() method is called on save and there's no customItem in the DB with ID 1 + $this->expectException(NotFoundException::class); // since the fetchEntity() method is called on save and there's no customItem in the DB with ID 1 $this->assertSame($this->customItem, $this->customItemModel->save($this->customItem)); } @@ -151,8 +191,8 @@ public function testSaveEdit(): void $this->customFieldValueModel->expects($this->once())->method('save')->with($customFieldValue); $this->dispatcher->method('dispatch') ->withConsecutive( - [CustomItemEvents::ON_CUSTOM_ITEM_PRE_SAVE, $this->isInstanceOf(CustomItemEvent::class)], - [CustomItemEvents::ON_CUSTOM_ITEM_POST_SAVE, $this->isInstanceOf(CustomItemEvent::class)] + [$this->isInstanceOf(CustomItemEvent::class), CustomItemEvents::ON_CUSTOM_ITEM_PRE_SAVE], + [$this->isInstanceOf(CustomItemEvent::class), CustomItemEvents::ON_CUSTOM_ITEM_POST_SAVE] ); $this->validator->expects($this->once())->method('validate')->with($this->customItem)->willReturn($this->violationList); @@ -164,8 +204,8 @@ public function testDelete(): void $this->customItem->expects($this->once())->method('getId')->willReturn(34); $this->dispatcher->method('dispatch') ->withConsecutive( - [CustomItemEvents::ON_CUSTOM_ITEM_PRE_DELETE, $this->isInstanceOf(CustomItemEvent::class)], - [CustomItemEvents::ON_CUSTOM_ITEM_POST_DELETE, $this->isInstanceOf(CustomItemEvent::class)] + [$this->isInstanceOf(CustomItemEvent::class), CustomItemEvents::ON_CUSTOM_ITEM_PRE_DELETE], + [$this->isInstanceOf(CustomItemEvent::class), CustomItemEvents::ON_CUSTOM_ITEM_POST_DELETE] ); $this->entityManager->expects($this->once())->method('remove')->with($this->customItem); $this->entityManager->expects($this->once())->method('flush'); @@ -178,17 +218,17 @@ public function testLinkEntityIfXrefNotFound(): void $this->dispatcher->expects($this->once()) ->method('dispatch') ->with( - CustomItemEvents::ON_CUSTOM_ITEM_LINK_ENTITY_DISCOVERY, $this->callback(function (CustomItemXrefEntityDiscoveryEvent $event) { $this->assertSame($this->customItem, $event->getCustomItem()); $this->assertSame('contact', $event->getEntityType()); $this->assertSame(123, $event->getEntityId()); return true; - }) + }), + CustomItemEvents::ON_CUSTOM_ITEM_LINK_ENTITY_DISCOVERY ); - $this->expectException(UnexpectedValueException::class); + $this->expectException(\UnexpectedValueException::class); $this->customItemModel->linkEntity($this->customItem, 'contact', 123); } @@ -200,7 +240,6 @@ public function testLinkEntity(): void ->method('dispatch') ->withConsecutive( [ - CustomItemEvents::ON_CUSTOM_ITEM_LINK_ENTITY_DISCOVERY, $this->callback(function (CustomItemXrefEntityDiscoveryEvent $event) use ($xref) { $this->assertSame($this->customItem, $event->getCustomItem()); $this->assertSame('contact', $event->getEntityType()); @@ -211,14 +250,15 @@ public function testLinkEntity(): void return true; }), + CustomItemEvents::ON_CUSTOM_ITEM_LINK_ENTITY_DISCOVERY, ], [ - CustomItemEvents::ON_CUSTOM_ITEM_LINK_ENTITY, $this->callback(function (CustomItemXrefEntityEvent $event) use ($xref) { $this->assertSame($xref, $event->getXref()); return true; }), + CustomItemEvents::ON_CUSTOM_ITEM_LINK_ENTITY, ] ); @@ -230,17 +270,17 @@ public function testUninkEntityIfXrefNotFound(): void $this->dispatcher->expects($this->once()) ->method('dispatch') ->with( - CustomItemEvents::ON_CUSTOM_ITEM_LINK_ENTITY_DISCOVERY, $this->callback(function (CustomItemXrefEntityDiscoveryEvent $event) { $this->assertSame($this->customItem, $event->getCustomItem()); $this->assertSame('contact', $event->getEntityType()); $this->assertSame(123, $event->getEntityId()); return true; - }) + }), + CustomItemEvents::ON_CUSTOM_ITEM_LINK_ENTITY_DISCOVERY ); - $this->expectException(UnexpectedValueException::class); + $this->expectException(\UnexpectedValueException::class); $this->customItemModel->unlinkEntity($this->customItem, 'contact', 123); } @@ -252,7 +292,6 @@ public function testUninkEntity(): void ->method('dispatch') ->withConsecutive( [ - CustomItemEvents::ON_CUSTOM_ITEM_LINK_ENTITY_DISCOVERY, $this->callback(function (CustomItemXrefEntityDiscoveryEvent $event) use ($xref) { $this->assertSame($this->customItem, $event->getCustomItem()); $this->assertSame('contact', $event->getEntityType()); @@ -263,14 +302,15 @@ public function testUninkEntity(): void return true; }), + CustomItemEvents::ON_CUSTOM_ITEM_LINK_ENTITY_DISCOVERY, ], [ - CustomItemEvents::ON_CUSTOM_ITEM_UNLINK_ENTITY, $this->callback(function (CustomItemXrefEntityEvent $event) use ($xref) { $this->assertSame($xref, $event->getXref()); return true; }), + CustomItemEvents::ON_CUSTOM_ITEM_UNLINK_ENTITY, ] ); @@ -314,7 +354,7 @@ public function testGetTableDataWithoutCustomObjectId(): void { $tableConfig = new TableConfig(10, 1, 'column'); - $this->expectException(UnexpectedValueException::class); + $this->expectException(\UnexpectedValueException::class); $this->expectExceptionMessage("customObjectId cannot be empty. It's required for permission management"); $this->customItemModel->getTableData($tableConfig); } @@ -341,8 +381,7 @@ public function testGetTableData(): void ->willReturn([]); $this->dispatcher->expects($this->once()) - ->method('dispatch') - ->with(CustomItemEvents::ON_CUSTOM_ITEM_LIST_ORM_QUERY); + ->method('dispatch'); $this->customItemModel->getTableData($tableConfig); } @@ -351,7 +390,7 @@ public function testGetArrayTableDataWithoutCustomObjectId(): void { $tableConfig = new TableConfig(10, 1, 'column'); - $this->expectException(UnexpectedValueException::class); + $this->expectException(\UnexpectedValueException::class); $this->expectExceptionMessage("customObjectId cannot be empty. It's required for permission management"); $this->customItemModel->getArrayTableData($tableConfig); } @@ -373,21 +412,22 @@ public function testGetArrayTableData(): void ->method('select') ->willReturn(CustomItem::TABLE_ALIAS.'.*'); + $result = $this->createMock(Result::class); + + $result->expects($this->once()) + ->method('fetchAllAssociative') + ->willReturn([]); + $this->dbalQueryBuilder->expects($this->once()) ->method('execute') - ->willReturn($this->statement); + ->willReturn($result); $this->dbalQueryBuilder->expects($this->once()) ->method('setParameter') ->with('customObjectId', 44); - $this->statement->expects($this->once()) - ->method('fetchAll') - ->willReturn([]); - $this->dispatcher->expects($this->once()) - ->method('dispatch') - ->with(CustomItemEvents::ON_CUSTOM_ITEM_LIST_DBAL_QUERY); + ->method('dispatch'); $this->customItemModel->getArrayTableData($tableConfig); } diff --git a/Tests/Unit/Model/CustomItemXrefContactModelTest.php b/Tests/Unit/Model/CustomItemXrefContactModelTest.php index 0160aa3a7..f8102deb4 100644 --- a/Tests/Unit/Model/CustomItemXrefContactModelTest.php +++ b/Tests/Unit/Model/CustomItemXrefContactModelTest.php @@ -4,16 +4,21 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\Model; -use DateTime; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\Query\QueryBuilder as DBALQueryBuilder; use Doctrine\ORM\AbstractQuery; use Doctrine\ORM\EntityManager; use Doctrine\ORM\QueryBuilder; +use Mautic\CoreBundle\Helper\CoreParametersHelper; +use Mautic\CoreBundle\Helper\UserHelper; +use Mautic\CoreBundle\Security\Permissions\CorePermissions; +use Mautic\CoreBundle\Translation\Translator; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Model\CustomItemXrefContactModel; -use Symfony\Component\Translation\TranslatorInterface; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; class CustomItemXrefContactModelTest extends \PHPUnit\Framework\TestCase { @@ -21,12 +26,45 @@ class CustomItemXrefContactModelTest extends \PHPUnit\Framework\TestCase private $entityManager; - private $queryBuilder; + /** + * @var MockObject|CorePermissions + */ + private $security; - private $query; + /** + * @var MockObject|EventDispatcherInterface + */ + private $dispatcher; + + /** + * @var MockObject|UrlGeneratorInterface + */ + private $router; + /** + * @var MockObject|Translator + */ private $translator; + /** + * @var MockObject|UserHelper + */ + private $userHelper; + + /** + * @var MockObject|LoggerInterface + */ + private $logger; + + /** + * @var MockObject|CoreParametersHelper + */ + private $coreParametersHelper; + + private $queryBuilder; + + private $query; + /** * @var CustomItemXrefContactModel */ @@ -40,10 +78,22 @@ protected function setUp(): void $this->entityManager = $this->createMock(EntityManager::class); $this->queryBuilder = $this->createMock(QueryBuilder::class); $this->query = $this->createMock(AbstractQuery::class); - $this->translator = $this->createMock(TranslatorInterface::class); + $this->translator = $this->createMock(Translator::class); + $this->security = $this->createMock(CorePermissions::class); + $this->dispatcher = $this->createMock(EventDispatcherInterface::class); + $this->router = $this->createMock(UrlGeneratorInterface::class); + $this->userHelper = $this->createMock(UserHelper::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->coreParametersHelper = $this->createMock(CoreParametersHelper::class); $this->customItemXrefContactModel = new CustomItemXrefContactModel( $this->entityManager, - $this->translator + $this->security, + $this->dispatcher, + $this->router, + $this->translator, + $this->userHelper, + $this->logger, + $this->coreParametersHelper, ); $this->entityManager->method('createQueryBuilder')->willReturn($this->queryBuilder); @@ -52,13 +102,10 @@ protected function setUp(): void public function testGetLinksLineChartData(): void { - defined('MAUTIC_TABLE_PREFIX') || define('MAUTIC_TABLE_PREFIX', ''); - - $from = new DateTime('2019-03-02 12:30:00'); - $to = new DateTime('2019-04-02 12:30:00'); + $from = new \DateTime('2019-03-02 12:30:00'); + $to = new \DateTime('2019-04-02 12:30:00'); $connection = $this->createMock(Connection::class); $queryBuilder = $this->createMock(DBALQueryBuilder::class); - $statement = $this->createMock(Statement::class); $this->entityManager->expects($this->once()) ->method('getConnection') @@ -68,14 +115,6 @@ public function testGetLinksLineChartData(): void ->method('createQueryBuilder') ->willReturn($queryBuilder); - $queryBuilder->expects($this->once()) - ->method('execute') - ->willReturn($statement); - - $statement->expects($this->once()) - ->method('fetchAll') - ->willReturn([]); - $chartData = $this->customItemXrefContactModel->getLinksLineChartData( $from, $to, diff --git a/Tests/Unit/Model/CustomObjectModelTest.php b/Tests/Unit/Model/CustomObjectModelTest.php index 9ebc2cdeb..331e1da66 100644 --- a/Tests/Unit/Model/CustomObjectModelTest.php +++ b/Tests/Unit/Model/CustomObjectModelTest.php @@ -6,14 +6,17 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\Platforms\MySqlPlatform; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Query\QueryBuilder as QueryBuilderDbal; use Doctrine\DBAL\Statement; use Doctrine\ORM\AbstractQuery; use Doctrine\ORM\EntityManager; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; +use Mautic\CoreBundle\Helper\CoreParametersHelper; use Mautic\CoreBundle\Helper\UserHelper; +use Mautic\CoreBundle\Security\Permissions\CorePermissions; +use Mautic\CoreBundle\Translation\Translator; use Mautic\LeadBundle\Model\ListModel; use Mautic\UserBundle\Entity\User; use MauticPlugin\CustomObjectsBundle\CustomObjectEvents; @@ -27,9 +30,11 @@ use MauticPlugin\CustomObjectsBundle\Model\CustomObjectModel; use MauticPlugin\CustomObjectsBundle\Provider\CustomObjectPermissionProvider; use MauticPlugin\CustomObjectsBundle\Repository\CustomObjectRepository; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; class CustomObjectModelTest extends TestCase { @@ -37,6 +42,41 @@ class CustomObjectModelTest extends TestCase private $customField; private $user; private $entityManager; + + /** + * @var MockObject|CorePermissions + */ + private $security; + + /** + * @var MockObject|EventDispatcherInterface + */ + private $dispatcher; + + /** + * @var MockObject|UrlGeneratorInterface + */ + private $router; + + /** + * @var MockObject|Translator + */ + private $translator; + + /** + * @var MockObject|UserHelper + */ + private $userHelper; + + /** + * @var MockObject|LoggerInterface + */ + private $logger; + + /** + * @var MockObject|CoreParametersHelper + */ + private $coreParametersHelper; private $queryBuilder; private $queryBuilderDbal; private $query; @@ -45,10 +85,7 @@ class CustomObjectModelTest extends TestCase private $databasePlatform; private $customObjectRepository; private $customObjectPermissionProvider; - private $userHelper; private $customFieldModel; - private $dispatcher; - private $translator; /** * @var ListModel @@ -64,37 +101,41 @@ protected function setUp(): void { parent::setUp(); - defined('MAUTIC_TABLE_PREFIX') || define('MAUTIC_TABLE_PREFIX', ''); - $this->customObject = $this->createMock(CustomObject::class); $this->customField = $this->createMock(CustomField::class); $this->user = $this->createMock(User::class); $this->entityManager = $this->createMock(EntityManager::class); + $this->translator = $this->createMock(Translator::class); + $this->security = $this->createMock(CorePermissions::class); + $this->dispatcher = $this->createMock(EventDispatcherInterface::class); + $this->router = $this->createMock(UrlGeneratorInterface::class); + $this->userHelper = $this->createMock(UserHelper::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->coreParametersHelper = $this->createMock(CoreParametersHelper::class); $this->queryBuilder = $this->createMock(QueryBuilder::class); $this->queryBuilderDbal = $this->createMock(QueryBuilderDbal::class); $this->statement = $this->createMock(Statement::class); $this->query = $this->createMock(AbstractQuery::class); $this->connection = $this->createMock(Connection::class); - $this->databasePlatform = $this->createMock(MySqlPlatform::class); + $this->databasePlatform = $this->createMock(AbstractMySQLPlatform::class); $this->customObjectRepository = $this->createMock(CustomObjectRepository::class); $this->customObjectPermissionProvider = $this->createMock(CustomObjectPermissionProvider::class); - $this->userHelper = $this->createMock(UserHelper::class); $this->customFieldModel = $this->createMock(CustomFieldModel::class); - $this->dispatcher = $this->createMock(EventDispatcherInterface::class); - $this->translator = $this->createMock(TranslatorInterface::class); $this->listModel = $this->createMock(ListModel::class); $this->customObjectModel = new CustomObjectModel( $this->entityManager, + $this->security, + $this->dispatcher, + $this->router, + $this->translator, + $this->userHelper, + $this->logger, + $this->coreParametersHelper, $this->customObjectRepository, $this->customObjectPermissionProvider, - $this->userHelper, $this->customFieldModel, - $this->dispatcher, - $this->listModel ); - $this->customObjectModel->setEntityManager($this->entityManager); - $this->customObjectModel->setTranslator($this->translator); $this->entityManager->method('createQueryBuilder')->willReturn($this->queryBuilder); $this->entityManager->method('getConnection')->willReturn($this->connection); $this->connection->method('getDatabasePlatform')->willReturn($this->databasePlatform); @@ -161,8 +202,8 @@ public function testSaveNew(): void $this->dispatcher->method('dispatch') ->withConsecutive( - [CustomObjectEvents::ON_CUSTOM_OBJECT_PRE_SAVE, $this->isInstanceOf(CustomObjectEvent::class)], - [CustomObjectEvents::ON_CUSTOM_OBJECT_POST_SAVE, $this->isInstanceOf(CustomObjectEvent::class)] + [$this->isInstanceOf(CustomObjectEvent::class), CustomObjectEvents::ON_CUSTOM_OBJECT_PRE_SAVE], + [$this->isInstanceOf(CustomObjectEvent::class), CustomObjectEvents::ON_CUSTOM_OBJECT_POST_SAVE] ); $this->entityManager->expects($this->once())->method('persist')->with($this->customObject); $this->entityManager->expects($this->once())->method('flush'); @@ -241,8 +282,8 @@ public function testSaveNewWhenAliasIsNotUnique(): void $this->dispatcher->method('dispatch') ->withConsecutive( - [CustomObjectEvents::ON_CUSTOM_OBJECT_PRE_SAVE, $this->isInstanceOf(CustomObjectEvent::class)], - [CustomObjectEvents::ON_CUSTOM_OBJECT_POST_SAVE, $this->isInstanceOf(CustomObjectEvent::class)] + [$this->isInstanceOf(CustomObjectEvent::class), CustomObjectEvents::ON_CUSTOM_OBJECT_PRE_SAVE], + [$this->isInstanceOf(CustomObjectEvent::class), CustomObjectEvents::ON_CUSTOM_OBJECT_POST_SAVE] ); $this->entityManager->expects($this->once())->method('persist')->with($this->customObject); $this->entityManager->expects($this->once())->method('flush'); @@ -294,8 +335,8 @@ public function testSaveEdit(): void $this->dispatcher->method('dispatch') ->withConsecutive( - [CustomObjectEvents::ON_CUSTOM_OBJECT_PRE_SAVE, $this->isInstanceOf(CustomObjectEvent::class)], - [CustomObjectEvents::ON_CUSTOM_OBJECT_POST_SAVE, $this->isInstanceOf(CustomObjectEvent::class)] + [$this->isInstanceOf(CustomObjectEvent::class), CustomObjectEvents::ON_CUSTOM_OBJECT_PRE_SAVE], + [$this->isInstanceOf(CustomObjectEvent::class), CustomObjectEvents::ON_CUSTOM_OBJECT_POST_SAVE] ); $this->entityManager->expects($this->once())->method('persist')->with($this->customObject); $this->entityManager->expects($this->once())->method('flush'); @@ -311,7 +352,7 @@ public function testDelete(): void $this->dispatcher->method('dispatch') ->withConsecutive( - [CustomObjectEvents::ON_CUSTOM_OBJECT_PRE_DELETE, $this->isInstanceOf(CustomObjectEvent::class)] + [$this->isInstanceOf(CustomObjectEvent::class), CustomObjectEvents::ON_CUSTOM_OBJECT_PRE_DELETE] ); $this->entityManager->expects($this->once()) @@ -577,10 +618,6 @@ public function testGetItemsLineChartData(): void ->with('custom.object.created.items') ->willReturn('Items Created'); - $this->statement->expects($this->once()) - ->method('fetchAll') - ->willReturn([]); - $chartData = $this->customObjectModel->getItemsLineChartData( $from, $to, diff --git a/Tests/Unit/Provider/CustomFieldTypeProviderTest.php b/Tests/Unit/Provider/CustomFieldTypeProviderTest.php index 31f126a1f..14f4dd578 100644 --- a/Tests/Unit/Provider/CustomFieldTypeProviderTest.php +++ b/Tests/Unit/Provider/CustomFieldTypeProviderTest.php @@ -11,7 +11,7 @@ use MauticPlugin\CustomObjectsBundle\CustomFieldType\TextType; use MauticPlugin\CustomObjectsBundle\Exception\NotFoundException; use MauticPlugin\CustomObjectsBundle\Provider\CustomFieldTypeProvider; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class CustomFieldTypeProviderTest extends \PHPUnit\Framework\TestCase { diff --git a/Tests/Unit/Report/ReportColumnsBuilderTest.php b/Tests/Unit/Report/ReportColumnsBuilderTest.php index eb34c1167..05c2822c7 100644 --- a/Tests/Unit/Report/ReportColumnsBuilderTest.php +++ b/Tests/Unit/Report/ReportColumnsBuilderTest.php @@ -17,7 +17,7 @@ use MauticPlugin\CustomObjectsBundle\Report\ReportColumnsBuilder; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class ReportColumnsBuilderTest extends TestCase { @@ -58,8 +58,6 @@ class ReportColumnsBuilderTest extends TestCase protected function setUp(): void { - defined('MAUTIC_TABLE_PREFIX') || define('MAUTIC_TABLE_PREFIX', getenv('MAUTIC_DB_PREFIX') ?: ''); - $this->customObject = $this->createMock(CustomObject::class); $this->reportColumnsBuilder = new ReportColumnsBuilder($this->customObject); $this->connection = $this->createMock(Connection::class); diff --git a/Tests/Unit/Repository/CustomFieldRepositoryTest.php b/Tests/Unit/Repository/CustomFieldRepositoryTest.php index 8746c0b85..af91594b8 100644 --- a/Tests/Unit/Repository/CustomFieldRepositoryTest.php +++ b/Tests/Unit/Repository/CustomFieldRepositoryTest.php @@ -5,21 +5,32 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\Repository; use Doctrine\ORM\AbstractQuery; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; +use Doctrine\Persistence\ManagerRegistry; use MauticPlugin\CustomObjectsBundle\Entity\CustomField; use MauticPlugin\CustomObjectsBundle\Repository\CustomFieldRepository; +use PHPUnit\Framework\MockObject\MockObject; class CustomFieldRepositoryTest extends \PHPUnit\Framework\TestCase { private $entityManager; - private $classMetadata; private $queryBuilder; private $query; private $expression; + /** + * @var MockObject|ClassMetadata + */ + private $classMetadata; + + /** + * @var MockObject|ManagerRegistry + */ + private $registry; + /** * @var CustomFieldRepository */ @@ -29,16 +40,18 @@ protected function setUp(): void { parent::setUp(); - $this->entityManager = $this->createMock(EntityManager::class); + $this->registry = $this->createMock(ManagerRegistry::class); + $this->entityManager = $this->createMock(EntityManagerInterface::class); $this->classMetadata = $this->createMock(ClassMetadata::class); $this->queryBuilder = $this->createMock(QueryBuilder::class); $this->query = $this->createMock(AbstractQuery::class); $this->expression = $this->createMock(Expr::class); $this->repository = new CustomFieldRepository( - $this->entityManager, - $this->classMetadata + $this->registry, ); + $this->registry->method('getManagerForClass')->willReturn($this->entityManager); + $this->entityManager->method('getClassMetadata')->willReturn($this->classMetadata); $this->entityManager->method('createQueryBuilder')->willReturn($this->queryBuilder); $this->queryBuilder->method('getQuery')->willReturn($this->query); $this->queryBuilder->method('expr')->willReturn($this->expression); diff --git a/Tests/Unit/Repository/CustomItemRepositoryTest.php b/Tests/Unit/Repository/CustomItemRepositoryTest.php index 5c2430bdd..d4dedbc9b 100644 --- a/Tests/Unit/Repository/CustomItemRepositoryTest.php +++ b/Tests/Unit/Repository/CustomItemRepositoryTest.php @@ -9,6 +9,7 @@ use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; +use Doctrine\Persistence\ManagerRegistry; use Mautic\LeadBundle\Entity\Lead; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Entity\CustomItemXrefContact; @@ -16,6 +17,7 @@ use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; use MauticPlugin\CustomObjectsBundle\Repository\CustomItemRepository; use PHPUnit\Framework\Assert; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class CustomItemRepositoryTest extends TestCase @@ -32,12 +34,15 @@ class CustomItemRepositoryTest extends TestCase */ private $customItemRepository; + /** + * @var MockObject|ManagerRegistry + */ + private $registry; + protected function setUp(): void { parent::setUp(); - defined('MAUTIC_TABLE_PREFIX') || define('MAUTIC_TABLE_PREFIX', ''); - $this->entityManager = $this->createMock(EntityManager::class); $classMetadata = $this->createMock(ClassMetadata::class); $this->customObject = $this->createMock(CustomObject::class); @@ -45,10 +50,13 @@ protected function setUp(): void $this->queryBuilder = $this->createMock(QueryBuilder::class); $this->expr = $this->createMock(Expr::class); $this->query = $this->createMock(AbstractQuery::class); + $this->registry = $this->createMock(ManagerRegistry::class); $this->customItemRepository = new CustomItemRepository( - $this->entityManager, - $classMetadata + $this->registry, ); + + $this->registry->method('getManagerForClass')->willReturn($this->entityManager); + $this->entityManager->method('getClassMetadata')->willReturn($classMetadata); } public function testCountItemsLinkedToContact(): void diff --git a/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php b/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php index 85784b66e..ceb4d303e 100644 --- a/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php +++ b/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php @@ -13,12 +13,14 @@ use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; +use Doctrine\Persistence\ManagerRegistry; use Mautic\LeadBundle\Entity\Lead; use MauticPlugin\CustomObjectsBundle\DTO\TableConfig; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Entity\CustomItemXrefContact; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; use MauticPlugin\CustomObjectsBundle\Repository\CustomItemXrefContactRepository; +use PHPUnit\Framework\MockObject\MockObject; class CustomItemXrefContactRepositoryTest extends \PHPUnit\Framework\TestCase { @@ -38,12 +40,15 @@ class CustomItemXrefContactRepositoryTest extends \PHPUnit\Framework\TestCase */ private $repository; + /** + * @var MockObject|ManagerRegistry + */ + private $registry; + protected function setUp(): void { parent::setUp(); - defined('MAUTIC_TABLE_PREFIX') || define('MAUTIC_TABLE_PREFIX', ''); - $this->entityManager = $this->createMock(EntityManager::class); $this->classMetadata = $this->createMock(ClassMetadata::class); $this->contact = $this->createMock(Lead::class); @@ -54,11 +59,13 @@ protected function setUp(): void $this->expr = $this->createMock(Expr::class); $this->expressionBuilder = $this->createMock(ExpressionBuilder::class); $this->query = $this->createMock(AbstractQuery::class); + $this->registry = $this->createMock(ManagerRegistry::class); $this->repository = new CustomItemXrefContactRepository( - $this->entityManager, - $this->classMetadata + $this->registry, ); + $this->registry->method('getManagerForClass')->willReturn($this->entityManager); + $this->entityManager->method('getClassMetadata')->willReturn($this->classMetadata); $this->entityManager->method('createQueryBuilder')->willReturn($this->queryBuilder); $this->entityManager->method('getConnection')->willReturn($this->connection); $this->connection->method('createQueryBuilder')->willReturn($this->queryBuilderDbal); diff --git a/Tests/Unit/Repository/CustomObjectRepositoryTest.php b/Tests/Unit/Repository/CustomObjectRepositoryTest.php index 20f60c82b..d522892c0 100644 --- a/Tests/Unit/Repository/CustomObjectRepositoryTest.php +++ b/Tests/Unit/Repository/CustomObjectRepositoryTest.php @@ -10,6 +10,7 @@ use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; +use Doctrine\Persistence\ManagerRegistry; use MauticPlugin\CustomObjectsBundle\Entity\CustomField; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; use MauticPlugin\CustomObjectsBundle\Repository\CustomObjectRepository; @@ -48,6 +49,11 @@ class CustomObjectRepositoryTest extends TestCase */ private $repository; + /** + * @var MockObject|ManagerRegistry + */ + private $registry; + protected function setUp(): void { parent::setUp(); @@ -57,11 +63,13 @@ protected function setUp(): void $this->queryBuilder = $this->createMock(QueryBuilder::class); $this->query = $this->createMock(AbstractQuery::class); $this->expression = $this->createMock(Expr::class); + $this->registry = $this->createMock(ManagerRegistry::class); $this->repository = new CustomObjectRepository( - $this->entityManager, - $this->classMetadata + $this->registry, ); + $this->registry->method('getManagerForClass')->willReturn($this->entityManager); + $this->entityManager->method('getClassMetadata')->willReturn($this->classMetadata); $this->entityManager->method('createQueryBuilder')->willReturn($this->queryBuilder); $this->queryBuilder->method('getQuery')->willReturn($this->query); $this->queryBuilder->method('expr')->willReturn($this->expression); diff --git a/Tests/Unit/Security/Permissions/CustomObjectPermissionsTest.php b/Tests/Unit/Security/Permissions/CustomObjectPermissionsTest.php index 13f8cb88e..a63cd0841 100644 --- a/Tests/Unit/Security/Permissions/CustomObjectPermissionsTest.php +++ b/Tests/Unit/Security/Permissions/CustomObjectPermissionsTest.php @@ -12,7 +12,7 @@ use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class CustomObjectPermissionsTest extends TestCase { diff --git a/Tests/Unit/Segment/Query/Filter/CustomItemNameFilterQueryBuilderTest.php b/Tests/Unit/Segment/Query/Filter/CustomItemNameFilterQueryBuilderTest.php index 663ea1547..6d479bbae 100644 --- a/Tests/Unit/Segment/Query/Filter/CustomItemNameFilterQueryBuilderTest.php +++ b/Tests/Unit/Segment/Query/Filter/CustomItemNameFilterQueryBuilderTest.php @@ -50,7 +50,6 @@ class CustomItemNameFilterQueryBuilderTest extends TestCase protected function setUp(): void { parent::setUp(); - defined('MAUTIC_TABLE_PREFIX') || define('MAUTIC_TABLE_PREFIX', ''); $randomParameter = new RandomParameterName(); $eventDispatcher = $this->createMock(EventDispatcherInterface::class); @@ -68,7 +67,8 @@ protected function setUp(): void $this->createMock(CustomFieldRepository::class), new QueryFilterFactory\Calculator(), 1 - ) + ), + new RandomParameterName() ); $this->queryBuilder = $this->createMock(QueryBuilder::class); @@ -90,8 +90,6 @@ public function testGetServiceId(): void /** * @dataProvider parameterValueProvider - * - * @param $parameterValue */ public function testApplyQuery($parameterValue): void { diff --git a/Tests/Unit/Segment/Query/Filter/QueryFilterFactoryTest.php b/Tests/Unit/Segment/Query/Filter/QueryFilterFactoryTest.php index 8ea086251..622b0dc9d 100644 --- a/Tests/Unit/Segment/Query/Filter/QueryFilterFactoryTest.php +++ b/Tests/Unit/Segment/Query/Filter/QueryFilterFactoryTest.php @@ -52,8 +52,6 @@ protected function setUp(): void { parent::setUp(); - defined('MAUTIC_TABLE_PREFIX') || define('MAUTIC_TABLE_PREFIX', ''); - $this->contactSegmentFilterFactory = $this->createMock(ContactSegmentFilterFactory::class); $this->queryFilterHelper = $this->createMock(QueryFilterHelper::class); $this->contactSegmentFilter = $this->createMock(ContactSegmentFilter::class); diff --git a/Translations/en_US/messages.ini b/Translations/en_US/messages.ini index 5ea104d7f..646e1353a 100644 --- a/Translations/en_US/messages.ini +++ b/Translations/en_US/messages.ini @@ -99,3 +99,4 @@ mautic.report.group.custom.objects="Custom Objects" custom.item.export="Export As CSV" custom.item.export.email_subject="Custom Items Exported : %file_name%" custom.item.export.email="Your requested custom item export: %label%." +custom.item.import.invalid.contactid.for.link="warning: Invalid contact %contactId% to link with customItem %customItemId%" diff --git a/Views/CustomField/detail.html.php b/Views/CustomField/detail.html.php deleted file mode 100644 index c97b8ac83..000000000 --- a/Views/CustomField/detail.html.php +++ /dev/null @@ -1,56 +0,0 @@ -extend('MauticCoreBundle:Default:content.html.php'); -$view['slots']->set('mauticContent', 'customField'); -$view['slots']->set('headerTitle', $item->getName()); -$view['slots']->set('actions', $view->render('MauticCoreBundle:Helper:page_actions.html.php', [ - 'item' => $item, -])); -?> - - -
    - -
    -
    - -
    -
    -
    -
    getType(); ?>
    -
    -
    - render('MauticCoreBundle:Helper:publishstatus_badge.html.php', ['entity' => $item]); ?> -
    -
    -
    - -
    -
    -
    -
    -
    -
    -
    -
    - - -
    - -
    -
    -
    trans('mautic.webhook.webhook_url');?>
    -
    -
    -
    -
    -
    - -
    - - - render('MauticCoreBundle:Helper:recentactivity.html.php', ['logs' => $logs]);?> -
    -
    - -
    diff --git a/Views/CustomField/form.html.php b/Views/CustomField/form.html.php deleted file mode 100644 index 1ca60993e..000000000 --- a/Views/CustomField/form.html.php +++ /dev/null @@ -1,105 +0,0 @@ -getId() ? $customField->getLabel() : $customField->getTypeObject()->getName(); - -$showProperties = isset($form['options']) || $customField->getTypeObject()->usePlaceholder(); -?> - -
    - -
    -

    -
    - - start($form); ?> - -
    - - - -
    -
    - -
    -
    - row($form['label']); ?> -
    -
    - row($form['showInCustomObjectDetailList']); ?> -
    -
    - -
    -
    - row($form['alias']); ?> -
    -
    - row($form['showInContactDetailList']); ?> -
    -
    - -
    -
    - row($form['defaultValue']); ?> -
    -
    - row($form['isUniqueIdentifier']); ?> -
    -
    - -
    - -
    -
    -
    - row($form['required']); ?> -
    -
    -
    - - -
    -
    - -
    - row($form['options']); ?> -
    - -
    -
    -getTypeObject()->usePlaceholder()): ?> -
    - row($form['params']['placeholder']); ?> -
    - -
    -
    - - -
    - -
    - - rest($form); ?> - end($form); ?> - -
    \ No newline at end of file diff --git a/Views/CustomField/index.html.php b/Views/CustomField/index.html.php deleted file mode 100644 index c1a0aaa20..000000000 --- a/Views/CustomField/index.html.php +++ /dev/null @@ -1,21 +0,0 @@ -extend('MauticCoreBundle:Default:content.html.php'); - -$view['slots']->set('mauticContent', 'customField'); -$view['slots']->set('headerTitle', $view['translator']->trans('custom.field.title')); -$view['slots']->set('actions', $view->render('MauticCoreBundle:Helper:page_actions.html.php')); -?> - -
    - render( - 'MauticCoreBundle:Helper:list_toolbar.html.php', - [ - // 'searchValue' => $searchValue, - // 'action' => $currentRoute, - ] -); ?> -
    - output('_content'); ?> -
    -
    diff --git a/Views/CustomField/value.html.php b/Views/CustomField/value.html.php deleted file mode 100644 index 35be77316..000000000 --- a/Views/CustomField/value.html.php +++ /dev/null @@ -1,23 +0,0 @@ -getCustomField()->getType(); -?> -getValue() instanceof DateTimeInterface) : ?> - - toDate($fieldValue->getValue()); ?> - - toFull($fieldValue->getValue()); ?> - - - escape($fieldValue->getCustomField()->getTypeObject()->valueToString($fieldValue)); ?> -getValue())) : ?> - escape($view['formatter']->arrayToString($fieldValue->getValue())); ?> - - escape($fieldValue->getValue()); ?> - \ No newline at end of file diff --git a/Views/CustomItem/detail.html.php b/Views/CustomItem/detail.html.php deleted file mode 100644 index 25b27e74e..000000000 --- a/Views/CustomItem/detail.html.php +++ /dev/null @@ -1,125 +0,0 @@ -extend('MauticCoreBundle:Default:content.html.php'); -$view['slots']->set('mauticContent', 'customItem'); -$view['slots']->set('headerTitle', $item->getName()); -$view['slots']->set('actions', $view->render('MauticCoreBundle:Helper:page_actions.html.php', [ - 'item' => $item, -])); -?> - - -
    - -
    -
    - -
    -
    -
    -
    escape($item->getCustomObject()->getNameSingular()); ?>
    -
    -
    - render('MauticCoreBundle:Helper:publishstatus_badge.html.php', ['entity' => $item]); ?> -
    -
    -
    - - -
    -
    -
    - - - render( - 'MauticCoreBundle:Helper:details.html.php', - ['entity' => $item] -); ?> - getCustomFieldValues() as $fieldValue) : ?> - - - - - - -
    escape($fieldValue->getCustomField()->getName()); ?> - render('CustomObjectsBundle:CustomField:value.html.php', ['fieldValue' => $fieldValue]); ?> -
    -
    -
    -
    -
    - - -
    - - - - -
    -
    -
    -
    -
    -
    -
    - - trans('custom.item.links.in.time'); ?> -
    -
    -
    - render( - 'MauticCoreBundle:Helper:graph_dateselect.html.php', - ['dateRangeForm' => $dateRangeForm, 'class' => 'pull-right'] -); ?> -
    -
    -
    - render( - 'MauticCoreBundle:Helper:chart.html.php', - ['chartData' => $stats, 'chartType' => 'line', 'chartHeight' => 300] -); ?> -
    -
    -
    -
    -
    - - getCustomContent('details.stats.graph.below', $mauticTemplateVars); ?> -
    - - - - - - -
    -
    - -
    - getCustomContent('tabs.content', $mauticTemplateVars); ?> -
    - -
    - - -
    - - render('MauticCoreBundle:Helper:recentactivity.html.php', ['logs' => $logs]); ?> -
    - -
    diff --git a/Views/CustomItem/form.html.php b/Views/CustomItem/form.html.php deleted file mode 100644 index c39a6f0b7..000000000 --- a/Views/CustomItem/form.html.php +++ /dev/null @@ -1,71 +0,0 @@ -extend('MauticCoreBundle:Default:content.html.php'); - -$view['slots']->set('mauticContent', 'customItem'); - -if ($entity->getId()) { - $header = $view['translator']->trans( - 'custom.item.edit', - [ - '%object%' => $view['translator']->trans($customObject->getNameSingular()), - '%item%' => $view['translator']->trans($entity->getName()), - ] - ); -} else { - $header = $view['translator']->trans( - 'custom.item.new', - ['%object%' => $view['translator']->trans($customObject->getNameSingular())] - ); -} - -$view['slots']->set('headerTitle', $header); - -$hideCategories = CustomObject::TYPE_RELATIONSHIP === $customObject->getType() ? 'hide' : null; -?> - -start($form); ?> - - -
    - -
    -
    -
    -
    - rowIfExists($form, 'name'); ?> - row($form['custom_field_values']); ?> - row($form['contact_id']); ?> -
    - getRelationshipObject() && !empty($form['contact_id']->vars['value'])) : ?> -
    -
    -
    -

    - trans( - 'custom.item.new', - ['%object%' => $view['translator']->trans($customObject->getRelationshipObject()->getNameSingular())] -); ?> -

    -
    -
    - rowIfExists($form, 'child_custom_field_values'); ?> -
    -
    -
    - -
    -
    -
    -
    -
    - row($form['category']); ?> - row($form['isPublished']); ?> -
    -
    -
    - -end($form); ?> diff --git a/Views/CustomItem/index.html.php b/Views/CustomItem/index.html.php deleted file mode 100644 index a8cf67cb5..000000000 --- a/Views/CustomItem/index.html.php +++ /dev/null @@ -1,27 +0,0 @@ -extend('MauticCoreBundle:Default:content.html.php'); - - $view['slots']->set('mauticContent', 'customItem'); - $view['slots']->set('headerTitle', $customObject->getName()); - $view['slots']->set('actions', $view->render('MauticCoreBundle:Helper:page_actions.html.php')); -} -?> - -
    -
    - render( - 'MauticCoreBundle:Helper:list_toolbar.html.php', - [ - 'searchValue' => $searchValue, - 'action' => $currentRoute, - 'target' => '#'.$namespace, - 'overlayDisabled' => $lookup, - ] -); ?> -
    - output('_content'); ?> -
    -
    -
    diff --git a/Views/CustomItem/list.html.php b/Views/CustomItem/list.html.php deleted file mode 100644 index 317d6deb4..000000000 --- a/Views/CustomItem/list.html.php +++ /dev/null @@ -1,124 +0,0 @@ -extend('CustomObjectsBundle:CustomItem:index.html.php'); -} - -$target = '#'.$namespace; -$routeSelf = $view['router']->path( - CustomItemRouteProvider::ROUTE_LIST, - [ - 'objectId' => $customObject->getId(), - 'filterEntityId' => $filterEntityId, - 'filterEntityType' => $filterEntityType, - 'lookup' => $lookup, - 'tmpl' => 'list', - ] -); -?> - -
    - - - - render( - 'MauticCoreBundle:Helper:tableheader.html.php', - [ - 'checkall' => 'true', - 'target' => $target, - 'langVar' => 'custom.item', - 'routeBase' => 'custom_item', - 'baseUrl' => $routeSelf, - ] -); - - echo $view->render( - 'MauticCoreBundle:Helper:tableheader.html.php', - [ - 'sessionVar' => $sessionVar, - 'orderBy' => CustomItem::TABLE_ALIAS.'.name', - 'text' => 'mautic.core.name', - 'class' => 'col-custom_item_name', - 'baseUrl' => $routeSelf, - 'target' => $target, - ] - ); - - echo $view->render( - 'MauticCoreBundle:Helper:tableheader.html.php', - [ - 'sessionVar' => $sessionVar, - 'orderBy' => CustomItem::TABLE_ALIAS.'.id', - 'text' => 'mautic.core.id', - 'default' => true, - 'baseUrl' => $routeSelf, - 'target' => $target, - ] - ); - ?> - - getColumnLabels() as $columnLabel): ?> - render('MauticCoreBundle:Helper:tableheader.html.php', ['text' => $columnLabel]); ?> - - - - - - - - - - - - getFields($item->getId()) as $fieldValue): ?> - - - - - - -
    - render('MauticCoreBundle:Helper:list_actions.html.php', ['item' => $item]); ?> - -
    - render( - 'MauticCoreBundle:Helper:publishstatus_icon.html.php', - [ - 'item' => $item, - 'model' => 'custom.item', - ] - ) : ''; ?> - - getName(); ?> - -
    -
    getId(); ?> - render('CustomObjectsBundle:CustomField:value.html.php', ['fieldValue' => $fieldValue]); ?> -
    -
    - - - render('MauticCoreBundle:Helper:noresults.html.php', ['tip' => $lookup ? 'custom.item.link.noresults.tip' : 'custom.object.noresults.tip']); ?> - diff --git a/Views/CustomObject/Form/Panel/_field.html.php b/Views/CustomObject/Form/Panel/_field.html.php deleted file mode 100644 index 97841a964..000000000 --- a/Views/CustomObject/Form/Panel/_field.html.php +++ /dev/null @@ -1,52 +0,0 @@ -vars['data']; -$customField->vars['index'] = $customField->vars['name']; -$order = (int) $customField->vars['value']->getOrder(); -$deleted = !empty($_POST['custom_object']['customFields'][$order]['deleted']) ? 'style="display:none;"' : ''; - -$panelId = !empty($panelId) ? $panelId : (int) $customField->vars['value']->getOrder(); -?> -
    > - -
    - - - - - - - -
    - -
    -
    -
    - row($customField['defaultValue']); ?> -
    -
    -
    -
    - rest($customField); ?> -
    - -
    \ No newline at end of file diff --git a/Views/CustomObject/Form/Panel/checkbox_group.html.php b/Views/CustomObject/Form/Panel/checkbox_group.html.php deleted file mode 100644 index 14616e6fc..000000000 --- a/Views/CustomObject/Form/Panel/checkbox_group.html.php +++ /dev/null @@ -1,5 +0,0 @@ -extend('CustomObjectsBundle:CustomObject:Form\\Panel\\_field.html.php'); diff --git a/Views/CustomObject/Form/Panel/country.html.php b/Views/CustomObject/Form/Panel/country.html.php deleted file mode 100644 index 14616e6fc..000000000 --- a/Views/CustomObject/Form/Panel/country.html.php +++ /dev/null @@ -1,5 +0,0 @@ -extend('CustomObjectsBundle:CustomObject:Form\\Panel\\_field.html.php'); diff --git a/Views/CustomObject/Form/Panel/date.html.php b/Views/CustomObject/Form/Panel/date.html.php deleted file mode 100644 index 14616e6fc..000000000 --- a/Views/CustomObject/Form/Panel/date.html.php +++ /dev/null @@ -1,5 +0,0 @@ -extend('CustomObjectsBundle:CustomObject:Form\\Panel\\_field.html.php'); diff --git a/Views/CustomObject/Form/Panel/datetime.html.php b/Views/CustomObject/Form/Panel/datetime.html.php deleted file mode 100644 index 14616e6fc..000000000 --- a/Views/CustomObject/Form/Panel/datetime.html.php +++ /dev/null @@ -1,5 +0,0 @@ -extend('CustomObjectsBundle:CustomObject:Form\\Panel\\_field.html.php'); diff --git a/Views/CustomObject/Form/Panel/email.html.php b/Views/CustomObject/Form/Panel/email.html.php deleted file mode 100644 index 14616e6fc..000000000 --- a/Views/CustomObject/Form/Panel/email.html.php +++ /dev/null @@ -1,5 +0,0 @@ -extend('CustomObjectsBundle:CustomObject:Form\\Panel\\_field.html.php'); diff --git a/Views/CustomObject/Form/Panel/hidden.html.php b/Views/CustomObject/Form/Panel/hidden.html.php deleted file mode 100644 index 14616e6fc..000000000 --- a/Views/CustomObject/Form/Panel/hidden.html.php +++ /dev/null @@ -1,5 +0,0 @@ -extend('CustomObjectsBundle:CustomObject:Form\\Panel\\_field.html.php'); diff --git a/Views/CustomObject/Form/Panel/html_area.html.php b/Views/CustomObject/Form/Panel/html_area.html.php deleted file mode 100644 index 14616e6fc..000000000 --- a/Views/CustomObject/Form/Panel/html_area.html.php +++ /dev/null @@ -1,5 +0,0 @@ -extend('CustomObjectsBundle:CustomObject:Form\\Panel\\_field.html.php'); diff --git a/Views/CustomObject/Form/Panel/int.html.php b/Views/CustomObject/Form/Panel/int.html.php deleted file mode 100644 index 14616e6fc..000000000 --- a/Views/CustomObject/Form/Panel/int.html.php +++ /dev/null @@ -1,5 +0,0 @@ -extend('CustomObjectsBundle:CustomObject:Form\\Panel\\_field.html.php'); diff --git a/Views/CustomObject/Form/Panel/multiselect.html.php b/Views/CustomObject/Form/Panel/multiselect.html.php deleted file mode 100644 index 14616e6fc..000000000 --- a/Views/CustomObject/Form/Panel/multiselect.html.php +++ /dev/null @@ -1,5 +0,0 @@ -extend('CustomObjectsBundle:CustomObject:Form\\Panel\\_field.html.php'); diff --git a/Views/CustomObject/Form/Panel/phone.html.php b/Views/CustomObject/Form/Panel/phone.html.php deleted file mode 100644 index 14616e6fc..000000000 --- a/Views/CustomObject/Form/Panel/phone.html.php +++ /dev/null @@ -1,5 +0,0 @@ -extend('CustomObjectsBundle:CustomObject:Form\\Panel\\_field.html.php'); diff --git a/Views/CustomObject/Form/Panel/radio_group.html.php b/Views/CustomObject/Form/Panel/radio_group.html.php deleted file mode 100644 index 14616e6fc..000000000 --- a/Views/CustomObject/Form/Panel/radio_group.html.php +++ /dev/null @@ -1,5 +0,0 @@ -extend('CustomObjectsBundle:CustomObject:Form\\Panel\\_field.html.php'); diff --git a/Views/CustomObject/Form/Panel/select.html.php b/Views/CustomObject/Form/Panel/select.html.php deleted file mode 100644 index 14616e6fc..000000000 --- a/Views/CustomObject/Form/Panel/select.html.php +++ /dev/null @@ -1,5 +0,0 @@ -extend('CustomObjectsBundle:CustomObject:Form\\Panel\\_field.html.php'); diff --git a/Views/CustomObject/Form/Panel/text.html.php b/Views/CustomObject/Form/Panel/text.html.php deleted file mode 100644 index 14616e6fc..000000000 --- a/Views/CustomObject/Form/Panel/text.html.php +++ /dev/null @@ -1,5 +0,0 @@ -extend('CustomObjectsBundle:CustomObject:Form\\Panel\\_field.html.php'); diff --git a/Views/CustomObject/Form/Panel/textarea.html.php b/Views/CustomObject/Form/Panel/textarea.html.php deleted file mode 100644 index 14616e6fc..000000000 --- a/Views/CustomObject/Form/Panel/textarea.html.php +++ /dev/null @@ -1,5 +0,0 @@ -extend('CustomObjectsBundle:CustomObject:Form\\Panel\\_field.html.php'); diff --git a/Views/CustomObject/Form/Panel/url.html.php b/Views/CustomObject/Form/Panel/url.html.php deleted file mode 100644 index 14616e6fc..000000000 --- a/Views/CustomObject/Form/Panel/url.html.php +++ /dev/null @@ -1,5 +0,0 @@ -extend('CustomObjectsBundle:CustomObject:Form\\Panel\\_field.html.php'); diff --git a/Views/CustomObject/_form-fields.html.php b/Views/CustomObject/_form-fields.html.php deleted file mode 100644 index 8f92e0006..000000000 --- a/Views/CustomObject/_form-fields.html.php +++ /dev/null @@ -1,24 +0,0 @@ -children['customFields']->getIterator() as $customField): - $customFieldEntity = $customField->vars['data']; - if (!in_array($customFieldEntity->getId(), $deletedFields, true)) : - echo $view->render( - "CustomObjectsBundle:CustomObject:Form\\Panel\\{$customFieldEntity->getType()}.html.php", - [ - 'customField' => $customField, - 'customObject' => $customObject, - 'panelId' => $panelId ?? null, - ] - ); - endif; -endforeach; -$form->children['customFields']->setRendered(); diff --git a/Views/CustomObject/detail.html.php b/Views/CustomObject/detail.html.php deleted file mode 100644 index f5d9072e4..000000000 --- a/Views/CustomObject/detail.html.php +++ /dev/null @@ -1,149 +0,0 @@ -extend('MauticCoreBundle:Default:content.html.php'); -$view['slots']->set('mauticContent', 'customObject'); -$view['slots']->set('headerTitle', $customObject->getNameSingular()); -$view['slots']->set( - 'actions', - $view->render( - 'MauticCoreBundle:Helper:page_actions.html.php', - ['item' => $customObject] - ) -); - -$view['slots']->set( - 'publishStatus', - $view->render('MauticCoreBundle:Helper:publishstatus_badge.html.php', ['entity' => $customObject]) -); -?> - - -
    - -
    -
    - -
    -
    -
    -
    -
    -
    - - - -
    -
    -
    - - - render( - 'MauticCoreBundle:Helper:details.html.php', - ['entity' => $customObject] -); ?> - -
    -
    -
    -
    - -
    - - -
    - - - - -
    -
    -
    -
    -
    -
    -
    - - trans('custom.item.links.in.time'); ?> -
    -
    -
    - render( - 'MauticCoreBundle:Helper:graph_dateselect.html.php', - ['dateRangeForm' => $dateRangeForm, 'class' => 'pull-right'] -); ?> -
    -
    -
    - render( - 'MauticCoreBundle:Helper:chart.html.php', - ['chartData' => $stats, 'chartType' => 'line', 'chartHeight' => 300] -); ?> -
    -
    -
    -
    -
    - - getCustomContent('details.stats.graph.below', $mauticTemplateVars); ?> - - - - - -
    - -
    - - -
    -
      - getCustomFields() as $field) : ?> -
    • -
      -
      - isRequired() ? 'mautic.core.required' - : 'mautic.core.not_required'; ?> -

      -

      -
      -
      -
      getLabel(); ?>
      -
      -
      - getTypeObject()->getName(); ?> -
      -
      -
    • - -
    -
    - - -
    - -
    - - -
    - - render('MauticCoreBundle:Helper:recentactivity.html.php', ['logs' => $logs]); ?> -
    - -
    diff --git a/Views/CustomObject/form.html.php b/Views/CustomObject/form.html.php deleted file mode 100644 index 09459bb5a..000000000 --- a/Views/CustomObject/form.html.php +++ /dev/null @@ -1,125 +0,0 @@ -extend('MauticCoreBundle:Default:content.html.php'); - -$view['slots']->set('mauticContent', 'customObject'); - -if ($customObject->getId()) { - $header = $view['translator']->trans( - $customObject->getId() ? 'custom.object.edit' : 'custom.object.new', - ['%name%' => $view['translator']->trans($customObject->getName())] - ); -} else { - $header = $view['translator']->trans('custom.object.new'); -} - -$view['slots']->set('headerTitle', $header); -?> - -start($form); ?> - - -
    - -
    -
    -
    - - - -
    -
    -
    -
    - row($form['nameSingular']); ?> - row($form['namePlural']); ?> - -
    -
    - row($form['alias']); ?> -
    -
    -
    -
    - row($form['description']); ?> -
    -
    -
    - -
    - render('MauticFormBundle:Builder:style.html.php'); ?> -
    -
    -
    - -
    -
    -
    - -
    - -
    -

    trans('mautic.form.form.addfield'); ?>

    -
    - -
    -
    - -
    - -
    - -
    - -
    - -
    -
    - row($form['type']); ?> - row($form['masterObject']); ?> - row($form['category']); ?> - row($form['isPublished']); ?> -
    -
    - -
    - -end($form); ?> - -append( - 'modal', - $view->render( - 'MauticCoreBundle:Helper:modal.html.php', - [ - 'id' => 'objectFieldModal', - 'header' => false, - 'footerButtons' => true, - ] - ) - ); diff --git a/Views/CustomObject/index.html.php b/Views/CustomObject/index.html.php deleted file mode 100644 index 747f9e08f..000000000 --- a/Views/CustomObject/index.html.php +++ /dev/null @@ -1,21 +0,0 @@ -extend('MauticCoreBundle:Default:content.html.php'); - -$view['slots']->set('mauticContent', 'customObject'); -$view['slots']->set('headerTitle', $view['translator']->trans('custom.object.title')); -$view['slots']->set('actions', $view->render('MauticCoreBundle:Helper:page_actions.html.php')); -?> - -
    - render( - 'MauticCoreBundle:Helper:list_toolbar.html.php', - [ - // 'searchValue' => $searchValue, - // 'action' => $currentRoute, - ] -); ?> -
    - output('_content'); ?> -
    -
    diff --git a/Views/CustomObject/list.html.php b/Views/CustomObject/list.html.php deleted file mode 100644 index d493f775b..000000000 --- a/Views/CustomObject/list.html.php +++ /dev/null @@ -1,94 +0,0 @@ -extend('CustomObjectsBundle:CustomObject:index.html.php'); -} -?> - -
    - - - - render( - 'MauticCoreBundle:Helper:tableheader.html.php', - [ - 'checkall' => 'true', - 'target' => '#custom-objects-table', - 'langVar' => 'custom.object', - 'routeBase' => 'custom_object', - ] -); - - echo $view->render( - 'MauticCoreBundle:Helper:tableheader.html.php', - [ - 'sessionVar' => $sessionVar, - 'orderBy' => CustomObject::TABLE_ALIAS.'.namePlural', - 'text' => 'mautic.core.name', - 'class' => 'col-custom_object_-name', - ] - ); - - echo $view->render( - 'MauticCoreBundle:Helper:tableheader.html.php', - [ - 'sessionVar' => $sessionVar, - 'orderBy' => CustomObject::TABLE_ALIAS.'.id', - 'text' => 'mautic.core.id', - 'default' => true, - ] - ); - ?> - - - - - - - - - - - -
    - render('MauticCoreBundle:Helper:list_actions.html.php', ['item' => $item]); ?> - -
    - render( - 'MauticCoreBundle:Helper:publishstatus_icon.html.php', - [ - 'item' => $item, - 'model' => 'custom.object', - ] - ); ?> - - getName(); ?> - -
    - getDescription()): ?> -
    - getDescription(); ?> -
    - -
    getId(); ?>
    -
    - - - render('MauticCoreBundle:Helper:noresults.html.php', ['tip' => 'custom.object.noresults.tip']); ?> - diff --git a/Views/SubscribedEvents/Tab/content.html.php b/Views/SubscribedEvents/Tab/content.html.php deleted file mode 100644 index f4d974389..000000000 --- a/Views/SubscribedEvents/Tab/content.html.php +++ /dev/null @@ -1,50 +0,0 @@ - -
    -
    -
    - render( - 'MauticCoreBundle:Helper:search.html.php', - [ - 'searchValue' => $searchValue, - 'action' => $searchRoute, - 'searchId' => $searchId, - 'target' => '#'.$namespace, - 'searchHelp' => '', - ] -); ?> -
    - -
    -
    - Loading... -
    -
    - \ No newline at end of file diff --git a/Views/SubscribedEvents/Tab/link.html.php b/Views/SubscribedEvents/Tab/link.html.php deleted file mode 100644 index a3ca11442..000000000 --- a/Views/SubscribedEvents/Tab/link.html.php +++ /dev/null @@ -1,15 +0,0 @@ - -
  • - - - - - - - escape($view['translator']->trans($title)); ?> - -
  • \ No newline at end of file diff --git a/Views/SubscribedEvents/Tab/modal.html.php b/Views/SubscribedEvents/Tab/modal.html.php deleted file mode 100644 index cb1261e42..000000000 --- a/Views/SubscribedEvents/Tab/modal.html.php +++ /dev/null @@ -1,8 +0,0 @@ -append('modal', $view->render('MauticCoreBundle:Helper:modal.html.php', [ - 'id' => 'customItemLookupModal', - 'size' => 'xl', -])); diff --git a/Views/SubscribedEvents/Timeline/link.html.php b/Views/SubscribedEvents/Timeline/link.html.php deleted file mode 100644 index 89cfec02f..000000000 --- a/Views/SubscribedEvents/Timeline/link.html.php +++ /dev/null @@ -1,17 +0,0 @@ - -
    - -
    - trans('mautic.core.createdby'); ?> -
    -
    - - - -
    - -
    diff --git a/composer.json b/composer.json index 9dc69736b..e238da597 100644 --- a/composer.json +++ b/composer.json @@ -29,11 +29,9 @@ "wiki": "https://github.com/acquia/mc-cs-plugin-custom-objects/wiki" }, "require": { - "php": ">=7.4", + "php": ">=8.0", "ext-mbstring": "*", - "mautic/core-lib": "^4.3" - }, - "require-dev": { + "mautic/core-lib": "^5.0", "theofidry/alice-data-fixtures": "^1.1" }, "scripts": { diff --git a/phpstan-baseline-7.4.neon b/phpstan-baseline-7.4.neon new file mode 100644 index 000000000..480f18008 --- /dev/null +++ b/phpstan-baseline-7.4.neon @@ -0,0 +1,3022 @@ +parameters: + ignoreErrors: + - + message: "#^Method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) invoked with 2 parameters, 1 required\\.$#" + count: 3 + path: ../../plugins/CustomObjectsBundle/Command/CustomItemsScheduledExportCommand.php + + - + message: "#^Parameter \\#1 \\$event of method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) expects object, string given\\.$#" + count: 3 + path: ../../plugins/CustomObjectsBundle/Command/CustomItemsScheduledExportCommand.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 3 + path: ../../plugins/CustomObjectsBundle/Command/GenerateSampleDataCommand.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Command\\\\GenerateSampleDataCommand\\:\\:insertInto\\(\\) has parameter \\$row with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Command/GenerateSampleDataCommand.php + + - + message: "#^Offset 'list' on string in empty\\(\\) does not exist\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Controller/CustomField/SaveController.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Controller/CustomField/SaveController.php + + - + message: "#^Method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) invoked with 2 parameters, 1 required\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Controller/CustomItem/ExportController.php + + - + message: "#^Parameter \\#1 \\$event of method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) expects object, string given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Controller/CustomItem/ExportController.php + + - + message: "#^Call to an undefined method Symfony\\\\Component\\\\Form\\\\FormInterface\\:\\:isClicked\\(\\)\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Controller/CustomItem/SaveController.php + + - + message: "#^Method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) invoked with 2 parameters, 1 required\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Controller/CustomObject/DeleteController.php + + - + message: "#^Parameter \\#1 \\$event of method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) expects object, string given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Controller/CustomObject/DeleteController.php + + - + message: "#^Argument of an invalid type string supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Controller/CustomObject/SaveController.php + + - + message: "#^Call to an undefined method Symfony\\\\Component\\\\Form\\\\FormInterface\\:\\:isClicked\\(\\)\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Controller/CustomObject/SaveController.php + + - + message: "#^Empty array passed to foreach\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Controller/CustomObject/SaveController.php + + - + message: "#^PHPDoc tag @param for parameter \\$fieldValue with type mixed is not subtype of native type MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomFieldValueInterface\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/CustomFieldType/CustomFieldTypeInterface.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\CustomObjectsBundle\\:\\:installAllTablesIfMissing\\(\\) has parameter \\$metadata with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/CustomObjectsBundle.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\DTO\\\\CustomItemFieldListData\\:\\:__construct\\(\\) has parameter \\$columns with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/DTO/CustomItemFieldListData.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\DTO\\\\CustomItemFieldListData\\:\\:__construct\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/DTO/CustomItemFieldListData.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\DTO\\\\CustomItemFieldListData\\:\\:getColumnLabels\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/DTO/CustomItemFieldListData.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\DTO\\\\CustomItemFieldListData\\:\\:\\$columns type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/DTO/CustomItemFieldListData.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\DTO\\\\CustomItemFieldListData\\:\\:\\$data type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/DTO/CustomItemFieldListData.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\AbstractCustomFieldValue\\:\\:addValue\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/AbstractCustomFieldValue.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomField\\:\\:setAlias\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomField.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomFieldValueInterface\\:\\:addValue\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomFieldValueInterface.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomFieldValueInterface\\:\\:setValue\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomFieldValueInterface.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomFieldValueOption\\:\\:addValue\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomFieldValueOption.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomFieldValueOption\\:\\:setValue\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomFieldValueOption.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomFieldValueOption\\:\\:\\$id is unused\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomFieldValueOption.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:addCompanyReference\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:addContactReference\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:addCustomFieldValue\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:addCustomItemReference\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:createFieldValuesSnapshot\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:getFieldValues\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:recordCustomFieldValueChanges\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:setCategory\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:setCustomFieldValues\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:setCustomFieldValues\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:setFieldValues\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:setLanguage\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:setName\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:\\$fieldValues type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItemExportScheduler\\:\\:\\$id is never written, only read\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItemExportScheduler.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:addCustomField\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:createFieldsSnapshot\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:recordCustomFieldChanges\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:removeCustomField\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:setAlias\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:setCategory\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:setCustomFields\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:setDescription\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:setId\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:setLanguage\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:setNamePlural\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:setNameSingular\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Event\\\\CustomObjectListFormatEvent\\:\\:__construct\\(\\) has parameter \\$customObjectValues with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Event/CustomObjectListFormatEvent.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Event\\\\CustomObjectListFormatEvent\\:\\:getCustomObjectValues\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Event/CustomObjectListFormatEvent.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Event\\\\CustomObjectListFormatEvent\\:\\:\\$customObjectValues type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Event/CustomObjectListFormatEvent.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/CampaignSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\CampaignSubscriber\\:\\:executeSelect\\(\\) return type has no value type specified in iterable type Doctrine\\\\DBAL\\\\Driver\\\\Statement\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/CampaignSubscriber.php + + - + message: "#^Variable \\$contact in empty\\(\\) always exists and is not falsy\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/CampaignSubscriber.php + + - + message: "#^Parameter \\#2 \\$bundle of method Mautic\\\\LeadBundle\\\\Entity\\\\LeadEventLogRepository\\:\\:getEvents\\(\\) expects null, string given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ContactSubscriber.php + + - + message: "#^Parameter \\#3 \\$object of method Mautic\\\\LeadBundle\\\\Entity\\\\LeadEventLogRepository\\:\\:getEvents\\(\\) expects null, string given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ContactSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\CustomItemButtonSubscriber\\:\\:defineEditLinkFormButton\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/CustomItemButtonSubscriber.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/CustomItemXrefContactSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\CustomObjectButtonSubscriber\\:\\:defineCreateNewCustomItemButton\\(\\) should return array\\ but returns array\\\\|int\\|string\\>\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/CustomObjectButtonSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\CustomObjectButtonSubscriber\\:\\:defineViewCustomItemsButton\\(\\) should return array\\ but returns array\\\\|int\\|string\\>\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/CustomObjectButtonSubscriber.php + + - + message: "#^Call to an undefined method Psr\\\\Log\\\\LoggerInterface\\:\\:addError\\(\\)\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/DynamicContentSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\DynamicContentSubscriber\\:\\:executeSelect\\(\\) return type has no value type specified in iterable type Doctrine\\\\DBAL\\\\Driver\\\\Statement\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/DynamicContentSubscriber.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/EventListener/FilterOperatorSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\FilterOperatorSubscriber\\:\\:onOperatorsGenerate\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/FilterOperatorSubscriber.php + + - + message: "#^Call to an undefined method Mautic\\\\LeadBundle\\\\Event\\\\ImportProcessEvent\\:\\:addWarning\\(\\)\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ImportSubscriber.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ReportSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\ReportSubscriber\\:\\:addPrefixToColumnLabel\\(\\) has parameter \\$columns with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ReportSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\ReportSubscriber\\:\\:addPrefixToColumnLabel\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ReportSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\ReportSubscriber\\:\\:getCompanyColumns\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ReportSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\ReportSubscriber\\:\\:getContexts\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ReportSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\ReportSubscriber\\:\\:getCustomObjectColumns\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ReportSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\ReportSubscriber\\:\\:getLeadColumns\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ReportSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\ReportSubscriber\\:\\:getStandardColumns\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ReportSubscriber.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\ReportSubscriber\\:\\:\\$customObjects is never written, only read\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ReportSubscriber.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ReportSubscriber.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/EventListener/SegmentFiltersDictionarySubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\SegmentFiltersDictionarySubscriber\\:\\:executeSelect\\(\\) return type has no value type specified in iterable type Doctrine\\\\DBAL\\\\Driver\\\\Statement\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/SegmentFiltersDictionarySubscriber.php + + - + message: "#^Access to undefined constant Mautic\\\\LeadBundle\\\\Segment\\\\ContactSegmentFilterFactory\\:\\:CUSTOM_OPERATOR\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/SegmentFiltersMergeSubscriber.php + + - + message: "#^Call to method getFilters\\(\\) on an unknown class Mautic\\\\LeadBundle\\\\Event\\\\LeadListMergeFiltersEvent\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/SegmentFiltersMergeSubscriber.php + + - + message: "#^Call to method setFilters\\(\\) on an unknown class Mautic\\\\LeadBundle\\\\Event\\\\LeadListMergeFiltersEvent\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/SegmentFiltersMergeSubscriber.php + + - + message: "#^Parameter \\$event of method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\SegmentFiltersMergeSubscriber\\:\\:mergeCustomObjectFilters\\(\\) has invalid type Mautic\\\\LeadBundle\\\\Event\\\\LeadListMergeFiltersEvent\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/SegmentFiltersMergeSubscriber.php + + - + message: "#^Cannot access offset 'alias' on int\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/SerializerSubscriber.php + + - + message: "#^Cannot access offset 'id' on int\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/EventListener/SerializerSubscriber.php + + - + message: "#^Left side of && is always true\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/TokenSubscriber.php + + - + message: "#^Method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) invoked with 2 parameters, 1 required\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/TokenSubscriber.php + + - + message: "#^Negated boolean expression is always false\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/EventListener/TokenSubscriber.php + + - + message: "#^Parameter \\#1 \\$event of method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) expects object, string given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/TokenSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Exception\\\\InUseException\\:\\:getSegmentList\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Exception/InUseException.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Exception\\\\InUseException\\:\\:setSegmentList\\(\\) has parameter \\$segmentList with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Exception/InUseException.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Exception\\\\InUseException\\:\\:\\$segmentList type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Exception/InUseException.php + + - + message: "#^Argument of an invalid type string supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/DataTransformer/OptionsTransformer.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Form\\\\DataTransformer\\\\OptionsTransformer\\:\\:transform\\(\\) should return array\\ but returns array\\\\>\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/DataTransformer/OptionsTransformer.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Form\\\\DataTransformer\\\\OptionsTransformer\\:\\:transform\\(\\) should return array\\ but returns array\\\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/DataTransformer/OptionsTransformer.php + + - + message: "#^Negated boolean expression is always false\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/DataTransformer/OptionsTransformer.php + + - + message: "#^PHPDoc tag @var for variable \\$option has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/DataTransformer/OptionsTransformer.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Form\\\\Type\\\\CustomField\\\\OptionsType\\:\\:buildView\\(\\) has parameter \\$form with no value type specified in iterable type Symfony\\\\Component\\\\Form\\\\FormInterface\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/Type/CustomField/OptionsType.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Form\\\\Type\\\\CustomFieldType\\:\\:createDefaultValueInput\\(\\) has parameter \\$form with no value type specified in iterable type Symfony\\\\Component\\\\Form\\\\FormInterface\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/Type/CustomFieldType.php + + - + message: "#^Negated boolean expression is always false\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/Type/CustomFieldType.php + + - + message: "#^Variable \\$customFields in empty\\(\\) always exists and is not falsy\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/Type/CustomObjectType.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Form\\\\Validator\\\\Constraints\\\\CustomObjectTypeValues\\:\\:\\$missingMasterObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/Validator/Constraints/CustomObjectTypeValues.php + + - + message: "#^Access to an undefined property Symfony\\\\Component\\\\Validator\\\\Constraint\\:\\:\\$missingMasterObject\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/Validator/Constraints/CustomObjectTypeValuesValidator.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Form\\\\Validator\\\\Constraints\\\\CustomObjectTypeValuesValidator\\:\\:validate\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/Validator/Constraints/CustomObjectTypeValuesValidator.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 5 + path: ../../plugins/CustomObjectsBundle/Helper/QueryFilterFactory.php + + - + message: "#^Call to an undefined method Mautic\\\\LeadBundle\\\\Segment\\\\ContactSegmentFilterCrate\\:\\:getMergedProperty\\(\\)\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/QueryFilterHelper.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 5 + path: ../../plugins/CustomObjectsBundle/Helper/QueryFilterHelper.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\QueryFilterHelper\\:\\:addOperatorExpression\\(\\) has parameter \\$value with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/QueryFilterHelper.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\QueryFilterHelper\\:\\:executeSelect\\(\\) return type has no value type specified in iterable type Doctrine\\\\DBAL\\\\Driver\\\\Statement\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/QueryFilterHelper.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\QueryFilterHelper\\:\\:hasQueryJoinAlias\\(\\) has parameter \\$alias with no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/QueryFilterHelper.php + + - + message: "#^Parameter \\#3 \\$type of method Mautic\\\\LeadBundle\\\\Segment\\\\Query\\\\QueryBuilder\\:\\:setParameter\\(\\) expects string\\|null, int given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/QueryFilterHelper.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\TokenFormatter\\:\\:conjunctionList\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/TokenFormatter.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\TokenFormatter\\:\\:format\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/TokenFormatter.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\TokenFormatter\\:\\:formatAndList\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/TokenFormatter.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\TokenFormatter\\:\\:formatBulletList\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/TokenFormatter.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\TokenFormatter\\:\\:formatDefault\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/TokenFormatter.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\TokenFormatter\\:\\:formatOrList\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/TokenFormatter.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\TokenFormatter\\:\\:formatOrderedList\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/TokenFormatter.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\TokenFormatter\\:\\:htmlList\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/TokenFormatter.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\TokenFormatter\\:\\:removeEmptyValues\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/TokenFormatter.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\TokenFormatter\\:\\:removeEmptyValues\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/TokenFormatter.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomFieldModel\\:\\:fetchCustomFieldsForObject\\(\\) should return array\\ but returns Doctrine\\\\ORM\\\\Tools\\\\Pagination\\\\Paginator&iterable\\\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomFieldModel.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomFieldModel\\:\\:fetchEntities\\(\\) should return Doctrine\\\\ORM\\\\Tools\\\\Pagination\\\\Paginator&iterable\\ but returns array\\|Doctrine\\\\ORM\\\\Tools\\\\Pagination\\\\Paginator\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomFieldModel.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomFieldOptionModel.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomFieldValueModel\\:\\:buildItemsListData\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomFieldValueModel.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomFieldValueModel\\:\\:fetchItemsListData\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomFieldValueModel.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomFieldValueModel\\:\\:transformItemsListDataResult\\(\\) has parameter \\$result with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomFieldValueModel.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomFieldValueModel\\:\\:transformItemsListDataResult\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomFieldValueModel.php + + - + message: "#^Parameter \\#1 \\$event of method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) expects object, string given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomItemExportSchedulerModel.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomItemModel.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomItemModel\\:\\:getArrayTableData\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomItemModel.php + + - + message: "#^Method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) invoked with 2 parameters, 1 required\\.$#" + count: 12 + path: ../../plugins/CustomObjectsBundle/Model/CustomItemModel.php + + - + message: "#^Parameter \\#1 \\$event of method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) expects object, string given\\.$#" + count: 12 + path: ../../plugins/CustomObjectsBundle/Model/CustomItemModel.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomObjectModel\\:\\:fetchAllPublishedEntities\\(\\) should return array\\ but returns Doctrine\\\\ORM\\\\Tools\\\\Pagination\\\\Paginator&iterable\\\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomObjectModel.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomObjectModel\\:\\:fetchEntities\\(\\) should return Doctrine\\\\ORM\\\\Tools\\\\Pagination\\\\Paginator&iterable\\ but returns array\\|Doctrine\\\\ORM\\\\Tools\\\\Pagination\\\\Paginator\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomObjectModel.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomObjectModel\\:\\:getMasterCustomObjects\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomObjectModel.php + + - + message: "#^Method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) invoked with 2 parameters, 1 required\\.$#" + count: 4 + path: ../../plugins/CustomObjectsBundle/Model/CustomObjectModel.php + + - + message: "#^Parameter \\#1 \\$event of method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) expects object, string given\\.$#" + count: 4 + path: ../../plugins/CustomObjectsBundle/Model/CustomObjectModel.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomObjectModel\\:\\:\\$listModel is never read, only written\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomObjectModel.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Provider\\\\CustomItemRouteProvider\\:\\:buildListRoute\\(\\) has parameter \\$parameters with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Provider/CustomItemRouteProvider.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Provider\\\\SessionProvider\\:\\:setValue\\(\\) has parameter \\$value with no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Provider/SessionProvider.php + + - + message: "#^Unsafe access to private constant MauticPlugin\\\\CustomObjectsBundle\\\\Provider\\\\SessionProvider\\:\\:KEY_FILTER through static\\:\\:\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Provider/SessionProvider.php + + - + message: "#^Unsafe access to private constant MauticPlugin\\\\CustomObjectsBundle\\\\Provider\\\\SessionProvider\\:\\:KEY_LIMIT through static\\:\\:\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Provider/SessionProvider.php + + - + message: "#^Unsafe access to private constant MauticPlugin\\\\CustomObjectsBundle\\\\Provider\\\\SessionProvider\\:\\:KEY_ORDER_BY through static\\:\\:\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Provider/SessionProvider.php + + - + message: "#^Unsafe access to private constant MauticPlugin\\\\CustomObjectsBundle\\\\Provider\\\\SessionProvider\\:\\:KEY_ORDER_BY_DIR through static\\:\\:\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Provider/SessionProvider.php + + - + message: "#^Unsafe access to private constant MauticPlugin\\\\CustomObjectsBundle\\\\Provider\\\\SessionProvider\\:\\:KEY_PAGE through static\\:\\:\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Provider/SessionProvider.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Report\\\\ReportColumnsBuilder\\:\\:getColumns\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Report/ReportColumnsBuilder.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Report\\\\ReportColumnsBuilder\\:\\:getJoinableColumns\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Report/ReportColumnsBuilder.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Report\\\\ReportColumnsBuilder\\:\\:\\$columnTypeMapping type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Report/ReportColumnsBuilder.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Report\\\\ReportColumnsBuilder\\:\\:\\$columns type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Report/ReportColumnsBuilder.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Repository\\\\CustomItemRepository\\:\\:executeSelect\\(\\) return type has no value type specified in iterable type Doctrine\\\\DBAL\\\\Driver\\\\Statement\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Repository/CustomItemRepository.php + + - + message: "#^Call to method getId\\(\\) on an unknown class MauticPlugin\\\\CustomObjectsBundle\\\\Repository\\\\CustomField\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Repository/CustomObjectRepository.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Repository\\\\CustomObjectRepository\\:\\:getMasterObjectChoices\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Repository/CustomObjectRepository.php + + - + message: "#^PHPDoc tag @var for variable \\$customField contains unknown class MauticPlugin\\\\CustomObjectsBundle\\\\Repository\\\\CustomField\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Repository/CustomObjectRepository.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Security\\\\Permissions\\\\CustomObjectPermissions\\:\\:buildForm\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Security/Permissions/CustomObjectPermissions.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Security\\\\Permissions\\\\CustomObjectPermissions\\:\\:buildForm\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Security/Permissions/CustomObjectPermissions.php + + - + message: "#^Parameter \\#2 \\$level of method Mautic\\\\CoreBundle\\\\Security\\\\Permissions\\\\AbstractPermissions\\:\\:addExtendedFormFields\\(\\) expects string, int\\|null given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Security/Permissions/CustomObjectPermissions.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Segment/Query/Filter/CustomFieldFilterQueryBuilder.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Segment/Query/Filter/CustomItemNameFilterQueryBuilder.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Segment/Query/Filter/CustomObjectMergedFilterQueryBuilder.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Segment/Query/Filter/QueryFilterFactory.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Segment\\\\Query\\\\Filter\\\\QueryFilterFactory\\:\\:configureQueryBuilderFromSegmentFilter\\(\\) has parameter \\$segmentFilter with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Segment/Query/Filter/QueryFilterFactory.php + + - + message: "#^PHPDoc tag @throws with type MauticPlugin\\\\CustomObjectsBundle\\\\Exception\\\\InvalidSegmentFilterException\\|MauticPlugin\\\\CustomObjectsBundle\\\\Exception\\\\NotFoundException\\|MauticPlugin\\\\CustomObjectsBundle\\\\Segment\\\\Query\\\\Filter\\\\Exception is not subtype of Throwable$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Segment/Query/Filter/QueryFilterFactory.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Segment\\\\Query\\\\UnionQueryContainer\\:\\:getParameterTypes\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Segment/Query/UnionQueryContainer.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Segment\\\\Query\\\\UnionQueryContainer\\:\\:getParameters\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Segment/Query/UnionQueryContainer.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Segment\\\\Query\\\\UnionQueryContainer\\:\\:\\$parameterTypes type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Segment/Query/UnionQueryContainer.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Segment\\\\Query\\\\UnionQueryContainer\\:\\:\\$parameters type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Segment/Query/UnionQueryContainer.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\AbstractApiPlatformFunctionalTest\\:\\:createEntity\\(\\) has parameter \\$payload with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/AbstractApiPlatformFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\AbstractApiPlatformFunctionalTest\\:\\:requestEntity\\(\\) has parameter \\$payload with no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/AbstractApiPlatformFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\AbstractApiPlatformFunctionalTest\\:\\:setPermission\\(\\) has parameter \\$permissionArray with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/AbstractApiPlatformFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\AbstractApiPlatformFunctionalTest\\:\\:updateEntity\\(\\) has parameter \\$payload with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/AbstractApiPlatformFunctionalTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\AbstractApiPlatformFunctionalTest\\:\\:\\$clientServer type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/AbstractApiPlatformFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldFunctionalTest\\:\\:getCRUDProvider\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldFunctionalTest\\:\\:getCRUDWithOptionsProvider\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldFunctionalTest\\:\\:getCreatePayload\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldFunctionalTest\\:\\:getCreateWithOptionsPayload\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldFunctionalTest\\:\\:getEditPayload\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldFunctionalTest\\:\\:getEditWithOptionsPayload\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldFunctionalTest\\:\\:runTestCustomFieldCRUD\\(\\) has parameter \\$permissions with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldFunctionalTest\\:\\:runTestCustomFieldWithOptionsCRUD\\(\\) has parameter \\$permissions with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldFunctionalTest\\:\\:runTestCustomFieldWithOptionsCRUD\\(\\) has parameter \\$retrievedOptions with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldFunctionalTest\\:\\:runTestCustomFieldWithOptionsCRUD\\(\\) has parameter \\$updatedOptions with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldOptionFunctionalTest\\:\\:getCRUDProvider\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldOptionFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldOptionFunctionalTest\\:\\:getCreatePayload\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldOptionFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldOptionFunctionalTest\\:\\:getEditPayload\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldOptionFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldOptionFunctionalTest\\:\\:runTestCustomFieldOptionCRUD\\(\\) has parameter \\$permissions with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldOptionFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomObjectFunctionalTest\\:\\:getCRUDProvider\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomObjectFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomObjectFunctionalTest\\:\\:getCreatePayload\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomObjectFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomObjectFunctionalTest\\:\\:getEditPayload\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomObjectFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomObjectFunctionalTest\\:\\:runTestCustomObjectCRUD\\(\\) has parameter \\$permissions with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomObjectFunctionalTest.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/Controller/CustomItemListControllerShownFieldTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\Controller\\\\CustomObject\\\\DeleteControllerTest\\:\\:testDeleteChildObject\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/Controller/CustomObject/DeleteControllerTest.php + + - + message: "#^Call to an undefined method MauticPlugin\\\\CustomObjectsBundle\\\\Repository\\\\CustomObjectRepository\\:\\:findOneById\\(\\)\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/Controller/CustomObjectFormTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\Controller\\\\CustomObjectFormTest\\:\\:assertCustomObject\\(\\) has parameter \\$expected with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/Controller/CustomObjectFormTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\EventListener\\\\FilterOperatorSubscriberTest\\:\\:testIfNewOperatorNotInCustomObjectsAddedinSegmentFilter\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/EventListener/FilterOperatorSubscriberTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\EventListener\\\\FilterOperatorSubscriberTest\\:\\:testIfProperContactsAreAddedinSegmentWithNotInCustomObjectsFilter\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/EventListener/FilterOperatorSubscriberTest.php + + - + message: "#^Negated boolean expression is always false\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/EventListener/ImportSubscriberTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\Helper\\\\QueryFilterHelperTest\\:\\:assertMatchWhere\\(\\) has parameter \\$filter with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/Helper/QueryFilterHelperTest.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/Segment/Query/Filter/CustomFieldFilterQueryBuilderTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\Segment\\\\Query\\\\Filter\\\\CustomFieldFilterQueryBuilderTest\\:\\:executeSelect\\(\\) return type has no value type specified in iterable type Doctrine\\\\DBAL\\\\Driver\\\\Statement\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/Segment/Query/Filter/CustomFieldFilterQueryBuilderTest.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/Segment/Query/Filter/CustomItemNameFilterQueryBuilderTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\Segment\\\\Query\\\\Filter\\\\CustomItemNameFilterQueryBuilderTest\\:\\:executeSelect\\(\\) return type has no value type specified in iterable type Doctrine\\\\DBAL\\\\Driver\\\\Statement\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/Segment/Query/Filter/CustomItemNameFilterQueryBuilderTest.php + + - + message: "#^Call to an undefined method Mautic\\\\LeadBundle\\\\Entity\\\\LeadRepository\\:\\:findOneByEmail\\(\\)\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/Segment/Query/Filter/CustomItemRelationQueryBuilderTestCase.php + + - + message: "#^Call to an undefined method Mautic\\\\CoreBundle\\\\Controller\\\\MauticController&Symfony\\\\Bundle\\\\FrameworkBundle\\\\Controller\\\\Controller\\:\\:setRequest\\(\\)\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/ControllerTestCase.php + + - + message: "#^Call to an undefined method Mautic\\\\CoreBundle\\\\Controller\\\\MauticController&Symfony\\\\Bundle\\\\FrameworkBundle\\\\Controller\\\\Controller\\:\\:setTranslator\\(\\)\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/ControllerTestCase.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\ControllerTestCase\\:\\:\\$request has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/ControllerTestCase.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\ControllerTestCase\\:\\:\\$requestStack has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/ControllerTestCase.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\ControllerTestCase\\:\\:\\$router \\(Symfony\\\\Component\\\\Routing\\\\Router\\) does not accept PHPUnit\\\\Framework\\\\MockObject\\\\MockObject&Symfony\\\\Component\\\\Routing\\\\RouterInterface\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/ControllerTestCase.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\ControllerTestCase\\:\\:\\$session has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/ControllerTestCase.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\AbstractFieldControllerTest\\:\\:createRequestMock\\(\\) has parameter \\$fieldId with no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\AbstractFieldControllerTest\\:\\:createRequestMock\\(\\) has parameter \\$fieldType with no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\AbstractFieldControllerTest\\:\\:createRequestMock\\(\\) has parameter \\$mapExtras with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\AbstractFieldControllerTest\\:\\:createRequestMock\\(\\) has parameter \\$objectId with no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\AbstractFieldControllerTest\\:\\:createRequestMock\\(\\) has parameter \\$panelCount with no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\AbstractFieldControllerTest\\:\\:createRequestMock\\(\\) has parameter \\$panelId with no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\FormControllerTest\\:\\:\\$customFieldFactory has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\FormControllerTest\\:\\:\\$customFieldModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\FormControllerTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\FormControllerTest\\:\\:\\$fieldRouteProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\FormControllerTest\\:\\:\\$form has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\FormControllerTest\\:\\:\\$formController has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\FormControllerTest\\:\\:\\$formFactory has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\FormControllerTest\\:\\:\\$objectRouteProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\FormControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\SaveControllerTest\\:\\:\\$customFieldFactory has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\SaveControllerTest\\:\\:\\$customFieldModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\SaveControllerTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\SaveControllerTest\\:\\:\\$fieldRouteProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\SaveControllerTest\\:\\:\\$form has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\SaveControllerTest\\:\\:\\$formFactory has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\SaveControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\SaveControllerTest\\:\\:\\$saveController has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\SaveControllerTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\BatchDeleteControllerTest\\:\\:\\$customItemModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/BatchDeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\BatchDeleteControllerTest\\:\\:\\$flashBag has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/BatchDeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\BatchDeleteControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/BatchDeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\BatchDeleteControllerTest\\:\\:\\$routeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/BatchDeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\BatchDeleteControllerTest\\:\\:\\$sessionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/BatchDeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\CancelControllerTest\\:\\:\\$customItemModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/CancelControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\CancelControllerTest\\:\\:\\$routeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/CancelControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\CancelControllerTest\\:\\:\\$sessionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/CancelControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\DeleteControllerTest\\:\\:\\$customItemModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/DeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\DeleteControllerTest\\:\\:\\$flashBag has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/DeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\DeleteControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/DeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\DeleteControllerTest\\:\\:\\$routeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/DeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\DeleteControllerTest\\:\\:\\$sessionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/DeleteControllerTest.php + + - + message: "#^Call to an undefined method Mautic\\\\CoreBundle\\\\Helper\\\\UserHelper\\:\\:expects\\(\\)\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/FormControllerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\FormControllerTest\\:\\:testEditActionWhenTheItemIsLocked\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/FormControllerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\FormControllerTest\\:\\:testEditWithRedirectToContactActionWhenTheItemIsLocked\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\FormControllerTest\\:\\:\\$form type has no value type specified in iterable type Symfony\\\\Component\\\\Form\\\\FormInterface\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\LinkControllerTest\\:\\:\\$customItemModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/LinkControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\LinkControllerTest\\:\\:\\$flashBag has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/LinkControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\LinkControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/LinkControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ListControllerTest\\:\\:\\$customItemModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ListControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ListControllerTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ListControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ListControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ListControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ListControllerTest\\:\\:\\$routeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ListControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ListControllerTest\\:\\:\\$sessionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ListControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\LookupControllerTest\\:\\:\\$customItemModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/LookupControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\LookupControllerTest\\:\\:\\$flashBag has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/LookupControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\LookupControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/LookupControllerTest.php + + - + message: "#^Call to an undefined method Mautic\\\\CoreBundle\\\\Helper\\\\UserHelper\\:\\:expects\\(\\)\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/SaveControllerTest.php + + - + message: "#^Call to an undefined method Symfony\\\\Component\\\\Routing\\\\Router\\:\\:expects\\(\\)\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\SaveControllerTest\\:\\:\\$form type has no value type specified in iterable type Symfony\\\\Component\\\\Form\\\\FormInterface\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ViewControllerTest\\:\\:\\$auditLog has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ViewControllerTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ViewControllerTest\\:\\:\\$customItemModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ViewControllerTest\\:\\:\\$customItemXrefContactModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ViewControllerTest\\:\\:\\$form has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ViewControllerTest\\:\\:\\$formFactory has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ViewControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ViewControllerTest\\:\\:\\$routeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\CancelControllerTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/CancelControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\CancelControllerTest\\:\\:\\$routeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/CancelControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\CancelControllerTest\\:\\:\\$sessionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/CancelControllerTest.php + + - + message: "#^Call to an undefined method Symfony\\\\Component\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:expects\\(\\)\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/DeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\DeleteControllerTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/DeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\DeleteControllerTest\\:\\:\\$flashBag has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/DeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\DeleteControllerTest\\:\\:\\$leadListIndex is never read, only written\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/DeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\DeleteControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/DeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\DeleteControllerTest\\:\\:\\$sessionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/DeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\FormControllerTest\\:\\:\\$customFieldModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\FormControllerTest\\:\\:\\$customFieldTypeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\FormControllerTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\FormControllerTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\FormControllerTest\\:\\:\\$form has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\FormControllerTest\\:\\:\\$formFactory has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\FormControllerTest\\:\\:\\$lockFlashMessageHelper has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\FormControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\FormControllerTest\\:\\:\\$routeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ListControllerTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/ListControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ListControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/ListControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ListControllerTest\\:\\:\\$routeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/ListControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ListControllerTest\\:\\:\\$sessionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/ListControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$customFieldModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$customFieldTypeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$flashBag has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$form has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$formFactory has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$lockFlashMessageHelper has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$optionsToStringTransformer has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$paramsToStringTransformer has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$routeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ViewControllerTest\\:\\:\\$auditLog has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ViewControllerTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ViewControllerTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ViewControllerTest\\:\\:\\$form has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ViewControllerTest\\:\\:\\$formFactory has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ViewControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ViewControllerTest\\:\\:\\$routeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/ViewControllerTest.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractCustomFieldTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractCustomFieldTypeTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractCustomFieldTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractCustomFieldTypeTest\\:\\:\\$fieldType \\(MauticPlugin\\\\CustomObjectsBundle\\\\CustomFieldType\\\\EmailType\\) does not accept MauticPlugin\\\\CustomObjectsBundle\\\\CustomFieldType\\\\AbstractCustomFieldType&PHPUnit\\\\Framework\\\\MockObject\\\\MockObject\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractCustomFieldTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractCustomFieldTypeTest\\:\\:\\$filterOperatorProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractCustomFieldTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractCustomFieldTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractCustomFieldTypeTest.php + + - + message: "#^Parameter \\#3 \\$value of method MauticPlugin\\\\CustomObjectsBundle\\\\CustomFieldType\\\\AbstractMultivalueType\\:\\:createValueEntity\\(\\) expects null, array\\ given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractMultivalueTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractMultivalueTypeTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractMultivalueTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractMultivalueTypeTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractMultivalueTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractMultivalueTypeTest\\:\\:\\$provider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractMultivalueTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractMultivalueTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractMultivalueTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractTextTypeTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractTextTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractTextTypeTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractTextTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractTextTypeTest\\:\\:\\$filterOperatorProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractTextTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractTextTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractTextTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\CountryTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/CountryTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\DateTimeTypeTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/DateTimeTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\DateTimeTypeTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/DateTimeTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\DateTimeTypeTest\\:\\:\\$filterOperatorProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/DateTimeTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\DateTimeTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/DateTimeTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\DateTypeTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/DateTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\DateTypeTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/DateTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\DateTypeTest\\:\\:\\$filterOperatorProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/DateTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\DateTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/DateTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\EmailTypeTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/EmailTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\EmailTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/EmailTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\IntTypeTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/IntTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\IntTypeTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/IntTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\IntTypeTest\\:\\:\\$filterOperatorProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/IntTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\IntTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/IntTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\MultiselectTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/MultiselectTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\PhoneTypeTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/PhoneTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\PhoneTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/PhoneTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\SelectTypeTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/SelectTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\SelectTypeTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/SelectTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\SelectTypeTest\\:\\:\\$filterOperatorProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/SelectTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\SelectTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/SelectTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\UrlTypeTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/UrlTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\UrlTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/UrlTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\AbstractCustomFieldValueTest\\:\\:\\$abstractCFValue has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/AbstractCustomFieldValueTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\AbstractCustomFieldValueTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/AbstractCustomFieldValueTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\AbstractCustomFieldValueTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/AbstractCustomFieldValueTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\AbstractCustomFieldValueTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/AbstractCustomFieldValueTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\CustomField\\\\ParamsTest\\:\\:testConstructorAndToArray\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomField/ParamsTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\CustomField\\\\ParamsTest\\:\\:testGettersSetters\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomField/ParamsTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\CustomField\\\\ParamsTest\\:\\:testToArrayRemovingFalseAndNullValues\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomField/ParamsTest.php + + - + message: "#^Parameter \\#1 \\$array \\(array\\{placeholder\\: null\\}\\) to function array_filter contains falsy values only, the result will always be an empty array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomField/ParamsTest.php + + - + message: "#^Unable to resolve the template type RealInstanceType in call to method PHPUnit\\\\Framework\\\\TestCase\\:\\:createMock\\(\\)$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomFieldFactoryTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\CustomFieldOptionTest\\:\\:testArrayAccessor\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomFieldOptionTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\CustomFieldOptionTest\\:\\:testConstructorAndToArray\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomFieldOptionTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\CustomFieldOptionTest\\:\\:testGettersSetters\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomFieldOptionTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\CustomFieldTest\\:\\:testCanHaveMultipleValuesForCheckboxType\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomFieldTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\CustomFieldTest\\:\\:testCanHaveMultipleValuesForDateType\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomFieldTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\CustomFieldTest\\:\\:testDefaultValueTransformation\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomFieldTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\CustomObjectTest\\:\\:testGetCfByOrder\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomObjectTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ApiSubscriberTest\\:\\:\\$apiEntityEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ApiSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ApiSubscriberTest\\:\\:\\$configProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ApiSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ApiSubscriberTest\\:\\:\\$customItemModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ApiSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ApiSubscriberTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ApiSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ApiSubscriberTest\\:\\:\\$request has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ApiSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AssetsSubscriberTest\\:\\:\\$assetsHelper has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AssetsSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AssetsSubscriberTest\\:\\:\\$assetsSubscriber has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AssetsSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AssetsSubscriberTest\\:\\:\\$configProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AssetsSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AssetsSubscriberTest\\:\\:\\$getResponseEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AssetsSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AssetsSubscriberTest\\:\\:\\$request has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AssetsSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AuditLogSubscriberTest\\:\\:\\$auditLogModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AuditLogSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AuditLogSubscriberTest\\:\\:\\$auditLogSubscriber has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AuditLogSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AuditLogSubscriberTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AuditLogSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AuditLogSubscriberTest\\:\\:\\$customItemEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AuditLogSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AuditLogSubscriberTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AuditLogSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AuditLogSubscriberTest\\:\\:\\$customObjectEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AuditLogSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AuditLogSubscriberTest\\:\\:\\$ipLookupHelper has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AuditLogSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$campaignBuilderEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$campaignExecutionEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$configProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$connection has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$contact has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$customFieldModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$customItemModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$queryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$queryFilterFactory has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$queryFilterHelper has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$segmentQueryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$statement has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ContactSubscriberTest\\:\\:\\$configProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ContactSubscriberTest\\:\\:\\$customItemModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ContactSubscriberTest\\:\\:\\$entityManager has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ContactSubscriberTest\\:\\:\\$leadEventLogRepo has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ContactSubscriberTest\\:\\:\\$leadTimelineEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ContactSubscriberTest\\:\\:\\$routeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ContactSubscriberTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ContactSubscriberTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ContactTabSubscriberTest\\:\\:testSubscriberEvents\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ContactTabSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomFieldPostLoadSubscriberTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomFieldPostLoadSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomFieldPostLoadSubscriberTest\\:\\:\\$customFieldTypeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomFieldPostLoadSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomFieldPostLoadSubscriberTest\\:\\:\\$event has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomFieldPostLoadSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomFieldPostLoadSubscriberTest\\:\\:\\$subscriber has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomFieldPostLoadSubscriberTest.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$contact has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$discoveryEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$entityManager has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$event has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$listDbalEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$listEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$query has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$queryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$queryBuilderDbal has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$xref has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefCustomItemSubscriberTest\\:\\:\\$customItemA has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefCustomItemSubscriberTest\\:\\:\\$customItemB has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefCustomItemSubscriberTest\\:\\:\\$discoveryEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefCustomItemSubscriberTest\\:\\:\\$entityManager has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefCustomItemSubscriberTest\\:\\:\\$event has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefCustomItemSubscriberTest\\:\\:\\$expr has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefCustomItemSubscriberTest\\:\\:\\$listEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefCustomItemSubscriberTest\\:\\:\\$query has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefCustomItemSubscriberTest\\:\\:\\$queryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefCustomItemSubscriberTest\\:\\:\\$xref has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomObjectButtonSubscriberTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomObjectButtonSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomObjectButtonSubscriberTest\\:\\:\\$event has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomObjectButtonSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomObjectButtonSubscriberTest\\:\\:\\$itemPermissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomObjectButtonSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomObjectButtonSubscriberTest\\:\\:\\$itemRouteProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomObjectButtonSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomObjectButtonSubscriberTest\\:\\:\\$objectPermissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomObjectButtonSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomObjectButtonSubscriberTest\\:\\:\\$objectRouteProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomObjectButtonSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomObjectButtonSubscriberTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomObjectButtonSubscriberTest.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/FilterOperatorSubscriberTest.php + + - + message: "#^PHPDoc tag @var for variable \\$formMock has no value type specified in iterable type Symfony\\\\Component\\\\Form\\\\FormInterface\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/FilterOperatorSubscriberTest.php + + - + message: "#^Parameter \\#1 \\$form of class Mautic\\\\LeadBundle\\\\Event\\\\FormAdjustmentEvent constructor expects iterable\\&Symfony\\\\Component\\\\Form\\\\FormInterface, PHPUnit\\\\Framework\\\\MockObject\\\\MockObject\\|Symfony\\\\Component\\\\Form\\\\FormInterface given\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/FilterOperatorSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$configProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$customFieldRepository has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$customItemImportModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$form has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$import has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$importInitEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$importMappingEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$importProcessEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$importValidateEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\MenuSubscriberTest\\:\\:\\$configProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/MenuSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\MenuSubscriberTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/MenuSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\MenuSubscriberTest\\:\\:\\$menuEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/MenuSubscriberTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ReportSubscriberTest\\:\\:getCustomObjectsCollection\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ReportSubscriberTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ReportSubscriberTest\\:\\:testThatIdDoesntProcessContextsWithEmptyOrNotIntCustomObjectsID\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ReportSubscriberTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ReportSubscriberTest\\:\\:testThatIdDoesntProcessNotExistingCustomObjects\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ReportSubscriberTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ReportSubscriberTest\\:\\:testThatOnReportGenerateMethodDoesntProcessWrongContexts\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ReportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\SerializerSubscriberTest\\:\\:\\$configProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/SerializerSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\SerializerSubscriberTest\\:\\:\\$customItemModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/SerializerSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\SerializerSubscriberTest\\:\\:\\$customItemXrefContactRepository has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/SerializerSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\SerializerSubscriberTest\\:\\:\\$objectEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/SerializerSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\SerializerSubscriberTest\\:\\:\\$request has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/SerializerSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\SerializerSubscriberTest\\:\\:\\$requestStack has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/SerializerSubscriberTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Exception\\\\InvalidCustomObjectFormatListExceptionTest\\:\\:testAll\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Exception/InvalidCustomObjectFormatListExceptionTest.php + + - + message: "#^Parameter \\#1 \\$value of method MauticPlugin\\\\CustomObjectsBundle\\\\Form\\\\DataTransformer\\\\OptionsTransformer\\:\\:reverseTransform\\(\\) expects array\\, array\\\\>\\> given\\.$#" + count: 4 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/DataTransformer/OptionsTransformerTest.php + + - + message: "#^Parameter \\#1 \\$value of method MauticPlugin\\\\CustomObjectsBundle\\\\Form\\\\DataTransformer\\\\OptionsTransformer\\:\\:transform\\(\\) expects Doctrine\\\\ORM\\\\PersistentCollection&iterable\\, Doctrine\\\\Common\\\\Collections\\\\ArrayCollection\\<\\*NEVER\\*, \\*NEVER\\*\\> given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/DataTransformer/OptionsTransformerTest.php + + - + message: "#^Parameter \\#1 \\$value of method MauticPlugin\\\\CustomObjectsBundle\\\\Form\\\\DataTransformer\\\\OptionsTransformer\\:\\:transform\\(\\) expects Doctrine\\\\ORM\\\\PersistentCollection&iterable\\, Doctrine\\\\Common\\\\Collections\\\\ArrayCollection\\ given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/DataTransformer/OptionsTransformerTest.php + + - + message: "#^Parameter \\#1 \\$value of method MauticPlugin\\\\CustomObjectsBundle\\\\Form\\\\DataTransformer\\\\OptionsTransformer\\:\\:transform\\(\\) expects Doctrine\\\\ORM\\\\PersistentCollection&iterable\\, null given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/DataTransformer/OptionsTransformerTest.php + + - + message: "#^Parameter \\#1 \\$params of method MauticPlugin\\\\CustomObjectsBundle\\\\Form\\\\DataTransformer\\\\ParamsToStringTransformer\\:\\:transform\\(\\) expects MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomField\\\\Params\\|null, array given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/DataTransformer/ParamsToStringTransformerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Type\\\\CampaignConditionFieldValueTypeTest\\:\\:testConfigureOptions\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Type/CampaignConditionFieldValueTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Type\\\\CustomFieldValueTypeTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Type/CustomFieldValueTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Type\\\\CustomFieldValueTypeTest\\:\\:\\$customFieldType has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Type/CustomFieldValueTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Type\\\\CustomFieldValueTypeTest\\:\\:\\$customFieldValue has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Type/CustomFieldValueTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Type\\\\CustomFieldValueTypeTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Type/CustomFieldValueTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Type\\\\CustomFieldValueTypeTest\\:\\:\\$formBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Type/CustomFieldValueTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Type\\\\CustomFieldValueTypeTest\\:\\:\\$optionsResolver has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Type/CustomFieldValueTypeTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Type\\\\CustomObjectTypeTest\\:\\:buildForm\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Type/CustomObjectTypeTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Type\\\\CustomObjectTypeTest\\:\\:testBuildFormExistingObject\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Type/CustomObjectTypeTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Type\\\\CustomObjectTypeTest\\:\\:testBuildFormNewObject\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Type/CustomObjectTypeTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Type\\\\CustomObjectTypeTest\\:\\:testConfigureOptions\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Type/CustomObjectTypeTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Validator\\\\CustomObjectTypeValuesTest\\:\\:testGetTargets\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Validator/CustomObjectTypeValuesTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Validator\\\\CustomObjectTypeValuesTest\\:\\:testValidatedBy\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Validator/CustomObjectTypeValuesTest.php + + - + message: "#^Access to an undefined property PHPUnit\\\\Framework\\\\MockObject\\\\MockObject\\|Symfony\\\\Component\\\\Validator\\\\Constraint\\:\\:\\$missingMasterObject\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Validator/CustomObjectTypeValuesValidatorTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Validator\\\\CustomObjectTypeValuesValidatorTest\\:\\:testValidateIgnoreCompletely\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Validator/CustomObjectTypeValuesValidatorTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Validator\\\\CustomObjectTypeValuesValidatorTest\\:\\:testValidateIgnoreMasterObject\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Validator/CustomObjectTypeValuesValidatorTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Validator\\\\CustomObjectTypeValuesValidatorTest\\:\\:testValidateNoCustomObject\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Validator/CustomObjectTypeValuesValidatorTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\CustomFieldQueryBuilder\\\\CalculatorTest\\:\\:assertMatrixEquals\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/CustomFieldQueryBuilder/CalculatorTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\CustomFieldQueryBuilder\\\\CalculatorTest\\:\\:assertMatrixEquals\\(\\) has parameter \\$expectedMatrix with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/CustomFieldQueryBuilder/CalculatorTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\CustomFieldQueryBuilder\\\\CalculatorTest\\:\\:getSuffix\\(\\) has parameter \\$decisionValue with no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/CustomFieldQueryBuilder/CalculatorTest.php + + - + message: "#^Parameter \\#4 \\$value of method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\QueryFilterHelper\\:\\:addCustomObjectNameExpression\\(\\) expects string\\|null, int given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/QueryFilterHelperTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\TokenFormatterTest\\:\\:testAvailableFormats\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/TokenFormatterTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\TokenFormatterTest\\:\\:testFormatManyValues\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/TokenFormatterTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\TokenFormatterTest\\:\\:testFormatOneValue\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/TokenFormatterTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\TokenFormatterTest\\:\\:testIsValidFormat\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/TokenFormatterTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\TokenFormatterTest\\:\\:\\$availableFormats has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/TokenFormatterTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\TokenFormatterTest\\:\\:\\$manyValues has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/TokenFormatterTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\TokenFormatterTest\\:\\:\\$noValues has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/TokenFormatterTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\TokenFormatterTest\\:\\:\\$oneValue has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/TokenFormatterTest.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldOptionModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldOptionModelTest\\:\\:\\$connection has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldOptionModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldOptionModelTest\\:\\:\\$entityManager has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldOptionModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldOptionModelTest\\:\\:\\$queryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldOptionModelTest.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$connection has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$customFieldValueModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$entityManager has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$filterOperatorProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$queryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$statement has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$validator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$violationList has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$connection has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$customFieldValueModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$customItemPermissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$customItemRepository has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$dbalQueryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$dispatcher has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$entityManager has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$query has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$queryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$statement has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$user has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$userHelper has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$validator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$violationList has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemXrefContactModelTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemXrefContactModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemXrefContactModelTest\\:\\:\\$entityManager has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemXrefContactModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemXrefContactModelTest\\:\\:\\$query has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemXrefContactModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemXrefContactModelTest\\:\\:\\$queryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemXrefContactModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemXrefContactModelTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemXrefContactModelTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:testGetMasterCustomObjects\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$connection has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$customFieldModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$customObjectPermissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$customObjectRepository has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$databasePlatform has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$dispatcher has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$entityManager has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$query has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$queryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$queryBuilderDbal has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$statement has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$user has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$userHelper has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Provider\\\\CustomFieldRouteProviderTest\\:\\:\\$router has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Provider/CustomFieldRouteProviderTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Provider\\\\CustomItemPermissionProviderTest\\:\\:\\$corePermissions has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Provider/CustomItemPermissionProviderTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Provider\\\\CustomItemPermissionProviderTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Provider/CustomItemPermissionProviderTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Provider\\\\CustomItemPermissionProviderTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Provider/CustomItemPermissionProviderTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Provider\\\\CustomItemRouteProviderTest\\:\\:testThatBuildContactViewRouteReturnsCorrectUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Provider/CustomItemRouteProviderTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Provider\\\\CustomItemRouteProviderTest\\:\\:testThatBuildEditRouteWithRedirectToContactReturnsCorrectUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Provider/CustomItemRouteProviderTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Provider\\\\CustomItemRouteProviderTest\\:\\:testThatBuildNewRouteWithRedirectToContactReturnsCorrectUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Provider/CustomItemRouteProviderTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Provider\\\\CustomItemRouteProviderTest\\:\\:\\$router has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Provider/CustomItemRouteProviderTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Provider\\\\CustomObjectPermissionProviderTest\\:\\:\\$entity has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Provider/CustomObjectPermissionProviderTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Provider\\\\CustomObjectPermissionProviderTest\\:\\:\\$permissions has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Provider/CustomObjectPermissionProviderTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Provider\\\\CustomObjectRouteProviderTest\\:\\:\\$router has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Provider/CustomObjectRouteProviderTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomFieldRepositoryTest\\:\\:\\$classMetadata has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomFieldRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomFieldRepositoryTest\\:\\:\\$entityManager has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomFieldRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomFieldRepositoryTest\\:\\:\\$expression has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomFieldRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomFieldRepositoryTest\\:\\:\\$query has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomFieldRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomFieldRepositoryTest\\:\\:\\$queryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomFieldRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemRepositoryTest\\:\\:\\$contact has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemRepositoryTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemRepositoryTest\\:\\:\\$entityManager has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemRepositoryTest\\:\\:\\$expr has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemRepositoryTest\\:\\:\\$query has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemRepositoryTest\\:\\:\\$queryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemXrefContactRepositoryTest\\:\\:\\$classMetadata has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemXrefContactRepositoryTest\\:\\:\\$connection has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemXrefContactRepositoryTest\\:\\:\\$contact has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemXrefContactRepositoryTest\\:\\:\\$entityManager has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemXrefContactRepositoryTest\\:\\:\\$expr has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemXrefContactRepositoryTest\\:\\:\\$expressionBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemXrefContactRepositoryTest\\:\\:\\$query has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemXrefContactRepositoryTest\\:\\:\\$queryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemXrefContactRepositoryTest\\:\\:\\$queryBuilderDbal has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemXrefContactRepositoryTest\\:\\:\\$statement has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Segment\\\\Query\\\\Filter\\\\CustomItemNameFilterQueryBuilderTest\\:\\:parameterValueProvider\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Segment/Query/Filter/CustomItemNameFilterQueryBuilderTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Segment\\\\Query\\\\Filter\\\\CustomItemNameFilterQueryBuilderTest\\:\\:testApplyQuery\\(\\) has parameter \\$parameterValue with no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Segment/Query/Filter/CustomItemNameFilterQueryBuilderTest.php + + - + message: "#^PHPDoc tag @param has invalid value \\(\\$parameterValue\\)\\: Unexpected token \"\\$parameterValue\", expected type at offset 69$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Segment/Query/Filter/CustomItemNameFilterQueryBuilderTest.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 3 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Segment/Query/Filter/QueryFilterFactoryTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Segment\\\\Query\\\\UnionQueryContainerTest\\:\\:testParameterTypesCheck\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Segment/Query/UnionQueryContainerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Segment\\\\Query\\\\UnionQueryContainerTest\\:\\:testParametersCheck\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Segment/Query/UnionQueryContainerTest.php + + - + message: "#^Parameter \\#3 \\$type of method Mautic\\\\LeadBundle\\\\Segment\\\\Query\\\\QueryBuilder\\:\\:setParameter\\(\\) expects string\\|null, int given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Segment/Query/UnionQueryContainerTest.php + diff --git a/phpstan-baseline-8.0.neon b/phpstan-baseline-8.0.neon new file mode 100644 index 000000000..480f18008 --- /dev/null +++ b/phpstan-baseline-8.0.neon @@ -0,0 +1,3022 @@ +parameters: + ignoreErrors: + - + message: "#^Method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) invoked with 2 parameters, 1 required\\.$#" + count: 3 + path: ../../plugins/CustomObjectsBundle/Command/CustomItemsScheduledExportCommand.php + + - + message: "#^Parameter \\#1 \\$event of method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) expects object, string given\\.$#" + count: 3 + path: ../../plugins/CustomObjectsBundle/Command/CustomItemsScheduledExportCommand.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 3 + path: ../../plugins/CustomObjectsBundle/Command/GenerateSampleDataCommand.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Command\\\\GenerateSampleDataCommand\\:\\:insertInto\\(\\) has parameter \\$row with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Command/GenerateSampleDataCommand.php + + - + message: "#^Offset 'list' on string in empty\\(\\) does not exist\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Controller/CustomField/SaveController.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Controller/CustomField/SaveController.php + + - + message: "#^Method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) invoked with 2 parameters, 1 required\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Controller/CustomItem/ExportController.php + + - + message: "#^Parameter \\#1 \\$event of method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) expects object, string given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Controller/CustomItem/ExportController.php + + - + message: "#^Call to an undefined method Symfony\\\\Component\\\\Form\\\\FormInterface\\:\\:isClicked\\(\\)\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Controller/CustomItem/SaveController.php + + - + message: "#^Method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) invoked with 2 parameters, 1 required\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Controller/CustomObject/DeleteController.php + + - + message: "#^Parameter \\#1 \\$event of method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) expects object, string given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Controller/CustomObject/DeleteController.php + + - + message: "#^Argument of an invalid type string supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Controller/CustomObject/SaveController.php + + - + message: "#^Call to an undefined method Symfony\\\\Component\\\\Form\\\\FormInterface\\:\\:isClicked\\(\\)\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Controller/CustomObject/SaveController.php + + - + message: "#^Empty array passed to foreach\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Controller/CustomObject/SaveController.php + + - + message: "#^PHPDoc tag @param for parameter \\$fieldValue with type mixed is not subtype of native type MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomFieldValueInterface\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/CustomFieldType/CustomFieldTypeInterface.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\CustomObjectsBundle\\:\\:installAllTablesIfMissing\\(\\) has parameter \\$metadata with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/CustomObjectsBundle.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\DTO\\\\CustomItemFieldListData\\:\\:__construct\\(\\) has parameter \\$columns with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/DTO/CustomItemFieldListData.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\DTO\\\\CustomItemFieldListData\\:\\:__construct\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/DTO/CustomItemFieldListData.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\DTO\\\\CustomItemFieldListData\\:\\:getColumnLabels\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/DTO/CustomItemFieldListData.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\DTO\\\\CustomItemFieldListData\\:\\:\\$columns type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/DTO/CustomItemFieldListData.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\DTO\\\\CustomItemFieldListData\\:\\:\\$data type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/DTO/CustomItemFieldListData.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\AbstractCustomFieldValue\\:\\:addValue\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/AbstractCustomFieldValue.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomField\\:\\:setAlias\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomField.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomFieldValueInterface\\:\\:addValue\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomFieldValueInterface.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomFieldValueInterface\\:\\:setValue\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomFieldValueInterface.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomFieldValueOption\\:\\:addValue\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomFieldValueOption.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomFieldValueOption\\:\\:setValue\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomFieldValueOption.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomFieldValueOption\\:\\:\\$id is unused\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomFieldValueOption.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:addCompanyReference\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:addContactReference\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:addCustomFieldValue\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:addCustomItemReference\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:createFieldValuesSnapshot\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:getFieldValues\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:recordCustomFieldValueChanges\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:setCategory\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:setCustomFieldValues\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:setCustomFieldValues\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:setFieldValues\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:setLanguage\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:setName\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItem\\:\\:\\$fieldValues type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItem.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomItemExportScheduler\\:\\:\\$id is never written, only read\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomItemExportScheduler.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:addCustomField\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:createFieldsSnapshot\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:recordCustomFieldChanges\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:removeCustomField\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:setAlias\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:setCategory\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:setCustomFields\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:setDescription\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:setId\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:setLanguage\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:setNamePlural\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject\\:\\:setNameSingular\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Entity/CustomObject.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Event\\\\CustomObjectListFormatEvent\\:\\:__construct\\(\\) has parameter \\$customObjectValues with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Event/CustomObjectListFormatEvent.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Event\\\\CustomObjectListFormatEvent\\:\\:getCustomObjectValues\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Event/CustomObjectListFormatEvent.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Event\\\\CustomObjectListFormatEvent\\:\\:\\$customObjectValues type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Event/CustomObjectListFormatEvent.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/CampaignSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\CampaignSubscriber\\:\\:executeSelect\\(\\) return type has no value type specified in iterable type Doctrine\\\\DBAL\\\\Driver\\\\Statement\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/CampaignSubscriber.php + + - + message: "#^Variable \\$contact in empty\\(\\) always exists and is not falsy\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/CampaignSubscriber.php + + - + message: "#^Parameter \\#2 \\$bundle of method Mautic\\\\LeadBundle\\\\Entity\\\\LeadEventLogRepository\\:\\:getEvents\\(\\) expects null, string given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ContactSubscriber.php + + - + message: "#^Parameter \\#3 \\$object of method Mautic\\\\LeadBundle\\\\Entity\\\\LeadEventLogRepository\\:\\:getEvents\\(\\) expects null, string given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ContactSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\CustomItemButtonSubscriber\\:\\:defineEditLinkFormButton\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/CustomItemButtonSubscriber.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/CustomItemXrefContactSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\CustomObjectButtonSubscriber\\:\\:defineCreateNewCustomItemButton\\(\\) should return array\\ but returns array\\\\|int\\|string\\>\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/CustomObjectButtonSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\CustomObjectButtonSubscriber\\:\\:defineViewCustomItemsButton\\(\\) should return array\\ but returns array\\\\|int\\|string\\>\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/CustomObjectButtonSubscriber.php + + - + message: "#^Call to an undefined method Psr\\\\Log\\\\LoggerInterface\\:\\:addError\\(\\)\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/DynamicContentSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\DynamicContentSubscriber\\:\\:executeSelect\\(\\) return type has no value type specified in iterable type Doctrine\\\\DBAL\\\\Driver\\\\Statement\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/DynamicContentSubscriber.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/EventListener/FilterOperatorSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\FilterOperatorSubscriber\\:\\:onOperatorsGenerate\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/FilterOperatorSubscriber.php + + - + message: "#^Call to an undefined method Mautic\\\\LeadBundle\\\\Event\\\\ImportProcessEvent\\:\\:addWarning\\(\\)\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ImportSubscriber.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ReportSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\ReportSubscriber\\:\\:addPrefixToColumnLabel\\(\\) has parameter \\$columns with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ReportSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\ReportSubscriber\\:\\:addPrefixToColumnLabel\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ReportSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\ReportSubscriber\\:\\:getCompanyColumns\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ReportSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\ReportSubscriber\\:\\:getContexts\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ReportSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\ReportSubscriber\\:\\:getCustomObjectColumns\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ReportSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\ReportSubscriber\\:\\:getLeadColumns\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ReportSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\ReportSubscriber\\:\\:getStandardColumns\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ReportSubscriber.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\ReportSubscriber\\:\\:\\$customObjects is never written, only read\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ReportSubscriber.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/ReportSubscriber.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/EventListener/SegmentFiltersDictionarySubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\SegmentFiltersDictionarySubscriber\\:\\:executeSelect\\(\\) return type has no value type specified in iterable type Doctrine\\\\DBAL\\\\Driver\\\\Statement\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/SegmentFiltersDictionarySubscriber.php + + - + message: "#^Access to undefined constant Mautic\\\\LeadBundle\\\\Segment\\\\ContactSegmentFilterFactory\\:\\:CUSTOM_OPERATOR\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/SegmentFiltersMergeSubscriber.php + + - + message: "#^Call to method getFilters\\(\\) on an unknown class Mautic\\\\LeadBundle\\\\Event\\\\LeadListMergeFiltersEvent\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/SegmentFiltersMergeSubscriber.php + + - + message: "#^Call to method setFilters\\(\\) on an unknown class Mautic\\\\LeadBundle\\\\Event\\\\LeadListMergeFiltersEvent\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/SegmentFiltersMergeSubscriber.php + + - + message: "#^Parameter \\$event of method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\SegmentFiltersMergeSubscriber\\:\\:mergeCustomObjectFilters\\(\\) has invalid type Mautic\\\\LeadBundle\\\\Event\\\\LeadListMergeFiltersEvent\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/SegmentFiltersMergeSubscriber.php + + - + message: "#^Cannot access offset 'alias' on int\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/SerializerSubscriber.php + + - + message: "#^Cannot access offset 'id' on int\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/EventListener/SerializerSubscriber.php + + - + message: "#^Left side of && is always true\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/TokenSubscriber.php + + - + message: "#^Method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) invoked with 2 parameters, 1 required\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/TokenSubscriber.php + + - + message: "#^Negated boolean expression is always false\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/EventListener/TokenSubscriber.php + + - + message: "#^Parameter \\#1 \\$event of method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) expects object, string given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/EventListener/TokenSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Exception\\\\InUseException\\:\\:getSegmentList\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Exception/InUseException.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Exception\\\\InUseException\\:\\:setSegmentList\\(\\) has parameter \\$segmentList with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Exception/InUseException.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Exception\\\\InUseException\\:\\:\\$segmentList type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Exception/InUseException.php + + - + message: "#^Argument of an invalid type string supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/DataTransformer/OptionsTransformer.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Form\\\\DataTransformer\\\\OptionsTransformer\\:\\:transform\\(\\) should return array\\ but returns array\\\\>\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/DataTransformer/OptionsTransformer.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Form\\\\DataTransformer\\\\OptionsTransformer\\:\\:transform\\(\\) should return array\\ but returns array\\\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/DataTransformer/OptionsTransformer.php + + - + message: "#^Negated boolean expression is always false\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/DataTransformer/OptionsTransformer.php + + - + message: "#^PHPDoc tag @var for variable \\$option has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/DataTransformer/OptionsTransformer.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Form\\\\Type\\\\CustomField\\\\OptionsType\\:\\:buildView\\(\\) has parameter \\$form with no value type specified in iterable type Symfony\\\\Component\\\\Form\\\\FormInterface\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/Type/CustomField/OptionsType.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Form\\\\Type\\\\CustomFieldType\\:\\:createDefaultValueInput\\(\\) has parameter \\$form with no value type specified in iterable type Symfony\\\\Component\\\\Form\\\\FormInterface\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/Type/CustomFieldType.php + + - + message: "#^Negated boolean expression is always false\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/Type/CustomFieldType.php + + - + message: "#^Variable \\$customFields in empty\\(\\) always exists and is not falsy\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/Type/CustomObjectType.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Form\\\\Validator\\\\Constraints\\\\CustomObjectTypeValues\\:\\:\\$missingMasterObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/Validator/Constraints/CustomObjectTypeValues.php + + - + message: "#^Access to an undefined property Symfony\\\\Component\\\\Validator\\\\Constraint\\:\\:\\$missingMasterObject\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/Validator/Constraints/CustomObjectTypeValuesValidator.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Form\\\\Validator\\\\Constraints\\\\CustomObjectTypeValuesValidator\\:\\:validate\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Form/Validator/Constraints/CustomObjectTypeValuesValidator.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 5 + path: ../../plugins/CustomObjectsBundle/Helper/QueryFilterFactory.php + + - + message: "#^Call to an undefined method Mautic\\\\LeadBundle\\\\Segment\\\\ContactSegmentFilterCrate\\:\\:getMergedProperty\\(\\)\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/QueryFilterHelper.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 5 + path: ../../plugins/CustomObjectsBundle/Helper/QueryFilterHelper.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\QueryFilterHelper\\:\\:addOperatorExpression\\(\\) has parameter \\$value with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/QueryFilterHelper.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\QueryFilterHelper\\:\\:executeSelect\\(\\) return type has no value type specified in iterable type Doctrine\\\\DBAL\\\\Driver\\\\Statement\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/QueryFilterHelper.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\QueryFilterHelper\\:\\:hasQueryJoinAlias\\(\\) has parameter \\$alias with no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/QueryFilterHelper.php + + - + message: "#^Parameter \\#3 \\$type of method Mautic\\\\LeadBundle\\\\Segment\\\\Query\\\\QueryBuilder\\:\\:setParameter\\(\\) expects string\\|null, int given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/QueryFilterHelper.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\TokenFormatter\\:\\:conjunctionList\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/TokenFormatter.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\TokenFormatter\\:\\:format\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/TokenFormatter.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\TokenFormatter\\:\\:formatAndList\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/TokenFormatter.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\TokenFormatter\\:\\:formatBulletList\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/TokenFormatter.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\TokenFormatter\\:\\:formatDefault\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/TokenFormatter.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\TokenFormatter\\:\\:formatOrList\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/TokenFormatter.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\TokenFormatter\\:\\:formatOrderedList\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/TokenFormatter.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\TokenFormatter\\:\\:htmlList\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/TokenFormatter.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\TokenFormatter\\:\\:removeEmptyValues\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/TokenFormatter.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\TokenFormatter\\:\\:removeEmptyValues\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Helper/TokenFormatter.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomFieldModel\\:\\:fetchCustomFieldsForObject\\(\\) should return array\\ but returns Doctrine\\\\ORM\\\\Tools\\\\Pagination\\\\Paginator&iterable\\\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomFieldModel.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomFieldModel\\:\\:fetchEntities\\(\\) should return Doctrine\\\\ORM\\\\Tools\\\\Pagination\\\\Paginator&iterable\\ but returns array\\|Doctrine\\\\ORM\\\\Tools\\\\Pagination\\\\Paginator\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomFieldModel.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomFieldOptionModel.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomFieldValueModel\\:\\:buildItemsListData\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomFieldValueModel.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomFieldValueModel\\:\\:fetchItemsListData\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomFieldValueModel.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomFieldValueModel\\:\\:transformItemsListDataResult\\(\\) has parameter \\$result with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomFieldValueModel.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomFieldValueModel\\:\\:transformItemsListDataResult\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomFieldValueModel.php + + - + message: "#^Parameter \\#1 \\$event of method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) expects object, string given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomItemExportSchedulerModel.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomItemModel.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomItemModel\\:\\:getArrayTableData\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomItemModel.php + + - + message: "#^Method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) invoked with 2 parameters, 1 required\\.$#" + count: 12 + path: ../../plugins/CustomObjectsBundle/Model/CustomItemModel.php + + - + message: "#^Parameter \\#1 \\$event of method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) expects object, string given\\.$#" + count: 12 + path: ../../plugins/CustomObjectsBundle/Model/CustomItemModel.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomObjectModel\\:\\:fetchAllPublishedEntities\\(\\) should return array\\ but returns Doctrine\\\\ORM\\\\Tools\\\\Pagination\\\\Paginator&iterable\\\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomObjectModel.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomObjectModel\\:\\:fetchEntities\\(\\) should return Doctrine\\\\ORM\\\\Tools\\\\Pagination\\\\Paginator&iterable\\ but returns array\\|Doctrine\\\\ORM\\\\Tools\\\\Pagination\\\\Paginator\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomObjectModel.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomObjectModel\\:\\:getMasterCustomObjects\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomObjectModel.php + + - + message: "#^Method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) invoked with 2 parameters, 1 required\\.$#" + count: 4 + path: ../../plugins/CustomObjectsBundle/Model/CustomObjectModel.php + + - + message: "#^Parameter \\#1 \\$event of method Symfony\\\\Contracts\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:dispatch\\(\\) expects object, string given\\.$#" + count: 4 + path: ../../plugins/CustomObjectsBundle/Model/CustomObjectModel.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomObjectModel\\:\\:\\$listModel is never read, only written\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Model/CustomObjectModel.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Provider\\\\CustomItemRouteProvider\\:\\:buildListRoute\\(\\) has parameter \\$parameters with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Provider/CustomItemRouteProvider.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Provider\\\\SessionProvider\\:\\:setValue\\(\\) has parameter \\$value with no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Provider/SessionProvider.php + + - + message: "#^Unsafe access to private constant MauticPlugin\\\\CustomObjectsBundle\\\\Provider\\\\SessionProvider\\:\\:KEY_FILTER through static\\:\\:\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Provider/SessionProvider.php + + - + message: "#^Unsafe access to private constant MauticPlugin\\\\CustomObjectsBundle\\\\Provider\\\\SessionProvider\\:\\:KEY_LIMIT through static\\:\\:\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Provider/SessionProvider.php + + - + message: "#^Unsafe access to private constant MauticPlugin\\\\CustomObjectsBundle\\\\Provider\\\\SessionProvider\\:\\:KEY_ORDER_BY through static\\:\\:\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Provider/SessionProvider.php + + - + message: "#^Unsafe access to private constant MauticPlugin\\\\CustomObjectsBundle\\\\Provider\\\\SessionProvider\\:\\:KEY_ORDER_BY_DIR through static\\:\\:\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Provider/SessionProvider.php + + - + message: "#^Unsafe access to private constant MauticPlugin\\\\CustomObjectsBundle\\\\Provider\\\\SessionProvider\\:\\:KEY_PAGE through static\\:\\:\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Provider/SessionProvider.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Report\\\\ReportColumnsBuilder\\:\\:getColumns\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Report/ReportColumnsBuilder.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Report\\\\ReportColumnsBuilder\\:\\:getJoinableColumns\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Report/ReportColumnsBuilder.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Report\\\\ReportColumnsBuilder\\:\\:\\$columnTypeMapping type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Report/ReportColumnsBuilder.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Report\\\\ReportColumnsBuilder\\:\\:\\$columns type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Report/ReportColumnsBuilder.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Repository\\\\CustomItemRepository\\:\\:executeSelect\\(\\) return type has no value type specified in iterable type Doctrine\\\\DBAL\\\\Driver\\\\Statement\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Repository/CustomItemRepository.php + + - + message: "#^Call to method getId\\(\\) on an unknown class MauticPlugin\\\\CustomObjectsBundle\\\\Repository\\\\CustomField\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Repository/CustomObjectRepository.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Repository\\\\CustomObjectRepository\\:\\:getMasterObjectChoices\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Repository/CustomObjectRepository.php + + - + message: "#^PHPDoc tag @var for variable \\$customField contains unknown class MauticPlugin\\\\CustomObjectsBundle\\\\Repository\\\\CustomField\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Repository/CustomObjectRepository.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Security\\\\Permissions\\\\CustomObjectPermissions\\:\\:buildForm\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Security/Permissions/CustomObjectPermissions.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Security\\\\Permissions\\\\CustomObjectPermissions\\:\\:buildForm\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Security/Permissions/CustomObjectPermissions.php + + - + message: "#^Parameter \\#2 \\$level of method Mautic\\\\CoreBundle\\\\Security\\\\Permissions\\\\AbstractPermissions\\:\\:addExtendedFormFields\\(\\) expects string, int\\|null given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Security/Permissions/CustomObjectPermissions.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Segment/Query/Filter/CustomFieldFilterQueryBuilder.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Segment/Query/Filter/CustomItemNameFilterQueryBuilder.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Segment/Query/Filter/CustomObjectMergedFilterQueryBuilder.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Segment/Query/Filter/QueryFilterFactory.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Segment\\\\Query\\\\Filter\\\\QueryFilterFactory\\:\\:configureQueryBuilderFromSegmentFilter\\(\\) has parameter \\$segmentFilter with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Segment/Query/Filter/QueryFilterFactory.php + + - + message: "#^PHPDoc tag @throws with type MauticPlugin\\\\CustomObjectsBundle\\\\Exception\\\\InvalidSegmentFilterException\\|MauticPlugin\\\\CustomObjectsBundle\\\\Exception\\\\NotFoundException\\|MauticPlugin\\\\CustomObjectsBundle\\\\Segment\\\\Query\\\\Filter\\\\Exception is not subtype of Throwable$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Segment/Query/Filter/QueryFilterFactory.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Segment\\\\Query\\\\UnionQueryContainer\\:\\:getParameterTypes\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Segment/Query/UnionQueryContainer.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Segment\\\\Query\\\\UnionQueryContainer\\:\\:getParameters\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Segment/Query/UnionQueryContainer.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Segment\\\\Query\\\\UnionQueryContainer\\:\\:\\$parameterTypes type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Segment/Query/UnionQueryContainer.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Segment\\\\Query\\\\UnionQueryContainer\\:\\:\\$parameters type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Segment/Query/UnionQueryContainer.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\AbstractApiPlatformFunctionalTest\\:\\:createEntity\\(\\) has parameter \\$payload with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/AbstractApiPlatformFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\AbstractApiPlatformFunctionalTest\\:\\:requestEntity\\(\\) has parameter \\$payload with no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/AbstractApiPlatformFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\AbstractApiPlatformFunctionalTest\\:\\:setPermission\\(\\) has parameter \\$permissionArray with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/AbstractApiPlatformFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\AbstractApiPlatformFunctionalTest\\:\\:updateEntity\\(\\) has parameter \\$payload with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/AbstractApiPlatformFunctionalTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\AbstractApiPlatformFunctionalTest\\:\\:\\$clientServer type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/AbstractApiPlatformFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldFunctionalTest\\:\\:getCRUDProvider\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldFunctionalTest\\:\\:getCRUDWithOptionsProvider\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldFunctionalTest\\:\\:getCreatePayload\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldFunctionalTest\\:\\:getCreateWithOptionsPayload\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldFunctionalTest\\:\\:getEditPayload\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldFunctionalTest\\:\\:getEditWithOptionsPayload\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldFunctionalTest\\:\\:runTestCustomFieldCRUD\\(\\) has parameter \\$permissions with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldFunctionalTest\\:\\:runTestCustomFieldWithOptionsCRUD\\(\\) has parameter \\$permissions with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldFunctionalTest\\:\\:runTestCustomFieldWithOptionsCRUD\\(\\) has parameter \\$retrievedOptions with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldFunctionalTest\\:\\:runTestCustomFieldWithOptionsCRUD\\(\\) has parameter \\$updatedOptions with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldOptionFunctionalTest\\:\\:getCRUDProvider\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldOptionFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldOptionFunctionalTest\\:\\:getCreatePayload\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldOptionFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldOptionFunctionalTest\\:\\:getEditPayload\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldOptionFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomFieldOptionFunctionalTest\\:\\:runTestCustomFieldOptionCRUD\\(\\) has parameter \\$permissions with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomFieldOptionFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomObjectFunctionalTest\\:\\:getCRUDProvider\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomObjectFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomObjectFunctionalTest\\:\\:getCreatePayload\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomObjectFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomObjectFunctionalTest\\:\\:getEditPayload\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomObjectFunctionalTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\ApiPlatform\\\\CustomObjectFunctionalTest\\:\\:runTestCustomObjectCRUD\\(\\) has parameter \\$permissions with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/ApiPlatform/CustomObjectFunctionalTest.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/Controller/CustomItemListControllerShownFieldTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\Controller\\\\CustomObject\\\\DeleteControllerTest\\:\\:testDeleteChildObject\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/Controller/CustomObject/DeleteControllerTest.php + + - + message: "#^Call to an undefined method MauticPlugin\\\\CustomObjectsBundle\\\\Repository\\\\CustomObjectRepository\\:\\:findOneById\\(\\)\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/Controller/CustomObjectFormTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\Controller\\\\CustomObjectFormTest\\:\\:assertCustomObject\\(\\) has parameter \\$expected with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/Controller/CustomObjectFormTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\EventListener\\\\FilterOperatorSubscriberTest\\:\\:testIfNewOperatorNotInCustomObjectsAddedinSegmentFilter\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/EventListener/FilterOperatorSubscriberTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\EventListener\\\\FilterOperatorSubscriberTest\\:\\:testIfProperContactsAreAddedinSegmentWithNotInCustomObjectsFilter\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/EventListener/FilterOperatorSubscriberTest.php + + - + message: "#^Negated boolean expression is always false\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/EventListener/ImportSubscriberTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\Helper\\\\QueryFilterHelperTest\\:\\:assertMatchWhere\\(\\) has parameter \\$filter with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/Helper/QueryFilterHelperTest.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/Segment/Query/Filter/CustomFieldFilterQueryBuilderTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\Segment\\\\Query\\\\Filter\\\\CustomFieldFilterQueryBuilderTest\\:\\:executeSelect\\(\\) return type has no value type specified in iterable type Doctrine\\\\DBAL\\\\Driver\\\\Statement\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/Segment/Query/Filter/CustomFieldFilterQueryBuilderTest.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/Segment/Query/Filter/CustomItemNameFilterQueryBuilderTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\Segment\\\\Query\\\\Filter\\\\CustomItemNameFilterQueryBuilderTest\\:\\:executeSelect\\(\\) return type has no value type specified in iterable type Doctrine\\\\DBAL\\\\Driver\\\\Statement\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/Segment/Query/Filter/CustomItemNameFilterQueryBuilderTest.php + + - + message: "#^Call to an undefined method Mautic\\\\LeadBundle\\\\Entity\\\\LeadRepository\\:\\:findOneByEmail\\(\\)\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Functional/Segment/Query/Filter/CustomItemRelationQueryBuilderTestCase.php + + - + message: "#^Call to an undefined method Mautic\\\\CoreBundle\\\\Controller\\\\MauticController&Symfony\\\\Bundle\\\\FrameworkBundle\\\\Controller\\\\Controller\\:\\:setRequest\\(\\)\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/ControllerTestCase.php + + - + message: "#^Call to an undefined method Mautic\\\\CoreBundle\\\\Controller\\\\MauticController&Symfony\\\\Bundle\\\\FrameworkBundle\\\\Controller\\\\Controller\\:\\:setTranslator\\(\\)\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/ControllerTestCase.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\ControllerTestCase\\:\\:\\$request has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/ControllerTestCase.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\ControllerTestCase\\:\\:\\$requestStack has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/ControllerTestCase.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\ControllerTestCase\\:\\:\\$router \\(Symfony\\\\Component\\\\Routing\\\\Router\\) does not accept PHPUnit\\\\Framework\\\\MockObject\\\\MockObject&Symfony\\\\Component\\\\Routing\\\\RouterInterface\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/ControllerTestCase.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\ControllerTestCase\\:\\:\\$session has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/ControllerTestCase.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\AbstractFieldControllerTest\\:\\:createRequestMock\\(\\) has parameter \\$fieldId with no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\AbstractFieldControllerTest\\:\\:createRequestMock\\(\\) has parameter \\$fieldType with no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\AbstractFieldControllerTest\\:\\:createRequestMock\\(\\) has parameter \\$mapExtras with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\AbstractFieldControllerTest\\:\\:createRequestMock\\(\\) has parameter \\$objectId with no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\AbstractFieldControllerTest\\:\\:createRequestMock\\(\\) has parameter \\$panelCount with no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\AbstractFieldControllerTest\\:\\:createRequestMock\\(\\) has parameter \\$panelId with no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\FormControllerTest\\:\\:\\$customFieldFactory has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\FormControllerTest\\:\\:\\$customFieldModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\FormControllerTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\FormControllerTest\\:\\:\\$fieldRouteProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\FormControllerTest\\:\\:\\$form has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\FormControllerTest\\:\\:\\$formController has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\FormControllerTest\\:\\:\\$formFactory has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\FormControllerTest\\:\\:\\$objectRouteProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\FormControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\SaveControllerTest\\:\\:\\$customFieldFactory has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\SaveControllerTest\\:\\:\\$customFieldModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\SaveControllerTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\SaveControllerTest\\:\\:\\$fieldRouteProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\SaveControllerTest\\:\\:\\$form has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\SaveControllerTest\\:\\:\\$formFactory has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\SaveControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\SaveControllerTest\\:\\:\\$saveController has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\SaveControllerTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomField/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\BatchDeleteControllerTest\\:\\:\\$customItemModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/BatchDeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\BatchDeleteControllerTest\\:\\:\\$flashBag has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/BatchDeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\BatchDeleteControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/BatchDeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\BatchDeleteControllerTest\\:\\:\\$routeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/BatchDeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\BatchDeleteControllerTest\\:\\:\\$sessionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/BatchDeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\CancelControllerTest\\:\\:\\$customItemModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/CancelControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\CancelControllerTest\\:\\:\\$routeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/CancelControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\CancelControllerTest\\:\\:\\$sessionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/CancelControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\DeleteControllerTest\\:\\:\\$customItemModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/DeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\DeleteControllerTest\\:\\:\\$flashBag has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/DeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\DeleteControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/DeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\DeleteControllerTest\\:\\:\\$routeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/DeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\DeleteControllerTest\\:\\:\\$sessionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/DeleteControllerTest.php + + - + message: "#^Call to an undefined method Mautic\\\\CoreBundle\\\\Helper\\\\UserHelper\\:\\:expects\\(\\)\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/FormControllerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\FormControllerTest\\:\\:testEditActionWhenTheItemIsLocked\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/FormControllerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\FormControllerTest\\:\\:testEditWithRedirectToContactActionWhenTheItemIsLocked\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\FormControllerTest\\:\\:\\$form type has no value type specified in iterable type Symfony\\\\Component\\\\Form\\\\FormInterface\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\LinkControllerTest\\:\\:\\$customItemModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/LinkControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\LinkControllerTest\\:\\:\\$flashBag has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/LinkControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\LinkControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/LinkControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ListControllerTest\\:\\:\\$customItemModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ListControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ListControllerTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ListControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ListControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ListControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ListControllerTest\\:\\:\\$routeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ListControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ListControllerTest\\:\\:\\$sessionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ListControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\LookupControllerTest\\:\\:\\$customItemModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/LookupControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\LookupControllerTest\\:\\:\\$flashBag has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/LookupControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\LookupControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/LookupControllerTest.php + + - + message: "#^Call to an undefined method Mautic\\\\CoreBundle\\\\Helper\\\\UserHelper\\:\\:expects\\(\\)\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/SaveControllerTest.php + + - + message: "#^Call to an undefined method Symfony\\\\Component\\\\Routing\\\\Router\\:\\:expects\\(\\)\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\SaveControllerTest\\:\\:\\$form type has no value type specified in iterable type Symfony\\\\Component\\\\Form\\\\FormInterface\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ViewControllerTest\\:\\:\\$auditLog has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ViewControllerTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ViewControllerTest\\:\\:\\$customItemModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ViewControllerTest\\:\\:\\$customItemXrefContactModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ViewControllerTest\\:\\:\\$form has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ViewControllerTest\\:\\:\\$formFactory has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ViewControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ViewControllerTest\\:\\:\\$routeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomItem/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\CancelControllerTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/CancelControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\CancelControllerTest\\:\\:\\$routeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/CancelControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\CancelControllerTest\\:\\:\\$sessionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/CancelControllerTest.php + + - + message: "#^Call to an undefined method Symfony\\\\Component\\\\EventDispatcher\\\\EventDispatcherInterface\\:\\:expects\\(\\)\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/DeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\DeleteControllerTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/DeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\DeleteControllerTest\\:\\:\\$flashBag has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/DeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\DeleteControllerTest\\:\\:\\$leadListIndex is never read, only written\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/DeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\DeleteControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/DeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\DeleteControllerTest\\:\\:\\$sessionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/DeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\FormControllerTest\\:\\:\\$customFieldModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\FormControllerTest\\:\\:\\$customFieldTypeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\FormControllerTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\FormControllerTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\FormControllerTest\\:\\:\\$form has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\FormControllerTest\\:\\:\\$formFactory has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\FormControllerTest\\:\\:\\$lockFlashMessageHelper has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\FormControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\FormControllerTest\\:\\:\\$routeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ListControllerTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/ListControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ListControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/ListControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ListControllerTest\\:\\:\\$routeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/ListControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ListControllerTest\\:\\:\\$sessionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/ListControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$customFieldModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$customFieldTypeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$flashBag has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$form has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$formFactory has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$lockFlashMessageHelper has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$optionsToStringTransformer has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$paramsToStringTransformer has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\SaveControllerTest\\:\\:\\$routeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ViewControllerTest\\:\\:\\$auditLog has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ViewControllerTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ViewControllerTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ViewControllerTest\\:\\:\\$form has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ViewControllerTest\\:\\:\\$formFactory has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ViewControllerTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/ViewControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ViewControllerTest\\:\\:\\$routeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Controller/CustomObject/ViewControllerTest.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractCustomFieldTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractCustomFieldTypeTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractCustomFieldTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractCustomFieldTypeTest\\:\\:\\$fieldType \\(MauticPlugin\\\\CustomObjectsBundle\\\\CustomFieldType\\\\EmailType\\) does not accept MauticPlugin\\\\CustomObjectsBundle\\\\CustomFieldType\\\\AbstractCustomFieldType&PHPUnit\\\\Framework\\\\MockObject\\\\MockObject\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractCustomFieldTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractCustomFieldTypeTest\\:\\:\\$filterOperatorProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractCustomFieldTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractCustomFieldTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractCustomFieldTypeTest.php + + - + message: "#^Parameter \\#3 \\$value of method MauticPlugin\\\\CustomObjectsBundle\\\\CustomFieldType\\\\AbstractMultivalueType\\:\\:createValueEntity\\(\\) expects null, array\\ given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractMultivalueTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractMultivalueTypeTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractMultivalueTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractMultivalueTypeTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractMultivalueTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractMultivalueTypeTest\\:\\:\\$provider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractMultivalueTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractMultivalueTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractMultivalueTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractTextTypeTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractTextTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractTextTypeTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractTextTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractTextTypeTest\\:\\:\\$filterOperatorProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractTextTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\AbstractTextTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/AbstractTextTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\CountryTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/CountryTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\DateTimeTypeTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/DateTimeTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\DateTimeTypeTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/DateTimeTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\DateTimeTypeTest\\:\\:\\$filterOperatorProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/DateTimeTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\DateTimeTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/DateTimeTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\DateTypeTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/DateTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\DateTypeTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/DateTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\DateTypeTest\\:\\:\\$filterOperatorProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/DateTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\DateTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/DateTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\EmailTypeTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/EmailTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\EmailTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/EmailTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\IntTypeTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/IntTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\IntTypeTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/IntTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\IntTypeTest\\:\\:\\$filterOperatorProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/IntTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\IntTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/IntTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\MultiselectTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/MultiselectTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\PhoneTypeTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/PhoneTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\PhoneTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/PhoneTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\SelectTypeTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/SelectTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\SelectTypeTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/SelectTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\SelectTypeTest\\:\\:\\$filterOperatorProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/SelectTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\SelectTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/SelectTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\UrlTypeTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/UrlTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\CustomFieldType\\\\UrlTypeTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/CustomFieldType/UrlTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\AbstractCustomFieldValueTest\\:\\:\\$abstractCFValue has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/AbstractCustomFieldValueTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\AbstractCustomFieldValueTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/AbstractCustomFieldValueTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\AbstractCustomFieldValueTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/AbstractCustomFieldValueTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\AbstractCustomFieldValueTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/AbstractCustomFieldValueTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\CustomField\\\\ParamsTest\\:\\:testConstructorAndToArray\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomField/ParamsTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\CustomField\\\\ParamsTest\\:\\:testGettersSetters\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomField/ParamsTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\CustomField\\\\ParamsTest\\:\\:testToArrayRemovingFalseAndNullValues\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomField/ParamsTest.php + + - + message: "#^Parameter \\#1 \\$array \\(array\\{placeholder\\: null\\}\\) to function array_filter contains falsy values only, the result will always be an empty array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomField/ParamsTest.php + + - + message: "#^Unable to resolve the template type RealInstanceType in call to method PHPUnit\\\\Framework\\\\TestCase\\:\\:createMock\\(\\)$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomFieldFactoryTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\CustomFieldOptionTest\\:\\:testArrayAccessor\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomFieldOptionTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\CustomFieldOptionTest\\:\\:testConstructorAndToArray\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomFieldOptionTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\CustomFieldOptionTest\\:\\:testGettersSetters\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomFieldOptionTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\CustomFieldTest\\:\\:testCanHaveMultipleValuesForCheckboxType\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomFieldTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\CustomFieldTest\\:\\:testCanHaveMultipleValuesForDateType\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomFieldTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\CustomFieldTest\\:\\:testDefaultValueTransformation\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomFieldTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Entity\\\\CustomObjectTest\\:\\:testGetCfByOrder\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Entity/CustomObjectTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ApiSubscriberTest\\:\\:\\$apiEntityEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ApiSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ApiSubscriberTest\\:\\:\\$configProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ApiSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ApiSubscriberTest\\:\\:\\$customItemModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ApiSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ApiSubscriberTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ApiSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ApiSubscriberTest\\:\\:\\$request has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ApiSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AssetsSubscriberTest\\:\\:\\$assetsHelper has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AssetsSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AssetsSubscriberTest\\:\\:\\$assetsSubscriber has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AssetsSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AssetsSubscriberTest\\:\\:\\$configProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AssetsSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AssetsSubscriberTest\\:\\:\\$getResponseEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AssetsSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AssetsSubscriberTest\\:\\:\\$request has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AssetsSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AuditLogSubscriberTest\\:\\:\\$auditLogModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AuditLogSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AuditLogSubscriberTest\\:\\:\\$auditLogSubscriber has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AuditLogSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AuditLogSubscriberTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AuditLogSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AuditLogSubscriberTest\\:\\:\\$customItemEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AuditLogSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AuditLogSubscriberTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AuditLogSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AuditLogSubscriberTest\\:\\:\\$customObjectEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AuditLogSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AuditLogSubscriberTest\\:\\:\\$ipLookupHelper has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/AuditLogSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$campaignBuilderEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$campaignExecutionEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$configProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$connection has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$contact has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$customFieldModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$customItemModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$queryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$queryFilterFactory has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$queryFilterHelper has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$segmentQueryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$statement has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ContactSubscriberTest\\:\\:\\$configProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ContactSubscriberTest\\:\\:\\$customItemModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ContactSubscriberTest\\:\\:\\$entityManager has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ContactSubscriberTest\\:\\:\\$leadEventLogRepo has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ContactSubscriberTest\\:\\:\\$leadTimelineEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ContactSubscriberTest\\:\\:\\$routeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ContactSubscriberTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ContactSubscriberTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ContactTabSubscriberTest\\:\\:testSubscriberEvents\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ContactTabSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomFieldPostLoadSubscriberTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomFieldPostLoadSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomFieldPostLoadSubscriberTest\\:\\:\\$customFieldTypeProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomFieldPostLoadSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomFieldPostLoadSubscriberTest\\:\\:\\$event has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomFieldPostLoadSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomFieldPostLoadSubscriberTest\\:\\:\\$subscriber has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomFieldPostLoadSubscriberTest.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$contact has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$discoveryEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$entityManager has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$event has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$listDbalEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$listEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$query has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$queryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$queryBuilderDbal has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$xref has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefCustomItemSubscriberTest\\:\\:\\$customItemA has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefCustomItemSubscriberTest\\:\\:\\$customItemB has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefCustomItemSubscriberTest\\:\\:\\$discoveryEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefCustomItemSubscriberTest\\:\\:\\$entityManager has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefCustomItemSubscriberTest\\:\\:\\$event has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefCustomItemSubscriberTest\\:\\:\\$expr has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefCustomItemSubscriberTest\\:\\:\\$listEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefCustomItemSubscriberTest\\:\\:\\$query has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefCustomItemSubscriberTest\\:\\:\\$queryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefCustomItemSubscriberTest\\:\\:\\$xref has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomObjectButtonSubscriberTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomObjectButtonSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomObjectButtonSubscriberTest\\:\\:\\$event has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomObjectButtonSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomObjectButtonSubscriberTest\\:\\:\\$itemPermissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomObjectButtonSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomObjectButtonSubscriberTest\\:\\:\\$itemRouteProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomObjectButtonSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomObjectButtonSubscriberTest\\:\\:\\$objectPermissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomObjectButtonSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomObjectButtonSubscriberTest\\:\\:\\$objectRouteProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomObjectButtonSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomObjectButtonSubscriberTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/CustomObjectButtonSubscriberTest.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/FilterOperatorSubscriberTest.php + + - + message: "#^PHPDoc tag @var for variable \\$formMock has no value type specified in iterable type Symfony\\\\Component\\\\Form\\\\FormInterface\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/FilterOperatorSubscriberTest.php + + - + message: "#^Parameter \\#1 \\$form of class Mautic\\\\LeadBundle\\\\Event\\\\FormAdjustmentEvent constructor expects iterable\\&Symfony\\\\Component\\\\Form\\\\FormInterface, PHPUnit\\\\Framework\\\\MockObject\\\\MockObject\\|Symfony\\\\Component\\\\Form\\\\FormInterface given\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/FilterOperatorSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$configProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$customFieldRepository has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$customItemImportModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$form has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$import has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$importInitEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$importMappingEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$importProcessEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$importValidateEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$permissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ImportSubscriberTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ImportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\MenuSubscriberTest\\:\\:\\$configProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/MenuSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\MenuSubscriberTest\\:\\:\\$customObjectModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/MenuSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\MenuSubscriberTest\\:\\:\\$menuEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/MenuSubscriberTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ReportSubscriberTest\\:\\:getCustomObjectsCollection\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ReportSubscriberTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ReportSubscriberTest\\:\\:testThatIdDoesntProcessContextsWithEmptyOrNotIntCustomObjectsID\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ReportSubscriberTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ReportSubscriberTest\\:\\:testThatIdDoesntProcessNotExistingCustomObjects\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ReportSubscriberTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\ReportSubscriberTest\\:\\:testThatOnReportGenerateMethodDoesntProcessWrongContexts\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/ReportSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\SerializerSubscriberTest\\:\\:\\$configProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/SerializerSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\SerializerSubscriberTest\\:\\:\\$customItemModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/SerializerSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\SerializerSubscriberTest\\:\\:\\$customItemXrefContactRepository has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/SerializerSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\SerializerSubscriberTest\\:\\:\\$objectEvent has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/SerializerSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\SerializerSubscriberTest\\:\\:\\$request has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/SerializerSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\SerializerSubscriberTest\\:\\:\\$requestStack has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/EventListener/SerializerSubscriberTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Exception\\\\InvalidCustomObjectFormatListExceptionTest\\:\\:testAll\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Exception/InvalidCustomObjectFormatListExceptionTest.php + + - + message: "#^Parameter \\#1 \\$value of method MauticPlugin\\\\CustomObjectsBundle\\\\Form\\\\DataTransformer\\\\OptionsTransformer\\:\\:reverseTransform\\(\\) expects array\\, array\\\\>\\> given\\.$#" + count: 4 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/DataTransformer/OptionsTransformerTest.php + + - + message: "#^Parameter \\#1 \\$value of method MauticPlugin\\\\CustomObjectsBundle\\\\Form\\\\DataTransformer\\\\OptionsTransformer\\:\\:transform\\(\\) expects Doctrine\\\\ORM\\\\PersistentCollection&iterable\\, Doctrine\\\\Common\\\\Collections\\\\ArrayCollection\\<\\*NEVER\\*, \\*NEVER\\*\\> given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/DataTransformer/OptionsTransformerTest.php + + - + message: "#^Parameter \\#1 \\$value of method MauticPlugin\\\\CustomObjectsBundle\\\\Form\\\\DataTransformer\\\\OptionsTransformer\\:\\:transform\\(\\) expects Doctrine\\\\ORM\\\\PersistentCollection&iterable\\, Doctrine\\\\Common\\\\Collections\\\\ArrayCollection\\ given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/DataTransformer/OptionsTransformerTest.php + + - + message: "#^Parameter \\#1 \\$value of method MauticPlugin\\\\CustomObjectsBundle\\\\Form\\\\DataTransformer\\\\OptionsTransformer\\:\\:transform\\(\\) expects Doctrine\\\\ORM\\\\PersistentCollection&iterable\\, null given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/DataTransformer/OptionsTransformerTest.php + + - + message: "#^Parameter \\#1 \\$params of method MauticPlugin\\\\CustomObjectsBundle\\\\Form\\\\DataTransformer\\\\ParamsToStringTransformer\\:\\:transform\\(\\) expects MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomField\\\\Params\\|null, array given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/DataTransformer/ParamsToStringTransformerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Type\\\\CampaignConditionFieldValueTypeTest\\:\\:testConfigureOptions\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Type/CampaignConditionFieldValueTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Type\\\\CustomFieldValueTypeTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Type/CustomFieldValueTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Type\\\\CustomFieldValueTypeTest\\:\\:\\$customFieldType has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Type/CustomFieldValueTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Type\\\\CustomFieldValueTypeTest\\:\\:\\$customFieldValue has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Type/CustomFieldValueTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Type\\\\CustomFieldValueTypeTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Type/CustomFieldValueTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Type\\\\CustomFieldValueTypeTest\\:\\:\\$formBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Type/CustomFieldValueTypeTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Type\\\\CustomFieldValueTypeTest\\:\\:\\$optionsResolver has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Type/CustomFieldValueTypeTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Type\\\\CustomObjectTypeTest\\:\\:buildForm\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Type/CustomObjectTypeTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Type\\\\CustomObjectTypeTest\\:\\:testBuildFormExistingObject\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Type/CustomObjectTypeTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Type\\\\CustomObjectTypeTest\\:\\:testBuildFormNewObject\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Type/CustomObjectTypeTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Type\\\\CustomObjectTypeTest\\:\\:testConfigureOptions\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Type/CustomObjectTypeTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Validator\\\\CustomObjectTypeValuesTest\\:\\:testGetTargets\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Validator/CustomObjectTypeValuesTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Validator\\\\CustomObjectTypeValuesTest\\:\\:testValidatedBy\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Validator/CustomObjectTypeValuesTest.php + + - + message: "#^Access to an undefined property PHPUnit\\\\Framework\\\\MockObject\\\\MockObject\\|Symfony\\\\Component\\\\Validator\\\\Constraint\\:\\:\\$missingMasterObject\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Validator/CustomObjectTypeValuesValidatorTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Validator\\\\CustomObjectTypeValuesValidatorTest\\:\\:testValidateIgnoreCompletely\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Validator/CustomObjectTypeValuesValidatorTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Validator\\\\CustomObjectTypeValuesValidatorTest\\:\\:testValidateIgnoreMasterObject\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Validator/CustomObjectTypeValuesValidatorTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Form\\\\Validator\\\\CustomObjectTypeValuesValidatorTest\\:\\:testValidateNoCustomObject\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Form/Validator/CustomObjectTypeValuesValidatorTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\CustomFieldQueryBuilder\\\\CalculatorTest\\:\\:assertMatrixEquals\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/CustomFieldQueryBuilder/CalculatorTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\CustomFieldQueryBuilder\\\\CalculatorTest\\:\\:assertMatrixEquals\\(\\) has parameter \\$expectedMatrix with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/CustomFieldQueryBuilder/CalculatorTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\CustomFieldQueryBuilder\\\\CalculatorTest\\:\\:getSuffix\\(\\) has parameter \\$decisionValue with no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/CustomFieldQueryBuilder/CalculatorTest.php + + - + message: "#^Parameter \\#4 \\$value of method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\QueryFilterHelper\\:\\:addCustomObjectNameExpression\\(\\) expects string\\|null, int given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/QueryFilterHelperTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\TokenFormatterTest\\:\\:testAvailableFormats\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/TokenFormatterTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\TokenFormatterTest\\:\\:testFormatManyValues\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/TokenFormatterTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\TokenFormatterTest\\:\\:testFormatOneValue\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/TokenFormatterTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\TokenFormatterTest\\:\\:testIsValidFormat\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/TokenFormatterTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\TokenFormatterTest\\:\\:\\$availableFormats has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/TokenFormatterTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\TokenFormatterTest\\:\\:\\$manyValues has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/TokenFormatterTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\TokenFormatterTest\\:\\:\\$noValues has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/TokenFormatterTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\TokenFormatterTest\\:\\:\\$oneValue has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Helper/TokenFormatterTest.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldOptionModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldOptionModelTest\\:\\:\\$connection has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldOptionModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldOptionModelTest\\:\\:\\$entityManager has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldOptionModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldOptionModelTest\\:\\:\\$queryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldOptionModelTest.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 2 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$connection has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$customFieldValueModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$entityManager has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$filterOperatorProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$queryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$statement has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$validator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomFieldValueModelTest\\:\\:\\$violationList has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$connection has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$customFieldValueModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$customItemPermissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$customItemRepository has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$dbalQueryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$dispatcher has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$entityManager has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$query has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$queryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$statement has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$user has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$userHelper has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$validator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$violationList has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemXrefContactModelTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemXrefContactModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemXrefContactModelTest\\:\\:\\$entityManager has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemXrefContactModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemXrefContactModelTest\\:\\:\\$query has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemXrefContactModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemXrefContactModelTest\\:\\:\\$queryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemXrefContactModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemXrefContactModelTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomItemXrefContactModelTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:testGetMasterCustomObjects\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$connection has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$customField has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$customFieldModel has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$customObjectPermissionProvider has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$customObjectRepository has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$databasePlatform has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$dispatcher has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$entityManager has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$query has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$queryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$queryBuilderDbal has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$statement has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$translator has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$user has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$userHelper has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Provider\\\\CustomFieldRouteProviderTest\\:\\:\\$router has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Provider/CustomFieldRouteProviderTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Provider\\\\CustomItemPermissionProviderTest\\:\\:\\$corePermissions has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Provider/CustomItemPermissionProviderTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Provider\\\\CustomItemPermissionProviderTest\\:\\:\\$customItem has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Provider/CustomItemPermissionProviderTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Provider\\\\CustomItemPermissionProviderTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Provider/CustomItemPermissionProviderTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Provider\\\\CustomItemRouteProviderTest\\:\\:testThatBuildContactViewRouteReturnsCorrectUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Provider/CustomItemRouteProviderTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Provider\\\\CustomItemRouteProviderTest\\:\\:testThatBuildEditRouteWithRedirectToContactReturnsCorrectUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Provider/CustomItemRouteProviderTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Provider\\\\CustomItemRouteProviderTest\\:\\:testThatBuildNewRouteWithRedirectToContactReturnsCorrectUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Provider/CustomItemRouteProviderTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Provider\\\\CustomItemRouteProviderTest\\:\\:\\$router has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Provider/CustomItemRouteProviderTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Provider\\\\CustomObjectPermissionProviderTest\\:\\:\\$entity has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Provider/CustomObjectPermissionProviderTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Provider\\\\CustomObjectPermissionProviderTest\\:\\:\\$permissions has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Provider/CustomObjectPermissionProviderTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Provider\\\\CustomObjectRouteProviderTest\\:\\:\\$router has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Provider/CustomObjectRouteProviderTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomFieldRepositoryTest\\:\\:\\$classMetadata has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomFieldRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomFieldRepositoryTest\\:\\:\\$entityManager has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomFieldRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomFieldRepositoryTest\\:\\:\\$expression has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomFieldRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomFieldRepositoryTest\\:\\:\\$query has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomFieldRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomFieldRepositoryTest\\:\\:\\$queryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomFieldRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemRepositoryTest\\:\\:\\$contact has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemRepositoryTest\\:\\:\\$customObject has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemRepositoryTest\\:\\:\\$entityManager has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemRepositoryTest\\:\\:\\$expr has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemRepositoryTest\\:\\:\\$query has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemRepositoryTest\\:\\:\\$queryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemXrefContactRepositoryTest\\:\\:\\$classMetadata has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemXrefContactRepositoryTest\\:\\:\\$connection has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemXrefContactRepositoryTest\\:\\:\\$contact has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemXrefContactRepositoryTest\\:\\:\\$entityManager has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemXrefContactRepositoryTest\\:\\:\\$expr has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemXrefContactRepositoryTest\\:\\:\\$expressionBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemXrefContactRepositoryTest\\:\\:\\$query has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemXrefContactRepositoryTest\\:\\:\\$queryBuilder has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemXrefContactRepositoryTest\\:\\:\\$queryBuilderDbal has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Repository\\\\CustomItemXrefContactRepositoryTest\\:\\:\\$statement has no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Segment\\\\Query\\\\Filter\\\\CustomItemNameFilterQueryBuilderTest\\:\\:parameterValueProvider\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Segment/Query/Filter/CustomItemNameFilterQueryBuilderTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Segment\\\\Query\\\\Filter\\\\CustomItemNameFilterQueryBuilderTest\\:\\:testApplyQuery\\(\\) has parameter \\$parameterValue with no type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Segment/Query/Filter/CustomItemNameFilterQueryBuilderTest.php + + - + message: "#^PHPDoc tag @param has invalid value \\(\\$parameterValue\\)\\: Unexpected token \"\\$parameterValue\", expected type at offset 69$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Segment/Query/Filter/CustomItemNameFilterQueryBuilderTest.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 3 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Segment/Query/Filter/QueryFilterFactoryTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Segment\\\\Query\\\\UnionQueryContainerTest\\:\\:testParameterTypesCheck\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Segment/Query/UnionQueryContainerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Segment\\\\Query\\\\UnionQueryContainerTest\\:\\:testParametersCheck\\(\\) has no return type specified\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Segment/Query/UnionQueryContainerTest.php + + - + message: "#^Parameter \\#3 \\$type of method Mautic\\\\LeadBundle\\\\Segment\\\\Query\\\\QueryBuilder\\:\\:setParameter\\(\\) expects string\\|null, int given\\.$#" + count: 1 + path: ../../plugins/CustomObjectsBundle/Tests/Unit/Segment/Query/UnionQueryContainerTest.php + diff --git a/phpstan-baseline-php-versions.neon.php b/phpstan-baseline-php-versions.neon.php new file mode 100644 index 000000000..067bc2d19 --- /dev/null +++ b/phpstan-baseline-php-versions.neon.php @@ -0,0 +1,17 @@ += 70400 && PHP_VERSION_ID < 80000) { + $includes[] = __DIR__.'/phpstan-baseline-7.4.neon'; +} elseif (PHP_VERSION_ID >= 80000) { + $includes[] = __DIR__.'/phpstan-baseline-8.0.neon'; +} + +$config = []; +$config['includes'] = $includes; +$config['parameters']['phpVersion'] = PHP_VERSION_ID; + +return $config; diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 000000000..59bfd9961 --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,701 @@ +parameters: + ignoreErrors: + - + message: "#^Call to an undefined method Symfony\\\\Component\\\\Console\\\\Helper\\\\HelperInterface\\:\\:ask\\(\\)\\.$#" + count: 1 + path: Command/GenerateSampleDataCommand.php + + - + message: "#^Trait MauticPlugin\\\\CustomObjectsBundle\\\\CustomFieldType\\\\DateOperatorTrait is used zero times and is not analysed\\.$#" + count: 1 + path: CustomFieldType/DateOperatorTrait.php + + - + message: """ + #^Parameter \\$factory of method MauticPlugin\\\\CustomObjectsBundle\\\\CustomObjectsBundle\\:\\:installAllTablesIfMissing\\(\\) has typehint with deprecated class Mautic\\\\CoreBundle\\\\Factory\\\\MauticFactory\\: + 2\\.0 to be removed in 3\\.0$# + """ + count: 1 + path: CustomObjectsBundle.php + + - + message: """ + #^Call to deprecated method execute\\(\\) of class Doctrine\\\\DBAL\\\\Query\\\\QueryBuilder\\: + Use \\{@see executeQuery\\(\\)\\} or \\{@see executeStatement\\(\\)\\} instead\\.$# + """ + count: 1 + path: EventListener/CampaignSubscriber.php + + - + message: "#^Instanceof between int\\|string and Doctrine\\\\DBAL\\\\Driver\\\\Statement will always evaluate to false\\.$#" + count: 1 + path: EventListener/CampaignSubscriber.php + + - + message: """ + #^Parameter \\$event of method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\CampaignSubscriber\\:\\:onCampaignTriggerAction\\(\\) has typehint with deprecated class Mautic\\\\CampaignBundle\\\\Event\\\\CampaignExecutionEvent\\: + 2\\.13\\.0; to be removed in 3\\.0$# + """ + count: 1 + path: EventListener/CampaignSubscriber.php + + - + message: """ + #^Parameter \\$event of method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\CampaignSubscriber\\:\\:onCampaignTriggerCondition\\(\\) has typehint with deprecated class Mautic\\\\CampaignBundle\\\\Event\\\\CampaignExecutionEvent\\: + 2\\.13\\.0; to be removed in 3\\.0$# + """ + count: 1 + path: EventListener/CampaignSubscriber.php + + - + message: """ + #^Call to deprecated method execute\\(\\) of class Doctrine\\\\DBAL\\\\Query\\\\QueryBuilder\\: + Use \\{@see executeQuery\\(\\)\\} or \\{@see executeStatement\\(\\)\\} instead\\.$# + """ + count: 1 + path: EventListener/DynamicContentSubscriber.php + + - + message: "#^Instanceof between int\\|string and Doctrine\\\\DBAL\\\\Driver\\\\Statement will always evaluate to false\\.$#" + count: 1 + path: EventListener/DynamicContentSubscriber.php + + - + message: "#^Expression on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: EventListener/ImportSubscriber.php + + - + message: "#^Instanceof between Doctrine\\\\Common\\\\Collections\\\\ArrayCollection and Doctrine\\\\Common\\\\Collections\\\\ArrayCollection will always evaluate to true\\.$#" + count: 1 + path: EventListener/ReportSubscriber.php + + - + message: "#^Instanceof between MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject and MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomObject will always evaluate to true\\.$#" + count: 1 + path: EventListener/ReportSubscriber.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\ReportSubscriber\\:\\:sortCustomObjects\\(\\) is unused\\.$#" + count: 1 + path: EventListener/ReportSubscriber.php + + - + message: """ + #^Call to deprecated method execute\\(\\) of class Doctrine\\\\DBAL\\\\Query\\\\QueryBuilder\\: + Use \\{@see executeQuery\\(\\)\\} or \\{@see executeStatement\\(\\)\\} instead\\.$# + """ + count: 1 + path: EventListener/SegmentFiltersDictionarySubscriber.php + + - + message: "#^Instanceof between int\\|string and Doctrine\\\\DBAL\\\\Driver\\\\Statement will always evaluate to false\\.$#" + count: 1 + path: EventListener/SegmentFiltersDictionarySubscriber.php + + - + message: "#^Instanceof between Mautic\\\\LeadBundle\\\\Entity\\\\Lead and Mautic\\\\LeadBundle\\\\Entity\\\\Lead will always evaluate to true\\.$#" + count: 1 + path: EventListener/SerializerSubscriber.php + + - + message: "#^Instanceof between MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomField\\\\Params and MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomField\\\\Params will always evaluate to true\\.$#" + count: 1 + path: Form/DataTransformer/ParamsToStringTransformer.php + + - + message: """ + #^Call to deprecated method add\\(\\) of class Doctrine\\\\DBAL\\\\Query\\\\Expression\\\\CompositeExpression\\: + This class will be made immutable\\. Use with\\(\\) instead\\.$# + """ + count: 2 + path: Helper/QueryFilterHelper.php + + - + message: """ + #^Call to deprecated method execute\\(\\) of class Doctrine\\\\DBAL\\\\Query\\\\QueryBuilder\\: + Use \\{@see executeQuery\\(\\)\\} or \\{@see executeStatement\\(\\)\\} instead\\.$# + """ + count: 1 + path: Helper/QueryFilterHelper.php + + - + message: """ + #^Call to deprecated method orX\\(\\) of class Doctrine\\\\DBAL\\\\Query\\\\Expression\\\\ExpressionBuilder\\: + Use `or\\(\\)` instead\\.$# + """ + count: 2 + path: Helper/QueryFilterHelper.php + + - + message: "#^Instanceof between int\\|string and Doctrine\\\\DBAL\\\\Driver\\\\Statement will always evaluate to false\\.$#" + count: 1 + path: Helper/QueryFilterHelper.php + + - + message: """ + #^Call to deprecated method hasPrimaryKey\\(\\) of class Doctrine\\\\DBAL\\\\Schema\\\\Table\\: + Use \\{@see getPrimaryKey\\(\\)\\} instead\\.$# + """ + count: 1 + path: Migrations/Version_0_0_12.php + + - + message: """ + #^Call to deprecated method execute\\(\\) of class Doctrine\\\\DBAL\\\\Query\\\\QueryBuilder\\: + Use \\{@see executeQuery\\(\\)\\} or \\{@see executeStatement\\(\\)\\} instead\\.$# + """ + count: 1 + path: Model/CustomFieldOptionModel.php + + - + message: """ + #^Call to deprecated method merge\\(\\) of class Doctrine\\\\ORM\\\\EntityManager\\: + 2\\.7 This method is being removed from the ORM and won't have any replacement$# + """ + count: 1 + path: Model/CustomFieldValueModel.php + + - + message: """ + #^Fetching deprecated class constant PARAM_INT_ARRAY of class Doctrine\\\\DBAL\\\\Connection\\: + Use \\{@see ArrayParameterType\\:\\:INTEGER\\} instead\\.$# + """ + count: 2 + path: Model/CustomFieldValueModel.php + + - + message: "#^Parameter \\#2 \\$contactIds of method MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomItemImportModel\\:\\:linkContacts\\(\\) expects array\\, array\\ given\\.$#" + count: 1 + path: Model/CustomItemImportModel.php + + - + message: """ + #^Call to deprecated method execute\\(\\) of class Doctrine\\\\DBAL\\\\Query\\\\QueryBuilder\\: + Use \\{@see executeQuery\\(\\)\\} or \\{@see executeStatement\\(\\)\\} instead\\.$# + """ + count: 1 + path: Model/CustomItemModel.php + + - + message: """ + #^Call to deprecated method getConnection\\(\\) of class Doctrine\\\\DBAL\\\\Query\\\\QueryBuilder\\: + Use the connection used to instantiate the builder instead\\.$# + """ + count: 1 + path: Report/ReportColumnsBuilder.php + + - + message: "#^Call to function is_callable\\(\\) with callable\\(\\)\\: mixed will always evaluate to true\\.$#" + count: 1 + path: Report/ReportColumnsBuilder.php + + - + message: """ + #^Call to deprecated method execute\\(\\) of class Doctrine\\\\DBAL\\\\Query\\\\QueryBuilder\\: + Use \\{@see executeQuery\\(\\)\\} or \\{@see executeStatement\\(\\)\\} instead\\.$# + """ + count: 1 + path: Repository/CustomItemRepository.php + + - + message: "#^Instanceof between int\\|string and Doctrine\\\\DBAL\\\\Driver\\\\Statement will always evaluate to false\\.$#" + count: 1 + path: Repository/CustomItemRepository.php + + - + message: "#^PHPDoc tag @throws with type Doctrine\\\\DBAL\\\\DBALException is not subtype of Throwable$#" + count: 1 + path: Segment/Query/Filter/CustomFieldFilterQueryBuilder.php + + - + message: "#^PHPDoc tag @throws with type Doctrine\\\\DBAL\\\\DBALException is not subtype of Throwable$#" + count: 1 + path: Segment/Query/Filter/CustomItemNameFilterQueryBuilder.php + + - + message: "#^PHPDoc tag @throws with type Doctrine\\\\DBAL\\\\DBALException is not subtype of Throwable$#" + count: 1 + path: Segment/Query/UnionQueryContainer.php + + - + message: "#^You should use assertCount\\(\\$expectedCount, \\$variable\\) instead of assertSame\\(\\$expectedCount, \\$variable\\-\\>count\\(\\)\\)\\.$#" + count: 2 + path: Tests/Functional/Controller/CustomItemListControllerSearchTest.php + + - + message: "#^You should use assertCount\\(\\$expectedCount, \\$variable\\) instead of assertSame\\(\\$expectedCount, \\$variable\\-\\>count\\(\\)\\)\\.$#" + count: 3 + path: Tests/Functional/Controller/CustomItemListControllerShownFieldTest.php + + - + message: "#^You should use assertCount\\(\\$expectedCount, \\$variable\\) instead of assertSame\\(\\$expectedCount, \\$variable\\-\\>count\\(\\)\\)\\.$#" + count: 2 + path: Tests/Functional/Controller/CustomItemListControllerXrefTest.php + + - + message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertIsArray\\(\\) with array will always evaluate to true\\.$#" + count: 1 + path: Tests/Functional/Controller/CustomItemLookupControllerTest.php + + - + message: "#^You should use assertNull\\(\\) instead of assertSame\\(null, \\$actual\\)\\.$#" + count: 3 + path: Tests/Functional/EventListener/ApiSubscriberTest.php + + - + message: """ + #^Instantiation of deprecated class Mautic\\\\CampaignBundle\\\\Event\\\\CampaignExecutionEvent\\: + 2\\.13\\.0; to be removed in 3\\.0$# + """ + count: 1 + path: Tests/Functional/EventListener/CampaignSubscriberTest.php + + - + message: """ + #^Return type of method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\EventListener\\\\CampaignSubscriberTest\\:\\:createCampaignExecutionEvent\\(\\) has typehint with deprecated class Mautic\\\\CampaignBundle\\\\Event\\\\CampaignExecutionEvent\\: + 2\\.13\\.0; to be removed in 3\\.0$# + """ + count: 1 + path: Tests/Functional/EventListener/CampaignSubscriberTest.php + + - + message: "#^You should use assertCount\\(\\$expectedCount, \\$variable\\) instead of assertSame\\(\\$expectedCount, \\$variable\\-\\>count\\(\\)\\)\\.$#" + count: 4 + path: Tests/Functional/EventListener/ImportSubscriberTest.php + + - + message: "#^Call to function is_string\\(\\) with string will always evaluate to true\\.$#" + count: 1 + path: Tests/Functional/EventListener/SegmentFiltersDictionarySubscriberTest.php + + - + message: "#^Call to function is_string\\(\\) with string will always evaluate to true\\.$#" + count: 1 + path: Tests/Functional/Helper/QueryFilterHelperTest.php + + - + message: """ + #^Call to deprecated method execute\\(\\) of class Doctrine\\\\DBAL\\\\Query\\\\QueryBuilder\\: + Use \\{@see executeQuery\\(\\)\\} or \\{@see executeStatement\\(\\)\\} instead\\.$# + """ + count: 1 + path: Tests/Functional/Segment/Query/Filter/CustomFieldFilterQueryBuilderTest.php + + - + message: "#^Call to function is_string\\(\\) with string will always evaluate to true\\.$#" + count: 1 + path: Tests/Functional/Segment/Query/Filter/CustomFieldFilterQueryBuilderTest.php + + - + message: "#^Instanceof between int\\|string and Doctrine\\\\DBAL\\\\Driver\\\\Statement will always evaluate to false\\.$#" + count: 1 + path: Tests/Functional/Segment/Query/Filter/CustomFieldFilterQueryBuilderTest.php + + - + message: "#^PHPDoc tag @var with type Mautic\\\\LeadBundle\\\\Segment\\\\ContactSegmentFilter is not subtype of native type PHPUnit\\\\Framework\\\\MockObject\\\\MockObject\\.$#" + count: 2 + path: Tests/Functional/Segment/Query/Filter/CustomFieldFilterQueryBuilderTest.php + + - + message: """ + #^Call to deprecated method execute\\(\\) of class Doctrine\\\\DBAL\\\\Query\\\\QueryBuilder\\: + Use \\{@see executeQuery\\(\\)\\} or \\{@see executeStatement\\(\\)\\} instead\\.$# + """ + count: 1 + path: Tests/Functional/Segment/Query/Filter/CustomItemNameFilterQueryBuilderTest.php + + - + message: "#^Call to function is_string\\(\\) with string will always evaluate to true\\.$#" + count: 1 + path: Tests/Functional/Segment/Query/Filter/CustomItemNameFilterQueryBuilderTest.php + + - + message: "#^Instanceof between int\\|string and Doctrine\\\\DBAL\\\\Driver\\\\Statement will always evaluate to false\\.$#" + count: 1 + path: Tests/Functional/Segment/Query/Filter/CustomItemNameFilterQueryBuilderTest.php + + - + message: "#^Call to an undefined method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Functional\\\\Segment\\\\Query\\\\Filter\\\\CustomItemRelationQueryBuilderTest\\:\\:runCommand\\(\\)\\.$#" + count: 3 + path: Tests/Functional/Segment/Query/Filter/CustomItemRelationQueryBuilderTest.php + + - + message: "#^Call to function is_string\\(\\) with string will always evaluate to true\\.$#" + count: 1 + path: Tests/Functional/Segment/Query/Filter/CustomItemRelationQueryBuilderTest.php + + - + message: "#^Call to function is_string\\(\\) with string will always evaluate to true\\.$#" + count: 1 + path: Tests/Functional/Segment/Query/Filter/CustomObjectMergedFilterQueryBuilderTest.php + + - + message: "#^Call to function method_exists\\(\\) with 'Mautic\\\\\\\\LeadBundle\\\\\\\\Segment\\\\\\\\ContactSegmentFilterCrate' and 'getMergedProperty' will always evaluate to true\\.$#" + count: 1 + path: Tests/Functional/Segment/Query/Filter/NegativeOperatorFilterQueryBuilderTest.php + + - + message: "#^Call to an undefined method Symfony\\\\Component\\\\DependencyInjection\\\\ContainerInterface\\:\\:method\\(\\)\\.$#" + count: 2 + path: Tests/Unit/Controller/ControllerTestCase.php + + - + message: """ + #^Fetching class constant class of deprecated class Mautic\\\\CoreBundle\\\\Factory\\\\MauticFactory\\: + 2\\.0 to be removed in 3\\.0$# + """ + count: 1 + path: Tests/Unit/Controller/ControllerTestCase.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\ControllerTestCase\\:\\:\\$modelFactory \\(Mautic\\\\CoreBundle\\\\Factory\\\\ModelFactory&PHPUnit\\\\Framework\\\\MockObject\\\\MockObject\\) in empty\\(\\) is not falsy\\.$#" + count: 1 + path: Tests/Unit/Controller/ControllerTestCase.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\ControllerTestCase\\:\\:\\$requestStack \\(PHPUnit\\\\Framework\\\\MockObject\\\\MockObject&Symfony\\\\Component\\\\HttpFoundation\\\\RequestStack\\) in empty\\(\\) is not falsy\\.$#" + count: 1 + path: Tests/Unit/Controller/ControllerTestCase.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\AbstractFieldControllerTest\\:\\:createRequestStackMock\\(\\) has parameter \\$fieldId with no type specified\\.$#" + count: 1 + path: Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\AbstractFieldControllerTest\\:\\:createRequestStackMock\\(\\) has parameter \\$fieldType with no type specified\\.$#" + count: 1 + path: Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\AbstractFieldControllerTest\\:\\:createRequestStackMock\\(\\) has parameter \\$mapExtras with no value type specified in iterable type array\\.$#" + count: 1 + path: Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\AbstractFieldControllerTest\\:\\:createRequestStackMock\\(\\) has parameter \\$objectId with no type specified\\.$#" + count: 1 + path: Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\AbstractFieldControllerTest\\:\\:createRequestStackMock\\(\\) has parameter \\$panelCount with no type specified\\.$#" + count: 1 + path: Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\AbstractFieldControllerTest\\:\\:createRequestStackMock\\(\\) has parameter \\$panelId with no type specified\\.$#" + count: 1 + path: Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php + + - + message: "#^Property Symfony\\\\Component\\\\HttpFoundation\\\\Request\\:\\:\\$query \\(Symfony\\\\Component\\\\HttpFoundation\\\\InputBag\\\\) does not accept PHPUnit\\\\Framework\\\\MockObject\\\\MockObject&Symfony\\\\Component\\\\HttpFoundation\\\\ParameterBag\\.$#" + count: 1 + path: Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php + + - + message: "#^Property Symfony\\\\Component\\\\HttpFoundation\\\\Request\\:\\:\\$request \\(Symfony\\\\Component\\\\HttpFoundation\\\\InputBag\\\\) does not accept PHPUnit\\\\Framework\\\\MockObject\\\\MockObject&Symfony\\\\Component\\\\HttpFoundation\\\\ParameterBag\\.$#" + count: 1 + path: Tests/Unit/Controller/CustomField/AbstractFieldControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\FormControllerTest\\:\\:\\$formController \\(MauticPlugin\\\\CustomObjectsBundle\\\\Controller\\\\CustomField\\\\FormController&PHPUnit\\\\Framework\\\\MockObject\\\\MockObject\\) does not accept MauticPlugin\\\\CustomObjectsBundle\\\\Controller\\\\CustomField\\\\FormController\\.$#" + count: 1 + path: Tests/Unit/Controller/CustomField/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\FormControllerTest\\:\\:\\$requestStack \\(PHPUnit\\\\Framework\\\\MockObject\\\\MockObject&Symfony\\\\Component\\\\HttpFoundation\\\\RequestStack\\) does not accept Symfony\\\\Component\\\\HttpFoundation\\\\RequestStack\\.$#" + count: 1 + path: Tests/Unit/Controller/CustomField/FormControllerTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomField\\\\SaveControllerTest\\:\\:createSaveController\\(\\) has parameter \\$mapExtras with no value type specified in iterable type array\\.$#" + count: 1 + path: Tests/Unit/Controller/CustomField/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\ControllerTestCase\\:\\:\\$requestStack \\(PHPUnit\\\\Framework\\\\MockObject\\\\MockObject&Symfony\\\\Component\\\\HttpFoundation\\\\RequestStack\\) does not accept Symfony\\\\Component\\\\HttpFoundation\\\\RequestStack\\.$#" + count: 1 + path: Tests/Unit/Controller/CustomField/SaveControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\BatchDeleteControllerTest\\:\\:\\$model has no type specified\\.$#" + count: 1 + path: Tests/Unit/Controller/CustomItem/BatchDeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\BatchDeleteControllerTest\\:\\:\\$sessionProviderFactory has no type specified\\.$#" + count: 1 + path: Tests/Unit/Controller/CustomItem/BatchDeleteControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\CancelControllerTest\\:\\:\\$sessionProviderFactory has no type specified\\.$#" + count: 1 + path: Tests/Unit/Controller/CustomItem/CancelControllerTest.php + + - + message: "#^Access to an undefined property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\DeleteControllerTest\\:\\:\\$model\\.$#" + count: 2 + path: Tests/Unit/Controller/CustomItem/DeleteControllerTest.php + + - + message: "#^Access to an undefined property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\DeleteControllerTest\\:\\:\\$sessionProviderFactory\\.$#" + count: 5 + path: Tests/Unit/Controller/CustomItem/DeleteControllerTest.php + + - + message: "#^Call to method PHPUnit\\\\Framework\\\\Assert\\:\\:assertNotNull\\(\\) with list\\ and 'Custom Item Export…' will always evaluate to true\\.$#" + count: 1 + path: Tests/Unit/Controller/CustomItem/ExportControllerTest.php + + - + message: "#^Access to an undefined property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\FormControllerTest\\:\\:\\$model\\.$#" + count: 9 + path: Tests/Unit/Controller/CustomItem/FormControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomItem\\\\ListControllerTest\\:\\:\\$sessionProviderFactory has no type specified\\.$#" + count: 1 + path: Tests/Unit/Controller/CustomItem/ListControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\CancelControllerTest\\:\\:\\$sessionProviderFactory has no type specified\\.$#" + count: 1 + path: Tests/Unit/Controller/CustomObject/CancelControllerTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\DeleteControllerTest\\:\\:\\$sessionProviderFactory has no type specified\\.$#" + count: 1 + path: Tests/Unit/Controller/CustomObject/DeleteControllerTest.php + + - + message: "#^Access to an undefined property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\FormControllerTest\\:\\:\\$model\\.$#" + count: 7 + path: Tests/Unit/Controller/CustomObject/FormControllerTest.php + + - + message: "#^Access to an undefined property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Controller\\\\CustomObject\\\\ListControllerTest\\:\\:\\$sessionProviderFactory\\.$#" + count: 5 + path: Tests/Unit/Controller/CustomObject/ListControllerTest.php + + - + message: "#^You should use assertNull\\(\\) instead of assertSame\\(null, \\$actual\\)\\.$#" + count: 1 + path: Tests/Unit/CustomFieldType/DateTimeTypeTest.php + + - + message: "#^You should use assertNull\\(\\) instead of assertSame\\(null, \\$actual\\)\\.$#" + count: 1 + path: Tests/Unit/CustomFieldType/DateTypeTest.php + + - + message: "#^Unable to resolve the template type T in call to method PHPUnit\\\\Framework\\\\TestCase\\:\\:createMock\\(\\)$#" + count: 1 + path: Tests/Unit/Entity/CustomFieldFactoryTest.php + + - + message: "#^Parameter \\#1 \\$expected of method PHPUnit\\\\Framework\\\\Assert\\:\\:assertSame\\(\\) contains unresolvable type\\.$#" + count: 1 + path: Tests/Unit/Entity/CustomFieldValueOptionTest.php + + - + message: "#^Call to method PHPUnit\\\\Framework\\\\Assert\\:\\:assertSame\\(\\) with Doctrine\\\\Common\\\\Collections\\\\ArrayCollection\\<\\*NEVER\\*, \\*NEVER\\*\\> and Doctrine\\\\Common\\\\Collections\\\\Collection&iterable\\ will always evaluate to false\\.$#" + count: 1 + path: Tests/Unit/Entity/CustomObjectTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AssetsSubscriberTest\\:\\:\\$coreParametersHelper has no type specified\\.$#" + count: 1 + path: Tests/Unit/EventListener/AssetsSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AssetsSubscriberTest\\:\\:\\$packages has no type specified\\.$#" + count: 1 + path: Tests/Unit/EventListener/AssetsSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\AssetsSubscriberTest\\:\\:\\$requestEvent has no type specified\\.$#" + count: 1 + path: Tests/Unit/EventListener/AssetsSubscriberTest.php + + - + message: """ + #^Fetching class constant class of deprecated class Mautic\\\\CampaignBundle\\\\Event\\\\CampaignExecutionEvent\\: + 2\\.13\\.0; to be removed in 3\\.0$# + """ + count: 1 + path: Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$result has no type specified\\.$#" + count: 1 + path: Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CampaignSubscriberTest\\:\\:\\$statement is never read, only written\\.$#" + count: 1 + path: Tests/Unit/EventListener/CampaignSubscriberTest.php + + - + message: """ + #^Fetching class constant class of deprecated class Doctrine\\\\ORM\\\\Event\\\\LifecycleEventArgs\\: + This class will be removed in ORM 3\\.0\\. Use one of the dedicated classes instead\\.$# + """ + count: 1 + path: Tests/Unit/EventListener/CustomFieldPostLoadSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefContactSubscriberTest\\:\\:\\$xrefSubscriber \\(MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\CustomItemXrefContactSubscriber&PHPUnit\\\\Framework\\\\MockObject\\\\MockObject\\) does not accept MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\CustomItemXrefContactSubscriber\\.$#" + count: 1 + path: Tests/Unit/EventListener/CustomItemXrefContactSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\CustomItemXrefCustomItemSubscriberTest\\:\\:\\$xrefSubscriber \\(MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\CustomItemXrefCustomItemSubscriber&PHPUnit\\\\Framework\\\\MockObject\\\\MockObject\\) does not accept MauticPlugin\\\\CustomObjectsBundle\\\\EventListener\\\\CustomItemXrefCustomItemSubscriber\\.$#" + count: 1 + path: Tests/Unit/EventListener/CustomItemXrefCustomItemSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\DynamicContentSubscriberTest\\:\\:\\$statementMock is never read, only written\\.$#" + count: 1 + path: Tests/Unit/EventListener/DynamicContentSubscriberTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\EventListener\\\\TokenSubscriberTest\\:\\:\\$tokenParser \\(MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\TokenParser&PHPUnit\\\\Framework\\\\MockObject\\\\MockObject\\) does not accept MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\TokenParser\\.$#" + count: 1 + path: Tests/Unit/EventListener/TokenSubscriberTest.php + + - + message: "#^Call to method PHPUnit\\\\Framework\\\\Assert\\:\\:assertInstanceOf\\(\\) with 'Doctrine\\\\\\\\Common\\\\\\\\Collections\\\\\\\\ArrayCollection' and Doctrine\\\\Common\\\\Collections\\\\ArrayCollection&iterable\\ will always evaluate to true\\.$#" + count: 3 + path: Tests/Unit/Form/DataTransformer/OptionsToStringTransformerTest.php + + - + message: "#^Call to method PHPUnit\\\\Framework\\\\Assert\\:\\:assertInstanceOf\\(\\) with 'Doctrine\\\\\\\\Common\\\\\\\\Collections\\\\\\\\ArrayCollection' and Doctrine\\\\Common\\\\Collections\\\\ArrayCollection will always evaluate to true\\.$#" + count: 4 + path: Tests/Unit/Form/DataTransformer/OptionsTransformerTest.php + + - + message: "#^Call to method PHPUnit\\\\Framework\\\\Assert\\:\\:assertSame\\(\\) with array\\{list\\: array\\{11, 221\\}\\} and array\\ will always evaluate to false\\.$#" + count: 1 + path: Tests/Unit/Form/DataTransformer/OptionsTransformerTest.php + + - + message: "#^Call to method PHPUnit\\\\Framework\\\\Assert\\:\\:assertSame\\(\\) with array\\{list\\: array\\{\\}\\} and array\\ will always evaluate to false\\.$#" + count: 2 + path: Tests/Unit/Form/DataTransformer/OptionsTransformerTest.php + + - + message: "#^You should use assertCount\\(\\$expectedCount, \\$variable\\) instead of assertSame\\(\\$expectedCount, \\$variable\\-\\>count\\(\\)\\)\\.$#" + count: 3 + path: Tests/Unit/Form/DataTransformer/OptionsTransformerTest.php + + - + message: "#^Call to method PHPUnit\\\\Framework\\\\Assert\\:\\:assertInstanceOf\\(\\) with 'MauticPlugin\\\\\\\\CustomObjectsBundle\\\\\\\\Entity\\\\\\\\CustomField\\\\\\\\Params' and MauticPlugin\\\\CustomObjectsBundle\\\\Entity\\\\CustomField\\\\Params will always evaluate to true\\.$#" + count: 1 + path: Tests/Unit/Form/DataTransformer/ParamsToStringTransformerTest.php + + - + message: "#^Access to an undefined property PHPUnit\\\\Framework\\\\MockObject\\\\MockObject&Symfony\\\\Component\\\\Validator\\\\Constraint\\:\\:\\$message\\.$#" + count: 1 + path: Tests/Unit/Form/Validator/AllowUniqueIdentifierValidatorTest.php + + - + message: "#^Access to an undefined property PHPUnit\\\\Framework\\\\MockObject\\\\MockObject&Symfony\\\\Component\\\\Validator\\\\Constraint\\:\\:\\$missingMasterObject\\.$#" + count: 1 + path: Tests/Unit/Form/Validator/CustomObjectTypeValuesValidatorTest.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Helper\\\\CustomFieldQueryBuilder\\\\CalculatorTest\\:\\:getSuffix\\(\\) is unused\\.$#" + count: 1 + path: Tests/Unit/Helper/CustomFieldQueryBuilder/CalculatorTest.php + + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: Tests/Unit/Helper/QueryFilterFactoryTest.php + + - + message: """ + #^Call to deprecated method setMethods\\(\\) of class PHPUnit\\\\Framework\\\\MockObject\\\\MockBuilder\\: + https\\://github\\.com/sebastianbergmann/phpunit/pull/3687$# + """ + count: 1 + path: Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^You should use assertCount\\(\\$expectedCount, \\$variable\\) instead of assertSame\\(\\$expectedCount, \\$variable\\-\\>count\\(\\)\\)\\.$#" + count: 1 + path: Tests/Unit/Model/CustomFieldValueModelTest.php + + - + message: "#^Call to an undefined method MauticPlugin\\\\CustomObjectsBundle\\\\Model\\\\CustomItemImportModel\\:\\:setTranslator\\(\\)\\.$#" + count: 1 + path: Tests/Unit/Model/CustomItemImportModelTest.php + + - + message: "#^Call to an undefined method Mautic\\\\CoreBundle\\\\Twig\\\\Helper\\\\FormatterHelper\\:\\:expects\\(\\)\\.$#" + count: 1 + path: Tests/Unit/Model/CustomItemImportModelTest.php + + - + message: "#^Call to method expects\\(\\) on an unknown class MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\TranslatorInterface\\.$#" + count: 1 + path: Tests/Unit/Model/CustomItemImportModelTest.php + + - + message: "#^Class MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\TranslatorInterface not found\\.$#" + count: 1 + path: Tests/Unit/Model/CustomItemImportModelTest.php + + - + message: "#^Trying to mock an undefined method exists\\(\\) on class Mautic\\\\LeadBundle\\\\Entity\\\\LeadRepository\\.$#" + count: 3 + path: Tests/Unit/Model/CustomItemImportModelTest.php + + - + message: "#^Trying to mock an undefined method trans\\(\\) on class MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\TranslatorInterface\\.$#" + count: 1 + path: Tests/Unit/Model/CustomItemImportModelTest.php + + - + message: "#^You should use assertFalse\\(\\) instead of assertSame\\(\\) when expecting \"false\"$#" + count: 1 + path: Tests/Unit/Model/CustomItemImportModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomItemModelTest\\:\\:\\$statement is never read, only written\\.$#" + count: 1 + path: Tests/Unit/Model/CustomItemModelTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Model\\\\CustomObjectModelTest\\:\\:\\$listModel is never read, only written\\.$#" + count: 1 + path: Tests/Unit/Model/CustomObjectModelTest.php + + - + message: "#^You should use assertCount\\(\\$expectedCount, \\$variable\\) instead of assertSame\\(\\$expectedCount, count\\(\\$variable\\)\\)\\.$#" + count: 1 + path: Tests/Unit/Provider/CustomFieldTypeProviderTest.php + + - + message: "#^Call to method PHPUnit\\\\Framework\\\\Assert\\:\\:assertSame\\(\\) with array\\{'some items here'\\} and array\\ will always evaluate to false\\.$#" + count: 1 + path: Tests/Unit/Repository/CustomItemXrefContactRepositoryTest.php + + - + message: "#^Property MauticPlugin\\\\CustomObjectsBundle\\\\Tests\\\\Unit\\\\Security\\\\Permissions\\\\CustomObjectPermissionsTest\\:\\:\\$permissions \\(MauticPlugin\\\\CustomObjectsBundle\\\\Security\\\\Permissions\\\\CustomObjectPermissions&PHPUnit\\\\Framework\\\\MockObject\\\\MockObject\\) does not accept MauticPlugin\\\\CustomObjectsBundle\\\\Security\\\\Permissions\\\\CustomObjectPermissions\\.$#" + count: 1 + path: Tests/Unit/Security/Permissions/CustomObjectPermissionsTest.php + + - + message: "#^Call to method PHPUnit\\\\Framework\\\\Assert\\:\\:assertInstanceOf\\(\\) with 'Mautic\\\\\\\\LeadBundle\\\\\\\\Segment\\\\\\\\Query\\\\\\\\QueryBuilder' and Mautic\\\\LeadBundle\\\\Segment\\\\Query\\\\QueryBuilder will always evaluate to true\\.$#" + count: 1 + path: Tests/Unit/Segment/Query/UnionQueryContainerTest.php + + - + message: """ + #^Fetching deprecated class constant PARAM_INT_ARRAY of class Doctrine\\\\DBAL\\\\Connection\\: + Use \\{@see ArrayParameterType\\:\\:INTEGER\\} instead\\.$# + """ + count: 2 + path: Tests/Unit/Segment/Query/UnionQueryContainerTest.php diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 000000000..3eb4949c0 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,28 @@ +includes: + - phpstan-baseline-php-versions.neon.php + - phpstan-baseline.neon + - ../../vendor/phpstan/phpstan/conf/bleedingEdge.neon + +parameters: + level: 6 + reportUnmatchedIgnoredErrors: false + checkGenericClassInNonGenericObjectType: false + parallel: + maximumNumberOfProcesses: 4 + processTimeout: 1000.0 + scanDirectories: + - ../../app + paths: + - . + excludePaths: + - CustomFieldType/*Type.php # This should be refactored + - *.html.php # this can be removed in Mautic 5 + - Extension/CustomItemListeningExtension.php # PHPSTAN is confused because it exists only if API Platform does. + - Serializer/ApiNormalizer.php # PHPSTAN is confused because it exists only if API Platform does. + - Tests/Unit/Serializer/ApiNormalizerTest.php # PHPSTAN is confused because it exists only if API Platform does. + - DataPersister/CustomItemDataPersister.php # PHPSTAN is confused because it exists only if API Platform does. + - Tests/Unit/EventListener/SegmentFiltersChoicesGenerateSubscriberTest.php + dynamicConstantNames: + - MAUTIC_ENV + - MAUTIC_TABLE_PREFIX + - MAUTIC_VERSION diff --git a/phpunit.xml b/phpunit.xml index 874d2f418..9d223d1ac 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -22,10 +22,13 @@ - - - - + + + + + + + From f9c3d1d96f66dedc08bfaf59417ae934a244d842 Mon Sep 17 00:00:00 2001 From: Jason Woods Date: Wed, 2 Jul 2025 15:08:49 +0100 Subject: [PATCH 02/25] fix: Resolve contact tabs not being searchable and pagination not working (#369) * fix: Resolve contact tabs not being searchable and pagination not working * chore: Update to v4 upload-artifact --- .github/workflows/tests.yml | 4 ++-- Resources/views/SubscribedEvents/Tab/content.html.twig | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c21a33557..c84493d07 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -109,7 +109,7 @@ jobs: run: bin/php-cs-fixer fix ${{ env.PLUGIN_DIR }} --config=.php-cs-fixer.php -v --dry-run --show-progress=dots --diff # - name: PHPSTAN - baseline (debug, enable if you need to regenerate baseline for all PHP versions) - # run: bin/phpstan --configuration=${{ env.PLUGIN_DIR }}/phpstan.neon --generate-baseline=var/logs/phpstan-baseline-${{ matrix.php-versions }}.neon --allow-empty-baseline + # run: bin/phpstan --configuration=${{ env.PLUGIN_DIR }}/phpstan.neon --generate-baseline=var/logs/phpstan-baseline-${{ matrix.php-versions }}.neon --allow-empty-baseline - name: PHPSTAN run: bin/phpstan --configuration=${{ env.PLUGIN_DIR }}/phpstan.neon @@ -142,7 +142,7 @@ jobs: # verbose: true - name: Upload logs as artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: mautic-logs path: var/logs/ diff --git a/Resources/views/SubscribedEvents/Tab/content.html.twig b/Resources/views/SubscribedEvents/Tab/content.html.twig index 702c12c7f..d5f99f144 100644 --- a/Resources/views/SubscribedEvents/Tab/content.html.twig +++ b/Resources/views/SubscribedEvents/Tab/content.html.twig @@ -32,7 +32,7 @@ -
    +
    Loading...
    @@ -46,4 +46,4 @@ "{{ currentEntityType }}", "{{ tabId }}" ); - \ No newline at end of file + From f49fc5d9cd132e072aeb44e65ecb69f8083cd496 Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Mon, 9 Mar 2026 11:23:34 +0100 Subject: [PATCH 03/25] fix(DynamicContentSubscriber): complete Mautic 5 migration of filter evaluation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- Config/config.php | 20 ++ EventListener/DynamicContentSubscriber.php | 69 ++---- Helper/ContactFilterMatcher.php | 220 +++++++++++++++++ .../EventListener/MatchFilterForLeadTrait.php | 232 ++++++++++++++++++ .../DynamicContentSubscriberTest.php | 208 +++++++++------- 5 files changed, 613 insertions(+), 136 deletions(-) create mode 100644 Helper/ContactFilterMatcher.php create mode 100644 Polyfill/EventListener/MatchFilterForLeadTrait.php diff --git a/Config/config.php b/Config/config.php index 313fb8820..a3156c846 100644 --- a/Config/config.php +++ b/Config/config.php @@ -413,6 +413,14 @@ '%mautic.custom_item_fetch_limit_per_lead%', ], ], + 'custom_object.dynamic_content.subscriber' => [ + 'class' => MauticPlugin\CustomObjectsBundle\EventListener\DynamicContentSubscriber::class, + 'arguments' => [ + 'custom_object.query.filter.factory', + 'custom_object.helper.contact_filter_matcher', + 'custom_object.config.provider', + ], + ], ], 'forms' => [ 'custom_field.field.params.to.string.transformer' => [ @@ -636,6 +644,18 @@ 'custom_object.helper.token_formatter' => [ 'class' => MauticPlugin\CustomObjectsBundle\Helper\TokenFormatter::class, ], + 'custom_object.helper.contact_filter_matcher' => [ + 'class' => MauticPlugin\CustomObjectsBundle\Helper\ContactFilterMatcher::class, + 'arguments' => [ + 'mautic.custom.model.field', + 'mautic.custom.model.object', + 'mautic.custom.model.item', + 'mautic.lead.repository.lead_list', + 'mautic.lead.repository.company', + 'doctrine.dbal.default_connection', + '%mautic.custom_item_fetch_limit_per_lead%', + ], + ], 'custom_object.data_persister.custom_item' => [ 'class' => MauticPlugin\CustomObjectsBundle\DataPersister\CustomItemDataPersister::class, 'tag' => 'api_platform.data_persister', diff --git a/EventListener/DynamicContentSubscriber.php b/EventListener/DynamicContentSubscriber.php index 054bcf5f6..e72fa4bd3 100644 --- a/EventListener/DynamicContentSubscriber.php +++ b/EventListener/DynamicContentSubscriber.php @@ -6,32 +6,23 @@ use Mautic\DynamicContentBundle\DynamicContentEvents; use Mautic\DynamicContentBundle\Event\ContactFiltersEvaluateEvent; -use Mautic\EmailBundle\EventListener\MatchFilterForLeadTrait; -use MauticPlugin\CustomObjectsBundle\Exception\InvalidArgumentException; use MauticPlugin\CustomObjectsBundle\Exception\InvalidSegmentFilterException; -use MauticPlugin\CustomObjectsBundle\Exception\NotFoundException; -use MauticPlugin\CustomObjectsBundle\Helper\QueryFilterHelper; +use MauticPlugin\CustomObjectsBundle\Helper\ContactFilterMatcher; use MauticPlugin\CustomObjectsBundle\Provider\ConfigProvider; -use MauticPlugin\CustomObjectsBundle\Repository\DbalQueryTrait; use MauticPlugin\CustomObjectsBundle\Segment\Query\Filter\QueryFilterFactory; -use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class DynamicContentSubscriber implements EventSubscriberInterface { - use MatchFilterForLeadTrait; - use DbalQueryTrait; - public function __construct( private QueryFilterFactory $queryFilterFactory, - private QueryFilterHelper $queryFilterHelper, + private ContactFilterMatcher $contactFilterMatcher, private ConfigProvider $configProvider, - private LoggerInterface $logger ) { } /** - * @return mixed[] + * @return array */ public static function getSubscribedEvents(): array { @@ -40,47 +31,37 @@ public static function getSubscribedEvents(): array ]; } - /** - * @throws InvalidArgumentException - * @throws NotFoundException - */ public function evaluateFilters(ContactFiltersEvaluateEvent $event): void { - if (!$this->configProvider->pluginIsEnabled()) { - return; - } - - $eventFilters = $event->getFilters(); - - if ($event->isEvaluated()) { + if ($event->isEvaluated() + || !$this->configProvider->pluginIsEnabled() + || !$this->hasCustomObjectFilters($event->getFilters()) + ) { return; } - foreach ($eventFilters as $key => $eventFilter) { - $queryAlias = "filter_{$key}"; - - try { - $filterQueryBuilder = $this->queryFilterFactory->configureQueryBuilderFromSegmentFilter($eventFilter, $queryAlias); - } catch (InvalidSegmentFilterException $e) { - continue; - } - - $this->queryFilterHelper->addContactIdRestriction($filterQueryBuilder, $queryAlias, (int) $event->getContact()->getId()); + $event->setIsEvaluated(true); + $event->stopPropagation(); + $event->setIsMatched($this->contactFilterMatcher->match( + $event->getFilters(), + $event->getContact()->getProfileFields() + )); + } + /** + * @param mixed[] $filters + */ + private function hasCustomObjectFilters(array $filters): bool + { + foreach ($filters as $filter) { try { - if ($this->executeSelect($filterQueryBuilder)->rowCount()) { - $event->setIsEvaluated(true); - $event->setIsMatched(true); - } else { - $event->setIsEvaluated(true); - } - } catch (\PDOException $e) { - $this->logger->error('Failed to evaluate dynamic content for custom object '.$e->getMessage()); + $this->queryFilterFactory->configureQueryBuilderFromSegmentFilter($filter, 'filter'); - throw $e; + return true; + } catch (InvalidSegmentFilterException $e) { } - - $event->stopPropagation(); // The filter is ours, we won't allow no more processing } + + return false; } } diff --git a/Helper/ContactFilterMatcher.php b/Helper/ContactFilterMatcher.php new file mode 100644 index 000000000..28ab162bb --- /dev/null +++ b/Helper/ContactFilterMatcher.php @@ -0,0 +1,220 @@ +customFieldModel = $customFieldModel; + $this->customObjectModel = $customObjectModel; + $this->customItemModel = $customItemModel; + $this->segmentRepository = $segmentRepository; + $this->companyRepository = $companyRepository; + $this->connection = $connection; + $this->leadCustomItemFetchLimit = $leadCustomItemFetchLimit; + } + + /** + * @param mixed[] $filters + * @param mixed[] $lead + */ + public function match(array $filters, array $lead, bool &$hasCustomFields = false): bool + { + $leadId = (string) $lead['id']; + $customFieldValues = $this->getCustomFieldDataForLead($filters, $leadId); + + if (!$customFieldValues) { + return false; + } + + $hasCustomFields = true; + $lead = array_merge($lead, $customFieldValues); + + if (!isset($lead['companies']) && $this->doFiltersContainCompanyFilter($filters)) { + $lead['companies'] = $this->companyRepository->getCompaniesByLeadId($leadId); + } + + if (!isset($lead['tags']) && $this->doFiltersContainTagsFilter($filters)) { + $lead['tags'] = $this->getTagIdsByLeadId($leadId); + } + + return $this->matchFilterForLead($filters, $lead); + } + + /** + * @param mixed[] $filters + * + * @return mixed[] + */ + private function getCustomFieldDataForLead(array $filters, string $leadId): array + { + $customFieldValues = $cachedCustomItems = []; + + foreach ($filters as $condition) { + try { + if ('custom_object' !== $condition['object']) { + continue; + } + + if ('cmf_' === substr($condition['field'], 0, 4)) { + $customField = $this->customFieldModel->fetchEntity( + (int) explode('cmf_', $condition['field'])[1] + ); + $customObject = $customField->getCustomObject(); + $fieldAlias = $customField->getAlias(); + } elseif ('cmo_' === substr($condition['field'], 0, 4)) { + $customObject = $this->customObjectModel->fetchEntity( + (int) explode('cmo_', $condition['field'])[1] + ); + $fieldAlias = 'name'; + } else { + continue; + } + + $key = $customObject->getId().'-'.$leadId; + if (!isset($cachedCustomItems[$key])) { + $cachedCustomItems[$key] = $this->getCustomItems($customObject, $leadId); + } + + $result = $this->getCustomFieldValue($customObject, $fieldAlias, $cachedCustomItems[$key]); + + $customFieldValues[$condition['field']] = $result; + } catch (NotFoundException|InvalidCustomObjectFormatListException $e) { + continue; + } + } + + return $customFieldValues; + } + + /** + * @param mixed[] $customItems + * + * @return mixed[] + */ + private function getCustomFieldValue( + CustomObject $customObject, + string $customFieldAlias, + array $customItems + ): array { + $fieldValues = []; + + foreach ($customItems as $customItemData) { + // Name is known from the CI data array. + if ('name' === $customFieldAlias) { + $fieldValues[] = $customItemData['name']; + + continue; + } + + // Custom Field values are handled like this. + $customItem = new CustomItem($customObject); + $customItem->populateFromArray($customItemData); + $customItem = $this->customItemModel->populateCustomFields($customItem); + + try { + $fieldValue = $customItem->findCustomFieldValueForFieldAlias($customFieldAlias); + // If the CO item doesn't have a value, get the default value + if (empty($fieldValue->getValue())) { + $fieldValue->setValue($fieldValue->getCustomField()->getDefaultValue()); + } + + if (in_array($fieldValue->getCustomField()->getType(), ['multiselect', 'select'])) { + $fieldValues[] = $fieldValue->getValue(); + } else { + $fieldValues[] = $fieldValue->getCustomField()->getTypeObject()->valueToString($fieldValue); + } + } catch (NotFoundException $e) { + // Custom field not found. + } + } + + return $fieldValues; + } + + /** + * @return array + */ + private function getCustomItems(CustomObject $customObject, string $leadId): array + { + $orderBy = CustomItem::TABLE_ALIAS.'.id'; + $orderDir = 'DESC'; + + $tableConfig = new TableConfig($this->leadCustomItemFetchLimit, 1, $orderBy, $orderDir); + $tableConfig->addParameter('customObjectId', $customObject->getId()); + $tableConfig->addParameter('filterEntityType', 'contact'); + $tableConfig->addParameter('filterEntityId', $leadId); + + return $this->customItemModel->getArrayTableData($tableConfig); + } + + /** + * @param mixed[] $data + * @param mixed[] $lead + * + * @return ?mixed[] + */ + private function transformFilterDataForLead(array $data, array $lead): ?array + { + if ('custom_object' === $data['object']) { + return $lead[$data['field']]; + } + + return $this->transformFilterDataForLeadAlias($data, $lead); + } + + /** + * @return string[] + */ + public function getTagIdsByLeadId(string $leadId): array + { + return $this->connection->createQueryBuilder() + ->select('tag_id') + ->from(MAUTIC_TABLE_PREFIX.'lead_tags_xref', 'x') + ->where('x.lead_id = :leadId') + ->setParameter('leadId', $leadId) + ->execute() + ->fetchFirstColumn(); + } +} diff --git a/Polyfill/EventListener/MatchFilterForLeadTrait.php b/Polyfill/EventListener/MatchFilterForLeadTrait.php new file mode 100644 index 000000000..19304737e --- /dev/null +++ b/Polyfill/EventListener/MatchFilterForLeadTrait.php @@ -0,0 +1,232 @@ + $filterVal; + break; + case 'gte': + $groups[$groupNum] = $leadVal >= $filterVal; + break; + case 'lt': + $groups[$groupNum] = $leadVal < $filterVal; + break; + case 'lte': + $groups[$groupNum] = $leadVal <= $filterVal; + break; + case 'empty': + $groups[$groupNum] = empty($leadVal); + break; + case '!empty': + $groups[$groupNum] = !empty($leadVal); + break; + case 'like': + $matchVal = str_replace(['.', '*', '%'], ['\.', '\*', '.*'], $filterVal); + $groups[$groupNum] = 1 === preg_match('/'.$matchVal.'/', $leadVal); + break; + case '!like': + $matchVal = str_replace(['.', '*'], ['\.', '\*'], $filterVal); + $matchVal = str_replace('%', '.*', $matchVal); + $groups[$groupNum] = 1 !== preg_match('/'.$matchVal.'/', $leadVal); + break; + case OperatorOptions::IN: + $groups[$groupNum] = $this->checkLeadValueIsInFilter($leadVal, $filterVal, false); + break; + case OperatorOptions::NOT_IN: + $groups[$groupNum] = $this->checkLeadValueIsInFilter($leadVal, $filterVal, true); + break; + case 'regexp': + $groups[$groupNum] = 1 === preg_match('/'.$filterVal.'/i', $leadVal); + break; + case '!regexp': + $groups[$groupNum] = 1 !== preg_match('/'.$filterVal.'/i', $leadVal); + break; + case 'startsWith': + $groups[$groupNum] = 0 === strncmp($leadVal, $filterVal, strlen($filterVal)); + break; + case 'endsWith': + $endOfString = substr($leadVal, strlen($leadVal) - strlen($filterVal)); + $groups[$groupNum] = 0 === strcmp($endOfString, $filterVal); + break; + case 'contains': + $groups[$groupNum] = false !== strpos((string) $leadVal, (string) $filterVal); + break; + default: + throw new OperatorsNotFoundException('Operator is not defined or invalid operator found.'); + } + + $subgroup = $groups[$groupNum]; + } + } + } + + return in_array(true, $groups); + } + + /** + * @param mixed[] $data + * @param mixed[] $lead + * + * @return ?mixed[] + */ + private function transformFilterDataForLead(array $data, array $lead): ?array + { + return null; + } + + /** + * @param mixed[] $filters + */ + private function doFiltersContainCompanyFilter(array $filters): bool + { + foreach ($filters as $filter) { + $object = $filter['object'] ?? ''; + + if ('company' === $object) { + return true; + } + + if ((0 === strpos($filter['field'], 'company') && 'company' !== $filter['field'])) { + return true; + } + } + + return false; + } + + /** + * @param mixed[] $filters + */ + private function doFiltersContainTagsFilter(array $filters): bool + { + foreach ($filters as $filter) { + if ('tags' === ($filter['type'] ?? null)) { + return true; + } + } + + return false; + } +} diff --git a/Tests/Unit/EventListener/DynamicContentSubscriberTest.php b/Tests/Unit/EventListener/DynamicContentSubscriberTest.php index 6f28959d0..d366cfc0f 100644 --- a/Tests/Unit/EventListener/DynamicContentSubscriberTest.php +++ b/Tests/Unit/EventListener/DynamicContentSubscriberTest.php @@ -4,152 +4,176 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\EventListener; -use Doctrine\DBAL\Result; -use Doctrine\DBAL\Statement; +use Mautic\DynamicContentBundle\DynamicContentEvents; use Mautic\DynamicContentBundle\Event\ContactFiltersEvaluateEvent; use Mautic\LeadBundle\Entity\Lead; -use Mautic\LeadBundle\Segment\Query\QueryBuilder; use MauticPlugin\CustomObjectsBundle\EventListener\DynamicContentSubscriber; use MauticPlugin\CustomObjectsBundle\Exception\InvalidSegmentFilterException; -use MauticPlugin\CustomObjectsBundle\Helper\QueryFilterHelper; +use MauticPlugin\CustomObjectsBundle\Helper\ContactFilterMatcher; use MauticPlugin\CustomObjectsBundle\Provider\ConfigProvider; use MauticPlugin\CustomObjectsBundle\Segment\Query\Filter\CustomFieldFilterQueryBuilder; use MauticPlugin\CustomObjectsBundle\Segment\Query\Filter\CustomItemNameFilterQueryBuilder; use MauticPlugin\CustomObjectsBundle\Segment\Query\Filter\QueryFilterFactory; -use Monolog\Logger; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class DynamicContentSubscriberTest extends TestCase { - /** @var ConfigProvider|MockObject */ - private $configProviderMock; + /** @var QueryFilterFactory&MockObject */ + private MockObject $queryFilterFactory; - /** @var QueryFilterHelper|MockObject */ - private $queryFilterHelperMock; + /** @var ContactFilterMatcher&MockObject */ + private MockObject $contactFilterMatcher; - /** @var QueryFilterFactory|MockObject */ - private $queryFilterFactory; + /** @var ConfigProvider&MockObject */ + private MockObject $configProvider; - /** @var Logger|MockObject */ - private $loggerMock; - - /** @var QueryBuilder|MockObject */ - private $queryBuilderMock; - - /** @var DynamicContentSubscriber */ - private $dynamicContentSubscriber; - - /** @var Statement|MockObject */ - private $statementMock; + private DynamicContentSubscriber $subscriber; protected function setUp(): void { parent::setUp(); - $this->configProviderMock = $this->createMock(ConfigProvider::class); - $this->queryFilterFactory = $this->createMock(QueryFilterFactory::class); - $this->queryFilterHelperMock = $this->createMock(QueryFilterHelper::class); - $this->loggerMock = $this->createMock(Logger::class); - $this->queryBuilderMock = $this->createMock(QueryBuilder::class); - $this->statementMock = $this->createMock(Statement::class); + $this->queryFilterFactory = $this->createMock(QueryFilterFactory::class); + $this->contactFilterMatcher = $this->createMock(ContactFilterMatcher::class); + $this->configProvider = $this->createMock(ConfigProvider::class); - $this->dynamicContentSubscriber = new DynamicContentSubscriber( + $this->subscriber = new DynamicContentSubscriber( $this->queryFilterFactory, - $this->queryFilterHelperMock, - $this->configProviderMock, - $this->loggerMock + $this->contactFilterMatcher, + $this->configProvider, ); } - public function testOnCampaignBuildWhenPluginDisabled(): void + public function testGetSubscribedEventsReturnsCorrectMapping(): void + { + $events = DynamicContentSubscriber::getSubscribedEvents(); + + $this->assertArrayHasKey(DynamicContentEvents::ON_CONTACTS_FILTER_EVALUATE, $events); + $this->assertSame(['evaluateFilters', 0], $events[DynamicContentEvents::ON_CONTACTS_FILTER_EVALUATE]); + } + + public function testEvaluateFiltersSkipsWhenEventAlreadyEvaluated(): void { - $this->configProviderMock->expects($this->once()) + $event = $this->buildEvent(); + $event->setIsEvaluated(true); + + // pluginIsEnabled must never be called — early exit on isEvaluated() + $this->configProvider->expects($this->never())->method('pluginIsEnabled'); + $this->queryFilterFactory->expects($this->never())->method('configureQueryBuilderFromSegmentFilter'); + $this->contactFilterMatcher->expects($this->never())->method('match'); + + $this->subscriber->evaluateFilters($event); + } + + public function testEvaluateFiltersSkipsWhenPluginDisabled(): void + { + $this->configProvider->expects($this->once()) ->method('pluginIsEnabled') ->willReturn(false); $this->queryFilterFactory->expects($this->never())->method('configureQueryBuilderFromSegmentFilter'); + $this->contactFilterMatcher->expects($this->never())->method('match'); - $this->dynamicContentSubscriber->evaluateFilters($this->buildEventWithFilters()); + $this->subscriber->evaluateFilters($this->buildEvent()); } - public function testFiltersNotEvaluatedIfEventMarkedEvaluated(): void + public function testEvaluateFiltersSkipsWhenNoCustomObjectFiltersFound(): void { - $this->configProviderMock->expects($this->once())->method('pluginIsEnabled')->willReturn(true); + $this->configProvider->expects($this->once()) + ->method('pluginIsEnabled') + ->willReturn(true); - $event = $this->buildEventWithFilters(); - $event->setIsEvaluated(true); + // All filters throw → no custom object filters present + $this->queryFilterFactory->expects($this->exactly(2)) + ->method('configureQueryBuilderFromSegmentFilter') + ->willThrowException(new InvalidSegmentFilterException('not a CO filter')); - $this->queryFilterFactory->expects($this->never())->method('configureQueryBuilderFromSegmentFilter'); + $this->contactFilterMatcher->expects($this->never())->method('match'); - $this->dynamicContentSubscriber->evaluateFilters($event); + $event = $this->buildEvent(); + $this->subscriber->evaluateFilters($event); + + $this->assertFalse($event->isEvaluated()); } - public function testFiltersInsertedIntoEvent(): void + public function testEvaluateFiltersMatchesAndSetsResultOnEvent(): void { - $this->configProviderMock->expects($this->once())->method('pluginIsEnabled')->willReturn(true); + $contact = new Lead(); + $contact->setFields(['email' => 'test@example.com']); + + $event = new ContactFiltersEvaluateEvent($this->buildFilters(), $contact); + $this->configProvider->expects($this->once()) + ->method('pluginIsEnabled') + ->willReturn(true); + + // First filter throws (not a CO filter), second succeeds → hasCustomObjectFilters returns true $this->queryFilterFactory->expects($this->exactly(2)) ->method('configureQueryBuilderFromSegmentFilter') - ->withConsecutive( - [ - [ - 'type' => CustomFieldFilterQueryBuilder::getServiceId(), - 'table' => 'custom_field_text', - 'field' => 'cfwq_1', - 'foreign_table' => 'custom_objects', - ], - 'filter_custom_field_1', - ], - [ - [ - 'type' => CustomItemNameFilterQueryBuilder::getServiceId(), - 'table' => 'custom_field_text', - 'field' => 'cowq_2', - 'foreign_table' => 'custom_objects', - ], - 'filter_custom_item_1', - ] - ) ->will($this->onConsecutiveCalls( - $this->queryBuilderMock, - $this->throwException(new InvalidSegmentFilterException('Testing invalid segment handling here.')) + $this->throwException(new InvalidSegmentFilterException('not a CO filter')), + $this->returnValue(null), )); - $event = $this->buildEventWithFilters(); - $event->setIsEvaluated(false); + $this->contactFilterMatcher->expects($this->once()) + ->method('match') + ->with($this->buildFilters(), ['email' => 'test@example.com']) + ->willReturn(true); + + $this->subscriber->evaluateFilters($event); + + $this->assertTrue($event->isEvaluated()); + $this->assertTrue($event->isMatched()); + } + + public function testEvaluateFiltersSetsMismatchOnEvent(): void + { + $contact = new Lead(); + $contact->setFields([]); + + $event = new ContactFiltersEvaluateEvent($this->buildFilters(), $contact); - $result = $this->createMock(Result::class); + $this->configProvider->method('pluginIsEnabled')->willReturn(true); - $this->queryBuilderMock->expects($this->once()) - ->method('execute') - ->willReturn($result); + // First filter is a valid CO filter → hasCustomObjectFilters returns true immediately + $this->queryFilterFactory->expects($this->once()) + ->method('configureQueryBuilderFromSegmentFilter') + ->willReturn(null); - $this->loggerMock - ->expects($this->never()) - ->method('error'); + $this->contactFilterMatcher->expects($this->once()) + ->method('match') + ->willReturn(false); - $this->dynamicContentSubscriber->evaluateFilters($event); + $this->subscriber->evaluateFilters($event); + + $this->assertTrue($event->isEvaluated()); + $this->assertFalse($event->isMatched()); } - private function buildEventWithFilters(): ContactFiltersEvaluateEvent + /** + * @return mixed[] + */ + private function buildFilters(): array { - return new ContactFiltersEvaluateEvent( - [ - 'custom_field_1' => [ - 'type' => CustomFieldFilterQueryBuilder::getServiceId(), - 'table' => 'custom_field_text', - 'field' => 'cfwq_1', - 'foreign_table' => 'custom_objects', - ], - 'custom_item_1' => [ - 'type' => CustomItemNameFilterQueryBuilder::getServiceId(), - 'table' => 'custom_field_text', - 'field' => 'cowq_2', - 'foreign_table' => 'custom_objects', - ], + return [ + 'custom_field_1' => [ + 'type' => CustomFieldFilterQueryBuilder::getServiceId(), + 'table' => 'custom_field_text', + 'field' => 'cfwq_1', + 'foreign_table' => 'custom_objects', ], - new Lead() - ); + 'custom_item_1' => [ + 'type' => CustomItemNameFilterQueryBuilder::getServiceId(), + 'table' => 'custom_field_text', + 'field' => 'cowq_2', + 'foreign_table' => 'custom_objects', + ], + ]; + } + + private function buildEvent(): ContactFiltersEvaluateEvent + { + return new ContactFiltersEvaluateEvent($this->buildFilters(), new Lead()); } } From 6f22f418720a57bf6d2c4ea901cf99d5117e7633 Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Mon, 9 Mar 2026 22:40:18 +0100 Subject: [PATCH 04/25] refactor(ContactFilterMatcher): remove class_alias pattern, use polyfill trait directly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- Helper/ContactFilterMatcher.php | 13 +++---------- phpstan-baseline.neon | 10 ++++++++++ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Helper/ContactFilterMatcher.php b/Helper/ContactFilterMatcher.php index 28ab162bb..726b128f1 100644 --- a/Helper/ContactFilterMatcher.php +++ b/Helper/ContactFilterMatcher.php @@ -5,7 +5,6 @@ namespace MauticPlugin\CustomObjectsBundle\Helper; use Doctrine\DBAL\Connection; -use Mautic\EmailBundle\EventListener\MatchFilterForLeadTrait; use Mautic\LeadBundle\Entity\CompanyRepository; use Mautic\LeadBundle\Entity\LeadListRepository; use MauticPlugin\CustomObjectsBundle\DTO\TableConfig; @@ -18,16 +17,10 @@ use MauticPlugin\CustomObjectsBundle\Model\CustomObjectModel; use MauticPlugin\CustomObjectsBundle\Polyfill\EventListener\MatchFilterForLeadTrait as MatchFilterForLeadTraitPolyfill; -if (method_exists(MatchFilterForLeadTrait::class, 'transformFilterDataForLead')) { - class_alias(MatchFilterForLeadTrait::class, '\MauticPlugin\CustomObjectsBundle\Helper\MatchFilterForLeadTraitAlias'); -} else { - class_alias(MatchFilterForLeadTraitPolyfill::class, '\MauticPlugin\CustomObjectsBundle\Helper\MatchFilterForLeadTraitAlias'); -} - class ContactFilterMatcher { - use MatchFilterForLeadTraitAlias { - transformFilterDataForLead as transformFilterDataForLeadAlias; + use MatchFilterForLeadTraitPolyfill { + transformFilterDataForLead as transformFilterDataForLeadPolyfill; } private CustomFieldModel $customFieldModel; @@ -201,7 +194,7 @@ private function transformFilterDataForLead(array $data, array $lead): ?array return $lead[$data['field']]; } - return $this->transformFilterDataForLeadAlias($data, $lead); + return $this->transformFilterDataForLeadPolyfill($data, $lead); } /** diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 59bfd9961..4446d50f3 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -692,6 +692,16 @@ parameters: count: 1 path: Tests/Unit/Segment/Query/UnionQueryContainerTest.php + - + message: "#^Constant MAUTIC_TABLE_PREFIX not found\\.$#" + count: 1 + path: Helper/ContactFilterMatcher.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\ContactFilterMatcher\\:\\:transformFilterDataForLead\\(\\) is unused\\.$#" + count: 1 + path: Helper/ContactFilterMatcher.php + - message: """ #^Fetching deprecated class constant PARAM_INT_ARRAY of class Doctrine\\\\DBAL\\\\Connection\\: From 8c8f3005cd2e9c4068a903f024e3f5e9aa43b228 Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Tue, 10 Mar 2026 21:44:19 +0100 Subject: [PATCH 05/25] refactor(config): remove explicit service definitions, use autowiring 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 --- Config/config.php | 22 ++-------------------- Config/services.php | 3 ++- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/Config/config.php b/Config/config.php index a3156c846..318024d42 100644 --- a/Config/config.php +++ b/Config/config.php @@ -413,14 +413,7 @@ '%mautic.custom_item_fetch_limit_per_lead%', ], ], - 'custom_object.dynamic_content.subscriber' => [ - 'class' => MauticPlugin\CustomObjectsBundle\EventListener\DynamicContentSubscriber::class, - 'arguments' => [ - 'custom_object.query.filter.factory', - 'custom_object.helper.contact_filter_matcher', - 'custom_object.config.provider', - ], - ], + ], 'forms' => [ 'custom_field.field.params.to.string.transformer' => [ @@ -644,18 +637,7 @@ 'custom_object.helper.token_formatter' => [ 'class' => MauticPlugin\CustomObjectsBundle\Helper\TokenFormatter::class, ], - 'custom_object.helper.contact_filter_matcher' => [ - 'class' => MauticPlugin\CustomObjectsBundle\Helper\ContactFilterMatcher::class, - 'arguments' => [ - 'mautic.custom.model.field', - 'mautic.custom.model.object', - 'mautic.custom.model.item', - 'mautic.lead.repository.lead_list', - 'mautic.lead.repository.company', - 'doctrine.dbal.default_connection', - '%mautic.custom_item_fetch_limit_per_lead%', - ], - ], + 'custom_object.data_persister.custom_item' => [ 'class' => MauticPlugin\CustomObjectsBundle\DataPersister\CustomItemDataPersister::class, 'tag' => 'api_platform.data_persister', diff --git a/Config/services.php b/Config/services.php index 2f7e94f21..397ae0627 100644 --- a/Config/services.php +++ b/Config/services.php @@ -10,7 +10,8 @@ ->defaults() ->autowire() ->autoconfigure() - ->public(); + ->public() + ->bind('int $leadCustomItemFetchLimit', '%mautic.custom_item_fetch_limit_per_lead%'); $excludes = [ 'Provider/SessionProvider.php', From e49bc8d53132d9ced6ec79899f7ece332934d1b6 Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Wed, 11 Mar 2026 14:47:13 +0100 Subject: [PATCH 06/25] refactor(ContactFilterMatcher): use #[Autowire] for scalar parameter 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.). --- Config/services.php | 3 +-- Helper/ContactFilterMatcher.php | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Config/services.php b/Config/services.php index 397ae0627..2f7e94f21 100644 --- a/Config/services.php +++ b/Config/services.php @@ -10,8 +10,7 @@ ->defaults() ->autowire() ->autoconfigure() - ->public() - ->bind('int $leadCustomItemFetchLimit', '%mautic.custom_item_fetch_limit_per_lead%'); + ->public(); $excludes = [ 'Provider/SessionProvider.php', diff --git a/Helper/ContactFilterMatcher.php b/Helper/ContactFilterMatcher.php index 726b128f1..93b5482c7 100644 --- a/Helper/ContactFilterMatcher.php +++ b/Helper/ContactFilterMatcher.php @@ -7,6 +7,7 @@ use Doctrine\DBAL\Connection; use Mautic\LeadBundle\Entity\CompanyRepository; use Mautic\LeadBundle\Entity\LeadListRepository; +use Symfony\Component\DependencyInjection\Attribute\Autowire; use MauticPlugin\CustomObjectsBundle\DTO\TableConfig; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; @@ -37,6 +38,7 @@ public function __construct( LeadListRepository $segmentRepository, CompanyRepository $companyRepository, Connection $connection, + #[Autowire(param: 'mautic.custom_item_fetch_limit_per_lead')] int $leadCustomItemFetchLimit ) { $this->customFieldModel = $customFieldModel; From 442f0af1065c46b0f91e4a6edae7a3caec198682 Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Wed, 11 Mar 2026 16:14:08 +0100 Subject: [PATCH 07/25] test(ContactFilterMatcher): add unit tests 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. --- .../Unit/Helper/ContactFilterMatcherTest.php | 295 ++++++++++++++++++ 1 file changed, 295 insertions(+) create mode 100644 Tests/Unit/Helper/ContactFilterMatcherTest.php diff --git a/Tests/Unit/Helper/ContactFilterMatcherTest.php b/Tests/Unit/Helper/ContactFilterMatcherTest.php new file mode 100644 index 000000000..16b1b977d --- /dev/null +++ b/Tests/Unit/Helper/ContactFilterMatcherTest.php @@ -0,0 +1,295 @@ +customFieldModel = $this->createMock(CustomFieldModel::class); + $this->customObjectModel = $this->createMock(CustomObjectModel::class); + $this->customItemModel = $this->createMock(CustomItemModel::class); + $this->segmentRepository = $this->createMock(LeadListRepository::class); + $this->companyRepository = $this->createMock(CompanyRepository::class); + $this->connection = $this->createMock(Connection::class); + + $this->matcher = new ContactFilterMatcher( + $this->customFieldModel, + $this->customObjectModel, + $this->customItemModel, + $this->segmentRepository, + $this->companyRepository, + $this->connection, + 10 + ); + } + + public function testMatchReturnsFalseWhenNoCustomObjectFiltersPresent(): void + { + $filters = [ + $this->buildLeadFilter('email', '=', 'test@example.com'), + ]; + + $hasCustomFields = false; + $result = $this->matcher->match($filters, ['id' => 1, 'email' => 'test@example.com'], $hasCustomFields); + + $this->assertFalse($result); + $this->assertFalse($hasCustomFields); + $this->customObjectModel->expects($this->never())->method('fetchEntity'); + } + + public function testMatchReturnsFalseWhenCustomObjectFetchThrowsNotFoundException(): void + { + $this->customObjectModel->method('fetchEntity') + ->willThrowException(new NotFoundException('Custom object not found')); + + $hasCustomFields = false; + $result = $this->matcher->match([$this->buildCmoFilter('cmo_1', '=', 'Acme')], ['id' => 42], $hasCustomFields); + + $this->assertFalse($result); + $this->assertFalse($hasCustomFields); + } + + public function testMatchReturnsFalseWhenCustomObjectFetchThrowsInvalidCustomObjectFormatListException(): void + { + $this->customObjectModel->method('fetchEntity') + ->willThrowException(new InvalidCustomObjectFormatListException('bad format')); + + $hasCustomFields = false; + $result = $this->matcher->match([$this->buildCmoFilter('cmo_1', '=', 'Acme')], ['id' => 42], $hasCustomFields); + + $this->assertFalse($result); + $this->assertFalse($hasCustomFields); + } + + public function testMatchReturnsFalseWhenContactHasNoLinkedCustomItems(): void + { + $this->customObjectModel->method('fetchEntity')->willReturn($this->buildCustomObject(5)); + $this->customItemModel->method('getArrayTableData')->willReturn([]); + + $hasCustomFields = false; + $result = $this->matcher->match([$this->buildCmoFilter('cmo_5', '=', 'Acme')], ['id' => 42], $hasCustomFields); + + $this->assertFalse($result); + // hasCustomFields is true because the CO filter was found and processed + $this->assertTrue($hasCustomFields); + } + + public function testMatchReturnsTrueWhenItemNameMatchesEqualFilter(): void + { + $this->customObjectModel->method('fetchEntity')->willReturn($this->buildCustomObject(3)); + $this->customItemModel->method('getArrayTableData')->willReturn([['name' => 'Acme Corp']]); + + $result = $this->matcher->match([$this->buildCmoFilter('cmo_3', '=', 'Acme Corp')], ['id' => 42]); + + $this->assertTrue($result); + } + + public function testMatchReturnsFalseWhenItemNameDoesNotMatchEqualFilter(): void + { + $this->customObjectModel->method('fetchEntity')->willReturn($this->buildCustomObject(3)); + $this->customItemModel->method('getArrayTableData')->willReturn([['name' => 'Wrong Corp']]); + + $result = $this->matcher->match([$this->buildCmoFilter('cmo_3', '=', 'Acme Corp')], ['id' => 42]); + + $this->assertFalse($result); + } + + public function testMatchReturnsTrueWhenAnyLinkedItemNameMatchesFilter(): void + { + $this->customObjectModel->method('fetchEntity')->willReturn($this->buildCustomObject(3)); + $this->customItemModel->method('getArrayTableData')->willReturn([ + ['name' => 'First Item'], + ['name' => 'Acme Corp'], + ['name' => 'Third Item'], + ]); + + $result = $this->matcher->match([$this->buildCmoFilter('cmo_3', '=', 'Acme Corp')], ['id' => 42]); + + $this->assertTrue($result); + } + + public function testMatchSetsHasCustomFieldsToTrueWhenCustomObjectFilterIsProcessed(): void + { + $this->customObjectModel->method('fetchEntity')->willReturn($this->buildCustomObject(1)); + $this->customItemModel->method('getArrayTableData')->willReturn([['name' => 'Any']]); + + $hasCustomFields = false; + $this->matcher->match([$this->buildCmoFilter('cmo_1', '=', 'Any')], ['id' => 42], $hasCustomFields); + + $this->assertTrue($hasCustomFields); + } + + public function testCustomItemsAreFetchedOncePerObjectAndLeadAcrossMultipleFilters(): void + { + $this->customObjectModel->method('fetchEntity')->willReturn($this->buildCustomObject(1)); + + $this->customItemModel->expects($this->once()) + ->method('getArrayTableData') + ->willReturn([['name' => 'Acme']]); + + $filters = [ + $this->buildCmoFilter('cmo_1', '=', 'Acme'), + $this->buildCmoFilter('cmo_1', '!=', 'Other'), + ]; + + $this->matcher->match($filters, ['id' => 42]); + } + + public function testMatchFetchesCompanyDataWhenFilterFieldStartsWithCompany(): void + { + $this->customObjectModel->method('fetchEntity')->willReturn($this->buildCustomObject(1)); + $this->customItemModel->method('getArrayTableData')->willReturn([['name' => 'Test']]); + + $this->companyRepository->expects($this->once()) + ->method('getCompaniesByLeadId') + ->with('42') + ->willReturn([]); + + $filters = [ + $this->buildCmoFilter('cmo_1', '=', 'Test'), + $this->buildLeadFilter('companycountry', '=', 'US'), + ]; + + $this->matcher->match($filters, ['id' => 42]); + } + + public function testMatchDoesNotFetchCompanyDataWhenLeadAlreadyHasCompanies(): void + { + $this->customObjectModel->method('fetchEntity')->willReturn($this->buildCustomObject(1)); + $this->customItemModel->method('getArrayTableData')->willReturn([['name' => 'Test']]); + + $this->companyRepository->expects($this->never())->method('getCompaniesByLeadId'); + + $filters = [ + $this->buildCmoFilter('cmo_1', '=', 'Test'), + $this->buildLeadFilter('companycountry', '=', 'US'), + ]; + + $this->matcher->match($filters, ['id' => 42, 'companies' => [['companycountry' => 'US']]]); + } + + public function testMatchFetchesTagsWhenFilterTypeIsTags(): void + { + $this->customObjectModel->method('fetchEntity')->willReturn($this->buildCustomObject(1)); + $this->customItemModel->method('getArrayTableData')->willReturn([['name' => 'Test']]); + + $result = $this->createMock(Result::class); + $queryBuilder = $this->createMock(DbalQueryBuilder::class); + $result->method('fetchFirstColumn')->willReturn(['1', '5']); + $queryBuilder->method('select')->willReturnSelf(); + $queryBuilder->method('from')->willReturnSelf(); + $queryBuilder->method('where')->willReturnSelf(); + $queryBuilder->method('setParameter')->willReturnSelf(); + $queryBuilder->method('execute')->willReturn($result); + + $this->connection->expects($this->once()) + ->method('createQueryBuilder') + ->willReturn($queryBuilder); + + $filters = [ + $this->buildCmoFilter('cmo_1', '=', 'Test'), + ['object' => 'lead', 'field' => 'tags', 'type' => 'tags', 'operator' => 'in', 'filter' => ['1'], 'glue' => 'and'], + ]; + + $this->matcher->match($filters, ['id' => 42]); + } + + public function testMatchDoesNotFetchTagsWhenLeadAlreadyHasTags(): void + { + $this->customObjectModel->method('fetchEntity')->willReturn($this->buildCustomObject(1)); + $this->customItemModel->method('getArrayTableData')->willReturn([['name' => 'Test']]); + + $this->connection->expects($this->never())->method('createQueryBuilder'); + + $filters = [ + $this->buildCmoFilter('cmo_1', '=', 'Test'), + ['object' => 'lead', 'field' => 'tags', 'type' => 'tags', 'operator' => 'in', 'filter' => ['1'], 'glue' => 'and'], + ]; + + $this->matcher->match($filters, ['id' => 42, 'tags' => ['1', '5']]); + } + + // Helpers + + private function buildCustomObject(int $id): CustomObject&MockObject + { + $customObject = $this->createMock(CustomObject::class); + $customObject->method('getId')->willReturn($id); + + return $customObject; + } + + /** + * @return mixed[] + */ + private function buildCmoFilter(string $field, string $operator, string $filterValue): array + { + return [ + 'object' => 'custom_object', + 'field' => $field, + 'type' => 'text', + 'operator' => $operator, + 'filter' => $filterValue, + 'glue' => 'and', + ]; + } + + /** + * @return mixed[] + */ + private function buildLeadFilter(string $field, string $operator, string $filterValue): array + { + return [ + 'object' => 'lead', + 'field' => $field, + 'type' => 'text', + 'operator' => $operator, + 'filter' => $filterValue, + 'glue' => 'and', + ]; + } +} From 3a9335ab4c52b9d0693869b03d64f752d80067ba Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Wed, 11 Mar 2026 16:40:00 +0100 Subject: [PATCH 08/25] fix(ContactFilterMatcher): replace deprecated DBAL execute() with executeQuery() --- Helper/ContactFilterMatcher.php | 2 +- Tests/Unit/Helper/ContactFilterMatcherTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Helper/ContactFilterMatcher.php b/Helper/ContactFilterMatcher.php index 93b5482c7..21de1b6e4 100644 --- a/Helper/ContactFilterMatcher.php +++ b/Helper/ContactFilterMatcher.php @@ -209,7 +209,7 @@ public function getTagIdsByLeadId(string $leadId): array ->from(MAUTIC_TABLE_PREFIX.'lead_tags_xref', 'x') ->where('x.lead_id = :leadId') ->setParameter('leadId', $leadId) - ->execute() + ->executeQuery() ->fetchFirstColumn(); } } diff --git a/Tests/Unit/Helper/ContactFilterMatcherTest.php b/Tests/Unit/Helper/ContactFilterMatcherTest.php index 16b1b977d..69994cabe 100644 --- a/Tests/Unit/Helper/ContactFilterMatcherTest.php +++ b/Tests/Unit/Helper/ContactFilterMatcherTest.php @@ -224,7 +224,7 @@ public function testMatchFetchesTagsWhenFilterTypeIsTags(): void $queryBuilder->method('from')->willReturnSelf(); $queryBuilder->method('where')->willReturnSelf(); $queryBuilder->method('setParameter')->willReturnSelf(); - $queryBuilder->method('execute')->willReturn($result); + $queryBuilder->method('executeQuery')->willReturn($result); $this->connection->expects($this->once()) ->method('createQueryBuilder') From 7227295d4c5b39a7f384e0dcd347bfaa4671cecc Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Wed, 11 Mar 2026 16:55:07 +0100 Subject: [PATCH 09/25] fix(MatchFilterForLeadTrait): handle empty operator when no custom items linked MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .../EventListener/MatchFilterForLeadTrait.php | 6 +++++ .../Unit/Helper/ContactFilterMatcherTest.php | 22 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/Polyfill/EventListener/MatchFilterForLeadTrait.php b/Polyfill/EventListener/MatchFilterForLeadTrait.php index 19304737e..6d3ecc16e 100644 --- a/Polyfill/EventListener/MatchFilterForLeadTrait.php +++ b/Polyfill/EventListener/MatchFilterForLeadTrait.php @@ -67,6 +67,12 @@ protected function matchFilterForLead(array $filter, array $lead): bool $subgroup = null; if (is_array($leadValues)) { + if ('custom_object' === $data['object'] && [] === $leadValues) { + // No custom items linked to this contact: only 'empty' is true. + $groups[$groupNum] = 'empty' === $data['operator']; + continue; + } + foreach ($leadValues as $leadVal) { if ($subgroup) { break; diff --git a/Tests/Unit/Helper/ContactFilterMatcherTest.php b/Tests/Unit/Helper/ContactFilterMatcherTest.php index 69994cabe..84f4d692f 100644 --- a/Tests/Unit/Helper/ContactFilterMatcherTest.php +++ b/Tests/Unit/Helper/ContactFilterMatcherTest.php @@ -118,6 +118,28 @@ public function testMatchReturnsFalseWhenContactHasNoLinkedCustomItems(): void $this->assertTrue($hasCustomFields); } + public function testMatchReturnsTrueForEmptyOperatorWhenContactHasNoLinkedItems(): void + { + $this->customObjectModel->method('fetchEntity')->willReturn($this->buildCustomObject(1)); + $this->customItemModel->method('getArrayTableData')->willReturn([]); + + $filter = array_merge($this->buildCmoFilter('cmo_1', 'empty', ''), ['type' => 'text']); + $result = $this->matcher->match([$filter], ['id' => 42]); + + $this->assertTrue($result); + } + + public function testMatchReturnsFalseForNotEmptyOperatorWhenContactHasNoLinkedItems(): void + { + $this->customObjectModel->method('fetchEntity')->willReturn($this->buildCustomObject(1)); + $this->customItemModel->method('getArrayTableData')->willReturn([]); + + $filter = array_merge($this->buildCmoFilter('cmo_1', '!empty', ''), ['type' => 'text']); + $result = $this->matcher->match([$filter], ['id' => 42]); + + $this->assertFalse($result); + } + public function testMatchReturnsTrueWhenItemNameMatchesEqualFilter(): void { $this->customObjectModel->method('fetchEntity')->willReturn($this->buildCustomObject(3)); From 63639a800f1c15c9ed46ca1b7f169aed05a34d24 Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Wed, 11 Mar 2026 17:14:15 +0100 Subject: [PATCH 10/25] fix(ContactFilterMatcher): replace #[Autowire] with explicit arg binding in services.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- Config/services.php | 4 ++++ Helper/ContactFilterMatcher.php | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Config/services.php b/Config/services.php index 2f7e94f21..12d09dda3 100644 --- a/Config/services.php +++ b/Config/services.php @@ -3,6 +3,7 @@ declare(strict_types=1); use Mautic\CoreBundle\DependencyInjection\MauticCoreExtension; +use MauticPlugin\CustomObjectsBundle\Helper\ContactFilterMatcher; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; return function (ContainerConfigurator $configurator): void { @@ -23,4 +24,7 @@ ->exclude('../{'.implode(',', array_merge(MauticCoreExtension::DEFAULT_EXCLUDES, $excludes)).'}'); $services->load('MauticPlugin\\CustomObjectsBundle\\Repository\\', '../Repository/*Repository.php'); + + $services->set(ContactFilterMatcher::class) + ->arg('$leadCustomItemFetchLimit', '%mautic.custom_item_fetch_limit_per_lead%'); }; diff --git a/Helper/ContactFilterMatcher.php b/Helper/ContactFilterMatcher.php index 21de1b6e4..53c436288 100644 --- a/Helper/ContactFilterMatcher.php +++ b/Helper/ContactFilterMatcher.php @@ -7,7 +7,6 @@ use Doctrine\DBAL\Connection; use Mautic\LeadBundle\Entity\CompanyRepository; use Mautic\LeadBundle\Entity\LeadListRepository; -use Symfony\Component\DependencyInjection\Attribute\Autowire; use MauticPlugin\CustomObjectsBundle\DTO\TableConfig; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; @@ -38,7 +37,6 @@ public function __construct( LeadListRepository $segmentRepository, CompanyRepository $companyRepository, Connection $connection, - #[Autowire(param: 'mautic.custom_item_fetch_limit_per_lead')] int $leadCustomItemFetchLimit ) { $this->customFieldModel = $customFieldModel; From 57cf15aee7c80aecce82e87639a73724cda02b85 Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Wed, 11 Mar 2026 17:38:35 +0100 Subject: [PATCH 11/25] ci: add fix/** branch trigger and workflow_dispatch for local testing --- .github/workflows/tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c84493d07..73fb6088f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,7 +7,9 @@ on: - '[0-9]+\.[0-9]+' - development - beta + - 'fix/**' pull_request: + workflow_dispatch: env: PLUGIN_DIR: plugins/CustomObjectsBundle # Same as extra.install-directory-name in composer.json From 4878ed9665fa5bff84d9ed4edda1e83fdeeb26bd Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Wed, 11 Mar 2026 17:42:27 +0100 Subject: [PATCH 12/25] fix(cs): remove extra blank line, extra parentheses, and PHP 8.1 intersection type --- Config/config.php | 1 - Polyfill/EventListener/MatchFilterForLeadTrait.php | 2 +- Tests/Unit/Helper/ContactFilterMatcherTest.php | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Config/config.php b/Config/config.php index 318024d42..172650282 100644 --- a/Config/config.php +++ b/Config/config.php @@ -413,7 +413,6 @@ '%mautic.custom_item_fetch_limit_per_lead%', ], ], - ], 'forms' => [ 'custom_field.field.params.to.string.transformer' => [ diff --git a/Polyfill/EventListener/MatchFilterForLeadTrait.php b/Polyfill/EventListener/MatchFilterForLeadTrait.php index 6d3ecc16e..885040593 100644 --- a/Polyfill/EventListener/MatchFilterForLeadTrait.php +++ b/Polyfill/EventListener/MatchFilterForLeadTrait.php @@ -214,7 +214,7 @@ private function doFiltersContainCompanyFilter(array $filters): bool return true; } - if ((0 === strpos($filter['field'], 'company') && 'company' !== $filter['field'])) { + if (0 === strpos($filter['field'], 'company') && 'company' !== $filter['field']) { return true; } } diff --git a/Tests/Unit/Helper/ContactFilterMatcherTest.php b/Tests/Unit/Helper/ContactFilterMatcherTest.php index 84f4d692f..d9cadf4ec 100644 --- a/Tests/Unit/Helper/ContactFilterMatcherTest.php +++ b/Tests/Unit/Helper/ContactFilterMatcherTest.php @@ -277,7 +277,7 @@ public function testMatchDoesNotFetchTagsWhenLeadAlreadyHasTags(): void // Helpers - private function buildCustomObject(int $id): CustomObject&MockObject + private function buildCustomObject(int $id): MockObject { $customObject = $this->createMock(CustomObject::class); $customObject->method('getId')->willReturn($id); From ecd58ed36fce28fd233e4307ddefacbb770488b4 Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Wed, 11 Mar 2026 21:19:04 +0100 Subject: [PATCH 13/25] fix(tests): remove MAUTIC_TABLE_PREFIX define from test file (defined in bootstrap) --- Tests/Unit/Helper/ContactFilterMatcherTest.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Tests/Unit/Helper/ContactFilterMatcherTest.php b/Tests/Unit/Helper/ContactFilterMatcherTest.php index d9cadf4ec..d29482d28 100644 --- a/Tests/Unit/Helper/ContactFilterMatcherTest.php +++ b/Tests/Unit/Helper/ContactFilterMatcherTest.php @@ -4,10 +4,6 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Unit\Helper; -if (!defined('MAUTIC_TABLE_PREFIX')) { - define('MAUTIC_TABLE_PREFIX', ''); -} - use Doctrine\DBAL\Connection; use Doctrine\DBAL\Query\QueryBuilder as DbalQueryBuilder; use Doctrine\DBAL\Result; From c7302cbde639d763232a96c7e367aa9dee61fcbb Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Wed, 11 Mar 2026 21:25:11 +0100 Subject: [PATCH 14/25] fix(phpstan): add baseline entry for transformFilterDataForLeadPolyfill return type --- phpstan-baseline.neon | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 4446d50f3..211fc53ea 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -702,6 +702,11 @@ parameters: count: 1 path: Helper/ContactFilterMatcher.php + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\ContactFilterMatcher\\:\\:transformFilterDataForLeadPolyfill\\(\\) never returns array so it can be removed from the return type\\.$#" + count: 1 + path: Polyfill/EventListener/MatchFilterForLeadTrait.php + - message: """ #^Fetching deprecated class constant PARAM_INT_ARRAY of class Doctrine\\\\DBAL\\\\Connection\\: From 6002c357819ca166aee84ed5214276dc2fed08a8 Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Wed, 11 Mar 2026 21:30:37 +0100 Subject: [PATCH 15/25] refactor: apply Rector rules (constructor promotion, str_starts_with, non-capturing catches) --- EventListener/DynamicContentSubscriber.php | 2 +- Helper/ContactFilterMatcher.php | 37 ++++++------------- .../EventListener/MatchFilterForLeadTrait.php | 8 ++-- 3 files changed, 15 insertions(+), 32 deletions(-) diff --git a/EventListener/DynamicContentSubscriber.php b/EventListener/DynamicContentSubscriber.php index e72fa4bd3..a2bd8839e 100644 --- a/EventListener/DynamicContentSubscriber.php +++ b/EventListener/DynamicContentSubscriber.php @@ -58,7 +58,7 @@ private function hasCustomObjectFilters(array $filters): bool $this->queryFilterFactory->configureQueryBuilderFromSegmentFilter($filter, 'filter'); return true; - } catch (InvalidSegmentFilterException $e) { + } catch (InvalidSegmentFilterException) { } } diff --git a/Helper/ContactFilterMatcher.php b/Helper/ContactFilterMatcher.php index 53c436288..503533ed7 100644 --- a/Helper/ContactFilterMatcher.php +++ b/Helper/ContactFilterMatcher.php @@ -23,29 +23,16 @@ class ContactFilterMatcher transformFilterDataForLead as transformFilterDataForLeadPolyfill; } - private CustomFieldModel $customFieldModel; - private CustomObjectModel $customObjectModel; - private CustomItemModel $customItemModel; - private CompanyRepository $companyRepository; - private Connection $connection; - private int $leadCustomItemFetchLimit; - public function __construct( - CustomFieldModel $customFieldModel, - CustomObjectModel $customObjectModel, - CustomItemModel $customItemModel, + private CustomFieldModel $customFieldModel, + private CustomObjectModel $customObjectModel, + private CustomItemModel $customItemModel, LeadListRepository $segmentRepository, - CompanyRepository $companyRepository, - Connection $connection, - int $leadCustomItemFetchLimit + private CompanyRepository $companyRepository, + private Connection $connection, + private int $leadCustomItemFetchLimit ) { - $this->customFieldModel = $customFieldModel; - $this->customObjectModel = $customObjectModel; - $this->customItemModel = $customItemModel; - $this->segmentRepository = $segmentRepository; - $this->companyRepository = $companyRepository; - $this->connection = $connection; - $this->leadCustomItemFetchLimit = $leadCustomItemFetchLimit; + $this->segmentRepository = $segmentRepository; } /** @@ -90,13 +77,13 @@ private function getCustomFieldDataForLead(array $filters, string $leadId): arra continue; } - if ('cmf_' === substr($condition['field'], 0, 4)) { + if (str_starts_with($condition['field'], 'cmf_')) { $customField = $this->customFieldModel->fetchEntity( (int) explode('cmf_', $condition['field'])[1] ); $customObject = $customField->getCustomObject(); $fieldAlias = $customField->getAlias(); - } elseif ('cmo_' === substr($condition['field'], 0, 4)) { + } elseif (str_starts_with($condition['field'], 'cmo_')) { $customObject = $this->customObjectModel->fetchEntity( (int) explode('cmo_', $condition['field'])[1] ); @@ -113,7 +100,7 @@ private function getCustomFieldDataForLead(array $filters, string $leadId): arra $result = $this->getCustomFieldValue($customObject, $fieldAlias, $cachedCustomItems[$key]); $customFieldValues[$condition['field']] = $result; - } catch (NotFoundException|InvalidCustomObjectFormatListException $e) { + } catch (NotFoundException|InvalidCustomObjectFormatListException) { continue; } } @@ -158,7 +145,7 @@ private function getCustomFieldValue( } else { $fieldValues[] = $fieldValue->getCustomField()->getTypeObject()->valueToString($fieldValue); } - } catch (NotFoundException $e) { + } catch (NotFoundException) { // Custom field not found. } } @@ -185,8 +172,6 @@ private function getCustomItems(CustomObject $customObject, string $leadId): arr /** * @param mixed[] $data * @param mixed[] $lead - * - * @return ?mixed[] */ private function transformFilterDataForLead(array $data, array $lead): ?array { diff --git a/Polyfill/EventListener/MatchFilterForLeadTrait.php b/Polyfill/EventListener/MatchFilterForLeadTrait.php index 885040593..269e4bb42 100644 --- a/Polyfill/EventListener/MatchFilterForLeadTrait.php +++ b/Polyfill/EventListener/MatchFilterForLeadTrait.php @@ -170,14 +170,14 @@ protected function matchFilterForLead(array $filter, array $lead): bool $groups[$groupNum] = 1 !== preg_match('/'.$filterVal.'/i', $leadVal); break; case 'startsWith': - $groups[$groupNum] = 0 === strncmp($leadVal, $filterVal, strlen($filterVal)); + $groups[$groupNum] = str_starts_with($leadVal, $filterVal); break; case 'endsWith': $endOfString = substr($leadVal, strlen($leadVal) - strlen($filterVal)); $groups[$groupNum] = 0 === strcmp($endOfString, $filterVal); break; case 'contains': - $groups[$groupNum] = false !== strpos((string) $leadVal, (string) $filterVal); + $groups[$groupNum] = str_contains((string) $leadVal, (string) $filterVal); break; default: throw new OperatorsNotFoundException('Operator is not defined or invalid operator found.'); @@ -194,8 +194,6 @@ protected function matchFilterForLead(array $filter, array $lead): bool /** * @param mixed[] $data * @param mixed[] $lead - * - * @return ?mixed[] */ private function transformFilterDataForLead(array $data, array $lead): ?array { @@ -214,7 +212,7 @@ private function doFiltersContainCompanyFilter(array $filters): bool return true; } - if (0 === strpos($filter['field'], 'company') && 'company' !== $filter['field']) { + if (str_starts_with($filter['field'], 'company') && 'company' !== $filter['field']) { return true; } } From 99974b5b2f4ed841c3396f3ca9ce266e2dd4c063 Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Wed, 11 Mar 2026 21:34:37 +0100 Subject: [PATCH 16/25] fix(phpstan): suppress array element type errors for transformFilterDataForLead methods --- phpstan-baseline.neon | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 211fc53ea..bc030b658 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -707,6 +707,16 @@ parameters: count: 1 path: Polyfill/EventListener/MatchFilterForLeadTrait.php + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\ContactFilterMatcher\\:\\:transformFilterDataForLeadPolyfill\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: Polyfill/EventListener/MatchFilterForLeadTrait.php + + - + message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\ContactFilterMatcher\\:\\:transformFilterDataForLead\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: Helper/ContactFilterMatcher.php + - message: """ #^Fetching deprecated class constant PARAM_INT_ARRAY of class Doctrine\\\\DBAL\\\\Connection\\: From 6e6ce5b60629670e0707a8b642ccc66db8095388 Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Wed, 15 Apr 2026 11:58:22 +0200 Subject: [PATCH 17/25] refactor(dynamic-content): replace MatchFilterForLeadTrait polyfill with FilterEvaluator service - Add Helper/FilterEvaluator.php: standalone service consolidating three divergent copies of filter evaluation logic (TokenSubscriber, ContactFilterMatcher, and the polyfill trait) into one authoritative implementation with multi-value any-match semantics for custom_object fields - Remove Polyfill/EventListener/MatchFilterForLeadTrait.php (236 lines deleted) - Remove dead transformFilterDataForLead() from ContactFilterMatcher - Inject FilterEvaluator into ContactFilterMatcher and TokenSubscriber - Register ContactFilterMatcher explicitly in config.php to resolve int $leadCustomItemFetchLimit DI argument (excluded from services.php auto-discovery to avoid conflict) - Remove 5 phpstan-baseline suppressions that covered dead code - Replace trivial DynamicContentSubscriberTest with 8 MauticMysqlTestCase functional tests covering operators, AND/OR glue, multi-item any-match, empty operator, and subscriber skip conditions - Update TokenSubscriberTest to include FilterEvaluator mock --- Config/config.php | 16 + Config/services.php | 5 +- EventListener/TokenSubscriber.php | 182 +------ Helper/ContactFilterMatcher.php | 44 +- Helper/FilterEvaluator.php | 201 ++++++++ .../EventListener/MatchFilterForLeadTrait.php | 236 --------- .../DynamicContentSubscriberTest.php | 466 +++++++++++++++++- .../EventListener/TokenSubscriberTest.php | 9 + phpstan-baseline.neon | 20 - 9 files changed, 719 insertions(+), 460 deletions(-) create mode 100644 Helper/FilterEvaluator.php delete mode 100644 Polyfill/EventListener/MatchFilterForLeadTrait.php diff --git a/Config/config.php b/Config/config.php index 172650282..297a8e542 100644 --- a/Config/config.php +++ b/Config/config.php @@ -410,6 +410,7 @@ 'mautic.campaign.model.event', 'event_dispatcher', 'custom_object.helper.token_formatter', + MauticPlugin\CustomObjectsBundle\Helper\FilterEvaluator::class, '%mautic.custom_item_fetch_limit_per_lead%', ], ], @@ -636,6 +637,21 @@ 'custom_object.helper.token_formatter' => [ 'class' => MauticPlugin\CustomObjectsBundle\Helper\TokenFormatter::class, ], + MauticPlugin\CustomObjectsBundle\Helper\ContactFilterMatcher::class => [ + 'class' => MauticPlugin\CustomObjectsBundle\Helper\ContactFilterMatcher::class, + 'arguments' => [ + 'mautic.custom.model.field', + 'mautic.custom.model.object', + 'mautic.custom.model.item', + 'mautic.lead.repository.company', + 'doctrine.dbal.default_connection', + MauticPlugin\CustomObjectsBundle\Helper\FilterEvaluator::class, + '%mautic.custom_item_fetch_limit_per_lead%', + ], + ], + MauticPlugin\CustomObjectsBundle\Helper\FilterEvaluator::class => [ + 'class' => MauticPlugin\CustomObjectsBundle\Helper\FilterEvaluator::class, + ], 'custom_object.data_persister.custom_item' => [ 'class' => MauticPlugin\CustomObjectsBundle\DataPersister\CustomItemDataPersister::class, diff --git a/Config/services.php b/Config/services.php index 12d09dda3..7af31c538 100644 --- a/Config/services.php +++ b/Config/services.php @@ -18,13 +18,12 @@ 'Report/ReportColumnsBuilder.php', 'Serializer/ApiNormalizer.php', 'Extension/CustomItemListeningExtension.php', + // Registered explicitly in config.php so the int $leadCustomItemFetchLimit arg can be set + 'Helper/ContactFilterMatcher.php', ]; $services->load('MauticPlugin\\CustomObjectsBundle\\', '../') ->exclude('../{'.implode(',', array_merge(MauticCoreExtension::DEFAULT_EXCLUDES, $excludes)).'}'); $services->load('MauticPlugin\\CustomObjectsBundle\\Repository\\', '../Repository/*Repository.php'); - - $services->set(ContactFilterMatcher::class) - ->arg('$leadCustomItemFetchLimit', '%mautic.custom_item_fetch_limit_per_lead%'); }; diff --git a/EventListener/TokenSubscriber.php b/EventListener/TokenSubscriber.php index 61b7cb8b6..24553ef8f 100644 --- a/EventListener/TokenSubscriber.php +++ b/EventListener/TokenSubscriber.php @@ -11,10 +11,7 @@ use Mautic\EmailBundle\EmailEvents; use Mautic\EmailBundle\Entity\Email; use Mautic\EmailBundle\Event\EmailSendEvent; -use Mautic\EmailBundle\EventListener\MatchFilterForLeadTrait; use Mautic\LeadBundle\Entity\LeadList; -use Mautic\LeadBundle\Exception\OperatorsNotFoundException; -use Mautic\LeadBundle\Segment\OperatorOptions; use MauticPlugin\CustomObjectsBundle\CustomItemEvents; use MauticPlugin\CustomObjectsBundle\CustomObjectEvents; use MauticPlugin\CustomObjectsBundle\DTO\TableConfig; @@ -28,6 +25,7 @@ use MauticPlugin\CustomObjectsBundle\Exception\InvalidCustomObjectFormatListException; use MauticPlugin\CustomObjectsBundle\Exception\InvalidSegmentFilterException; use MauticPlugin\CustomObjectsBundle\Exception\NotFoundException; +use MauticPlugin\CustomObjectsBundle\Helper\FilterEvaluator; use MauticPlugin\CustomObjectsBundle\Helper\QueryBuilderManipulatorTrait; use MauticPlugin\CustomObjectsBundle\Helper\QueryFilterHelper; use MauticPlugin\CustomObjectsBundle\Helper\TokenFormatter; @@ -45,7 +43,6 @@ */ class TokenSubscriber implements EventSubscriberInterface { - use MatchFilterForLeadTrait; use QueryBuilderManipulatorTrait; public function __construct( @@ -59,6 +56,7 @@ public function __construct( private EventModel $eventModel, private EventDispatcherInterface $eventDispatcher, private TokenFormatter $tokenFormatter, + private FilterEvaluator $filterEvaluator, private int $leadCustomItemFetchLimit ) { } @@ -300,7 +298,7 @@ public function onTokenReplacement(TokenReplacementEvent $event): void $lead = array_merge($lead, $customFieldValues); } - if ($isCustomObject && $this->matchFilterForLeadInCustomObject($filter['filters'], $lead)) { + if ($isCustomObject && $this->filterEvaluator->evaluate($filter['filters'], $lead)) { $filterContent = $filter['content']; break; } @@ -419,178 +417,4 @@ private function getCustomItems(CustomObject $customObject, string $leadId): arr return $this->customItemModel->getArrayTableData($tableConfig); } - // We have a similar function in MatchFilterForLeadTrait since we are unable to alter anything in Mautic 4.4, - // hence there is some duplication of code. - - /** - * @param array $filter - * @param array $lead - * - * @throws OperatorsNotFoundException - */ - protected function matchFilterForLeadInCustomObject(array $filter, array $lead): bool - { - if (empty($lead['id'])) { - // Lead in generated for preview with faked data - return false; - } - - $groups = []; - $groupNum = 0; - - foreach ($filter as $data) { - if (!array_key_exists($data['field'], $lead)) { - continue; - } - - /* - * Split the filters into groups based on the glue. - * The first filter and any filters whose glue is - * "or" will start a new group. - */ - if (0 === $groupNum || 'or' === $data['glue']) { - ++$groupNum; - $groups[$groupNum] = null; - } - - /* - * If the group has been marked as false, there - * is no need to continue checking the others - * in the group. - */ - if (false === $groups[$groupNum]) { - continue; - } - - /* - * If we are checking the first filter in a group - * assume that the group will not match. - */ - if (null === $groups[$groupNum]) { - $groups[$groupNum] = false; - } - - $leadValues = $lead[$data['field']]; - $leadValues = 'custom_object' === $data['object'] ? $leadValues : [$leadValues]; - $filterVal = $data['filter']; - $subgroup = null; - - if (is_array($leadValues)) { - foreach ($leadValues as $leadVal) { - if ($subgroup) { - break; - } - - switch ($data['type']) { - case 'boolean': - if (null !== $leadVal) { - $leadVal = (bool) $leadVal; - } - - if (null !== $filterVal) { - $filterVal = (bool) $filterVal; - } - break; - case 'datetime': - case 'time': - if (!is_null($leadVal) && !is_null($filterVal)) { - $leadValCount = substr_count($leadVal, ':'); - $filterValCount = substr_count($filterVal, ':'); - - if (2 === $leadValCount && 1 === $filterValCount) { - $filterVal .= ':00'; - } - } - break; - case 'tags': - case 'select': - case 'multiselect': - if (!is_array($leadVal) && !empty($leadVal)) { - $leadVal = explode('|', $leadVal); - } - if (!is_null($filterVal) && !is_array($filterVal)) { - $filterVal = explode('|', $filterVal); - } - break; - case 'number': - $leadVal = (int) $leadVal; - $filterVal = (int) $filterVal; - break; - } - - switch ($data['operator']) { - case '=': - if ('boolean' === $data['type']) { - $groups[$groupNum] = $leadVal === $filterVal; - } else { - $groups[$groupNum] = $leadVal == $filterVal; - } - break; - case '!=': - if ('boolean' === $data['type']) { - $groups[$groupNum] = $leadVal !== $filterVal; - } else { - $groups[$groupNum] = $leadVal != $filterVal; - } - break; - case 'gt': - $groups[$groupNum] = $leadVal > $filterVal; - break; - case 'gte': - $groups[$groupNum] = $leadVal >= $filterVal; - break; - case 'lt': - $groups[$groupNum] = $leadVal < $filterVal; - break; - case 'lte': - $groups[$groupNum] = $leadVal <= $filterVal; - break; - case 'empty': - $groups[$groupNum] = empty($leadVal); - break; - case '!empty': - $groups[$groupNum] = !empty($leadVal); - break; - case 'like': - $matchVal = str_replace(['.', '*', '%'], ['\.', '\*', '.*'], $filterVal); - $groups[$groupNum] = 1 === preg_match('/'.$matchVal.'/', $leadVal); - break; - case '!like': - $matchVal = str_replace(['.', '*'], ['\.', '\*'], $filterVal); - $matchVal = str_replace('%', '.*', $matchVal); - $groups[$groupNum] = 1 !== preg_match('/'.$matchVal.'/', $leadVal); - break; - case OperatorOptions::IN: - $groups[$groupNum] = $this->checkLeadValueIsInFilter($leadVal, $filterVal, false); - break; - case OperatorOptions::NOT_IN: - $groups[$groupNum] = $this->checkLeadValueIsInFilter($leadVal, $filterVal, true); - break; - case 'regexp': - $groups[$groupNum] = 1 === preg_match('/'.$filterVal.'/i', $leadVal); - break; - case '!regexp': - $groups[$groupNum] = 1 !== preg_match('/'.$filterVal.'/i', $leadVal); - break; - case 'startsWith': - $groups[$groupNum] = str_starts_with($leadVal, $filterVal); - break; - case 'endsWith': - $endOfString = substr($leadVal, strlen($leadVal) - strlen($filterVal)); - $groups[$groupNum] = 0 === strcmp($endOfString, $filterVal); - break; - case 'contains': - $groups[$groupNum] = str_contains((string) $leadVal, (string) $filterVal); - break; - default: - throw new OperatorsNotFoundException('Operator is not defined or invalid operator found.'); - } - - $subgroup = $groups[$groupNum]; - } - } - } - - return in_array(true, $groups); - } } diff --git a/Helper/ContactFilterMatcher.php b/Helper/ContactFilterMatcher.php index 503533ed7..ccf1550a3 100644 --- a/Helper/ContactFilterMatcher.php +++ b/Helper/ContactFilterMatcher.php @@ -6,7 +6,6 @@ use Doctrine\DBAL\Connection; use Mautic\LeadBundle\Entity\CompanyRepository; -use Mautic\LeadBundle\Entity\LeadListRepository; use MauticPlugin\CustomObjectsBundle\DTO\TableConfig; use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; @@ -15,24 +14,18 @@ use MauticPlugin\CustomObjectsBundle\Model\CustomFieldModel; use MauticPlugin\CustomObjectsBundle\Model\CustomItemModel; use MauticPlugin\CustomObjectsBundle\Model\CustomObjectModel; -use MauticPlugin\CustomObjectsBundle\Polyfill\EventListener\MatchFilterForLeadTrait as MatchFilterForLeadTraitPolyfill; class ContactFilterMatcher { - use MatchFilterForLeadTraitPolyfill { - transformFilterDataForLead as transformFilterDataForLeadPolyfill; - } - public function __construct( private CustomFieldModel $customFieldModel, private CustomObjectModel $customObjectModel, private CustomItemModel $customItemModel, - LeadListRepository $segmentRepository, private CompanyRepository $companyRepository, private Connection $connection, + private FilterEvaluator $filterEvaluator, private int $leadCustomItemFetchLimit ) { - $this->segmentRepository = $segmentRepository; } /** @@ -59,7 +52,7 @@ public function match(array $filters, array $lead, bool &$hasCustomFields = fals $lead['tags'] = $this->getTagIdsByLeadId($leadId); } - return $this->matchFilterForLead($filters, $lead); + return $this->filterEvaluator->evaluate($filters, $lead); } /** @@ -170,16 +163,37 @@ private function getCustomItems(CustomObject $customObject, string $leadId): arr } /** - * @param mixed[] $data - * @param mixed[] $lead + * @param mixed[] $filters */ - private function transformFilterDataForLead(array $data, array $lead): ?array + private function doFiltersContainCompanyFilter(array $filters): bool { - if ('custom_object' === $data['object']) { - return $lead[$data['field']]; + foreach ($filters as $filter) { + $object = $filter['object'] ?? ''; + + if ('company' === $object) { + return true; + } + + if (str_starts_with($filter['field'], 'company') && 'company' !== $filter['field']) { + return true; + } + } + + return false; + } + + /** + * @param mixed[] $filters + */ + private function doFiltersContainTagsFilter(array $filters): bool + { + foreach ($filters as $filter) { + if ('tags' === ($filter['type'] ?? null)) { + return true; + } } - return $this->transformFilterDataForLeadPolyfill($data, $lead); + return false; } /** diff --git a/Helper/FilterEvaluator.php b/Helper/FilterEvaluator.php new file mode 100644 index 000000000..d7ee54382 --- /dev/null +++ b/Helper/FilterEvaluator.php @@ -0,0 +1,201 @@ + + */ +class FilterEvaluator +{ + /** + * @param array $filters + * @param LeadArray $lead + * + * @throws OperatorsNotFoundException + */ + public function evaluate(array $filters, array $lead): bool + { + if (empty($lead['id'])) { + return false; + } + + /** @var array $groups */ + $groups = []; + $groupNum = 0; + + foreach ($filters as $data) { + if (!array_key_exists($data['field'], $lead)) { + continue; + } + + if (0 === $groupNum || 'or' === $data['glue']) { + ++$groupNum; + $groups[$groupNum] = null; + } + + if (false === $groups[$groupNum]) { + continue; + } + + if (null === $groups[$groupNum]) { + $groups[$groupNum] = false; + } + + $isCustomObject = 'custom_object' === $data['object']; + $leadValues = $isCustomObject ? $lead[$data['field']] : [$lead[$data['field']]]; + $filterVal = $data['filter']; + + if (!is_array($leadValues)) { + $leadValues = [$leadValues]; + } + + // No linked custom items: only 'empty' operator can match. + if ($isCustomObject && [] === $leadValues) { + $groups[$groupNum] = 'empty' === $data['operator']; + continue; + } + + $matched = null; + foreach ($leadValues as $leadVal) { + if (null !== $matched) { + break; + } + + [$leadVal, $filterVal] = $this->coerceTypes($data['type'], $leadVal, $filterVal); + $matched = $this->applyOperator($data['operator'], $data['type'], $leadVal, $filterVal); + } + + $groups[$groupNum] = $matched ?? false; + } + + return in_array(true, $groups, true); + } + + /** + * @param mixed $leadVal + * @param mixed $filterVal + * + * @return array{mixed, mixed} + */ + private function coerceTypes(string $type, mixed $leadVal, mixed $filterVal): array + { + switch ($type) { + case 'boolean': + if (null !== $leadVal) { + $leadVal = (bool) $leadVal; + } + if (null !== $filterVal) { + $filterVal = (bool) $filterVal; + } + break; + case 'datetime': + case 'time': + if (null !== $leadVal && null !== $filterVal) { + if (2 === substr_count($leadVal, ':') && 1 === substr_count($filterVal, ':')) { + $filterVal .= ':00'; + } + } + break; + case 'tags': + case 'select': + case 'multiselect': + if (!is_array($leadVal) && !empty($leadVal)) { + $leadVal = explode('|', $leadVal); + } + if (null !== $filterVal && !is_array($filterVal)) { + $filterVal = explode('|', $filterVal); + } + break; + case 'number': + $leadVal = (int) $leadVal; + $filterVal = (int) $filterVal; + break; + } + + return [$leadVal, $filterVal]; + } + + /** + * @param mixed $leadVal + * @param mixed $filterVal + * + * @throws OperatorsNotFoundException + */ + private function applyOperator(string $operator, string $type, mixed $leadVal, mixed $filterVal): bool + { + switch ($operator) { + case '=': + return 'boolean' === $type ? $leadVal === $filterVal : $leadVal == $filterVal; + case '!=': + return 'boolean' === $type ? $leadVal !== $filterVal : $leadVal != $filterVal; + case 'gt': + return $leadVal > $filterVal; + case 'gte': + return $leadVal >= $filterVal; + case 'lt': + return $leadVal < $filterVal; + case 'lte': + return $leadVal <= $filterVal; + case 'empty': + return empty($leadVal); + case '!empty': + return !empty($leadVal); + case 'like': + $pattern = str_replace(['.', '*', '%'], ['\.', '\*', '.*'], $filterVal); + + return 1 === preg_match('/'.$pattern.'/', $leadVal); + case '!like': + $pattern = str_replace(['.', '*', '%'], ['\.', '\*', '.*'], $filterVal); + + return 1 !== preg_match('/'.$pattern.'/', $leadVal); + case OperatorOptions::IN: + return $this->checkLeadValueIsInFilter($leadVal, $filterVal, false); + case OperatorOptions::NOT_IN: + return $this->checkLeadValueIsInFilter($leadVal, $filterVal, true); + case 'regexp': + return 1 === preg_match('/'.$filterVal.'/i', $leadVal); + case '!regexp': + return 1 !== preg_match('/'.$filterVal.'/i', $leadVal); + case 'startsWith': + return str_starts_with($leadVal, $filterVal); + case 'endsWith': + return 0 === strcmp(substr($leadVal, strlen($leadVal) - strlen($filterVal)), $filterVal); + case 'contains': + return str_contains((string) $leadVal, (string) $filterVal); + default: + throw new OperatorsNotFoundException('Operator is not defined or invalid operator found.'); + } + } + + /** + * @param mixed $leadVal + * @param mixed $filterVal + */ + private function checkLeadValueIsInFilter(mixed $leadVal, mixed $filterVal, bool $defaultFlag): bool + { + $leadVal = !is_array($leadVal) ? [$leadVal] : $leadVal; + $filterVal = !is_array($filterVal) ? [$filterVal] : $filterVal; + $retFlag = $defaultFlag; + + foreach ($leadVal as $v) { + if (in_array($v, $filterVal)) { + $retFlag = !$defaultFlag; + break; + } + } + + return $retFlag; + } +} diff --git a/Polyfill/EventListener/MatchFilterForLeadTrait.php b/Polyfill/EventListener/MatchFilterForLeadTrait.php deleted file mode 100644 index 269e4bb42..000000000 --- a/Polyfill/EventListener/MatchFilterForLeadTrait.php +++ /dev/null @@ -1,236 +0,0 @@ - $filterVal; - break; - case 'gte': - $groups[$groupNum] = $leadVal >= $filterVal; - break; - case 'lt': - $groups[$groupNum] = $leadVal < $filterVal; - break; - case 'lte': - $groups[$groupNum] = $leadVal <= $filterVal; - break; - case 'empty': - $groups[$groupNum] = empty($leadVal); - break; - case '!empty': - $groups[$groupNum] = !empty($leadVal); - break; - case 'like': - $matchVal = str_replace(['.', '*', '%'], ['\.', '\*', '.*'], $filterVal); - $groups[$groupNum] = 1 === preg_match('/'.$matchVal.'/', $leadVal); - break; - case '!like': - $matchVal = str_replace(['.', '*'], ['\.', '\*'], $filterVal); - $matchVal = str_replace('%', '.*', $matchVal); - $groups[$groupNum] = 1 !== preg_match('/'.$matchVal.'/', $leadVal); - break; - case OperatorOptions::IN: - $groups[$groupNum] = $this->checkLeadValueIsInFilter($leadVal, $filterVal, false); - break; - case OperatorOptions::NOT_IN: - $groups[$groupNum] = $this->checkLeadValueIsInFilter($leadVal, $filterVal, true); - break; - case 'regexp': - $groups[$groupNum] = 1 === preg_match('/'.$filterVal.'/i', $leadVal); - break; - case '!regexp': - $groups[$groupNum] = 1 !== preg_match('/'.$filterVal.'/i', $leadVal); - break; - case 'startsWith': - $groups[$groupNum] = str_starts_with($leadVal, $filterVal); - break; - case 'endsWith': - $endOfString = substr($leadVal, strlen($leadVal) - strlen($filterVal)); - $groups[$groupNum] = 0 === strcmp($endOfString, $filterVal); - break; - case 'contains': - $groups[$groupNum] = str_contains((string) $leadVal, (string) $filterVal); - break; - default: - throw new OperatorsNotFoundException('Operator is not defined or invalid operator found.'); - } - - $subgroup = $groups[$groupNum]; - } - } - } - - return in_array(true, $groups); - } - - /** - * @param mixed[] $data - * @param mixed[] $lead - */ - private function transformFilterDataForLead(array $data, array $lead): ?array - { - return null; - } - - /** - * @param mixed[] $filters - */ - private function doFiltersContainCompanyFilter(array $filters): bool - { - foreach ($filters as $filter) { - $object = $filter['object'] ?? ''; - - if ('company' === $object) { - return true; - } - - if (str_starts_with($filter['field'], 'company') && 'company' !== $filter['field']) { - return true; - } - } - - return false; - } - - /** - * @param mixed[] $filters - */ - private function doFiltersContainTagsFilter(array $filters): bool - { - foreach ($filters as $filter) { - if ('tags' === ($filter['type'] ?? null)) { - return true; - } - } - - return false; - } -} diff --git a/Tests/Functional/EventListener/DynamicContentSubscriberTest.php b/Tests/Functional/EventListener/DynamicContentSubscriberTest.php index 46a9460ae..977218504 100644 --- a/Tests/Functional/EventListener/DynamicContentSubscriberTest.php +++ b/Tests/Functional/EventListener/DynamicContentSubscriberTest.php @@ -4,17 +4,469 @@ namespace MauticPlugin\CustomObjectsBundle\Tests\Functional\EventListener; -use Mautic\DynamicContentBundle\DynamicContentEvents; +use Mautic\CoreBundle\Test\MauticMysqlTestCase; +use Mautic\DynamicContentBundle\Event\ContactFiltersEvaluateEvent; +use Mautic\LeadBundle\Entity\Lead; +use Mautic\LeadBundle\Model\LeadModel; +use MauticPlugin\CustomObjectsBundle\Entity\CustomItem; use MauticPlugin\CustomObjectsBundle\EventListener\DynamicContentSubscriber; -use PHPUnit\Framework\TestCase; +use MauticPlugin\CustomObjectsBundle\Model\CustomFieldValueModel; +use MauticPlugin\CustomObjectsBundle\Model\CustomItemModel; +use MauticPlugin\CustomObjectsBundle\Tests\Functional\DataFixtures\Traits\CustomObjectsTrait; -class DynamicContentSubscriberTest extends TestCase +#[\AllowDynamicProperties] +class DynamicContentSubscriberTest extends MauticMysqlTestCase { - public function testSubscribesToEvent(): void + use CustomObjectsTrait; + + private CustomItemModel $customItemModel; + private CustomFieldValueModel $customFieldValueModel; + private DynamicContentSubscriber $subscriber; + + protected function setUp(): void + { + parent::setUp(); + + $this->customItemModel = self::$container->get('mautic.custom.model.item'); + $this->customFieldValueModel = self::$container->get('mautic.custom.model.field.value'); + $this->subscriber = self::$container->get(DynamicContentSubscriber::class); + } + + public function testVariousOperators(): void + { + $customObject = $this->createCustomObjectWithAllFields(self::$container, 'Product'); + $contact = $this->createContact('operators@example.com'); + $customItem = new CustomItem($customObject); + $customItem->setName('Test Item'); + $this->customFieldValueModel->createValuesForItem($customItem); + + $textValue = $customItem->findCustomFieldValueForFieldAlias('text-test-field'); + $urlValue = $customItem->findCustomFieldValueForFieldAlias('url-test-field'); + $dateValue = $customItem->findCustomFieldValueForFieldAlias('date-test-field'); + $datetimeValue = $customItem->findCustomFieldValueForFieldAlias('datetime-test-field'); + $multiselectValue = $customItem->findCustomFieldValueForFieldAlias('multiselect-test-field'); + + $textValue->setValue('abracadabra'); + $dateValue->setValue('2019-07-17'); + $datetimeValue->setValue('2019-07-17 13:00:00'); + $multiselectValue->setValue(['option_b']); + // urlValue left empty intentionally + + $customItem = $this->customItemModel->save($customItem); + $this->customItemModel->linkEntity($customItem, 'contact', (int) $contact->getId()); + + $textFieldId = $textValue->getCustomField()->getId(); + $urlFieldId = $urlValue->getCustomField()->getId(); + $dateFieldId = $dateValue->getCustomField()->getId(); + $datetimeFieldId = $datetimeValue->getCustomField()->getId(); + $multiselectFieldId = $multiselectValue->getCustomField()->getId(); + + // = match + $this->assertMatched($contact, $textFieldId, 'text', '=', 'abracadabra'); + + // = no match + $this->assertNotMatched($contact, $textFieldId, 'text', '=', 'unicorn'); + + // != match + $this->assertMatched($contact, $textFieldId, 'text', '!=', 'unicorn'); + + // != no match + $this->assertNotMatched($contact, $textFieldId, 'text', '!=', 'abracadabra'); + + // empty — url field has no value + $this->assertMatched($contact, $urlFieldId, 'text', 'empty', null); + + // !empty — text field has a value + $this->assertMatched($contact, $textFieldId, 'text', '!empty', null); + + // !empty — url field is empty, so !empty should not match + $this->assertNotMatched($contact, $urlFieldId, 'text', '!empty', null); + + // startsWith match + $this->assertMatched($contact, $textFieldId, 'text', 'startsWith', 'abra'); + + // startsWith no match + $this->assertNotMatched($contact, $textFieldId, 'text', 'startsWith', 'unicorn'); + + // endsWith match + $this->assertMatched($contact, $textFieldId, 'text', 'endsWith', 'cadabra'); + + // endsWith no match + $this->assertNotMatched($contact, $textFieldId, 'text', 'endsWith', 'unicorn'); + + // contains match + $this->assertMatched($contact, $textFieldId, 'text', 'contains', 'cada'); + + // contains no match + $this->assertNotMatched($contact, $textFieldId, 'text', 'contains', 'unicorn'); + + // like with % wildcard match + $this->assertMatched($contact, $textFieldId, 'text', 'like', 'abra%'); + + // like no match + $this->assertNotMatched($contact, $textFieldId, 'text', 'like', 'unicorn%'); + + // !like no match (value matches pattern, so !like is false) + $this->assertNotMatched($contact, $textFieldId, 'text', '!like', 'abra%'); + + // !like match (value does not match pattern) + $this->assertMatched($contact, $textFieldId, 'text', '!like', 'unicorn%'); + + // in (multiselect) match + $this->assertMatched($contact, $multiselectFieldId, 'multiselect', 'in', ['option_b']); + + // in (multiselect) no match + $this->assertNotMatched($contact, $multiselectFieldId, 'multiselect', 'in', ['option_a']); + + // !in (multiselect) match + $this->assertMatched($contact, $multiselectFieldId, 'multiselect', '!in', ['option_a']); + + // !in (multiselect) no match (value is in list) + $this->assertNotMatched($contact, $multiselectFieldId, 'multiselect', '!in', ['option_b']); + + // date lt match + $this->assertMatched($contact, $dateFieldId, 'date', 'lt', '2019-08-05'); + + // date lt no match + $this->assertNotMatched($contact, $dateFieldId, 'date', 'lt', '2019-06-05'); + + // date gt match + $this->assertMatched($contact, $dateFieldId, 'date', 'gt', '2019-06-05'); + + // date gt no match + $this->assertNotMatched($contact, $dateFieldId, 'date', 'gt', '2019-08-05'); + + // datetime gt match + $this->assertMatched($contact, $datetimeFieldId, 'datetime', 'gt', '2019-07-16 13:00:00'); + + // datetime gt no match + $this->assertNotMatched($contact, $datetimeFieldId, 'datetime', 'gt', '2019-07-18 13:00:00'); + } + + public function testAndFiltersAllMustMatch(): void + { + $customObject = $this->createCustomObjectWithAllFields(self::$container, 'Product'); + $contact = $this->createContact('and-match@example.com'); + $customItem = new CustomItem($customObject); + $customItem->setName('Test Item'); + $this->customFieldValueModel->createValuesForItem($customItem); + + $textValue = $customItem->findCustomFieldValueForFieldAlias('text-test-field'); + $urlValue = $customItem->findCustomFieldValueForFieldAlias('url-test-field'); + $textValue->setValue('abracadabra'); + $urlValue->setValue('https://example.com'); + + $customItem = $this->customItemModel->save($customItem); + $this->customItemModel->linkEntity($customItem, 'contact', (int) $contact->getId()); + + $filters = [ + [ + 'glue' => 'and', + 'field' => 'cmf_'.$textValue->getCustomField()->getId(), + 'object' => 'custom_object', + 'type' => 'text', + 'filter' => 'abracadabra', + 'display' => null, + 'operator' => '=', + ], + [ + 'glue' => 'and', + 'field' => 'cmf_'.$urlValue->getCustomField()->getId(), + 'object' => 'custom_object', + 'type' => 'text', + 'filter' => null, + 'display' => null, + 'operator' => '!empty', + ], + ]; + + $event = new ContactFiltersEvaluateEvent($filters, $contact); + $this->subscriber->evaluateFilters($event); + + $this->assertTrue($event->isEvaluated()); + $this->assertTrue($event->isMatched(), 'Both AND conditions are true, should match'); + } + + public function testAndFiltersOneFailsNoMatch(): void + { + $customObject = $this->createCustomObjectWithAllFields(self::$container, 'Product'); + $contact = $this->createContact('and-no-match@example.com'); + $customItem = new CustomItem($customObject); + $customItem->setName('Test Item'); + $this->customFieldValueModel->createValuesForItem($customItem); + + $textValue = $customItem->findCustomFieldValueForFieldAlias('text-test-field'); + $urlValue = $customItem->findCustomFieldValueForFieldAlias('url-test-field'); + $textValue->setValue('abracadabra'); + // urlValue left empty intentionally + + $customItem = $this->customItemModel->save($customItem); + $this->customItemModel->linkEntity($customItem, 'contact', (int) $contact->getId()); + + $filters = [ + [ + 'glue' => 'and', + 'field' => 'cmf_'.$textValue->getCustomField()->getId(), + 'object' => 'custom_object', + 'type' => 'text', + 'filter' => 'abracadabra', + 'display' => null, + 'operator' => '=', + ], + [ + 'glue' => 'and', + 'field' => 'cmf_'.$urlValue->getCustomField()->getId(), + 'object' => 'custom_object', + 'type' => 'text', + 'filter' => null, + 'display' => null, + 'operator' => '!empty', // url is empty, so this fails + ], + ]; + + $event = new ContactFiltersEvaluateEvent($filters, $contact); + $this->subscriber->evaluateFilters($event); + + $this->assertTrue($event->isEvaluated()); + $this->assertFalse($event->isMatched(), 'One AND condition fails, should not match'); + } + + public function testOrFiltersSecondGroupMatches(): void + { + $customObject = $this->createCustomObjectWithAllFields(self::$container, 'Product'); + $contact = $this->createContact('or-match@example.com'); + $customItem = new CustomItem($customObject); + $customItem->setName('Test Item'); + $this->customFieldValueModel->createValuesForItem($customItem); + + $textValue = $customItem->findCustomFieldValueForFieldAlias('text-test-field'); + $urlValue = $customItem->findCustomFieldValueForFieldAlias('url-test-field'); + $textValue->setValue('abracadabra'); + $urlValue->setValue('https://example.com'); + + $customItem = $this->customItemModel->save($customItem); + $this->customItemModel->linkEntity($customItem, 'contact', (int) $contact->getId()); + + $filters = [ + [ + 'glue' => 'and', + 'field' => 'cmf_'.$textValue->getCustomField()->getId(), + 'object' => 'custom_object', + 'type' => 'text', + 'filter' => 'unicorn', // first group fails + 'display' => null, + 'operator' => '=', + ], + [ + 'glue' => 'or', // starts a new group + 'field' => 'cmf_'.$urlValue->getCustomField()->getId(), + 'object' => 'custom_object', + 'type' => 'text', + 'filter' => null, + 'display' => null, + 'operator' => '!empty', // second group passes + ], + ]; + + $event = new ContactFiltersEvaluateEvent($filters, $contact); + $this->subscriber->evaluateFilters($event); + + $this->assertTrue($event->isEvaluated()); + $this->assertTrue($event->isMatched(), 'Second OR group passes, overall result should match'); + } + + public function testMultipleLinkedItemsAnyMatchWins(): void + { + $customObject = $this->createCustomObjectWithAllFields(self::$container, 'Product'); + $contact = $this->createContact('multi-item@example.com'); + + $itemA = new CustomItem($customObject); + $itemA->setName('Item A'); + $this->customFieldValueModel->createValuesForItem($itemA); + $itemA->findCustomFieldValueForFieldAlias('text-test-field')->setValue('basic'); + $itemA = $this->customItemModel->save($itemA); + $this->customItemModel->linkEntity($itemA, 'contact', (int) $contact->getId()); + + $itemB = new CustomItem($customObject); + $itemB->setName('Item B'); + $this->customFieldValueModel->createValuesForItem($itemB); + $textValueB = $itemB->findCustomFieldValueForFieldAlias('text-test-field'); + $textValueB->setValue('premium'); + $itemB = $this->customItemModel->save($itemB); + $this->customItemModel->linkEntity($itemB, 'contact', (int) $contact->getId()); + + $filters = [ + [ + 'glue' => 'and', + 'field' => 'cmf_'.$textValueB->getCustomField()->getId(), + 'object' => 'custom_object', + 'type' => 'text', + 'filter' => 'premium', + 'display' => null, + 'operator' => '=', + ], + ]; + + $event = new ContactFiltersEvaluateEvent($filters, $contact); + $this->subscriber->evaluateFilters($event); + + $this->assertTrue($event->isEvaluated()); + $this->assertTrue($event->isMatched(), 'When any linked item matches, overall result should match'); + } + + public function testEmptyOperatorMatchesContactWithNoLinkedItems(): void + { + $customObject = $this->createCustomObjectWithAllFields(self::$container, 'Product'); + $contact = $this->createContact('no-items@example.com'); + // No custom item is created or linked to this contact + + // To make hasCustomObjectFilters() pass (so the subscriber takes ownership), + // we still need a filter with a valid custom field ID. Create a throwaway item + // just to get a field ID, but don't link it to this contact. + $tempItem = new CustomItem($customObject); + $tempItem->setName('Temp'); + $this->customFieldValueModel->createValuesForItem($tempItem); + $textValue = $tempItem->findCustomFieldValueForFieldAlias('text-test-field'); + $this->customItemModel->save($tempItem); + // Not linked to $contact + + $filters = [ + [ + 'glue' => 'and', + 'field' => 'cmf_'.$textValue->getCustomField()->getId(), + 'object' => 'custom_object', + 'type' => 'text', + 'filter' => null, + 'display' => null, + 'operator' => 'empty', + ], + ]; + + $event = new ContactFiltersEvaluateEvent($filters, $contact); + $this->subscriber->evaluateFilters($event); + + $this->assertTrue($event->isEvaluated()); + $this->assertTrue($event->isMatched(), 'Contact with no linked items should match the "empty" operator'); + } + + public function testAlreadyEvaluatedEventIsSkipped(): void + { + $customObject = $this->createCustomObjectWithAllFields(self::$container, 'Product'); + $contact = $this->createContact('already-evaluated@example.com'); + $customItem = new CustomItem($customObject); + $customItem->setName('Test Item'); + $this->customFieldValueModel->createValuesForItem($customItem); + + $textValue = $customItem->findCustomFieldValueForFieldAlias('text-test-field'); + $textValue->setValue('premium'); + $customItem = $this->customItemModel->save($customItem); + $this->customItemModel->linkEntity($customItem, 'contact', (int) $contact->getId()); + + $filters = [ + [ + 'glue' => 'and', + 'field' => 'cmf_'.$textValue->getCustomField()->getId(), + 'object' => 'custom_object', + 'type' => 'text', + 'filter' => 'premium', + 'display' => null, + 'operator' => '=', + ], + ]; + + $event = new ContactFiltersEvaluateEvent($filters, $contact); + $event->setIsEvaluated(true); // already handled by another listener + $event->setIsMatched(false); // prior result was false + + $this->subscriber->evaluateFilters($event); + + $this->assertFalse($event->isMatched(), 'Subscriber must not overwrite a result already set by another listener'); + } + + public function testEvaluateFiltersSkipsEventWithNoCustomObjectFilters(): void + { + $contact = $this->createContact('test-skip@example.com'); + + $filters = [ + [ + 'glue' => 'and', + 'field' => 'email', + 'object' => 'lead', + 'type' => 'email', + 'filter' => 'test-skip@example.com', + 'display' => null, + 'operator' => '=', + ], + ]; + + $event = new ContactFiltersEvaluateEvent($filters, $contact); + $this->subscriber->evaluateFilters($event); + + $this->assertFalse($event->isEvaluated(), 'Subscriber should not take ownership when no custom object filters are present'); + } + + /** + * @param mixed $filterValue + */ + private function assertMatched(Lead $contact, int $fieldId, string $type, string $operator, $filterValue): void + { + $event = new ContactFiltersEvaluateEvent( + $this->buildFilter($fieldId, $type, $operator, $filterValue), + $contact + ); + $this->subscriber->evaluateFilters($event); + + $this->assertTrue( + $event->isMatched(), + "Expected match for operator '{$operator}' with filter value '".json_encode($filterValue)."'" + ); + } + + /** + * @param mixed $filterValue + */ + private function assertNotMatched(Lead $contact, int $fieldId, string $type, string $operator, $filterValue): void + { + $event = new ContactFiltersEvaluateEvent( + $this->buildFilter($fieldId, $type, $operator, $filterValue), + $contact + ); + $this->subscriber->evaluateFilters($event); + + $this->assertFalse( + $event->isMatched(), + "Expected no match for operator '{$operator}' with filter value '".json_encode($filterValue)."'" + ); + } + + /** + * @param mixed $filterValue + * + * @return array> + */ + private function buildFilter(int $fieldId, string $type, string $operator, $filterValue): array + { + return [ + [ + 'glue' => 'and', + 'field' => 'cmf_'.$fieldId, + 'object' => 'custom_object', + 'type' => $type, + 'filter' => $filterValue, + 'display' => null, + 'operator' => $operator, + ], + ]; + } + + private function createContact(string $email): Lead { - $eventSubscriptions = DynamicContentSubscriber::getSubscribedEvents(); - $methodName = $eventSubscriptions[DynamicContentEvents::ON_CONTACTS_FILTER_EVALUATE][0]; + /** @var LeadModel $contactModel */ + $contactModel = self::$container->get('mautic.lead.model.lead'); + $contact = new Lead(); + $contact->setEmail($email); + $contactModel->saveEntity($contact); - $this->assertSame('evaluateFilters', $methodName); + return $contact; } } diff --git a/Tests/Unit/EventListener/TokenSubscriberTest.php b/Tests/Unit/EventListener/TokenSubscriberTest.php index 296d881f7..775483ab5 100644 --- a/Tests/Unit/EventListener/TokenSubscriberTest.php +++ b/Tests/Unit/EventListener/TokenSubscriberTest.php @@ -27,6 +27,7 @@ use MauticPlugin\CustomObjectsBundle\Event\CustomItemListDbalQueryEvent; use MauticPlugin\CustomObjectsBundle\EventListener\TokenSubscriber; use MauticPlugin\CustomObjectsBundle\Exception\NotFoundException; +use MauticPlugin\CustomObjectsBundle\Helper\FilterEvaluator; use MauticPlugin\CustomObjectsBundle\Helper\QueryFilterHelper; use MauticPlugin\CustomObjectsBundle\Helper\TokenFormatter; use MauticPlugin\CustomObjectsBundle\Helper\TokenParser; @@ -92,6 +93,11 @@ class TokenSubscriberTest extends TestCase */ private $tokenFormatter; + /** + * @var FilterEvaluator|MockObject + */ + private $filterEvaluator; + /** * @var TokenSubscriber */ @@ -126,6 +132,7 @@ protected function setUp(): void $this->eventModel = $this->createMock(EventModel::class); $this->eventDispatcher = $this->createMock(EventDispatcher::class); $this->tokenFormatter = $this->createMock(TokenFormatter::class); + $this->filterEvaluator = $this->createMock(FilterEvaluator::class); $this->subscriber = new TokenSubscriber( $this->configProvider, $this->queryFilterHelper, @@ -137,6 +144,7 @@ protected function setUp(): void $this->eventModel, $this->eventDispatcher, $this->tokenFormatter, + $this->filterEvaluator, 15 ); @@ -860,6 +868,7 @@ private function constructWithDependencies(): void $this->eventModel, $this->eventDispatcher, new TokenFormatter(), + $this->createMock(FilterEvaluator::class), 15 ); } diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index bc030b658..f0a54ab83 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -697,26 +697,6 @@ parameters: count: 1 path: Helper/ContactFilterMatcher.php - - - message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\ContactFilterMatcher\\:\\:transformFilterDataForLead\\(\\) is unused\\.$#" - count: 1 - path: Helper/ContactFilterMatcher.php - - - - message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\ContactFilterMatcher\\:\\:transformFilterDataForLeadPolyfill\\(\\) never returns array so it can be removed from the return type\\.$#" - count: 1 - path: Polyfill/EventListener/MatchFilterForLeadTrait.php - - - - message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\ContactFilterMatcher\\:\\:transformFilterDataForLeadPolyfill\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: Polyfill/EventListener/MatchFilterForLeadTrait.php - - - - message: "#^Method MauticPlugin\\\\CustomObjectsBundle\\\\Helper\\\\ContactFilterMatcher\\:\\:transformFilterDataForLead\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: Helper/ContactFilterMatcher.php - - message: """ #^Fetching deprecated class constant PARAM_INT_ARRAY of class Doctrine\\\\DBAL\\\\Connection\\: From 528977d840099318bb41c512be331ac170e491d6 Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Wed, 15 Apr 2026 12:07:13 +0200 Subject: [PATCH 18/25] fix(cs): apply PHP CS Fixer rules for new files and modified classes --- Config/services.php | 1 - EventListener/TokenSubscriber.php | 1 - Helper/FilterEvaluator.php | 12 +----------- .../EventListener/DynamicContentSubscriberTest.php | 8 ++++---- 4 files changed, 5 insertions(+), 17 deletions(-) diff --git a/Config/services.php b/Config/services.php index 7af31c538..26d9b3d64 100644 --- a/Config/services.php +++ b/Config/services.php @@ -3,7 +3,6 @@ declare(strict_types=1); use Mautic\CoreBundle\DependencyInjection\MauticCoreExtension; -use MauticPlugin\CustomObjectsBundle\Helper\ContactFilterMatcher; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; return function (ContainerConfigurator $configurator): void { diff --git a/EventListener/TokenSubscriber.php b/EventListener/TokenSubscriber.php index 24553ef8f..f2d113ba2 100644 --- a/EventListener/TokenSubscriber.php +++ b/EventListener/TokenSubscriber.php @@ -416,5 +416,4 @@ private function getCustomItems(CustomObject $customObject, string $leadId): arr return $this->customItemModel->getArrayTableData($tableConfig); } - } diff --git a/Helper/FilterEvaluator.php b/Helper/FilterEvaluator.php index d7ee54382..60e4bd39e 100644 --- a/Helper/FilterEvaluator.php +++ b/Helper/FilterEvaluator.php @@ -74,7 +74,7 @@ public function evaluate(array $filters, array $lead): bool } [$leadVal, $filterVal] = $this->coerceTypes($data['type'], $leadVal, $filterVal); - $matched = $this->applyOperator($data['operator'], $data['type'], $leadVal, $filterVal); + $matched = $this->applyOperator($data['operator'], $data['type'], $leadVal, $filterVal); } $groups[$groupNum] = $matched ?? false; @@ -84,9 +84,6 @@ public function evaluate(array $filters, array $lead): bool } /** - * @param mixed $leadVal - * @param mixed $filterVal - * * @return array{mixed, mixed} */ private function coerceTypes(string $type, mixed $leadVal, mixed $filterVal): array @@ -128,9 +125,6 @@ private function coerceTypes(string $type, mixed $leadVal, mixed $filterVal): ar } /** - * @param mixed $leadVal - * @param mixed $filterVal - * * @throws OperatorsNotFoundException */ private function applyOperator(string $operator, string $type, mixed $leadVal, mixed $filterVal): bool @@ -179,10 +173,6 @@ private function applyOperator(string $operator, string $type, mixed $leadVal, m } } - /** - * @param mixed $leadVal - * @param mixed $filterVal - */ private function checkLeadValueIsInFilter(mixed $leadVal, mixed $filterVal, bool $defaultFlag): bool { $leadVal = !is_array($leadVal) ? [$leadVal] : $leadVal; diff --git a/Tests/Functional/EventListener/DynamicContentSubscriberTest.php b/Tests/Functional/EventListener/DynamicContentSubscriberTest.php index 977218504..f605b544d 100644 --- a/Tests/Functional/EventListener/DynamicContentSubscriberTest.php +++ b/Tests/Functional/EventListener/DynamicContentSubscriberTest.php @@ -40,10 +40,10 @@ public function testVariousOperators(): void $customItem->setName('Test Item'); $this->customFieldValueModel->createValuesForItem($customItem); - $textValue = $customItem->findCustomFieldValueForFieldAlias('text-test-field'); - $urlValue = $customItem->findCustomFieldValueForFieldAlias('url-test-field'); - $dateValue = $customItem->findCustomFieldValueForFieldAlias('date-test-field'); - $datetimeValue = $customItem->findCustomFieldValueForFieldAlias('datetime-test-field'); + $textValue = $customItem->findCustomFieldValueForFieldAlias('text-test-field'); + $urlValue = $customItem->findCustomFieldValueForFieldAlias('url-test-field'); + $dateValue = $customItem->findCustomFieldValueForFieldAlias('date-test-field'); + $datetimeValue = $customItem->findCustomFieldValueForFieldAlias('datetime-test-field'); $multiselectValue = $customItem->findCustomFieldValueForFieldAlias('multiselect-test-field'); $textValue->setValue('abracadabra'); From 60fcb53434f766fa91332e75045c73ba4f4fd81a Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Wed, 15 Apr 2026 12:11:49 +0200 Subject: [PATCH 19/25] fix(tests): update ContactFilterMatcherTest for new constructor signature --- Tests/Unit/Helper/ContactFilterMatcherTest.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Tests/Unit/Helper/ContactFilterMatcherTest.php b/Tests/Unit/Helper/ContactFilterMatcherTest.php index d29482d28..eef34aee4 100644 --- a/Tests/Unit/Helper/ContactFilterMatcherTest.php +++ b/Tests/Unit/Helper/ContactFilterMatcherTest.php @@ -8,11 +8,11 @@ use Doctrine\DBAL\Query\QueryBuilder as DbalQueryBuilder; use Doctrine\DBAL\Result; use Mautic\LeadBundle\Entity\CompanyRepository; -use Mautic\LeadBundle\Entity\LeadListRepository; use MauticPlugin\CustomObjectsBundle\Entity\CustomObject; use MauticPlugin\CustomObjectsBundle\Exception\InvalidCustomObjectFormatListException; use MauticPlugin\CustomObjectsBundle\Exception\NotFoundException; use MauticPlugin\CustomObjectsBundle\Helper\ContactFilterMatcher; +use MauticPlugin\CustomObjectsBundle\Helper\FilterEvaluator; use MauticPlugin\CustomObjectsBundle\Model\CustomFieldModel; use MauticPlugin\CustomObjectsBundle\Model\CustomItemModel; use MauticPlugin\CustomObjectsBundle\Model\CustomObjectModel; @@ -30,9 +30,6 @@ class ContactFilterMatcherTest extends TestCase /** @var CustomItemModel&MockObject */ private MockObject $customItemModel; - /** @var LeadListRepository&MockObject */ - private MockObject $segmentRepository; - /** @var CompanyRepository&MockObject */ private MockObject $companyRepository; @@ -48,7 +45,6 @@ protected function setUp(): void $this->customFieldModel = $this->createMock(CustomFieldModel::class); $this->customObjectModel = $this->createMock(CustomObjectModel::class); $this->customItemModel = $this->createMock(CustomItemModel::class); - $this->segmentRepository = $this->createMock(LeadListRepository::class); $this->companyRepository = $this->createMock(CompanyRepository::class); $this->connection = $this->createMock(Connection::class); @@ -56,9 +52,9 @@ protected function setUp(): void $this->customFieldModel, $this->customObjectModel, $this->customItemModel, - $this->segmentRepository, $this->companyRepository, $this->connection, + new FilterEvaluator(), 10 ); } From 9fb226ec0631a2534a4353b3f0314f53f27ee84e Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Wed, 15 Apr 2026 12:17:54 +0200 Subject: [PATCH 20/25] fix(di): use string service IDs for FilterEvaluator and ContactFilterMatcher in config.php, add class-name aliases in services.php for autowiring --- Config/config.php | 12 ++++++------ Config/services.php | 7 +++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Config/config.php b/Config/config.php index 297a8e542..df583a48f 100644 --- a/Config/config.php +++ b/Config/config.php @@ -410,7 +410,7 @@ 'mautic.campaign.model.event', 'event_dispatcher', 'custom_object.helper.token_formatter', - MauticPlugin\CustomObjectsBundle\Helper\FilterEvaluator::class, + 'custom_object.helper.filter_evaluator', '%mautic.custom_item_fetch_limit_per_lead%', ], ], @@ -637,7 +637,10 @@ 'custom_object.helper.token_formatter' => [ 'class' => MauticPlugin\CustomObjectsBundle\Helper\TokenFormatter::class, ], - MauticPlugin\CustomObjectsBundle\Helper\ContactFilterMatcher::class => [ + 'custom_object.helper.filter_evaluator' => [ + 'class' => MauticPlugin\CustomObjectsBundle\Helper\FilterEvaluator::class, + ], + 'custom_object.helper.contact_filter_matcher' => [ 'class' => MauticPlugin\CustomObjectsBundle\Helper\ContactFilterMatcher::class, 'arguments' => [ 'mautic.custom.model.field', @@ -645,13 +648,10 @@ 'mautic.custom.model.item', 'mautic.lead.repository.company', 'doctrine.dbal.default_connection', - MauticPlugin\CustomObjectsBundle\Helper\FilterEvaluator::class, + 'custom_object.helper.filter_evaluator', '%mautic.custom_item_fetch_limit_per_lead%', ], ], - MauticPlugin\CustomObjectsBundle\Helper\FilterEvaluator::class => [ - 'class' => MauticPlugin\CustomObjectsBundle\Helper\FilterEvaluator::class, - ], 'custom_object.data_persister.custom_item' => [ 'class' => MauticPlugin\CustomObjectsBundle\DataPersister\CustomItemDataPersister::class, diff --git a/Config/services.php b/Config/services.php index 26d9b3d64..c513e2f70 100644 --- a/Config/services.php +++ b/Config/services.php @@ -3,6 +3,8 @@ declare(strict_types=1); use Mautic\CoreBundle\DependencyInjection\MauticCoreExtension; +use MauticPlugin\CustomObjectsBundle\Helper\ContactFilterMatcher; +use MauticPlugin\CustomObjectsBundle\Helper\FilterEvaluator; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; return function (ContainerConfigurator $configurator): void { @@ -19,10 +21,15 @@ 'Extension/CustomItemListeningExtension.php', // Registered explicitly in config.php so the int $leadCustomItemFetchLimit arg can be set 'Helper/ContactFilterMatcher.php', + 'Helper/FilterEvaluator.php', ]; $services->load('MauticPlugin\\CustomObjectsBundle\\', '../') ->exclude('../{'.implode(',', array_merge(MauticCoreExtension::DEFAULT_EXCLUDES, $excludes)).'}'); $services->load('MauticPlugin\\CustomObjectsBundle\\Repository\\', '../Repository/*Repository.php'); + + // Aliases so autowiring resolves the config.php-registered services by class name + $services->alias(ContactFilterMatcher::class, 'custom_object.helper.contact_filter_matcher')->public(); + $services->alias(FilterEvaluator::class, 'custom_object.helper.filter_evaluator')->public(); }; From 2d81055413b4908d2773ec2918b9b5155fb02ef2 Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Wed, 15 Apr 2026 12:26:32 +0200 Subject: [PATCH 21/25] fix(dynamic-content): include contact id in lead array and fix any-match loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DynamicContentSubscriber: pass array_merge(['id' => $contact->getId()], $contact->getProfileFields()) so ContactFilterMatcher can find 'id' (Lead::getProfileFields() does not include the entity id property) - FilterEvaluator: fix any-match semantics — previous loop broke on first non-match (null !== false → break), preventing evaluation of subsequent linked custom items --- EventListener/DynamicContentSubscriber.php | 3 ++- Helper/FilterEvaluator.php | 11 +++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/EventListener/DynamicContentSubscriber.php b/EventListener/DynamicContentSubscriber.php index a2bd8839e..dbef2642d 100644 --- a/EventListener/DynamicContentSubscriber.php +++ b/EventListener/DynamicContentSubscriber.php @@ -42,9 +42,10 @@ public function evaluateFilters(ContactFiltersEvaluateEvent $event): void $event->setIsEvaluated(true); $event->stopPropagation(); + $contact = $event->getContact(); $event->setIsMatched($this->contactFilterMatcher->match( $event->getFilters(), - $event->getContact()->getProfileFields() + array_merge(['id' => $contact->getId()], $contact->getProfileFields()) )); } diff --git a/Helper/FilterEvaluator.php b/Helper/FilterEvaluator.php index 60e4bd39e..d7fcbd609 100644 --- a/Helper/FilterEvaluator.php +++ b/Helper/FilterEvaluator.php @@ -67,17 +67,16 @@ public function evaluate(array $filters, array $lead): bool continue; } - $matched = null; + $matched = false; foreach ($leadValues as $leadVal) { - if (null !== $matched) { + [$leadVal, $filterVal] = $this->coerceTypes($data['type'], $leadVal, $filterVal); + if ($this->applyOperator($data['operator'], $data['type'], $leadVal, $filterVal)) { + $matched = true; break; } - - [$leadVal, $filterVal] = $this->coerceTypes($data['type'], $leadVal, $filterVal); - $matched = $this->applyOperator($data['operator'], $data['type'], $leadVal, $filterVal); } - $groups[$groupNum] = $matched ?? false; + $groups[$groupNum] = $matched; } return in_array(true, $groups, true); From 803c0cb982f9ac248ee4424695775008ffd055fb Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Wed, 15 Apr 2026 12:32:19 +0200 Subject: [PATCH 22/25] fix(test): update unit test expectation to include id in lead array for DynamicContentSubscriber --- Tests/Unit/EventListener/DynamicContentSubscriberTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Unit/EventListener/DynamicContentSubscriberTest.php b/Tests/Unit/EventListener/DynamicContentSubscriberTest.php index d366cfc0f..5bfaf35e6 100644 --- a/Tests/Unit/EventListener/DynamicContentSubscriberTest.php +++ b/Tests/Unit/EventListener/DynamicContentSubscriberTest.php @@ -118,7 +118,7 @@ public function testEvaluateFiltersMatchesAndSetsResultOnEvent(): void $this->contactFilterMatcher->expects($this->once()) ->method('match') - ->with($this->buildFilters(), ['email' => 'test@example.com']) + ->with($this->buildFilters(), ['id' => null, 'email' => 'test@example.com']) ->willReturn(true); $this->subscriber->evaluateFilters($event); From de7cc71266ddbd6ec0ef66f9177d53e61b1f3dd3 Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Wed, 15 Apr 2026 15:45:53 +0200 Subject: [PATCH 23/25] test: add FilterEvaluatorTest unit tests and fill functional test gaps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Tests/Unit/Helper/FilterEvaluatorTest: 36 tests covering all operators, type coercions, AND/OR group logic, custom-object any-match semantics, and edge cases (missing id, empty filters, scalar-to-array normalisation) - DynamicContentSubscriberTest: add testRegexpOperator, testNumberFieldComparisons, testOrFiltersFirstGroupPassesSecondFails - DynamicContentSubscriberTest: simplify testAlreadyEvaluatedEventIsSkipped — removes unnecessary DB fixture creation (subscriber bails out before DB access) --- .../DynamicContentSubscriberTest.php | 99 ++++- Tests/Unit/Helper/FilterEvaluatorTest.php | 362 ++++++++++++++++++ 2 files changed, 453 insertions(+), 8 deletions(-) create mode 100644 Tests/Unit/Helper/FilterEvaluatorTest.php diff --git a/Tests/Functional/EventListener/DynamicContentSubscriberTest.php b/Tests/Functional/EventListener/DynamicContentSubscriberTest.php index f605b544d..873428d8d 100644 --- a/Tests/Functional/EventListener/DynamicContentSubscriberTest.php +++ b/Tests/Functional/EventListener/DynamicContentSubscriberTest.php @@ -350,15 +350,91 @@ public function testEmptyOperatorMatchesContactWithNoLinkedItems(): void } public function testAlreadyEvaluatedEventIsSkipped(): void + { + // No DB setup needed — the subscriber bails out before touching the DB. + $contact = new Lead(); + $event = new ContactFiltersEvaluateEvent([], $contact); + $event->setIsEvaluated(true); // already handled by another listener + $event->setIsMatched(false); // prior result was false + + $this->subscriber->evaluateFilters($event); + + $this->assertFalse($event->isMatched(), 'Subscriber must not overwrite a result already set by another listener'); + } + + public function testRegexpOperator(): void + { + $customObject = $this->createCustomObjectWithAllFields(self::$container, 'Product'); + $contact = $this->createContact('regexp@example.com'); + $customItem = new CustomItem($customObject); + $customItem->setName('Test Item'); + $this->customFieldValueModel->createValuesForItem($customItem); + + $textValue = $customItem->findCustomFieldValueForFieldAlias('text-test-field'); + $textValue->setValue('abracadabra'); + $customItem = $this->customItemModel->save($customItem); + $this->customItemModel->linkEntity($customItem, 'contact', (int) $contact->getId()); + + $fieldId = $textValue->getCustomField()->getId(); + + // regexp match + $this->assertMatched($contact, $fieldId, 'text', 'regexp', 'abra.*cadabra'); + + // regexp no match + $this->assertNotMatched($contact, $fieldId, 'text', 'regexp', '^unicorn'); + + // !regexp match (value does not match pattern) + $this->assertMatched($contact, $fieldId, 'text', '!regexp', '^unicorn'); + + // !regexp no match (value matches pattern) + $this->assertNotMatched($contact, $fieldId, 'text', '!regexp', 'abra.*cadabra'); + } + + public function testNumberFieldComparisons(): void + { + $customObject = $this->createCustomObjectWithAllFields(self::$container, 'Product'); + $contact = $this->createContact('number@example.com'); + $customItem = new CustomItem($customObject); + $customItem->setName('Test Item'); + $this->customFieldValueModel->createValuesForItem($customItem); + + $intValue = $customItem->findCustomFieldValueForFieldAlias('int-test-field'); + $intValue->setValue(42); + $customItem = $this->customItemModel->save($customItem); + $this->customItemModel->linkEntity($customItem, 'contact', (int) $contact->getId()); + + $fieldId = $intValue->getCustomField()->getId(); + + // = match / no match + $this->assertMatched($contact, $fieldId, 'number', '=', 42); + $this->assertNotMatched($contact, $fieldId, 'number', '=', 99); + + // gt / gte + $this->assertMatched($contact, $fieldId, 'number', 'gt', 10); + $this->assertNotMatched($contact, $fieldId, 'number', 'gt', 42); + $this->assertMatched($contact, $fieldId, 'number', 'gte', 42); + $this->assertNotMatched($contact, $fieldId, 'number', 'gte', 43); + + // lt / lte + $this->assertMatched($contact, $fieldId, 'number', 'lt', 99); + $this->assertNotMatched($contact, $fieldId, 'number', 'lt', 42); + $this->assertMatched($contact, $fieldId, 'number', 'lte', 42); + $this->assertNotMatched($contact, $fieldId, 'number', 'lte', 41); + } + + public function testOrFiltersFirstGroupPassesSecondFails(): void { $customObject = $this->createCustomObjectWithAllFields(self::$container, 'Product'); - $contact = $this->createContact('already-evaluated@example.com'); + $contact = $this->createContact('or-first-passes@example.com'); $customItem = new CustomItem($customObject); $customItem->setName('Test Item'); $this->customFieldValueModel->createValuesForItem($customItem); $textValue = $customItem->findCustomFieldValueForFieldAlias('text-test-field'); - $textValue->setValue('premium'); + $urlValue = $customItem->findCustomFieldValueForFieldAlias('url-test-field'); + $textValue->setValue('abracadabra'); + // urlValue left empty + $customItem = $this->customItemModel->save($customItem); $this->customItemModel->linkEntity($customItem, 'contact', (int) $contact->getId()); @@ -368,19 +444,26 @@ public function testAlreadyEvaluatedEventIsSkipped(): void 'field' => 'cmf_'.$textValue->getCustomField()->getId(), 'object' => 'custom_object', 'type' => 'text', - 'filter' => 'premium', + 'filter' => 'abracadabra', 'display' => null, - 'operator' => '=', + 'operator' => '=', // first group passes + ], + [ + 'glue' => 'or', // starts a second group + 'field' => 'cmf_'.$urlValue->getCustomField()->getId(), + 'object' => 'custom_object', + 'type' => 'text', + 'filter' => null, + 'display' => null, + 'operator' => '!empty', // second group fails (url is empty) ], ]; $event = new ContactFiltersEvaluateEvent($filters, $contact); - $event->setIsEvaluated(true); // already handled by another listener - $event->setIsMatched(false); // prior result was false - $this->subscriber->evaluateFilters($event); - $this->assertFalse($event->isMatched(), 'Subscriber must not overwrite a result already set by another listener'); + $this->assertTrue($event->isEvaluated()); + $this->assertTrue($event->isMatched(), 'First OR group passes — overall result must be true even though second group fails'); } public function testEvaluateFiltersSkipsEventWithNoCustomObjectFilters(): void diff --git a/Tests/Unit/Helper/FilterEvaluatorTest.php b/Tests/Unit/Helper/FilterEvaluatorTest.php new file mode 100644 index 000000000..86062a602 --- /dev/null +++ b/Tests/Unit/Helper/FilterEvaluatorTest.php @@ -0,0 +1,362 @@ +evaluator = new FilterEvaluator(); + } + + // ------------------------------------------------------------------------- + // Guard conditions + // ------------------------------------------------------------------------- + + public function testReturnsFalseWhenLeadHasNoId(): void + { + $filters = [$this->leadFilter('email', 'text', '=', 'test@example.com')]; + $this->assertFalse($this->evaluator->evaluate($filters, ['email' => 'test@example.com'])); + } + + public function testReturnsFalseWhenFiltersAreEmpty(): void + { + $this->assertFalse($this->evaluator->evaluate([], ['id' => 1])); + } + + public function testSkipsFilterWhenFieldNotPresentInLead(): void + { + // Filter references a field that is not in $lead — should be skipped, result is false. + $filters = [$this->leadFilter('missing_field', 'text', '=', 'value')]; + $this->assertFalse($this->evaluator->evaluate($filters, ['id' => 1])); + } + + // ------------------------------------------------------------------------- + // AND / OR group logic + // ------------------------------------------------------------------------- + + public function testAndFiltersAllMustBeTrue(): void + { + $filters = [ + $this->leadFilter('first_name', 'text', '=', 'Alice'), + $this->leadFilter('last_name', 'text', '=', 'Smith'), + ]; + + $this->assertTrue( + $this->evaluator->evaluate($filters, ['id' => 1, 'first_name' => 'Alice', 'last_name' => 'Smith']) + ); + + $this->assertFalse( + $this->evaluator->evaluate($filters, ['id' => 1, 'first_name' => 'Alice', 'last_name' => 'Jones']) + ); + } + + public function testOrGroupPassesWhenFirstGroupFails(): void + { + $filters = [ + $this->leadFilter('email', 'text', '=', 'wrong@example.com'), + array_merge($this->leadFilter('city', 'text', '=', 'Paris'), ['glue' => 'or']), + ]; + + $lead = ['id' => 1, 'email' => 'test@example.com', 'city' => 'Paris']; + $this->assertTrue($this->evaluator->evaluate($filters, $lead)); + } + + public function testOrGroupPassesWhenFirstGroupPasses(): void + { + $filters = [ + $this->leadFilter('email', 'text', '=', 'test@example.com'), + array_merge($this->leadFilter('city', 'text', '=', 'Wrong'), ['glue' => 'or']), + ]; + + $lead = ['id' => 1, 'email' => 'test@example.com', 'city' => 'Paris']; + $this->assertTrue($this->evaluator->evaluate($filters, $lead)); + } + + public function testReturnsFalseWhenAllOrGroupsFail(): void + { + $filters = [ + $this->leadFilter('email', 'text', '=', 'wrong@example.com'), + array_merge($this->leadFilter('city', 'text', '=', 'Wrong'), ['glue' => 'or']), + ]; + + $lead = ['id' => 1, 'email' => 'test@example.com', 'city' => 'Paris']; + $this->assertFalse($this->evaluator->evaluate($filters, $lead)); + } + + // ------------------------------------------------------------------------- + // Custom object any-match semantics + // ------------------------------------------------------------------------- + + public function testCustomObjectAnyItemMatchWins(): void + { + $filters = [$this->cmoFilter('cmf_1', 'text', '=', 'premium')]; + $lead = ['id' => 1, 'cmf_1' => ['basic', 'premium', 'trial']]; + + $this->assertTrue($this->evaluator->evaluate($filters, $lead)); + } + + public function testCustomObjectReturnsFalseWhenNoItemMatches(): void + { + $filters = [$this->cmoFilter('cmf_1', 'text', '=', 'enterprise')]; + $lead = ['id' => 1, 'cmf_1' => ['basic', 'premium']]; + + $this->assertFalse($this->evaluator->evaluate($filters, $lead)); + } + + public function testCustomObjectEmptyOperatorMatchesWhenNoLinkedItems(): void + { + $filters = [$this->cmoFilter('cmf_1', 'text', 'empty', null)]; + $lead = ['id' => 1, 'cmf_1' => []]; + + $this->assertTrue($this->evaluator->evaluate($filters, $lead)); + } + + public function testCustomObjectNotEmptyOperatorFailsWhenNoLinkedItems(): void + { + $filters = [$this->cmoFilter('cmf_1', 'text', '!empty', null)]; + $lead = ['id' => 1, 'cmf_1' => []]; + + $this->assertFalse($this->evaluator->evaluate($filters, $lead)); + } + + public function testCustomObjectScalarValueIsWrappedInArray(): void + { + // cmf_ value stored as scalar rather than array — evaluator must normalise it. + $filters = [$this->cmoFilter('cmf_1', 'text', '=', 'hello')]; + $lead = ['id' => 1, 'cmf_1' => 'hello']; + + $this->assertTrue($this->evaluator->evaluate($filters, $lead)); + } + + // ------------------------------------------------------------------------- + // Operators — string/text + // ------------------------------------------------------------------------- + + public function testEqualOperator(): void + { + $this->assertOperator('text', '=', 'abc', 'abc', true); + $this->assertOperator('text', '=', 'abc', 'xyz', false); + } + + public function testNotEqualOperator(): void + { + $this->assertOperator('text', '!=', 'abc', 'xyz', true); + $this->assertOperator('text', '!=', 'abc', 'abc', false); + } + + public function testEmptyOperator(): void + { + $this->assertOperator('text', 'empty', '', null, true); + $this->assertOperator('text', 'empty', 'value', null, false); + } + + public function testNotEmptyOperator(): void + { + $this->assertOperator('text', '!empty', 'value', null, true); + $this->assertOperator('text', '!empty', '', null, false); + } + + public function testLikeOperatorWithPercentWildcard(): void + { + $this->assertOperator('text', 'like', 'abracadabra', 'abra%', true); + $this->assertOperator('text', 'like', 'abracadabra', '%cadabra', true); + $this->assertOperator('text', 'like', 'abracadabra', '%cada%', true); + $this->assertOperator('text', 'like', 'abracadabra', 'unicorn%', false); + } + + public function testNotLikeOperator(): void + { + $this->assertOperator('text', '!like', 'abracadabra', 'unicorn%', true); + $this->assertOperator('text', '!like', 'abracadabra', 'abra%', false); + } + + public function testStartsWithOperator(): void + { + $this->assertOperator('text', 'startsWith', 'abracadabra', 'abra', true); + $this->assertOperator('text', 'startsWith', 'abracadabra', 'cadabra', false); + } + + public function testEndsWithOperator(): void + { + $this->assertOperator('text', 'endsWith', 'abracadabra', 'cadabra', true); + $this->assertOperator('text', 'endsWith', 'abracadabra', 'unicorn', false); + } + + public function testContainsOperator(): void + { + $this->assertOperator('text', 'contains', 'abracadabra', 'cada', true); + $this->assertOperator('text', 'contains', 'abracadabra', 'unicorn', false); + } + + public function testRegexpOperator(): void + { + $this->assertOperator('text', 'regexp', 'abracadabra', 'abra.*cadabra', true); + $this->assertOperator('text', 'regexp', 'abracadabra', '^unicorn', false); + // Regexp is case-insensitive + $this->assertOperator('text', 'regexp', 'HELLO', 'hello', true); + } + + public function testNotRegexpOperator(): void + { + $this->assertOperator('text', '!regexp', 'abracadabra', '^unicorn', true); + $this->assertOperator('text', '!regexp', 'abracadabra', 'abra.*cadabra', false); + } + + public function testInOperator(): void + { + $this->assertOperator('text', 'in', 'b', ['a', 'b', 'c'], true); + $this->assertOperator('text', 'in', 'z', ['a', 'b', 'c'], false); + } + + public function testNotInOperator(): void + { + $this->assertOperator('text', '!in', 'z', ['a', 'b', 'c'], true); + $this->assertOperator('text', '!in', 'b', ['a', 'b', 'c'], false); + } + + public function testUnknownOperatorThrowsException(): void + { + $this->expectException(OperatorsNotFoundException::class); + + $filters = [$this->leadFilter('email', 'text', 'nonexistent_operator', 'value')]; + $this->evaluator->evaluate($filters, ['id' => 1, 'email' => 'test@example.com']); + } + + // ------------------------------------------------------------------------- + // Operators — comparison (number type) + // ------------------------------------------------------------------------- + + public function testGtOperator(): void + { + $this->assertOperator('number', 'gt', 10, 5, true); + $this->assertOperator('number', 'gt', 5, 10, false); + $this->assertOperator('number', 'gt', 5, 5, false); + } + + public function testGteOperator(): void + { + $this->assertOperator('number', 'gte', 10, 5, true); + $this->assertOperator('number', 'gte', 5, 5, true); + $this->assertOperator('number', 'gte', 4, 5, false); + } + + public function testLtOperator(): void + { + $this->assertOperator('number', 'lt', 3, 5, true); + $this->assertOperator('number', 'lt', 5, 5, false); + $this->assertOperator('number', 'lt', 10, 5, false); + } + + public function testLteOperator(): void + { + $this->assertOperator('number', 'lte', 3, 5, true); + $this->assertOperator('number', 'lte', 5, 5, true); + $this->assertOperator('number', 'lte', 10, 5, false); + } + + // ------------------------------------------------------------------------- + // Type coercions + // ------------------------------------------------------------------------- + + public function testBooleanCoercionEqualTrueValues(): void + { + // String '1' and int 1 are both coerced to true before comparison. + $this->assertOperator('boolean', '=', '1', 1, true); + $this->assertOperator('boolean', '=', '0', 0, true); + $this->assertOperator('boolean', '=', '1', 0, false); + } + + public function testBooleanStrictNotEqualUsesIdentity(): void + { + // For boolean type != uses strict identity after coercion. + $this->assertOperator('boolean', '!=', '1', 0, true); + $this->assertOperator('boolean', '!=', '0', 0, false); + } + + public function testMultiselectCoercionSplitsByPipe(): void + { + // Pipe-separated string is split into an array before in-check. + $this->assertOperator('multiselect', 'in', 'a|b|c', ['b'], true); + $this->assertOperator('multiselect', 'in', 'a|b|c', ['z'], false); + } + + public function testSelectCoercionSplitsByPipe(): void + { + $this->assertOperator('select', 'in', 'a|b', ['a'], true); + } + + public function testDatetimeCoercionAppendsMissingSeconds(): void + { + // Lead value has H:i:s, filter only H:i — evaluator appends :00 to filter. + $this->assertOperator('datetime', '=', '2024-01-01 12:00:00', '2024-01-01 12:00', true); + } + + public function testNumberCoercionConvertsToInt(): void + { + // String '42' in lead and int 42 as filter — both coerced to int. + $this->assertOperator('number', '=', '42', 42, true); + } + + // ------------------------------------------------------------------------- + // Helpers + // ------------------------------------------------------------------------- + + /** + * @param mixed $leadValue + * @param mixed $filterValue + */ + private function assertOperator(string $type, string $operator, $leadValue, $filterValue, bool $expected): void + { + $filters = [$this->leadFilter('field', $type, $operator, $filterValue)]; + $result = $this->evaluator->evaluate($filters, ['id' => 1, 'field' => $leadValue]); + + $this->assertSame( + $expected, + $result, + "Operator '{$operator}' (type: {$type}): lead=".json_encode($leadValue).' filter='.json_encode($filterValue) + ); + } + + /** + * @param mixed $filterValue + * + * @return array + */ + private function leadFilter(string $field, string $type, string $operator, $filterValue): array + { + return [ + 'glue' => 'and', + 'field' => $field, + 'object' => 'lead', + 'type' => $type, + 'filter' => $filterValue, + 'operator' => $operator, + ]; + } + + /** + * @param mixed $filterValue + * + * @return array + */ + private function cmoFilter(string $field, string $type, string $operator, $filterValue): array + { + return [ + 'glue' => 'and', + 'field' => $field, + 'object' => 'custom_object', + 'type' => $type, + 'filter' => $filterValue, + 'operator' => $operator, + ]; + } +} From b6fdc86e71664f6e202405773f6a0524e06a9075 Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Wed, 15 Apr 2026 15:51:57 +0200 Subject: [PATCH 24/25] fix(test): use number-test-field alias for int type (translates to Number) --- Tests/Functional/EventListener/DynamicContentSubscriberTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Functional/EventListener/DynamicContentSubscriberTest.php b/Tests/Functional/EventListener/DynamicContentSubscriberTest.php index 873428d8d..556bfb9aa 100644 --- a/Tests/Functional/EventListener/DynamicContentSubscriberTest.php +++ b/Tests/Functional/EventListener/DynamicContentSubscriberTest.php @@ -398,7 +398,7 @@ public function testNumberFieldComparisons(): void $customItem->setName('Test Item'); $this->customFieldValueModel->createValuesForItem($customItem); - $intValue = $customItem->findCustomFieldValueForFieldAlias('int-test-field'); + $intValue = $customItem->findCustomFieldValueForFieldAlias('number-test-field'); $intValue->setValue(42); $customItem = $this->customItemModel->save($customItem); $this->customItemModel->linkEntity($customItem, 'contact', (int) $contact->getId()); From 6ef44272304a4c023c3d14a10fc75e82f0b07dbe Mon Sep 17 00:00:00 2001 From: Edouard MANGEL Date: Wed, 15 Apr 2026 16:17:11 +0200 Subject: [PATCH 25/25] fix(evaluator): handle int type key in coerceTypes, use int type in functional test - FilterEvaluator: add 'int' case alongside 'number' in coerceTypes switch (CustomObjectsBundle IntType uses key 'int', Mautic lead fields use 'number') - Functional test: use 'int' as the type for int field filters (matches the actual type key registered by IntType, which QueryFilterFactory validates) - Unit test: add 'int' coercion assertion alongside existing 'number' test --- Helper/FilterEvaluator.php | 1 + .../DynamicContentSubscriberTest.php | 20 +++++++++---------- Tests/Unit/Helper/FilterEvaluatorTest.php | 2 ++ 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Helper/FilterEvaluator.php b/Helper/FilterEvaluator.php index d7fcbd609..e2e7d09a3 100644 --- a/Helper/FilterEvaluator.php +++ b/Helper/FilterEvaluator.php @@ -114,6 +114,7 @@ private function coerceTypes(string $type, mixed $leadVal, mixed $filterVal): ar $filterVal = explode('|', $filterVal); } break; + case 'int': case 'number': $leadVal = (int) $leadVal; $filterVal = (int) $filterVal; diff --git a/Tests/Functional/EventListener/DynamicContentSubscriberTest.php b/Tests/Functional/EventListener/DynamicContentSubscriberTest.php index 556bfb9aa..cd09ae3ce 100644 --- a/Tests/Functional/EventListener/DynamicContentSubscriberTest.php +++ b/Tests/Functional/EventListener/DynamicContentSubscriberTest.php @@ -406,20 +406,20 @@ public function testNumberFieldComparisons(): void $fieldId = $intValue->getCustomField()->getId(); // = match / no match - $this->assertMatched($contact, $fieldId, 'number', '=', 42); - $this->assertNotMatched($contact, $fieldId, 'number', '=', 99); + $this->assertMatched($contact, $fieldId, 'int', '=', 42); + $this->assertNotMatched($contact, $fieldId, 'int', '=', 99); // gt / gte - $this->assertMatched($contact, $fieldId, 'number', 'gt', 10); - $this->assertNotMatched($contact, $fieldId, 'number', 'gt', 42); - $this->assertMatched($contact, $fieldId, 'number', 'gte', 42); - $this->assertNotMatched($contact, $fieldId, 'number', 'gte', 43); + $this->assertMatched($contact, $fieldId, 'int', 'gt', 10); + $this->assertNotMatched($contact, $fieldId, 'int', 'gt', 42); + $this->assertMatched($contact, $fieldId, 'int', 'gte', 42); + $this->assertNotMatched($contact, $fieldId, 'int', 'gte', 43); // lt / lte - $this->assertMatched($contact, $fieldId, 'number', 'lt', 99); - $this->assertNotMatched($contact, $fieldId, 'number', 'lt', 42); - $this->assertMatched($contact, $fieldId, 'number', 'lte', 42); - $this->assertNotMatched($contact, $fieldId, 'number', 'lte', 41); + $this->assertMatched($contact, $fieldId, 'int', 'lt', 99); + $this->assertNotMatched($contact, $fieldId, 'int', 'lt', 42); + $this->assertMatched($contact, $fieldId, 'int', 'lte', 42); + $this->assertNotMatched($contact, $fieldId, 'int', 'lte', 41); } public function testOrFiltersFirstGroupPassesSecondFails(): void diff --git a/Tests/Unit/Helper/FilterEvaluatorTest.php b/Tests/Unit/Helper/FilterEvaluatorTest.php index 86062a602..8dfcf4b5d 100644 --- a/Tests/Unit/Helper/FilterEvaluatorTest.php +++ b/Tests/Unit/Helper/FilterEvaluatorTest.php @@ -304,6 +304,8 @@ public function testNumberCoercionConvertsToInt(): void { // String '42' in lead and int 42 as filter — both coerced to int. $this->assertOperator('number', '=', '42', 42, true); + // 'int' is the custom field type key — same coercion applies. + $this->assertOperator('int', '=', '42', 42, true); } // -------------------------------------------------------------------------