diff --git a/.github/workflows/run-test.yml b/.github/workflows/run-test.yml index 2fe1003b..a5e3045f 100644 --- a/.github/workflows/run-test.yml +++ b/.github/workflows/run-test.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php-version: ['8.1', '8.2', '8.3'] + php-version: ['8.2', '8.3'] steps: - uses: shivammathur/setup-php@v2 with: @@ -34,9 +34,7 @@ jobs: restore-keys: | ${{ runner.os }}-php-${{ matrix.php-version }}- - name: Install Dependencies - run: composer install --no-scripts --no-ansi --no-interaction --no-progress - - name: Run PHP Code Sniffer - run: vendor/bin/phpcs -p ./src + run: composer install --no-ansi --no-interaction --no-progress - name: Run PHPStan run: vendor/bin/phpstan analyse --no-progress -c phpstan.neon - name: Run PHP Unit diff --git a/composer.json b/composer.json index d4ca8d28..9df8748e 100644 --- a/composer.json +++ b/composer.json @@ -18,54 +18,55 @@ "type": "symfony-bundle", "prefer-stable": true, "require": { - "php": ">=8.1", + "php": ">=8.2", "ext-ctype": "*", "ext-iconv": "*", "ext-zip": "*", "ext-json": "*", - "api-platform/core": "~3.2.14", - "doctrine/annotations": "^1.0", + "ext-mbstring": "*", + "api-platform/core": "~3.3.11", + "doctrine/annotations": "^2.0", "doctrine/doctrine-bundle": "^2.8.1", "doctrine/doctrine-migrations-bundle": "^3.1", - "doctrine/orm": "~2.19.0", - "gedmo/doctrine-extensions": "^3.10.0", + "doctrine/orm": "~2.20.0", + "gedmo/doctrine-extensions": "^3.16.1", "inlinestyle/inlinestyle": "~1.2.7", "james-heinrich/getid3": "^1.9", "jms/serializer": "^3.9.0", "jms/serializer-bundle": "^4.2.0", "league/flysystem": "^3.0", "league/flysystem-bundle": "^3.0", - "lexik/jwt-authentication-bundle": "^2.19", + "lexik/jwt-authentication-bundle": "^3.1.0", "phpdocumentor/reflection-docblock": "^5.2", "phpoffice/phpspreadsheet": "^1.15", "ramsey/uuid": "^4.7", - "rezozero/intervention-request-bundle": "~3.0.0", - "rezozero/liform-bundle": "^0.19", + "rezozero/intervention-request-bundle": "~3.0.1", + "rezozero/liform-bundle": "^0.20.1", "rezozero/tree-walker": "^1.5.0", - "roadiz/doc-generator": "2.3.*", - "roadiz/documents": "2.3.*", - "roadiz/dts-generator": "2.3.*", - "roadiz/entity-generator": "2.3.*", - "roadiz/jwt": "2.3.*", - "roadiz/markdown": "2.3.*", - "roadiz/models": "2.3.*", + "roadiz/doc-generator": "2.4.*", + "roadiz/documents": "2.4.*", + "roadiz/dts-generator": "2.4.*", + "roadiz/entity-generator": "2.4.*", + "roadiz/jwt": "2.4.*", + "roadiz/markdown": "2.4.*", + "roadiz/models": "2.4.*", "roadiz/nodetype-contracts": "~1.1.2", - "roadiz/random": "2.3.*", - "rollerworks/password-common-list": "^0.2.0", - "rollerworks/password-strength-bundle": "^2.2", + "roadiz/random": "2.4.*", + "rollerworks/password-common-list": "^0.3.0", + "rollerworks/password-strength-bundle": "^3.0", "scienta/doctrine-json-functions": "^4.2", - "sensio/framework-extra-bundle": "^6.1", - "solarium/solarium": "^6.0.4", - "symfony-cmf/routing-bundle": "^3.0.2", + "solarium/solarium": "^6.3.6", + "symfony-cmf/routing-bundle": "^3.1.0", "symfony/asset": "6.4.*", "symfony/cache": "6.4.*", "symfony/console": "6.4.*", "symfony/dotenv": "6.4.*", "symfony/expression-language": "6.4.*", - "symfony/flex": "^2.2.3", + "symfony/flex": "^2.4.7", "symfony/form": "6.4.*", "symfony/framework-bundle": "6.4.*", "symfony/http-client": "6.4.*", + "symfony/http-client-contracts": "^3.5", "symfony/intl": "6.4.*", "symfony/lock": "6.4.*", "symfony/mailer": "6.4.*", @@ -88,10 +89,10 @@ "symfony/web-link": "6.4.*", "symfony/workflow": "6.4.*", "symfony/yaml": "6.4.*", - "twig/extra-bundle": "^3.0", + "twig/extra-bundle": "^3.16", "twig/intl-extra": "*", "twig/string-extra": "*", - "twig/twig": "^3.1" + "twig/twig": "^3.16" }, "replace": { "roadiz/roadiz": "*" @@ -101,7 +102,6 @@ "phpstan/phpstan": "^1.5.3", "phpstan/phpstan-doctrine": "^1.3", "phpunit/phpunit": "^9.5", - "squizlabs/php_codesniffer": "^3.5", "symfony/browser-kit": "6.4.*", "symfony/phpunit-bridge": "^7.0", "symfony/stopwatch": "6.4.*" @@ -136,8 +136,8 @@ }, "extra": { "branch-alias": { - "dev-main": "2.3.x-dev", - "dev-develop": "2.4.x-dev" + "dev-main": "2.4.x-dev", + "dev-develop": "2.5.x-dev" } } } diff --git a/config/packages/api_platform.yaml b/config/packages/api_platform.yaml index f9551bd7..20c65cc5 100644 --- a/config/packages/api_platform.yaml +++ b/config/packages/api_platform.yaml @@ -1,17 +1,34 @@ +parameters: + env(HTTP_CACHE_STALE_WHILE_REVALIDATE): 3600 + env(HTTP_CACHE_MAX_AGE): 60 + env(HTTP_CACHE_SHARED_MAX_AGE): 600 + api_platform: - patch_formats: - json: ['application/merge-patch+json'] - enable_swagger_ui: false + title: "%env(string:APP_TITLE)%" + description: "%env(string:APP_DESCRIPTION)%" + version: '%env(string:APP_VERSION)%' + enable_swagger_ui: true enable_re_doc: true + # Symfony inflector wrongly pluralizes "nodes_sources" to "nodes_sourcess" + keep_legacy_inflector: true + use_symfony_listeners: true + formats: + jsonld: ['application/ld+json'] + json: ['application/json'] + x-www-form-urlencoded: ['application/x-www-form-urlencoded'] + docs_formats: + jsonld: ['application/ld+json'] + jsonopenapi: ['application/vnd.openapi+json'] + html: ['text/html'] + patch_formats: + json: [ 'application/merge-patch+json' ] graphql: + introspection: '%kernel.debug%' graphiql: enabled: false + graphql_playground: + enabled: false show_webby: false - swagger: - versions: [3] - title: "%env(string:APP_TITLE)%" - description: "%env(string:APP_DESCRIPTION)%" - version: '%env(string:APP_VERSION)%' mapping: paths: - '%kernel.project_dir%/src/Entity' @@ -19,18 +36,13 @@ api_platform: - '%kernel.project_dir%/vendor/roadiz/core-bundle/src/Entity' - '%kernel.project_dir%/vendor/rezozero/tree-walker/src' - '%kernel.project_dir%/config/api_resources' - - collection: - pagination: - page_parameter_name: page - items_per_page_parameter_name: itemsPerPage - - http_cache: - invalidation: - enabled: true - varnish_urls: [ '%env(VARNISH_URL)%' ] - + swagger: + versions: [3] defaults: + stateless: true + extra_properties: + standard_put: true + rfc_7807_compliant_errors: false enable_max_depth: true normalization_context: skip_null_values: true @@ -38,8 +50,29 @@ api_platform: pagination_items_per_page: 15 pagination_maximum_items_per_page: 50 cache_headers: + # Automatically generate etags for API responses. etag: true public: true + # Default value for the response max age. max_age: '%env(int:HTTP_CACHE_MAX_AGE)%' + # Default value for the response shared (proxy) max age. shared_max_age: '%env(int:HTTP_CACHE_SHARED_MAX_AGE)%' - vary: [ 'Accept', 'Authorization', 'Origin', 'Accept-Encoding', 'Content-Type' ] + stale_while_revalidate: '%env(int:HTTP_CACHE_STALE_WHILE_REVALIDATE)%' + # Default values of the "Vary" HTTP header. + vary: ['Accept', 'Authorization', 'Origin', 'Accept-Encoding', 'Content-Type'] + collection: + pagination: + items_per_page_parameter_name: itemsPerPage + +when@prod: + api_platform: + graphql: + introspection: false + graphiql: + enabled: false + graphql_playground: + enabled: false + http_cache: + invalidation: + enabled: true + varnish_urls: [ '%env(VARNISH_URL)%' ] diff --git a/config/packages/framework.yaml b/config/packages/framework.yaml index ed735a18..d135adc5 100644 --- a/config/packages/framework.yaml +++ b/config/packages/framework.yaml @@ -20,6 +20,7 @@ framework: serializer: circular_reference_handler: 'RZ\Roadiz\CoreBundle\Serializer\CircularReferenceHandler' max_depth_handler: 'RZ\Roadiz\CoreBundle\Serializer\CircularReferenceHandler' + handle_all_throwables: true csrf_protection: enabled: true diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 8324dc43..b314b29a 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -75,6 +75,16 @@ security: secret: '%kernel.secret%' lifetime: 604800 # 1 week in seconds path: / + # Enable login-link feature + # https://symfony.com/doc/current/security/login_link.html + login_link: + check_route: login_link_check + signature_properties: [ 'id', 'email' ] + # lifetime in seconds + lifetime: 300 + # only allow the link to be used 3 times + max_uses: 3 + success_handler: RZ\Roadiz\CoreBundle\Security\Authentication\BackofficeAuthenticationSuccessHandler login_throttling: max_attempts: 3 logout: diff --git a/config/services.yaml b/config/services.yaml index 1ef2b07b..a9831817 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -1,6 +1,6 @@ --- parameters: - roadiz_core.cms_version: '2.3.31' + roadiz_core.cms_version: '2.4.0' roadiz_core.cms_version_prefix: 'main' env(APP_NAMESPACE): "roadiz" env(APP_VERSION): "0.1.0" @@ -61,8 +61,11 @@ services: - '../src/Traits/' - '../src/Kernel.php' - '../src/Tests/' - - '../src/DataCollector/' - '../src/Event/' + - '../src/Model/' + - '../src/ListManager/' + - '../src/Serializer/Normalizer/' + - '../src/Importer/' RZ\Roadiz\CoreBundle\EntityHandler\: resource: '../src/EntityHandler/' @@ -95,8 +98,6 @@ services: tags: [ { name: 'roadiz_core.media_finder', platform: 'ted' } ] RZ\Roadiz\CoreBundle\Document\MediaFinder\PodcastFinder: tags: [ { name: 'roadiz_core.media_finder', platform: 'podcast' } ] - RZ\Roadiz\CoreBundle\Document\MediaFinder\TwitchEmbedFinder: - tags: [ { name: 'roadiz_core.media_finder', platform: 'twitch' } ] # Removed DataTransformers RZ\Roadiz\CoreBundle\Api\DataTransformer\: @@ -178,16 +179,6 @@ services: decorates: 'api_platform.serializer.normalizer.item' decoration_priority: 21 - RZ\Roadiz\CoreBundle\DataCollector\RequestDataCollector: - autoconfigure: false - arguments: [ '%roadiz_core.cms_version%', '%roadiz_core.cms_version_prefix%'] - tags: - - name: data_collector - template: '@RoadizCore/DataCollector/request.html.twig' - # must match the value returned by the getName() method - id: 'roadiz.data_collector.request' - priority: 400 - # Document RZ\Roadiz\CoreBundle\Serializer\Normalizer\DocumentNormalizer: # By default, .inner is passed as argument @@ -412,11 +403,6 @@ services: RZ\Roadiz\CoreBundle\SearchEngine\ClientRegistry: arguments: ['@service_container'] - RZ\Roadiz\CoreBundle\SearchEngine\SolariumLogger: - tags: - - { name: data_collector, template: '@RoadizCore/DataCollector/solarium.html.twig', id: 'solarium' } - - { name: monolog.logger, channel: solr } - RZ\Roadiz\CoreBundle\SearchEngine\Indexer\IndexerFactory: arguments: ['@service_container'] @@ -455,7 +441,12 @@ services: arguments: ['%kernel.project_dir%'] public: true - RZ\Roadiz\Random\PasswordGenerator: ~ + RZ\Roadiz\Random\PasswordGeneratorInterface: + class: RZ\Roadiz\Random\PasswordGenerator + RZ\Roadiz\Random\SaltGeneratorInterface: + class: RZ\Roadiz\Random\SaltGenerator + RZ\Roadiz\Random\TokenGeneratorInterface: + class: RZ\Roadiz\Random\TokenGenerator JMS\Serializer\Construction\ObjectConstructorInterface: alias: RZ\Roadiz\CoreBundle\Serializer\ObjectConstructor\ObjectConstructor @@ -480,9 +471,6 @@ services: Solarium\Core\Client\Client: factory: ['RZ\Roadiz\CoreBundle\SearchEngine\ClientRegistry', 'getClient'] - RZ\Roadiz\CoreBundle\Security\Authentication\JwtAuthenticationSuccessHandler: - decorates: 'lexik_jwt_authentication.handler.authentication_success' - RZ\Roadiz\CoreBundle\Security\Authorization\Chroot\NodeChrootResolver: alias: RZ\Roadiz\CoreBundle\Security\Authorization\Chroot\NodeChrootChainResolver @@ -534,6 +522,7 @@ services: # RZ\Roadiz\CoreBundle\Document\MediaFinder\UnsplashPictureFinder: arguments: + - '@http_client' - '%roadiz_core.medias.unsplash_client_id%' RZ\Roadiz\Documents\MediaFinders\RandomImageFinder: alias: RZ\Roadiz\CoreBundle\Document\MediaFinder\UnsplashPictureFinder @@ -557,6 +546,7 @@ services: tags: [ 'roadiz_core.document_renderer' ] RZ\Roadiz\Documents\Renderer\RendererInterface: alias: RZ\Roadiz\Documents\Renderer\ChainRenderer + RZ\Roadiz\Documents\MediaFinders\FacebookPictureFinder: # Default AbstractDocumentFactory is the public one. RZ\Roadiz\Documents\AbstractDocumentFactory: @@ -655,6 +645,7 @@ services: RZ\Roadiz\Documents\MediaFinders\EmbedFinderFactory: arguments: + - '@http_client' - '%roadiz_core.medias.supported_platforms%' RZ\Roadiz\Documents\Renderer\ChainRenderer: diff --git a/migrations/Version20201203004857.php b/migrations/Version20201203004857.php index 48ccc417..57294c19 100644 --- a/migrations/Version20201203004857.php +++ b/migrations/Version20201203004857.php @@ -1,4 +1,5 @@ skipIf($schema->hasTable('nodes'), 'Database has been initialized before Doctrine Migration tool.'); - if ($this->connection->getDatabasePlatform()->getName() === 'mysql') { + if ('mysql' === $this->connection->getDatabasePlatform()->getName()) { $this->mysqlUp(); - } elseif ($this->connection->getDatabasePlatform()->getName() === 'postgresql') { + } elseif ('postgresql' === $this->connection->getDatabasePlatform()->getName()) { $this->postgresUp(); } } @@ -480,15 +479,14 @@ private function postgresUp(): void $this->addSql('ALTER TABLE users_groups ADD CONSTRAINT FK_FF8AB7E0FE54D947 FOREIGN KEY (group_id) REFERENCES usergroups (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); } - public function down(Schema $schema) : void + public function down(Schema $schema): void { $this->throwIrreversibleMigrationException(); } /** - * Temporary workaround + * Temporary workaround. * - * @return bool * @see https://github.com/doctrine/migrations/issues/1104 */ public function isTransactional(): bool diff --git a/migrations/Version20201214232628.php b/migrations/Version20201214232628.php index 3ec778c3..0f7a852c 100644 --- a/migrations/Version20201214232628.php +++ b/migrations/Version20201214232628.php @@ -1,4 +1,5 @@ skipIf( - $this->connection->getDatabasePlatform()->getName() !== 'mysql', + 'mysql' !== $this->connection->getDatabasePlatform()->getName(), 'Migration can only be executed safely on \'mysql\'.' ); $this->skipIf($schema->hasTable('usergroups'), 'Table `usergroups` already exists.'); @@ -33,10 +34,10 @@ public function up(Schema $schema) : void // $this->addSql('ALTER TABLE `usergroups` RENAME INDEX uniq_f06d39705e237e06 TO UNIQ_98972EB45E237E06'); } - public function down(Schema $schema) : void + public function down(Schema $schema): void { $this->skipIf( - $this->connection->getDatabasePlatform()->getName() !== 'mysql', + 'mysql' !== $this->connection->getDatabasePlatform()->getName(), 'Migration can only be executed safely on \'mysql\'.' ); $this->skipIf($schema->hasTable('groups'), 'Table `groups` already exists.'); @@ -54,9 +55,8 @@ public function down(Schema $schema) : void } /** - * Temporary workaround + * Temporary workaround. * - * @return bool * @see https://github.com/doctrine/migrations/issues/1104 */ public function isTransactional(): bool diff --git a/migrations/Version20201225181256.php b/migrations/Version20201225181256.php index 3e099267..91e16547 100644 --- a/migrations/Version20201225181256.php +++ b/migrations/Version20201225181256.php @@ -1,4 +1,5 @@ write('Nothing to do with RZ\Roadiz\Migrations\Version20201225181256.'); } - public function down(Schema $schema) : void + public function down(Schema $schema): void { $this->throwIrreversibleMigrationException(); } /** - * Temporary workaround + * Temporary workaround. * - * @return bool * @see https://github.com/doctrine/migrations/issues/1104 */ public function isTransactional(): bool diff --git a/migrations/Version20210423072744.php b/migrations/Version20210423072744.php index 2a92eff7..c463eaca 100644 --- a/migrations/Version20210423072744.php +++ b/migrations/Version20210423072744.php @@ -7,22 +7,19 @@ use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; -/** - * @package RZ\Roadiz\Migrations - */ final class Version20210423072744 extends AbstractMigration { - public function getDescription() : string + public function getDescription(): string { return 'Added Documents duration field.'; } - public function up(Schema $schema) : void + public function up(Schema $schema): void { $this->addSql('ALTER TABLE documents ADD duration INT DEFAULT 0 NOT NULL'); } - public function down(Schema $schema) : void + public function down(Schema $schema): void { $this->addSql('ALTER TABLE documents DROP duration'); } diff --git a/migrations/Version20210423161606.php b/migrations/Version20210423161606.php index 56ae3af1..707e52e2 100644 --- a/migrations/Version20210423161606.php +++ b/migrations/Version20210423161606.php @@ -12,12 +12,12 @@ */ final class Version20210423161606 extends AbstractMigration { - public function getDescription() : string + public function getDescription(): string { return 'Additional table indexes on documents, folders, logs and tags'; } - public function up(Schema $schema) : void + public function up(Schema $schema): void { $this->addSql('CREATE INDEX document_created_at ON documents (created_at)'); $this->addSql('CREATE INDEX document_updated_at ON documents (updated_at)'); @@ -33,9 +33,9 @@ public function up(Schema $schema) : void $this->addSql('CREATE INDEX tag_parent_position ON tags (parent_tag_id, position)'); } - public function down(Schema $schema) : void + public function down(Schema $schema): void { - if ($this->connection->getDatabasePlatform()->getName() === 'postgresql') { + if ('postgresql' === $this->connection->getDatabasePlatform()->getName()) { $this->addSql('DROP INDEX IF EXISTS document_created_at'); $this->addSql('DROP INDEX IF EXISTS document_updated_at'); $this->addSql('DROP INDEX IF EXISTS document_raw_created_at'); diff --git a/migrations/Version20210423164248.php b/migrations/Version20210423164248.php index 74af5a4a..044e1cfc 100644 --- a/migrations/Version20210423164248.php +++ b/migrations/Version20210423164248.php @@ -9,12 +9,12 @@ final class Version20210423164248 extends AbstractMigration { - public function getDescription() : string + public function getDescription(): string { return 'Additional table indexes and renaming important performance indexes'; } - public function up(Schema $schema) : void + public function up(Schema $schema): void { $this->addSql('CREATE INDEX answer_customform_submitted_at ON custom_form_answers (custom_form_id, submitted_at)'); $this->addSql('CREATE INDEX cffattribute_answer_field ON custom_form_field_attributes (custom_form_answer_id, custom_form_field_id)'); @@ -23,7 +23,7 @@ public function up(Schema $schema) : void $this->addSql('CREATE INDEX customform_node_position ON nodes_custom_forms (node_id, position)'); $this->addSql('CREATE INDEX customform_node_field_position ON nodes_custom_forms (node_id, node_type_field_id, position)'); - if ($this->connection->getDatabasePlatform()->getName() === 'postgresql') { + if ('postgresql' === $this->connection->getDatabasePlatform()->getName()) { $this->addSql('DROP INDEX IF EXISTS IDX_7C7DED6DE0D4FDE19CAA2B25'); $this->addSql('DROP INDEX IF EXISTS IDX_7C7DED6DE0D4FDE14AD260649CAA2B25'); $this->addSql('DROP INDEX IF EXISTS IDX_7C7DED6D2B36786BE0D4FDE19CAA2B25'); @@ -38,7 +38,7 @@ public function up(Schema $schema) : void $this->addSql('CREATE INDEX ns_discr_translation_published ON nodes_sources (discr, translation_id, published_at)'); $this->addSql('CREATE INDEX ns_title_translation_published ON nodes_sources (title, translation_id, published_at)'); - if ($this->connection->getDatabasePlatform()->getName() === 'postgresql') { + if ('postgresql' === $this->connection->getDatabasePlatform()->getName()) { $this->addSql('ALTER INDEX IF EXISTS ns_node_translation_discr RENAME TO ns_node_discr_translation'); $this->addSql('ALTER INDEX IF EXISTS idx_7c7ded6d460d9fd79caa2b25e0d4fde1 RENAME TO ns_node_translation_published'); $this->addSql('ALTER INDEX IF EXISTS idx_7c7ded6d4ad260649caa2b25 RENAME TO ns_discr_translation'); @@ -65,9 +65,9 @@ public function up(Schema $schema) : void } } - public function down(Schema $schema) : void + public function down(Schema $schema): void { - if ($this->connection->getDatabasePlatform()->getName() === 'postgresql') { + if ('postgresql' === $this->connection->getDatabasePlatform()->getName()) { $this->addSql('DROP INDEX IF EXISTS answer_customform_submitted_at'); $this->addSql('DROP INDEX IF EXISTS cffattribute_answer_field'); $this->addSql('DROP INDEX IF EXISTS cfield_customform_positio'); @@ -95,7 +95,7 @@ public function down(Schema $schema) : void $this->addSql('CREATE INDEX IDX_7C7DED6DE0D4FDE14AD260649CAA2B25 ON nodes_sources (published_at, discr, translation_id)'); $this->addSql('CREATE INDEX IDX_7C7DED6D2B36786BE0D4FDE19CAA2B25 ON nodes_sources (title, published_at, translation_id)'); - if ($this->connection->getDatabasePlatform()->getName() === 'postgresql') { + if ('postgresql' === $this->connection->getDatabasePlatform()->getName()) { $this->addSql('ALTER INDEX IF EXISTS ns_title_published RENAME TO IDX_7C7DED6D2B36786BE0D4FDE1'); $this->addSql('ALTER INDEX IF EXISTS ns_node_discr_translation RENAME TO ns_node_translation_discr'); $this->addSql('ALTER INDEX IF EXISTS ns_discr_translation RENAME TO IDX_7C7DED6D4AD260649CAA2B25'); diff --git a/migrations/Version20210506085247.php b/migrations/Version20210506085247.php index d1801bc4..11f2f7c3 100644 --- a/migrations/Version20210506085247.php +++ b/migrations/Version20210506085247.php @@ -25,7 +25,7 @@ public function up(Schema $schema): void $this->addSql('CREATE INDEX node_visible_parent_position ON nodes (visible, parent_node_id, position)'); $this->addSql('CREATE INDEX node_status_visible_parent_position ON nodes (status, visible, parent_node_id, position)'); - if ($this->connection->getDatabasePlatform()->getName() === 'postgresql') { + if ('postgresql' === $this->connection->getDatabasePlatform()->getName()) { $this->addSql('ALTER INDEX IF EXISTS idx_1d3d05fc7ab0e8597b00651c3445eb91 RENAME TO node_visible_status_parent'); $this->addSql('ALTER INDEX IF EXISTS idx_1d3d05fc7ab0e8593445eb91 RENAME TO node_visible_parent'); } else { @@ -36,7 +36,7 @@ public function up(Schema $schema): void $this->addSql('CREATE INDEX tag_visible_position ON tags (visible, position)'); $this->addSql('CREATE INDEX tag_parent_visible_position ON tags (parent_tag_id, visible, position)'); - if ($this->connection->getDatabasePlatform()->getName() === 'postgresql') { + if ('postgresql' === $this->connection->getDatabasePlatform()->getName()) { $this->addSql('ALTER INDEX IF EXISTS idx_6fbc9426f5c1a0d77ab0e859 RENAME TO tag_parent_visible'); } else { $this->addSql('ALTER TABLE tags RENAME INDEX idx_6fbc9426f5c1a0d77ab0e859 TO tag_parent_visible'); @@ -45,7 +45,7 @@ public function up(Schema $schema): void public function down(Schema $schema): void { - if ($this->connection->getDatabasePlatform()->getName() === 'postgresql') { + if ('postgresql' === $this->connection->getDatabasePlatform()->getName()) { $this->addSql('DROP INDEX node_status_parent'); $this->addSql('DROP INDEX node_nodetype_status_parent'); $this->addSql('DROP INDEX node_nodetype_status_parent_position'); diff --git a/migrations/Version20210520092543.php b/migrations/Version20210520092543.php index d20d9cc3..1b38b5ba 100644 --- a/migrations/Version20210520092543.php +++ b/migrations/Version20210520092543.php @@ -19,14 +19,14 @@ public function getDescription(): string public function up(Schema $schema): void { - if ($this->connection->getDatabasePlatform()->getName() === 'mysql') { + if ('mysql' === $this->connection->getDatabasePlatform()->getName()) { /* * MYSQL */ $this->addSql('ALTER TABLE node_type_fields ADD serialization_exclusion_expression LONGTEXT DEFAULT NULL, ADD serialization_groups JSON DEFAULT NULL, ADD serialization_max_depth INT DEFAULT NULL, ADD excluded_from_serialization TINYINT(1) DEFAULT \'0\' NOT NULL'); $this->addSql('ALTER TABLE node_types ADD searchable TINYINT(1) DEFAULT \'1\' NOT NULL'); $this->addSql('CREATE INDEX nt_searchable ON node_types (searchable)'); - } elseif ($this->connection->getDatabasePlatform()->getName() === 'postgresql') { + } elseif ('postgresql' === $this->connection->getDatabasePlatform()->getName()) { /* * POSTGRES */ @@ -42,11 +42,11 @@ public function up(Schema $schema): void public function down(Schema $schema): void { - if ($this->connection->getDatabasePlatform()->getName() === 'mysql') { + if ('mysql' === $this->connection->getDatabasePlatform()->getName()) { $this->addSql('ALTER TABLE node_type_fields DROP serialization_exclusion_expression, DROP serialization_groups, DROP serialization_max_depth, DROP excluded_from_serialization'); $this->addSql('DROP INDEX nt_searchable ON node_types'); $this->addSql('ALTER TABLE node_types DROP searchable'); - } elseif ($this->connection->getDatabasePlatform()->getName() === 'postgresql') { + } elseif ('postgresql' === $this->connection->getDatabasePlatform()->getName()) { /* * POSTGRES */ diff --git a/migrations/Version20210527131435.php b/migrations/Version20210527131435.php index 44edb4ff..081ec0ae 100644 --- a/migrations/Version20210527131435.php +++ b/migrations/Version20210527131435.php @@ -16,7 +16,7 @@ public function getDescription(): string public function up(Schema $schema): void { - if ($this->connection->getDatabasePlatform()->getName() === 'postgresql') { + if ('postgresql' === $this->connection->getDatabasePlatform()->getName()) { $this->addSql('ALTER TABLE redirections ALTER redirecturi TYPE TEXT'); $this->addSql('ALTER TABLE redirections ALTER redirecturi DROP DEFAULT'); $this->addSql('ALTER TABLE redirections ALTER redirecturi TYPE TEXT'); @@ -27,7 +27,7 @@ public function up(Schema $schema): void public function down(Schema $schema): void { - if ($this->connection->getDatabasePlatform()->getName() === 'postgresql') { + if ('postgresql' === $this->connection->getDatabasePlatform()->getName()) { $this->addSql('ALTER TABLE redirections ALTER redirecturi TYPE VARCHAR(255)'); $this->addSql('ALTER TABLE redirections ALTER redirecturi DROP DEFAULT'); $this->addSql('ALTER TABLE redirections ALTER redirecturi TYPE VARCHAR(255)'); diff --git a/migrations/Version20210701151713.php b/migrations/Version20210701151713.php index 00a6a06e..c0e65fd7 100644 --- a/migrations/Version20210701151713.php +++ b/migrations/Version20210701151713.php @@ -16,7 +16,7 @@ public function getDescription(): string public function up(Schema $schema): void { - if ($this->connection->getDatabasePlatform()->getName() === 'postgresql') { + if ('postgresql' === $this->connection->getDatabasePlatform()->getName()) { $this->addSql('CREATE TABLE webhooks (id VARCHAR(36) NOT NULL, message_type VARCHAR(255) DEFAULT NULL, uri TEXT DEFAULT NULL, payload JSON DEFAULT NULL, throttleSeconds INT NOT NULL, last_triggered_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, automatic BOOLEAN DEFAULT \'false\' NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, updated_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, PRIMARY KEY(id))'); $this->addSql('CREATE INDEX webhook_message_type ON webhooks (message_type)'); $this->addSql('CREATE INDEX webhook_created_at ON webhooks (created_at)'); diff --git a/migrations/Version20210715120118.php b/migrations/Version20210715120118.php index 9e28c5b6..9a577148 100644 --- a/migrations/Version20210715120118.php +++ b/migrations/Version20210715120118.php @@ -19,7 +19,7 @@ public function getDescription(): string public function up(Schema $schema): void { - if ($this->connection->getDatabasePlatform()->getName() === 'postgresql') { + if ('postgresql' === $this->connection->getDatabasePlatform()->getName()) { $this->addSql('ALTER TABLE webhooks ADD root_node INT DEFAULT NULL'); $this->addSql('ALTER TABLE webhooks ADD CONSTRAINT FK_998C4FDDC2A25172 FOREIGN KEY (root_node) REFERENCES nodes (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE'); } else { @@ -31,7 +31,7 @@ public function up(Schema $schema): void public function down(Schema $schema): void { - if ($this->connection->getDatabasePlatform()->getName() === 'postgresql') { + if ('postgresql' === $this->connection->getDatabasePlatform()->getName()) { $this->addSql('ALTER TABLE webhooks DROP CONSTRAINT FK_998C4FDDC2A25172'); $this->addSql('DROP INDEX webhook_root_node'); } else { diff --git a/migrations/Version20240713204610.php b/migrations/Version20240713204610.php new file mode 100644 index 00000000..80c938de --- /dev/null +++ b/migrations/Version20240713204610.php @@ -0,0 +1,31 @@ +addSql('CREATE INDEX ns_no_index ON nodes_sources (no_index)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('DROP INDEX ns_no_index ON nodes_sources'); + } +} diff --git a/migrations/Version20241204010215.php b/migrations/Version20241204010215.php new file mode 100644 index 00000000..4cf24130 --- /dev/null +++ b/migrations/Version20241204010215.php @@ -0,0 +1,41 @@ +addSql('ALTER TABLE custom_form_fields CHANGE type type SMALLINT DEFAULT 0 NOT NULL'); + $this->addSql('ALTER TABLE documents CHANGE imageWidth imageWidth SMALLINT DEFAULT 0 NOT NULL, CHANGE imageHeight imageHeight SMALLINT DEFAULT 0 NOT NULL'); + $this->addSql('ALTER TABLE node_type_fields CHANGE type type SMALLINT DEFAULT 0 NOT NULL, CHANGE min_length min_length SMALLINT DEFAULT NULL, CHANGE max_length max_length SMALLINT DEFAULT NULL, CHANGE serialization_max_depth serialization_max_depth SMALLINT DEFAULT NULL'); + $this->addSql('ALTER TABLE nodes CHANGE status status SMALLINT DEFAULT 10 NOT NULL'); + $this->addSql('ALTER TABLE redirections CHANGE type type SMALLINT NOT NULL'); + $this->addSql('ALTER TABLE settings CHANGE type type SMALLINT NOT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE custom_form_fields CHANGE type type INT NOT NULL'); + $this->addSql('ALTER TABLE documents CHANGE imageWidth imageWidth INT DEFAULT 0 NOT NULL, CHANGE imageHeight imageHeight INT DEFAULT 0 NOT NULL'); + $this->addSql('ALTER TABLE node_type_fields CHANGE serialization_max_depth serialization_max_depth INT DEFAULT NULL, CHANGE min_length min_length INT DEFAULT NULL, CHANGE max_length max_length INT DEFAULT NULL, CHANGE type type INT NOT NULL'); + $this->addSql('ALTER TABLE nodes CHANGE status status INT NOT NULL'); + $this->addSql('ALTER TABLE redirections CHANGE type type INT NOT NULL'); + $this->addSql('ALTER TABLE settings CHANGE type type INT NOT NULL'); + } +} diff --git a/phpcs.xml.dist b/phpcs.xml.dist deleted file mode 100644 index 19bff0cc..00000000 --- a/phpcs.xml.dist +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - src/ - diff --git a/src/Api/Breadcrumbs/Breadcrumbs.php b/src/Api/Breadcrumbs/Breadcrumbs.php index 6d0fb068..c5bf0df2 100644 --- a/src/Api/Breadcrumbs/Breadcrumbs.php +++ b/src/Api/Breadcrumbs/Breadcrumbs.php @@ -7,15 +7,15 @@ use RZ\Roadiz\Core\AbstractEntities\PersistableInterface; use Symfony\Component\Serializer\Annotation as Serializer; -final class Breadcrumbs implements BreadcrumbsInterface +final readonly class Breadcrumbs implements BreadcrumbsInterface { /** * @param PersistableInterface[] $items */ public function __construct( - #[Serializer\Groups(["breadcrumbs", "web_response"])] + #[Serializer\Groups(['breadcrumbs', 'web_response'])] #[Serializer\MaxDepth(1)] - private readonly array $items + private array $items, ) { } diff --git a/src/Api/Breadcrumbs/NodesSourcesBreadcrumbsFactory.php b/src/Api/Breadcrumbs/NodesSourcesBreadcrumbsFactory.php index 93cb2ee1..8779fb19 100644 --- a/src/Api/Breadcrumbs/NodesSourcesBreadcrumbsFactory.php +++ b/src/Api/Breadcrumbs/NodesSourcesBreadcrumbsFactory.php @@ -9,10 +9,6 @@ final class NodesSourcesBreadcrumbsFactory implements BreadcrumbsFactoryInterface { - /** - * @param PersistableInterface|null $entity - * @return BreadcrumbsInterface|null - */ public function create(?PersistableInterface $entity): ?BreadcrumbsInterface { if (!$entity instanceof NodesSources) { @@ -27,8 +23,8 @@ public function create(?PersistableInterface $entity): ?BreadcrumbsInterface while (null !== $entity = $entity->getParent()) { if ( - null !== $entity->getNode() && - $entity->getNode()->isVisible() + null !== $entity->getNode() + && $entity->getNode()->isVisible() ) { $parents[] = $entity; } diff --git a/src/Api/Controller/GetWebResponseByPathController.php b/src/Api/Controller/GetWebResponseByPathController.php index b6434889..3542e1df 100644 --- a/src/Api/Controller/GetWebResponseByPathController.php +++ b/src/Api/Controller/GetWebResponseByPathController.php @@ -4,10 +4,10 @@ namespace RZ\Roadiz\CoreBundle\Api\Controller; -use ApiPlatform\Api\IriConverterInterface; -use ApiPlatform\Exception\InvalidArgumentException; -use ApiPlatform\Exception\ResourceClassNotFoundException; +use ApiPlatform\Metadata\Exception\InvalidArgumentException; use ApiPlatform\Metadata\Exception\OperationNotFoundException; +use ApiPlatform\Metadata\Exception\ResourceClassNotFoundException; +use ApiPlatform\Metadata\IriConverterInterface; use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface; use Psr\Log\LoggerInterface; use RZ\Roadiz\Core\AbstractEntities\PersistableInterface; @@ -32,7 +32,7 @@ public function __construct( private readonly IriConverterInterface $iriConverter, private readonly PreviewResolverInterface $previewResolver, private readonly ApiResourceOperationNameGenerator $apiResourceOperationNameGenerator, - private readonly LoggerInterface $logger + private readonly LoggerInterface $logger, ) { } @@ -40,8 +40,8 @@ public function __invoke(?Request $request): ?WebResponseInterface { try { if ( - null === $request || - empty($request->query->get('path')) + null === $request + || empty($request->query->get('path')) ) { throw new InvalidArgumentException('path query parameter is mandatory'); } @@ -88,7 +88,7 @@ public function __invoke(?Request $request): ?WebResponseInterface $request->attributes->set('data', $data); return $data; - } catch (ResourceNotFoundException | ResourceClassNotFoundException $exception) { + } catch (ResourceNotFoundException|ResourceClassNotFoundException $exception) { throw $this->createNotFoundException($exception->getMessage(), $exception); } } @@ -121,8 +121,8 @@ protected function normalizeResourcePath(?Request $request, string $path): Persi } $resource = $nodeSource; } elseif ( - null !== $resource->getRedirectUri() && - (new UnicodeString($resource->getRedirectUri()))->startsWith('/') + null !== $resource->getRedirectUri() + && (new UnicodeString($resource->getRedirectUri()))->startsWith('/') ) { /* * Recursive call to normalize path coming from Redirection if redirected path @@ -153,7 +153,7 @@ protected function addResourceToCacheTags(?Request $request, PersistableInterfac { if (null !== $request) { $iri = $this->iriConverter->getIriFromResource($resource); - $request->attributes->set('_resources', $request->attributes->get('_resources', []) + [ $iri => $iri ]); + $request->attributes->set('_resources', $request->attributes->get('_resources', []) + [$iri => $iri]); } } } diff --git a/src/Api/Controller/NodesSourcesSearchController.php b/src/Api/Controller/NodesSourcesSearchController.php index ad76db3d..0fbfd1ed 100644 --- a/src/Api/Controller/NodesSourcesSearchController.php +++ b/src/Api/Controller/NodesSourcesSearchController.php @@ -19,21 +19,12 @@ class NodesSourcesSearchController extends AbstractController { use TranslationAwareControllerTrait; - private ManagerRegistry $managerRegistry; - private PreviewResolverInterface $previewResolver; - private ?NodeSourceSearchHandlerInterface $nodeSourceSearchHandler; - private int $highlightingFragmentSize; - public function __construct( - ManagerRegistry $managerRegistry, - PreviewResolverInterface $previewResolver, - ?NodeSourceSearchHandlerInterface $nodeSourceSearchHandler, - int $highlightingFragmentSize = 200 + private readonly ManagerRegistry $managerRegistry, + private readonly PreviewResolverInterface $previewResolver, + private readonly ?NodeSourceSearchHandlerInterface $nodeSourceSearchHandler, + private readonly int $highlightingFragmentSize = 200, ) { - $this->nodeSourceSearchHandler = $nodeSourceSearchHandler; - $this->highlightingFragmentSize = $highlightingFragmentSize; - $this->managerRegistry = $managerRegistry; - $this->previewResolver = $previewResolver; } protected function getManagerRegistry(): ManagerRegistry @@ -46,9 +37,6 @@ protected function getPreviewResolver(): PreviewResolverInterface return $this->previewResolver; } - /** - * @return SearchHandlerInterface - */ protected function getSearchHandler(): SearchHandlerInterface { if (null === $this->nodeSourceSearchHandler) { @@ -58,6 +46,7 @@ protected function getSearchHandler(): SearchHandlerInterface if ($this->highlightingFragmentSize > 0) { $this->nodeSourceSearchHandler->setHighlightingFragmentSize($this->highlightingFragmentSize); } + return $this->nodeSourceSearchHandler; } @@ -65,7 +54,7 @@ protected function getCriteria(Request $request): array { return [ 'publishedAt' => ['<=', new \DateTime()], - 'translation' => $this->getTranslation($request) + 'translation' => $this->getTranslation($request), ]; } @@ -77,6 +66,7 @@ public function __invoke(Request $request): SolrPaginator $this->getCriteria($request), true ); + return new SolrPaginator($entityListManager); } } diff --git a/src/Api/Controller/TranslationAwareControllerTrait.php b/src/Api/Controller/TranslationAwareControllerTrait.php index 47533414..465fb5d6 100644 --- a/src/Api/Controller/TranslationAwareControllerTrait.php +++ b/src/Api/Controller/TranslationAwareControllerTrait.php @@ -15,6 +15,7 @@ trait TranslationAwareControllerTrait { abstract protected function getManagerRegistry(): ManagerRegistry; + abstract protected function getPreviewResolver(): PreviewResolverInterface; /** @@ -30,7 +31,7 @@ protected function getTranslation(Request $request): TranslationInterface /** @var TranslationRepository $repository */ $repository = $this->getManagerRegistry()->getRepository(TranslationInterface::class); - if (!\is_string($locale) || $locale === '') { + if (!\is_string($locale) || '' === $locale) { return $repository->findDefault(); } diff --git a/src/Api/DataTransformer/BlocksAwareWebResponseOutputDataTransformerTrait.php b/src/Api/DataTransformer/BlocksAwareWebResponseOutputDataTransformerTrait.php index 2e89b12e..db62eb8c 100644 --- a/src/Api/DataTransformer/BlocksAwareWebResponseOutputDataTransformerTrait.php +++ b/src/Api/DataTransformer/BlocksAwareWebResponseOutputDataTransformerTrait.php @@ -16,8 +16,11 @@ trait BlocksAwareWebResponseOutputDataTransformerTrait { abstract protected function getWalkerContext(): WalkerContextInterface; + abstract protected function getCacheItemPool(): CacheItemPoolInterface; + abstract protected function getTreeWalkerGenerator(): TreeWalkerGenerator; + abstract protected function getChildrenNodeSourceWalkerMaxLevel(): int; /** diff --git a/src/Api/DataTransformer/RealmsAwareWebResponseOutputDataTransformerTrait.php b/src/Api/DataTransformer/RealmsAwareWebResponseOutputDataTransformerTrait.php index 5645704e..b34a8cd5 100644 --- a/src/Api/DataTransformer/RealmsAwareWebResponseOutputDataTransformerTrait.php +++ b/src/Api/DataTransformer/RealmsAwareWebResponseOutputDataTransformerTrait.php @@ -16,9 +16,6 @@ trait RealmsAwareWebResponseOutputDataTransformerTrait abstract protected function getRealmResolver(): RealmResolverInterface; /** - * @param RealmsAwareWebResponseInterface $output - * @param NodesSources $data - * @return WebResponseInterface * @throws UnauthorizedHttpException */ protected function injectRealms(RealmsAwareWebResponseInterface $output, NodesSources $data): WebResponseInterface @@ -27,14 +24,14 @@ protected function injectRealms(RealmsAwareWebResponseInterface $output, NodesSo $output->setHidingBlocks(false); $denyingRealms = array_filter($output->getRealms(), function (RealmInterface $realm) { - return $realm->getBehaviour() === RealmInterface::BEHAVIOUR_DENY; + return RealmInterface::BEHAVIOUR_DENY === $realm->getBehaviour(); }); foreach ($denyingRealms as $denyingRealm) { $this->getRealmResolver()->denyUnlessGranted($denyingRealm); } $blockHidingRealms = array_filter($output->getRealms(), function (RealmInterface $realm) { - return $realm->getBehaviour() === RealmInterface::BEHAVIOUR_HIDE_BLOCKS; + return RealmInterface::BEHAVIOUR_HIDE_BLOCKS === $realm->getBehaviour(); }); foreach ($blockHidingRealms as $blockHidingRealm) { if (!$this->getRealmResolver()->isGranted($blockHidingRealm)) { diff --git a/src/Api/DataTransformer/WebResponseDataTransformerInterface.php b/src/Api/DataTransformer/WebResponseDataTransformerInterface.php index 424d02a3..72adf6f8 100644 --- a/src/Api/DataTransformer/WebResponseDataTransformerInterface.php +++ b/src/Api/DataTransformer/WebResponseDataTransformerInterface.php @@ -11,12 +11,18 @@ interface WebResponseDataTransformerInterface { /** * @template T of PersistableInterface - * @param T $object - * @param string $to - * @param array $context + * + * @param T $object + * @param WebResponseInterface|null $output pass an existing WebResponseInterface instance to avoid creating a new one + * * @return WebResponseInterface|null */ - public function transform(PersistableInterface $object, string $to, array $context = []): ?WebResponseInterface; + public function transform( + PersistableInterface $object, + string $to, + array $context = [], + ?WebResponseInterface $output = null, + ): ?WebResponseInterface; public function createWebResponse(): WebResponseInterface; } diff --git a/src/Api/DataTransformer/WebResponseOutputDataTransformer.php b/src/Api/DataTransformer/WebResponseOutputDataTransformer.php index 7cd9a1e1..d6ace452 100644 --- a/src/Api/DataTransformer/WebResponseOutputDataTransformer.php +++ b/src/Api/DataTransformer/WebResponseOutputDataTransformer.php @@ -27,13 +27,6 @@ class WebResponseOutputDataTransformer implements WebResponseDataTransformerInte use RealmsAwareWebResponseOutputDataTransformerTrait; /** - * @param NodesSourcesHeadFactoryInterface $nodesSourcesHeadFactory - * @param BreadcrumbsFactoryInterface $breadcrumbsFactory - * @param WalkerContextInterface $walkerContext - * @param CacheItemPoolInterface $cacheItemPool - * @param UrlGeneratorInterface $urlGenerator - * @param RealmResolverInterface $realmResolver - * @param TreeWalkerGenerator $treeWalkerGenerator * @param class-string $webResponseClass */ public function __construct( @@ -44,7 +37,7 @@ public function __construct( protected readonly UrlGeneratorInterface $urlGenerator, protected readonly RealmResolverInterface $realmResolver, protected readonly TreeWalkerGenerator $treeWalkerGenerator, - private readonly string $webResponseClass + private readonly string $webResponseClass, ) { } @@ -86,9 +79,9 @@ public function createWebResponse(): WebResponseInterface return new ($this->webResponseClass)(); } - public function transform(PersistableInterface $object, string $to, array $context = []): ?WebResponseInterface + public function transform(PersistableInterface $object, string $to, array $context = [], ?WebResponseInterface $output = null): ?WebResponseInterface { - $output = $this->createWebResponse(); + $output = $output ?? $this->createWebResponse(); $output->setItem($object); if ($object instanceof NodesSources) { if ($output instanceof RealmsAwareWebResponseInterface) { @@ -99,7 +92,7 @@ public function transform(PersistableInterface $object, string $to, array $conte } $output->setPath($this->urlGenerator->generate(RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, [ - RouteObjectInterface::ROUTE_OBJECT => $object + RouteObjectInterface::ROUTE_OBJECT => $object, ], UrlGeneratorInterface::ABSOLUTE_PATH)); $output->setHead($this->nodesSourcesHeadFactory->createForNodeSource($object)); $output->setBreadcrumbs($this->breadcrumbsFactory->create($object)); @@ -108,6 +101,7 @@ public function transform(PersistableInterface $object, string $to, array $conte if ($object instanceof TranslationInterface) { $output->setHead($this->nodesSourcesHeadFactory->createForTranslation($object)); } + return $output; } } diff --git a/src/Api/Dto/Archive.php b/src/Api/Dto/Archive.php index d6204a70..9f410105 100644 --- a/src/Api/Dto/Archive.php +++ b/src/Api/Dto/Archive.php @@ -8,9 +8,9 @@ final class Archive { - #[Groups(["archives"])] + #[Groups(['archives'])] public int $year; - #[Groups(["archives"])] + #[Groups(['archives'])] public array $months; } diff --git a/src/Api/Extension/ArchiveExtension.php b/src/Api/Extension/ArchiveExtension.php index 14c615c6..222fa0ca 100644 --- a/src/Api/Extension/ArchiveExtension.php +++ b/src/Api/Extension/ArchiveExtension.php @@ -19,7 +19,7 @@ * pagination_client_enabled: false * archive_enabled: true * archive_publication_field_name: publishedAt - * ``` + * ```. * * ``` * "hydra:member": [ @@ -41,11 +41,11 @@ * ], * ``` */ -final class ArchiveExtension implements QueryResultCollectionExtensionInterface +final readonly class ArchiveExtension implements QueryResultCollectionExtensionInterface { public function __construct( - private readonly RequestStack $requestStack, - private readonly string $defaultPublicationFieldName = 'publishedAt' + private RequestStack $requestStack, + private string $defaultPublicationFieldName = 'publishedAt', ) { } @@ -54,7 +54,7 @@ public function applyToCollection( QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, - array $context = [] + array $context = [], ): void { if (!$this->supportsResult($resourceClass, $operation)) { return; @@ -65,7 +65,7 @@ public function applyToCollection( $aliases = $queryBuilder->getRootAliases(); $alias = reset($aliases); $publicationFieldName = $this->getPublicationFieldName($operation); - $publicationField = $alias . '.' . $publicationFieldName; + $publicationField = $alias.'.'.$publicationFieldName; $queryBuilder->select($publicationField) ->addGroupBy($publicationField) @@ -85,7 +85,7 @@ public function getResult( QueryBuilder $queryBuilder, ?string $resourceClass = null, ?Operation $operation = null, - array $context = [] + array $context = [], ): iterable { $entities = []; $dates = []; @@ -123,13 +123,13 @@ public function getResult( } private function isArchiveEnabled( - ?Operation $operation = null + ?Operation $operation = null, ): bool { return $operation->getExtraProperties()['archive_enabled'] ?? false; } private function getPublicationFieldName( - ?Operation $operation = null + ?Operation $operation = null, ): string { return $operation->getExtraProperties()['archive_publication_field_name'] ?? $this->defaultPublicationFieldName; } diff --git a/src/Api/Extension/AttributeValueQueryExtension.php b/src/Api/Extension/AttributeValueQueryExtension.php index 889d8ef4..f3fe8b4f 100644 --- a/src/Api/Extension/AttributeValueQueryExtension.php +++ b/src/Api/Extension/AttributeValueQueryExtension.php @@ -12,12 +12,13 @@ use Doctrine\ORM\QueryBuilder; use RZ\Roadiz\CoreBundle\Entity\AttributeValue; use RZ\Roadiz\CoreBundle\Entity\Node; +use RZ\Roadiz\CoreBundle\Enum\NodeStatus; use RZ\Roadiz\CoreBundle\Preview\PreviewResolverInterface; -final class AttributeValueQueryExtension implements QueryItemExtensionInterface, QueryCollectionExtensionInterface +final readonly class AttributeValueQueryExtension implements QueryItemExtensionInterface, QueryCollectionExtensionInterface { public function __construct( - private readonly PreviewResolverInterface $previewResolver + private PreviewResolverInterface $previewResolver, ) { } @@ -27,7 +28,7 @@ public function applyToItem( string $resourceClass, array $identifiers, ?Operation $operation = null, - array $context = [] + array $context = [], ): void { $this->apply($queryBuilder, $resourceClass); } @@ -37,17 +38,17 @@ public function applyToCollection( QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, - array $context = [] + array $context = [], ): void { $this->apply($queryBuilder, $resourceClass); } private function apply( QueryBuilder $queryBuilder, - string $resourceClass + string $resourceClass, ): void { if ( - $resourceClass !== AttributeValue::class + AttributeValue::class !== $resourceClass ) { return; } @@ -60,7 +61,7 @@ private function apply( */ $existingNodeJoin = QueryBuilderHelper::getExistingJoin($queryBuilder, 'o', 'node'); if (null === $existingNodeJoin || !$existingNodeJoin->getAlias()) { - $queryBuilder->leftJoin($rootAlias . '.node', 'node'); + $queryBuilder->leftJoin($rootAlias.'.node', 'node'); $joinAlias = 'node'; } else { $joinAlias = $existingNodeJoin->getAlias(); @@ -68,14 +69,16 @@ private function apply( if ($this->previewResolver->isPreview()) { $queryBuilder - ->andWhere($queryBuilder->expr()->lte($joinAlias . '.status', ':status')) - ->setParameter(':status', Node::PUBLISHED); + ->andWhere($queryBuilder->expr()->lte($joinAlias.'.status', ':status')) + ->setParameter(':status', NodeStatus::PUBLISHED); + return; } $queryBuilder - ->andWhere($queryBuilder->expr()->eq($joinAlias . '.status', ':status')) - ->setParameter(':status', Node::PUBLISHED); + ->andWhere($queryBuilder->expr()->eq($joinAlias.'.status', ':status')) + ->setParameter(':status', NodeStatus::PUBLISHED); + return; } } diff --git a/src/Api/Extension/AttributeValueRealmExtension.php b/src/Api/Extension/AttributeValueRealmExtension.php index d14b3437..0128fd87 100644 --- a/src/Api/Extension/AttributeValueRealmExtension.php +++ b/src/Api/Extension/AttributeValueRealmExtension.php @@ -14,27 +14,27 @@ use RZ\Roadiz\CoreBundle\Realm\RealmResolverInterface; use Symfony\Bundle\SecurityBundle\Security; -final class AttributeValueRealmExtension implements QueryCollectionExtensionInterface, QueryItemExtensionInterface +final readonly class AttributeValueRealmExtension implements QueryCollectionExtensionInterface, QueryItemExtensionInterface { public function __construct( - private readonly Security $security, - private readonly RealmResolverInterface $realmResolver + private Security $security, + private RealmResolverInterface $realmResolver, ) { } - public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, Operation $operation = null, array $context = []): void + public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, array $context = []): void { $this->addWhere($queryBuilder, $resourceClass); } - public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, Operation $operation = null, array $context = []): void + public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, ?Operation $operation = null, array $context = []): void { $this->addWhere($queryBuilder, $resourceClass); } private function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void { - if ($resourceClass !== AttributeValue::class || $this->security->isGranted('ROLE_ACCESS_NODE_ATTRIBUTES')) { + if (AttributeValue::class !== $resourceClass || $this->security->isGranted('ROLE_ACCESS_NODE_ATTRIBUTES')) { return; } @@ -44,6 +44,7 @@ private function addWhere(QueryBuilder $queryBuilder, string $resourceClass): vo $rootAlias = $queryBuilder->getRootAliases()[0]; if ($this->security->isGranted('IS_ANONYMOUS')) { $queryBuilder->andWhere($queryBuilder->expr()->isNull(sprintf('%s.realm', $rootAlias))); + return; } diff --git a/src/Api/Extension/DocumentQueryExtension.php b/src/Api/Extension/DocumentQueryExtension.php index 7d3894da..36daa36d 100644 --- a/src/Api/Extension/DocumentQueryExtension.php +++ b/src/Api/Extension/DocumentQueryExtension.php @@ -16,9 +16,9 @@ final class DocumentQueryExtension implements QueryItemExtensionInterface, Query private function apply( QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, - string $resourceClass + string $resourceClass, ): void { - if ($resourceClass !== Document::class) { + if (Document::class !== $resourceClass) { return; } @@ -32,8 +32,8 @@ public function applyToItem( QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, - Operation $operation = null, - array $context = [] + ?Operation $operation = null, + array $context = [], ): void { $this->apply($queryBuilder, $queryNameGenerator, $resourceClass); } @@ -42,8 +42,8 @@ public function applyToCollection( QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, - Operation $operation = null, - array $context = [] + ?Operation $operation = null, + array $context = [], ): void { $this->apply($queryBuilder, $queryNameGenerator, $resourceClass); } diff --git a/src/Api/Extension/NodeQueryExtension.php b/src/Api/Extension/NodeQueryExtension.php index 9a4ee6c6..65c08c95 100644 --- a/src/Api/Extension/NodeQueryExtension.php +++ b/src/Api/Extension/NodeQueryExtension.php @@ -12,12 +12,13 @@ use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\QueryBuilder; use RZ\Roadiz\CoreBundle\Entity\Node; +use RZ\Roadiz\CoreBundle\Enum\NodeStatus; use RZ\Roadiz\CoreBundle\Preview\PreviewResolverInterface; -final class NodeQueryExtension implements QueryItemExtensionInterface, QueryCollectionExtensionInterface +final readonly class NodeQueryExtension implements QueryItemExtensionInterface, QueryCollectionExtensionInterface { public function __construct( - private readonly PreviewResolverInterface $previewResolver + private PreviewResolverInterface $previewResolver, ) { } @@ -26,8 +27,8 @@ public function applyToItem( QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, - Operation $operation = null, - array $context = [] + ?Operation $operation = null, + array $context = [], ): void { $this->apply($queryBuilder, $queryNameGenerator, $resourceClass); } @@ -35,16 +36,17 @@ public function applyToItem( private function apply( QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, - string $resourceClass + string $resourceClass, ): void { - if ($resourceClass !== Node::class) { + if (Node::class !== $resourceClass) { return; } if ($this->previewResolver->isPreview()) { $queryBuilder ->andWhere($queryBuilder->expr()->lte('o.status', ':status')) - ->setParameter(':status', Node::PUBLISHED); + ->setParameter(':status', NodeStatus::PUBLISHED); + return; } @@ -56,10 +58,11 @@ private function apply( Join::INNER_JOIN ); $queryBuilder - ->andWhere($queryBuilder->expr()->lte($alias . '.publishedAt', ':lte_published_at')) + ->andWhere($queryBuilder->expr()->lte($alias.'.publishedAt', ':lte_published_at')) ->andWhere($queryBuilder->expr()->eq('o.status', ':status')) ->setParameter(':lte_published_at', new \DateTime()) - ->setParameter(':status', Node::PUBLISHED); + ->setParameter(':status', NodeStatus::PUBLISHED); + return; } @@ -67,8 +70,8 @@ public function applyToCollection( QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, - Operation $operation = null, - array $context = [] + ?Operation $operation = null, + array $context = [], ): void { $this->apply($queryBuilder, $queryNameGenerator, $resourceClass); } diff --git a/src/Api/Extension/NodesSourcesQueryExtension.php b/src/Api/Extension/NodesSourcesQueryExtension.php index aca8ba43..dd6507a2 100644 --- a/src/Api/Extension/NodesSourcesQueryExtension.php +++ b/src/Api/Extension/NodesSourcesQueryExtension.php @@ -11,15 +11,15 @@ use ApiPlatform\Metadata\Operation; use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\QueryBuilder; -use RZ\Roadiz\CoreBundle\Entity\Node; use RZ\Roadiz\CoreBundle\Entity\NodesSources; +use RZ\Roadiz\CoreBundle\Enum\NodeStatus; use RZ\Roadiz\CoreBundle\Preview\PreviewResolverInterface; -final class NodesSourcesQueryExtension implements QueryItemExtensionInterface, QueryCollectionExtensionInterface +final readonly class NodesSourcesQueryExtension implements QueryItemExtensionInterface, QueryCollectionExtensionInterface { public function __construct( - private readonly PreviewResolverInterface $previewResolver, - private readonly string $generatedEntityNamespacePattern = '#^App\\\GeneratedEntity\\\NS(?:[a-zA-Z]+)$#' + private PreviewResolverInterface $previewResolver, + private string $generatedEntityNamespacePattern = '#^App\\\GeneratedEntity\\\NS(?:[a-zA-Z]+)$#', ) { } @@ -29,7 +29,7 @@ public function applyToItem( string $resourceClass, array $identifiers, ?Operation $operation = null, - array $context = [] + array $context = [], ): void { $this->apply($queryBuilder, $queryNameGenerator, $resourceClass); } @@ -39,7 +39,7 @@ public function applyToCollection( QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, - array $context = [] + array $context = [], ): void { $this->apply($queryBuilder, $queryNameGenerator, $resourceClass); } @@ -47,11 +47,11 @@ public function applyToCollection( private function apply( QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, - string $resourceClass + string $resourceClass, ): void { if ( - $resourceClass !== NodesSources::class && - preg_match($this->generatedEntityNamespacePattern, $resourceClass) === 0 + NodesSources::class !== $resourceClass + && 0 === preg_match($this->generatedEntityNamespacePattern, $resourceClass) ) { return; } @@ -70,8 +70,9 @@ private function apply( Join::INNER_JOIN ); $queryBuilder - ->andWhere($queryBuilder->expr()->lte($alias . '.status', ':status')) - ->setParameter(':status', Node::PUBLISHED); + ->andWhere($queryBuilder->expr()->lte($alias.'.status', ':status')) + ->setParameter(':status', NodeStatus::PUBLISHED); + return; } @@ -84,9 +85,10 @@ private function apply( ); $queryBuilder ->andWhere($queryBuilder->expr()->lte('o.publishedAt', ':lte_published_at')) - ->andWhere($queryBuilder->expr()->eq($alias . '.status', ':status')) + ->andWhere($queryBuilder->expr()->eq($alias.'.status', ':status')) ->setParameter(':lte_published_at', new \DateTime()) - ->setParameter(':status', Node::PUBLISHED); + ->setParameter(':status', NodeStatus::PUBLISHED); + return; } } diff --git a/src/Api/Extension/NodesTagsQueryExtension.php b/src/Api/Extension/NodesTagsQueryExtension.php index 37afa629..c61c1f1b 100644 --- a/src/Api/Extension/NodesTagsQueryExtension.php +++ b/src/Api/Extension/NodesTagsQueryExtension.php @@ -10,14 +10,14 @@ use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface; use ApiPlatform\Metadata\Operation; use Doctrine\ORM\QueryBuilder; -use RZ\Roadiz\CoreBundle\Entity\Node; use RZ\Roadiz\CoreBundle\Entity\Tag; +use RZ\Roadiz\CoreBundle\Enum\NodeStatus; use RZ\Roadiz\CoreBundle\Preview\PreviewResolverInterface; -final class NodesTagsQueryExtension implements QueryItemExtensionInterface, QueryCollectionExtensionInterface +final readonly class NodesTagsQueryExtension implements QueryItemExtensionInterface, QueryCollectionExtensionInterface { public function __construct( - private readonly PreviewResolverInterface $previewResolver + private PreviewResolverInterface $previewResolver, ) { } @@ -27,7 +27,7 @@ public function applyToItem( string $resourceClass, array $identifiers, ?Operation $operation = null, - array $context = [] + array $context = [], ): void { $this->apply($queryBuilder, $resourceClass); } @@ -37,17 +37,17 @@ public function applyToCollection( QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, - array $context = [] + array $context = [], ): void { $this->apply($queryBuilder, $resourceClass); } private function apply( QueryBuilder $queryBuilder, - string $resourceClass + string $resourceClass, ): void { if ( - $resourceClass !== Tag::class + Tag::class !== $resourceClass ) { return; } @@ -73,14 +73,16 @@ private function apply( if ($this->previewResolver->isPreview()) { $queryBuilder - ->andWhere($queryBuilder->expr()->lte($existingNodeJoin->getAlias() . '.status', ':status')) - ->setParameter(':status', Node::PUBLISHED); + ->andWhere($queryBuilder->expr()->lte($existingNodeJoin->getAlias().'.status', ':status')) + ->setParameter(':status', NodeStatus::PUBLISHED); + return; } $queryBuilder - ->andWhere($queryBuilder->expr()->eq($existingNodeJoin->getAlias() . '.status', ':status')) - ->setParameter(':status', Node::PUBLISHED); + ->andWhere($queryBuilder->expr()->eq($existingNodeJoin->getAlias().'.status', ':status')) + ->setParameter(':status', NodeStatus::PUBLISHED); + return; } } diff --git a/src/Api/Filter/ArchiveFilter.php b/src/Api/Filter/ArchiveFilter.php index 7b58e2f5..a7e5b6dc 100644 --- a/src/Api/Filter/ArchiveFilter.php +++ b/src/Api/Filter/ArchiveFilter.php @@ -31,12 +31,10 @@ protected function isDateField(string $property, string $resourceClass): bool if (\is_string($type)) { return \in_array($type, \array_keys(DateFilter::DOCTRINE_DATE_TYPES), true); } - return $type->getName() === 'datetime' || $type->getName() === 'date'; + + return 'datetime' === $type->getName() || 'date' === $type->getName(); } - /** - * {@inheritdoc} - */ protected function filterProperty( string $property, mixed $value, @@ -44,14 +42,14 @@ protected function filterProperty( QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, - array $context = [] + array $context = [], ): void { // Expect $values to be an array having the period as keys and the date value as values if ( - !$this->isPropertyEnabled($property, $resourceClass) || - !$this->isPropertyMapped($property, $resourceClass) || - !$this->isDateField($property, $resourceClass) || - !isset($value[self::PARAMETER_ARCHIVE]) + !$this->isPropertyEnabled($property, $resourceClass) + || !$this->isPropertyMapped($property, $resourceClass) + || !$this->isDateField($property, $resourceClass) + || !isset($value[self::PARAMETER_ARCHIVE]) ) { return; } @@ -71,15 +69,12 @@ protected function filterProperty( } if (!is_string($value[self::PARAMETER_ARCHIVE])) { - throw new FilterValidationException([sprintf( - '“%s” filter must be only used with a string value.', - self::PARAMETER_ARCHIVE - )]); + throw new FilterValidationException([sprintf('“%s” filter must be only used with a string value.', self::PARAMETER_ARCHIVE)]); } $range = $this->normalizeFilteringDates($value[self::PARAMETER_ARCHIVE]); - if (null === $range || count($range) !== 2) { + if (null === $range || 2 !== count($range)) { return; } @@ -87,18 +82,18 @@ protected function filterProperty( $queryBuilder->andWhere($queryBuilder->expr()->isNotNull(sprintf('%s.%s', $alias, $field))) ->andWhere($queryBuilder->expr()->between( sprintf('%s.%s', $alias, $field), - ':' . $valueParameter . 'Start', - ':' . $valueParameter . 'End' + ':'.$valueParameter.'Start', + ':'.$valueParameter.'End' )) - ->setParameter($valueParameter . 'Start', $range[0]) - ->setParameter($valueParameter . 'End', $range[1]); + ->setParameter($valueParameter.'Start', $range[0]) + ->setParameter($valueParameter.'End', $range[1]); } /** * Support archive parameter with year or year-month. * - * @param string $value * @return \DateTime[]|null + * * @throws \Exception */ protected function normalizeFilteringDates(string $value): ?array @@ -107,24 +102,25 @@ protected function normalizeFilteringDates(string $value): ?array * Support archive parameter with year or year-month */ if (preg_match('#[0-9]{4}\-[0-9]{2}\-[0-9]{2}#', $value) > 0) { - $startDate = new \DateTime($value . ' 00:00:00'); + $startDate = new \DateTime($value.' 00:00:00'); $endDate = clone $startDate; $endDate->add(new \DateInterval('P1D')); return [$startDate, $this->limitEndDate($endDate)]; } elseif (preg_match('#[0-9]{4}\-[0-9]{2}#', $value) > 0) { - $startDate = new \DateTime($value . '-01 00:00:00'); + $startDate = new \DateTime($value.'-01 00:00:00'); $endDate = clone $startDate; $endDate->add(new \DateInterval('P1M')); return [$startDate, $this->limitEndDate($endDate)]; } elseif (preg_match('#[0-9]{4}#', $value) > 0) { - $startDate = new \DateTime($value . '-01-01 00:00:00'); + $startDate = new \DateTime($value.'-01-01 00:00:00'); $endDate = clone $startDate; $endDate->add(new \DateInterval('P1Y')); return [$startDate, $this->limitEndDate($endDate)]; } + return null; } @@ -134,6 +130,7 @@ protected function limitEndDate(\DateTime $endDate): \DateTime if ($endDate > $now) { return $now; } + return $endDate->sub(new \DateInterval('PT1S')); } diff --git a/src/Api/Filter/CopyrightValidFilter.php b/src/Api/Filter/CopyrightValidFilter.php index ea8f56f2..d20026a9 100644 --- a/src/Api/Filter/CopyrightValidFilter.php +++ b/src/Api/Filter/CopyrightValidFilter.php @@ -23,12 +23,12 @@ protected function filterProperty( QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, - array $context = [] + array $context = [], ): void { - if ($property !== self::PARAMETER) { + if (self::PARAMETER !== $property) { return; } - if ($resourceClass !== Document::class) { + if (Document::class !== $resourceClass) { return; } @@ -41,12 +41,13 @@ protected function filterProperty( if (in_array($value, self::TRUE_VALUES)) { // Copyright MUST be valid $queryBuilder->andWhere($queryBuilder->expr()->orX( - $queryBuilder->expr()->isNull($alias . '.copyrightValidSince'), - $queryBuilder->expr()->lte($alias . '.copyrightValidSince', ':now') + $queryBuilder->expr()->isNull($alias.'.copyrightValidSince'), + $queryBuilder->expr()->lte($alias.'.copyrightValidSince', ':now') ))->andWhere($queryBuilder->expr()->orX( - $queryBuilder->expr()->isNull($alias . '.copyrightValidUntil'), - $queryBuilder->expr()->gte($alias . '.copyrightValidUntil', ':now') + $queryBuilder->expr()->isNull($alias.'.copyrightValidUntil'), + $queryBuilder->expr()->gte($alias.'.copyrightValidUntil', ':now') ))->setParameter(':now', new \DateTime()); + return; } @@ -54,10 +55,11 @@ protected function filterProperty( // Copyright MUST NOT be valid $queryBuilder->andWhere( $queryBuilder->expr()->orX( - $queryBuilder->expr()->gt($alias . '.copyrightValidSince', ':now'), - $queryBuilder->expr()->lt($alias . '.copyrightValidUntil', ':now') + $queryBuilder->expr()->gt($alias.'.copyrightValidSince', ':now'), + $queryBuilder->expr()->lt($alias.'.copyrightValidUntil', ':now') ) )->setParameter(':now', new \DateTime()); + return; } } @@ -71,9 +73,9 @@ public function getDescription(string $resourceClass): array 'required' => false, 'description' => 'Filter items for which copyright dates are valid.', 'openapi' => [ - 'description' => 'Filter items for which copyright dates are valid.' - ] - ] + 'description' => 'Filter items for which copyright dates are valid.', + ], + ], ]; } } diff --git a/src/Api/Filter/GeneratedEntityFilter.php b/src/Api/Filter/GeneratedEntityFilter.php index 255be66d..3b39c6a7 100644 --- a/src/Api/Filter/GeneratedEntityFilter.php +++ b/src/Api/Filter/GeneratedEntityFilter.php @@ -13,18 +13,11 @@ abstract class GeneratedEntityFilter extends AbstractFilter { private string $generatedEntityNamespacePattern; - /** - * @param ManagerRegistry $managerRegistry - * @param LoggerInterface|null $logger - * @param array|null $properties - * @param NameConverterInterface|null $nameConverter - * @param string $generatedEntityNamespacePattern - */ public function __construct( ManagerRegistry $managerRegistry, - LoggerInterface $logger = null, - array $properties = null, - NameConverterInterface $nameConverter = null, + ?LoggerInterface $logger = null, + ?array $properties = null, + ?NameConverterInterface $nameConverter = null, string $generatedEntityNamespacePattern = '#^App\\\GeneratedEntity\\\NS(?:[a-zA-Z]+)$#', ) { parent::__construct($managerRegistry, $logger, $properties, $nameConverter); @@ -32,17 +25,11 @@ public function __construct( $this->generatedEntityNamespacePattern = $generatedEntityNamespacePattern; } - /** - * @return string - */ public function getGeneratedEntityNamespacePattern(): string { return $this->generatedEntityNamespacePattern; } - /** - * @inheritDoc - */ public function getDescription(string $resourceClass): array { return []; diff --git a/src/Api/Filter/IntersectionFilter.php b/src/Api/Filter/IntersectionFilter.php index 699e1edc..bd380435 100644 --- a/src/Api/Filter/IntersectionFilter.php +++ b/src/Api/Filter/IntersectionFilter.php @@ -4,8 +4,8 @@ namespace RZ\Roadiz\CoreBundle\Api\Filter; -use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface; use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter; +use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface; use ApiPlatform\Exception\FilterValidationException; use ApiPlatform\Metadata\Operation; use Doctrine\ORM\Query\Expr\Join; @@ -18,9 +18,6 @@ final class IntersectionFilter extends AbstractFilter { public const PARAMETER = 'intersect'; - /** - * @inheritDoc - */ protected function filterProperty( string $property, mixed $value, @@ -28,9 +25,9 @@ protected function filterProperty( QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, - array $context = [] + array $context = [], ): void { - if ($property !== IntersectionFilter::PARAMETER || !is_array($value)) { + if (IntersectionFilter::PARAMETER !== $property || !is_array($value)) { return; } @@ -52,7 +49,7 @@ protected function filterProperty( $resourceClass, Join::INNER_JOIN // Join type must be inner to filter out empty result sets ); - $placeholder = ':' . $alias . $splitFieldName; + $placeholder = ':'.$alias.$splitFieldName; $queryBuilder->andWhere($queryBuilder->expr()->eq(sprintf('%s.%s', $alias, $splitFieldName), $placeholder)); $queryBuilder->setParameter($placeholder, $singleValue); } @@ -60,9 +57,6 @@ protected function filterProperty( } } - /** - * @inheritDoc - */ public function getDescription(string $resourceClass): array { $properties = $this->properties; @@ -80,8 +74,8 @@ function ($carry, $property) { 'required' => false, 'description' => 'Discriminate an existing filter with additional filtering value using a new inner join.', 'openapi' => [ - 'description' => 'Discriminate an existing filter with additional filtering value using a new inner join.' - ] + 'description' => 'Discriminate an existing filter with additional filtering value using a new inner join.', + ], ]; $carry[sprintf('%s[%s][]', IntersectionFilter::PARAMETER, $property)] = [ 'property' => $property, @@ -89,9 +83,10 @@ function ($carry, $property) { 'required' => false, 'description' => 'Discriminate an existing filter with additional filtering value using a new inner join.', 'openapi' => [ - 'description' => 'Discriminate an existing filter with additional filtering value using a new inner join.' - ] + 'description' => 'Discriminate an existing filter with additional filtering value using a new inner join.', + ], ]; + return $carry; }, [] @@ -104,7 +99,7 @@ protected function addDuplicatedJoinsForNestedProperty( QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, - string $joinType + string $joinType, ): array { $propertyParts = $this->splitPropertyParts($property, $resourceClass); $parentAlias = $rootAlias; @@ -130,9 +125,9 @@ public static function addDuplicatedJoin( QueryNameGeneratorInterface $queryNameGenerator, string $alias, string $association, - string $joinType = null + ?string $joinType = null, ): string { - $associationAlias = $queryNameGenerator->generateJoinAlias($association) . uniqid(); + $associationAlias = $queryNameGenerator->generateJoinAlias($association).uniqid(); $query = "$alias.$association"; if (Join::LEFT_JOIN === $joinType) { diff --git a/src/Api/Filter/LocaleFilter.php b/src/Api/Filter/LocaleFilter.php index aaefd4a5..54e7f74b 100644 --- a/src/Api/Filter/LocaleFilter.php +++ b/src/Api/Filter/LocaleFilter.php @@ -22,10 +22,10 @@ final class LocaleFilter extends GeneratedEntityFilter public function __construct( private readonly PreviewResolverInterface $previewResolver, ManagerRegistry $managerRegistry, - LoggerInterface $logger = null, - array $properties = null, - NameConverterInterface $nameConverter = null, - string $generatedEntityNamespacePattern = '#^App\\\GeneratedEntity\\\NS(?:[a-zA-Z]+)$#' + ?LoggerInterface $logger = null, + ?array $properties = null, + ?NameConverterInterface $nameConverter = null, + string $generatedEntityNamespacePattern = '#^App\\\GeneratedEntity\\\NS(?:[a-zA-Z]+)$#', ) { parent::__construct($managerRegistry, $logger, $properties, $nameConverter, $generatedEntityNamespacePattern); } @@ -37,9 +37,9 @@ protected function filterProperty( QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, - array $context = [] + array $context = [], ): void { - if ($property !== self::PROPERTY) { + if (self::PROPERTY !== $property) { return; } @@ -53,28 +53,20 @@ protected function filterProperty( ->getAvailableLocales(); } - if (count($supportedLocales) === 0) { - throw new FilterValidationException( - ['Locale filter is not available because no translation exist.'] - ); + if (0 === count($supportedLocales)) { + throw new FilterValidationException(['Locale filter is not available because no translation exist.']); } if (!in_array($value, $supportedLocales)) { - throw new FilterValidationException( - [sprintf( - 'Locale filter value "%s" not supported. Supported values are %s', - $value, - implode(', ', $supportedLocales) - )] - ); + throw new FilterValidationException([sprintf('Locale filter value "%s" not supported. Supported values are %s', $value, implode(', ', $supportedLocales))]); } /* * Apply translation filter only for NodesSources */ if ( - $resourceClass === NodesSources::class || - preg_match($this->getGeneratedEntityNamespacePattern(), $resourceClass) > 0 + NodesSources::class === $resourceClass + || preg_match($this->getGeneratedEntityNamespacePattern(), $resourceClass) > 0 ) { if ($this->previewResolver->isPreview()) { $translation = $this->managerRegistry @@ -87,7 +79,7 @@ protected function filterProperty( } if (null === $translation) { - throw new FilterValidationException(['No translation exist for locale: ' . $value]); + throw new FilterValidationException(['No translation exist for locale: '.$value]); } $queryBuilder @@ -106,23 +98,20 @@ protected function filterProperty( * - strategy: the used strategy * - swagger (optional): additional parameters for the path operation, e.g. 'swagger' => ['description' => 'My Description'] * The description can contain additional data specific to a filter. - * - * @param string $resourceClass - * - * @return array */ public function getDescription(string $resourceClass): array { $supportedLocales = $this->managerRegistry->getRepository(Translation::class)->getAvailableLocales(); - return [ - self::PROPERTY => [ + + return [ + self::PROPERTY => [ 'property' => self::PROPERTY, 'type' => 'string', 'required' => false, 'openapi' => [ - 'description' => 'Filter items with translation locale (' . implode(', ', $supportedLocales) . ').' - ] - ] + 'description' => 'Filter items with translation locale ('.implode(', ', $supportedLocales).').', + ], + ], ]; } } diff --git a/src/Api/Filter/NotFilter.php b/src/Api/Filter/NotFilter.php index b1677bd0..de2f0682 100644 --- a/src/Api/Filter/NotFilter.php +++ b/src/Api/Filter/NotFilter.php @@ -4,8 +4,8 @@ namespace RZ\Roadiz\CoreBundle\Api\Filter; -use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface; use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter; +use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface; use ApiPlatform\Metadata\Operation; use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\QueryBuilder; @@ -22,9 +22,9 @@ protected function filterProperty( QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, - array $context = [] + array $context = [], ): void { - if ($property !== self::PARAMETER || !\is_array($value)) { + if (self::PARAMETER !== $property || !\is_array($value)) { return; } @@ -43,7 +43,7 @@ protected function filterProperty( ); } - $placeholder = ':' . (new AsciiSlugger())->slug($alias . '_' . $field, '_')->toString(); + $placeholder = ':'.(new AsciiSlugger())->slug($alias.'_'.$field, '_')->toString(); if (\is_array($notValue)) { $queryBuilder->andWhere( $queryBuilder->expr()->notIn(sprintf('%s.%s', $alias, $field), $placeholder) @@ -67,10 +67,6 @@ protected function filterProperty( * - strategy: the used strategy * - swagger (optional): additional parameters for the path operation, e.g. 'swagger' => ['description' => 'My Description'] * The description can contain additional data specific to a filter. - * - * @param string $resourceClass - * - * @return array */ public function getDescription(string $resourceClass): array { @@ -89,8 +85,8 @@ function ($carry, $property) { 'required' => false, 'description' => 'Filter items that are not equal.', 'openapi' => [ - 'description' => 'Filter items that are not equal.' - ] + 'description' => 'Filter items that are not equal.', + ], ]; $carry[sprintf('%s[%s][]', self::PARAMETER, $property)] = [ 'property' => $property, @@ -98,9 +94,10 @@ function ($carry, $property) { 'required' => false, 'description' => 'Filter items that are not equal.', 'openapi' => [ - 'description' => 'Filter items that are not equal.' - ] + 'description' => 'Filter items that are not equal.', + ], ]; + return $carry; }, [] diff --git a/src/Api/ListManager/SolrPaginator.php b/src/Api/ListManager/SolrPaginator.php index b5e3f448..5056d140 100644 --- a/src/Api/ListManager/SolrPaginator.php +++ b/src/Api/ListManager/SolrPaginator.php @@ -27,6 +27,7 @@ protected function handleOnce(): void public function count(): int { $this->handleOnce(); + return $this->listManager->getItemCount(); } @@ -34,24 +35,28 @@ public function getLastPage(): float { $this->handleOnce(); $lastPage = $this->listManager->getPageCount(); + return max($lastPage, 1); } public function getTotalItems(): float { $this->handleOnce(); + return $this->listManager->getItemCount(); } public function getCurrentPage(): float { $this->handleOnce(); + return $this->listManager->getAssignation()['currentPage']; } public function getItemsPerPage(): float { $this->handleOnce(); + return $this->listManager->getAssignation()['itemPerPage']; } @@ -59,9 +64,7 @@ public function getIterator(): \Traversable { $this->handleOnce(); $entities = $this->listManager->getEntities(); - if (\is_array($entities)) { - return new \ArrayIterator($entities); - } - return $entities->getIterator(); + + return new \ArrayIterator($entities); } } diff --git a/src/Api/ListManager/SolrSearchListManager.php b/src/Api/ListManager/SolrSearchListManager.php index e0dca7e7..e0a93137 100644 --- a/src/Api/ListManager/SolrSearchListManager.php +++ b/src/Api/ListManager/SolrSearchListManager.php @@ -9,32 +9,33 @@ use RZ\Roadiz\CoreBundle\SearchEngine\SearchResultsInterface; use Symfony\Component\DependencyInjection\Attribute\Exclude; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; #[Exclude] final class SolrSearchListManager extends AbstractEntityListManager { - private ?SearchResultsInterface $searchResults; + private ?SearchResultsInterface $searchResults = null; private ?string $query = null; public function __construct( ?Request $request, private readonly SearchHandlerInterface $searchHandler, private readonly array $criteria = [], - private readonly bool $searchInTags = true + private readonly bool $searchInTags = true, ) { parent::__construct($request); } - public function handle(bool $disabled = false) + public function handle(bool $disabled = false): void { - if ($this->request === null) { + if (null === $this->request) { throw new \InvalidArgumentException('Cannot handle a NULL request.'); } $this->handleRequestQuery($disabled); if (null === $this->query) { - throw new \InvalidArgumentException('Cannot handle a NULL query.'); + throw new BadRequestHttpException('Search param is required.'); } /* * Query must be longer than 3 chars or Solr might crash @@ -42,18 +43,18 @@ public function handle(bool $disabled = false) */ if (\mb_strlen($this->query) > 3) { $this->searchResults = $this->searchHandler->searchWithHighlight( - $this->query, # Use ?q query parameter to search with - $this->criteria, # a simple criteria array to filter search results - $this->getItemPerPage(), # result count - $this->searchInTags, # Search in tags too, + $this->query, // Use ?q query parameter to search with + $this->criteria, // a simple criteria array to filter search results + $this->getItemPerPage(), // result count + $this->searchInTags, // Search in tags too, $this->getPage() ); } else { $this->searchResults = $this->searchHandler->search( - $this->query, # Use ?q query parameter to search with - $this->criteria, # a simple criteria array to filter search results - $this->getItemPerPage(), # result count - $this->searchInTags, # Search in tags too, + $this->query, // Use ?q query parameter to search with + $this->criteria, // a simple criteria array to filter search results + $this->getItemPerPage(), // result count + $this->searchInTags, // Search in tags too, $this->getPage() ); } @@ -65,9 +66,6 @@ protected function handleSearchParam(string $search): void $this->query = trim($search); } - /** - * @inheritDoc - */ public function getItemCount(): int { if (null !== $this->searchResults) { @@ -76,9 +74,6 @@ public function getItemCount(): int throw new \InvalidArgumentException('Call EntityListManagerInterface::handle before counting entities.'); } - /** - * @inheritDoc - */ public function getEntities(): array { if (null !== $this->searchResults) { diff --git a/src/Api/Model/BlocksAwareWebResponseInterface.php b/src/Api/Model/BlocksAwareWebResponseInterface.php index bdf356fe..0dc8a927 100644 --- a/src/Api/Model/BlocksAwareWebResponseInterface.php +++ b/src/Api/Model/BlocksAwareWebResponseInterface.php @@ -16,6 +16,7 @@ public function getBlocks(): ?array; /** * @param Collection|null $blocks + * * @return $this */ public function setBlocks(?Collection $blocks): self; diff --git a/src/Api/Model/NodesSourcesHead.php b/src/Api/Model/NodesSourcesHead.php index c0f52e2b..f509483c 100644 --- a/src/Api/Model/NodesSourcesHead.php +++ b/src/Api/Model/NodesSourcesHead.php @@ -17,108 +17,61 @@ class NodesSourcesHead implements NodesSourcesHeadInterface { - #[Serializer\Ignore] - protected HandlerFactoryInterface $handlerFactory; - #[Serializer\Ignore] protected ?array $seo = null; - #[Serializer\Ignore] - protected ?NodesSources $nodesSource; - - #[Serializer\Ignore] - protected Settings $settingsBag; - - #[Serializer\Ignore] - protected UrlGeneratorInterface $urlGenerator; - - #[Serializer\Ignore] - protected NodeSourceApi $nodeSourceApi; - - #[Serializer\Ignore] - protected TranslationInterface $defaultTranslation; - - /** - * @param NodesSources|null $nodesSource - * @param Settings $settingsBag - * @param UrlGeneratorInterface $urlGenerator - * @param NodeSourceApi $nodeSourceApi - * @param HandlerFactoryInterface $handlerFactory - * @param TranslationInterface $defaultTranslation - */ public function __construct( - ?NodesSources $nodesSource, - Settings $settingsBag, - UrlGeneratorInterface $urlGenerator, - NodeSourceApi $nodeSourceApi, - HandlerFactoryInterface $handlerFactory, - TranslationInterface $defaultTranslation + #[Serializer\Ignore] + protected readonly ?NodesSources $nodesSource, + #[Serializer\Ignore] + protected readonly Settings $settingsBag, + #[Serializer\Ignore] + protected readonly UrlGeneratorInterface $urlGenerator, + #[Serializer\Ignore] + protected readonly NodeSourceApi $nodeSourceApi, + #[Serializer\Ignore] + protected readonly HandlerFactoryInterface $handlerFactory, + #[Serializer\Ignore] + protected readonly TranslationInterface $defaultTranslation, ) { - $this->nodesSource = $nodesSource; - $this->settingsBag = $settingsBag; - $this->urlGenerator = $urlGenerator; - $this->nodeSourceApi = $nodeSourceApi; - $this->defaultTranslation = $defaultTranslation; - $this->handlerFactory = $handlerFactory; } - /** - * @return string|null - */ - #[Serializer\Groups(["web_response", "nodes_sources_single", "walker"])] + #[Serializer\Groups(['web_response', 'nodes_sources_single', 'walker'])] public function getGoogleAnalytics(): ?string { return $this->settingsBag->get('universal_analytics_id', null) ?? null; } - /** - * @return string|null - */ - #[Serializer\Groups(["web_response", "nodes_sources_single", "walker"])] + #[Serializer\Groups(['web_response', 'nodes_sources_single', 'walker'])] public function getGoogleTagManager(): ?string { return $this->settingsBag->get('google_tag_manager_id', null) ?? null; } - /** - * @return string|null - */ - #[Serializer\Groups(["web_response", "nodes_sources_single", "walker"])] + #[Serializer\Groups(['web_response', 'nodes_sources_single', 'walker'])] public function getMatomoTagManager(): ?string { return $this->settingsBag->get('matomo_tag_manager_id', null) ?? null; } - /** - * @return string|null - */ - #[Serializer\Groups(["web_response", "nodes_sources_single", "walker"])] + #[Serializer\Groups(['web_response', 'nodes_sources_single', 'walker'])] public function getMatomoUrl(): ?string { return $this->settingsBag->get('matomo_url', null) ?? null; } - /** - * @return string|null - */ - #[Serializer\Groups(["web_response", "nodes_sources_single", "walker"])] + #[Serializer\Groups(['web_response', 'nodes_sources_single', 'walker'])] public function getMatomoSiteId(): ?string { return $this->settingsBag->get('matomo_site_id', null) ?? null; } - /** - * @return string|null - */ - #[Serializer\Groups(["web_response", "nodes_sources_single", "walker"])] + #[Serializer\Groups(['web_response', 'nodes_sources_single', 'walker'])] public function getSiteName(): ?string { return $this->settingsBag->get('site_name', null) ?? null; } - /** - * @return array - */ #[Serializer\Ignore] protected function getDefaultSeo(): array { @@ -128,16 +81,14 @@ protected function getDefaultSeo(): array return $nodesSourcesHandler->getSEO(); } } + return [ 'title' => $this->settingsBag->get('site_name'), 'description' => $this->settingsBag->get('seo_description'), ]; } - /** - * @return string|null - */ - #[Serializer\Groups(["web_response", "nodes_sources_single", "walker"])] + #[Serializer\Groups(['web_response', 'nodes_sources_single', 'walker'])] public function getMetaTitle(): ?string { if (null === $this->seo) { @@ -147,10 +98,7 @@ public function getMetaTitle(): ?string return $this->seo['title']; } - /** - * @return string|null - */ - #[Serializer\Groups(["web_response", "nodes_sources_single", "walker"])] + #[Serializer\Groups(['web_response', 'nodes_sources_single', 'walker'])] public function getMetaDescription(): ?string { if (null === $this->seo) { @@ -160,124 +108,125 @@ public function getMetaDescription(): ?string return $this->seo['description']; } - /** - * @return bool - */ - #[Serializer\Groups(["web_response", "nodes_sources_single", "walker"])] + #[Serializer\Groups(['web_response', 'nodes_sources_single', 'walker'])] public function isNoIndex(): bool { if (null !== $this->nodesSource) { return $this->nodesSource->isNoIndex(); } + return false; } - #[Serializer\Groups(["web_response", "nodes_sources_single", "walker"])] + #[Serializer\Groups(['web_response', 'nodes_sources_single', 'walker'])] public function getPolicyUrl(): ?string { $translation = $this->getTranslation(); $policyNodeSource = $this->nodeSourceApi->getOneBy([ 'node.nodeName' => 'privacy', - 'translation' => $translation + 'translation' => $translation, ]); if (null === $policyNodeSource) { $policyNodeSource = $this->nodeSourceApi->getOneBy([ 'node.nodeName' => 'legal', - 'translation' => $translation + 'translation' => $translation, ]); } if (null !== $policyNodeSource) { return $this->urlGenerator->generate(RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, [ - RouteObjectInterface::ROUTE_OBJECT => $policyNodeSource + RouteObjectInterface::ROUTE_OBJECT => $policyNodeSource, ]); } + return null; } - #[Serializer\Groups(["web_response", "nodes_sources_single", "walker"])] + #[Serializer\Groups(['web_response', 'nodes_sources_single', 'walker'])] public function getMainColor(): ?string { return $this->settingsBag->get('main_color', null) ?? null; } - #[Serializer\Groups(["web_response", "nodes_sources_single", "walker"])] + #[Serializer\Groups(['web_response', 'nodes_sources_single', 'walker'])] public function getFacebookUrl(): ?string { return $this->settingsBag->get('facebook_url', null) ?? null; } - #[Serializer\Groups(["web_response", "nodes_sources_single", "walker"])] + #[Serializer\Groups(['web_response', 'nodes_sources_single', 'walker'])] public function getInstagramUrl(): ?string { return $this->settingsBag->get('instagram_url', null) ?? null; } - #[Serializer\Groups(["web_response", "nodes_sources_single", "walker"])] + #[Serializer\Groups(['web_response', 'nodes_sources_single', 'walker'])] public function getTwitterUrl(): ?string { return $this->settingsBag->get('twitter_url', null) ?? null; } - #[Serializer\Groups(["web_response", "nodes_sources_single", "walker"])] + #[Serializer\Groups(['web_response', 'nodes_sources_single', 'walker'])] public function getYoutubeUrl(): ?string { return $this->settingsBag->get('youtube_url', null) ?? null; } - #[Serializer\Groups(["nodes_sources_single", "walker"])] + #[Serializer\Groups(['nodes_sources_single', 'walker'])] public function getLinkedinUrl(): ?string { return $this->settingsBag->get('linkedin_url', null) ?? null; } - #[Serializer\Groups(["nodes_sources_single", "walker"])] + #[Serializer\Groups(['nodes_sources_single', 'walker'])] public function getSpotifyUrl(): ?string { return $this->settingsBag->get('spotify_url', null) ?? null; } - #[Serializer\Groups(["nodes_sources_single", "walker"])] + #[Serializer\Groups(['nodes_sources_single', 'walker'])] public function getSoundcloudUrl(): ?string { return $this->settingsBag->get('soundcloud_url', null) ?? null; } - #[Serializer\Groups(["nodes_sources_single", "walker"])] + #[Serializer\Groups(['nodes_sources_single', 'walker'])] public function getTikTokUrl(): ?string { return $this->settingsBag->get('tiktok_url', null) ?? null; } - #[Serializer\Groups(["web_response", "nodes_sources_single", "walker"])] + #[Serializer\Groups(['web_response', 'nodes_sources_single', 'walker'])] public function getHomePageUrl(): ?string { $homePage = $this->getHomePage(); if (null !== $homePage) { return $this->urlGenerator->generate(RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, [ - RouteObjectInterface::ROUTE_OBJECT => $homePage + RouteObjectInterface::ROUTE_OBJECT => $homePage, ]); } + return null; } - #[Serializer\Groups(["web_response", "nodes_sources_single"])] + #[Serializer\Groups(['web_response', 'nodes_sources_single'])] public function getShareImage(): ?DocumentInterface { if ( - null !== $this->nodesSource && - method_exists($this->nodesSource, 'getHeaderImage') && - isset($this->nodesSource->getHeaderImage()[0]) + null !== $this->nodesSource + && method_exists($this->nodesSource, 'getHeaderImage') + && isset($this->nodesSource->getHeaderImage()[0]) ) { return $this->nodesSource->getHeaderImage()[0]; } if ( - null !== $this->nodesSource && - method_exists($this->nodesSource, 'getImage') && - isset($this->nodesSource->getImage()[0]) + null !== $this->nodesSource + && method_exists($this->nodesSource, 'getImage') + && isset($this->nodesSource->getImage()[0]) ) { return $this->nodesSource->getImage()[0]; } + return $this->settingsBag->getDocument('share_image') ?? null; } @@ -287,6 +236,7 @@ public function getTranslation(): TranslationInterface if (null !== $this->nodesSource) { return $this->nodesSource->getTranslation(); } + return $this->defaultTranslation; } @@ -295,7 +245,7 @@ public function getHomePage(): ?NodesSources { return $this->nodeSourceApi->getOneBy([ 'node.home' => true, - 'translation' => $this->getTranslation() + 'translation' => $this->getTranslation(), ]); } } diff --git a/src/Api/Model/NodesSourcesHeadFactory.php b/src/Api/Model/NodesSourcesHeadFactory.php index 9cae9098..e0639693 100644 --- a/src/Api/Model/NodesSourcesHeadFactory.php +++ b/src/Api/Model/NodesSourcesHeadFactory.php @@ -11,13 +11,13 @@ use RZ\Roadiz\CoreBundle\EntityApi\NodeSourceApi; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -final class NodesSourcesHeadFactory implements NodesSourcesHeadFactoryInterface +final readonly class NodesSourcesHeadFactory implements NodesSourcesHeadFactoryInterface { public function __construct( - private readonly Settings $settingsBag, - private readonly UrlGeneratorInterface $urlGenerator, - private readonly NodeSourceApi $nodeSourceApi, - private readonly HandlerFactoryInterface $handlerFactory + private Settings $settingsBag, + private UrlGeneratorInterface $urlGenerator, + private NodeSourceApi $nodeSourceApi, + private HandlerFactoryInterface $handlerFactory, ) { } diff --git a/src/Api/Model/NodesSourcesHeadFactoryInterface.php b/src/Api/Model/NodesSourcesHeadFactoryInterface.php index 51295929..b13f85f2 100644 --- a/src/Api/Model/NodesSourcesHeadFactoryInterface.php +++ b/src/Api/Model/NodesSourcesHeadFactoryInterface.php @@ -10,5 +10,6 @@ interface NodesSourcesHeadFactoryInterface { public function createForTranslation(TranslationInterface $translation): NodesSourcesHeadInterface; + public function createForNodeSource(NodesSources $nodesSources): NodesSourcesHeadInterface; } diff --git a/src/Api/Model/NodesSourcesHeadInterface.php b/src/Api/Model/NodesSourcesHeadInterface.php index 36e0fd92..3413ee1f 100644 --- a/src/Api/Model/NodesSourcesHeadInterface.php +++ b/src/Api/Model/NodesSourcesHeadInterface.php @@ -11,12 +11,20 @@ interface NodesSourcesHeadInterface { public function getSiteName(): ?string; + public function getMetaTitle(): ?string; + public function getMetaDescription(): ?string; + public function getPolicyUrl(): ?string; + public function getHomePageUrl(): ?string; + public function isNoIndex(): bool; + public function getHomePage(): ?NodesSources; + public function getShareImage(): ?DocumentInterface; + public function getTranslation(): TranslationInterface; } diff --git a/src/Api/Model/RealmsAwareWebResponseInterface.php b/src/Api/Model/RealmsAwareWebResponseInterface.php index 3962bfe0..adeded2b 100644 --- a/src/Api/Model/RealmsAwareWebResponseInterface.php +++ b/src/Api/Model/RealmsAwareWebResponseInterface.php @@ -15,17 +15,14 @@ public function getRealms(): ?array; /** * @param RealmInterface[]|null $realms + * * @return $this */ public function setRealms(?array $realms): self; - /** - * @return bool - */ public function isHidingBlocks(): bool; /** - * @param bool $hidingBlocks * @return $this */ public function setHidingBlocks(bool $hidingBlocks): self; diff --git a/src/Api/Model/WebResponseInterface.php b/src/Api/Model/WebResponseInterface.php index 61ff1727..6b8f73ae 100644 --- a/src/Api/Model/WebResponseInterface.php +++ b/src/Api/Model/WebResponseInterface.php @@ -13,18 +13,22 @@ interface WebResponseInterface { public function setHead(?NodesSourcesHeadInterface $head): self; + public function setBreadcrumbs(?BreadcrumbsInterface $breadcrumbs): self; /** * @param T|null $item - * @return self */ public function setItem(?PersistableInterface $item): self; + public function setPath(?string $path): self; + /** * @return T|null */ public function getItem(): ?PersistableInterface; + public function getMaxAge(): ?int; + public function setMaxAge(?int $maxAge): self; } diff --git a/src/Api/Model/WebResponseTrait.php b/src/Api/Model/WebResponseTrait.php index 8acf455f..a7707a77 100644 --- a/src/Api/Model/WebResponseTrait.php +++ b/src/Api/Model/WebResponseTrait.php @@ -15,39 +15,51 @@ trait WebResponseTrait { #[ApiProperty( - description: "The path of the current WebResponse.", + description: 'The path of the current WebResponse.', readable: true, writable: false, identifier: true )] public ?string $path = null; - #[Serializer\Groups(["web_response"])] + #[Serializer\Groups(['web_response'])] public ?PersistableInterface $item = null; - #[Serializer\Groups(["web_response"])] + #[Serializer\Groups(['web_response'])] + #[ApiProperty( + identifier: false, + genId: false, + )] public ?BreadcrumbsInterface $breadcrumbs = null; - #[Serializer\Groups(["web_response"])] + #[Serializer\Groups(['web_response'])] + #[ApiProperty( + identifier: false, + genId: false, + )] public ?NodesSourcesHeadInterface $head = null; /** * @var Collection|null */ - #[Serializer\Groups(["web_response"])] + #[Serializer\Groups(['web_response'])] + #[ApiProperty( + identifier: false, + genId: false, + )] private ?Collection $blocks = null; /** * @var array|null */ - #[Serializer\Groups(["web_response"])] + #[Serializer\Groups(['web_response'])] private ?array $realms = null; - #[Serializer\Groups(["web_response"])] + #[Serializer\Groups(['web_response'])] private bool $hidingBlocks = false; /** * @var int|null WebResponse item maximum age in seconds */ - #[Serializer\Groups(["web_response"])] + #[Serializer\Groups(['web_response'])] private ?int $maxAge = null; public function getMaxAge(): ?int @@ -58,24 +70,24 @@ public function getMaxAge(): ?int public function setMaxAge(?int $maxAge): self { $this->maxAge = $maxAge; + return $this; } public function setPath(?string $path): self { $this->path = $path; + return $this; } public function setItem(?PersistableInterface $item): self { $this->item = $item; + return $this; } - /** - * @return PersistableInterface|null - */ public function getItem(): ?PersistableInterface { return $this->item; @@ -91,11 +103,13 @@ public function getBlocks(): ?array /** * @param Collection|null $blocks + * * @return $this */ public function setBlocks(?Collection $blocks): self { $this->blocks = $blocks; + return $this; } @@ -109,41 +123,42 @@ public function getRealms(): ?array /** * @param RealmInterface[]|null $realms + * * @return $this */ public function setRealms(?array $realms): self { $this->realms = $realms; + return $this; } - /** - * @return bool - */ public function isHidingBlocks(): bool { return $this->hidingBlocks; } /** - * @param bool $hidingBlocks * @return $this */ public function setHidingBlocks(bool $hidingBlocks): self { $this->hidingBlocks = $hidingBlocks; + return $this; } public function setBreadcrumbs(?BreadcrumbsInterface $breadcrumbs): self { $this->breadcrumbs = $breadcrumbs; + return $this; } public function setHead(?NodesSourcesHeadInterface $head): self { $this->head = $head; + return $this; } } diff --git a/src/Api/OpenApi/JwtDecorator.php b/src/Api/OpenApi/JwtDecorator.php index cb41dee7..5b9b0e45 100644 --- a/src/Api/OpenApi/JwtDecorator.php +++ b/src/Api/OpenApi/JwtDecorator.php @@ -5,13 +5,13 @@ namespace RZ\Roadiz\CoreBundle\Api\OpenApi; use ApiPlatform\OpenApi\Factory\OpenApiFactoryInterface; -use ApiPlatform\OpenApi\OpenApi; use ApiPlatform\OpenApi\Model; +use ApiPlatform\OpenApi\OpenApi; -final class JwtDecorator implements OpenApiFactoryInterface +final readonly class JwtDecorator implements OpenApiFactoryInterface { public function __construct( - private readonly OpenApiFactoryInterface $decorated + private OpenApiFactoryInterface $decorated, ) { } diff --git a/src/Api/OpenApi/PreviewDecorator.php b/src/Api/OpenApi/PreviewDecorator.php index 7dcecaae..98103641 100644 --- a/src/Api/OpenApi/PreviewDecorator.php +++ b/src/Api/OpenApi/PreviewDecorator.php @@ -9,10 +9,10 @@ use ApiPlatform\OpenApi\Model\PathItem; use ApiPlatform\OpenApi\OpenApi; -final class PreviewDecorator implements OpenApiFactoryInterface +final readonly class PreviewDecorator implements OpenApiFactoryInterface { public function __construct( - private readonly OpenApiFactoryInterface $decorated + private OpenApiFactoryInterface $decorated, ) { } @@ -37,10 +37,10 @@ public function __invoke(array $context = []): OpenApi 'query', 'Enables preview mode (requires a valid bearer JWT token)', false - ))->withSchema(['type' => 'boolean'])->withExample('1') + ))->withSchema(['type' => 'boolean'])->withExample('1'), ])->withSecurity([ ...$operation->getSecurity() ?? [], - ['JWT' => []] + ['JWT' => []], ])->withResponses($responses); $openApi->getPaths()->addPath($path, $pathItem->withGet($newOperation)); } diff --git a/src/Api/OpenApi/WebResponseDecorator.php b/src/Api/OpenApi/WebResponseDecorator.php index e76a1947..46b9ec9d 100644 --- a/src/Api/OpenApi/WebResponseDecorator.php +++ b/src/Api/OpenApi/WebResponseDecorator.php @@ -8,10 +8,10 @@ use ApiPlatform\OpenApi\Model; use ApiPlatform\OpenApi\OpenApi; -final class WebResponseDecorator implements OpenApiFactoryInterface +final readonly class WebResponseDecorator implements OpenApiFactoryInterface { public function __construct( - private readonly OpenApiFactoryInterface $decorated + private OpenApiFactoryInterface $decorated, ) { } @@ -39,7 +39,7 @@ public function __invoke(array $context = []): OpenApi 'query', 'Enables preview mode (requires a valid bearer JWT token)', false - ))->withSchema(['type' => 'boolean'])->withExample('1') + ))->withSchema(['type' => 'boolean'])->withExample('1'), ]) )); diff --git a/src/Api/TreeWalker/AutoChildrenNodeSourceWalker.php b/src/Api/TreeWalker/AutoChildrenNodeSourceWalker.php index 96ea462d..3d0c9a27 100644 --- a/src/Api/TreeWalker/AutoChildrenNodeSourceWalker.php +++ b/src/Api/TreeWalker/AutoChildrenNodeSourceWalker.php @@ -42,18 +42,13 @@ protected function initializeAdditionalDefinitions(): void } /** - * @param NodeTypeInterface $nodeType - * @return callable * @throws InvalidArgumentException */ protected function createDefinitionForNodeType(NodeTypeInterface $nodeType): callable { $context = $this->getContext(); if (!$context instanceof NodeSourceWalkerContext) { - throw new \InvalidArgumentException( - 'TreeWalker context must be instance of ' . - NodeSourceWalkerContext::class - ); + throw new \InvalidArgumentException('TreeWalker context must be instance of '.NodeSourceWalkerContext::class); } $childrenNodeTypes = $context->getNodeTypeResolver()->getChildrenNodeTypeList($nodeType); if (count($childrenNodeTypes) > 0) { diff --git a/src/Api/TreeWalker/Definition/DefinitionFactoryConfiguration.php b/src/Api/TreeWalker/Definition/DefinitionFactoryConfiguration.php index a4326a3e..3b227a1c 100644 --- a/src/Api/TreeWalker/Definition/DefinitionFactoryConfiguration.php +++ b/src/Api/TreeWalker/Definition/DefinitionFactoryConfiguration.php @@ -8,13 +8,11 @@ final class DefinitionFactoryConfiguration { /** * @param class-string $classname - * @param DefinitionFactoryInterface $definitionFactory - * @param bool $onlyVisible */ public function __construct( public readonly string $classname, public readonly DefinitionFactoryInterface $definitionFactory, - public readonly bool $onlyVisible + public readonly bool $onlyVisible, ) { } } diff --git a/src/Api/TreeWalker/Definition/MultiTypeChildrenDefinition.php b/src/Api/TreeWalker/Definition/MultiTypeChildrenDefinition.php index 9e6999ea..fd0c85fa 100644 --- a/src/Api/TreeWalker/Definition/MultiTypeChildrenDefinition.php +++ b/src/Api/TreeWalker/Definition/MultiTypeChildrenDefinition.php @@ -4,9 +4,9 @@ namespace RZ\Roadiz\CoreBundle\Api\TreeWalker\Definition; -use Doctrine\ORM\Tools\Pagination\Paginator; use RZ\Roadiz\CoreBundle\Api\TreeWalker\NodeSourceWalkerContext; use RZ\Roadiz\CoreBundle\Entity\NodesSources; +use RZ\Roadiz\CoreBundle\Entity\NodeType; use RZ\TreeWalker\Definition\ContextualDefinitionTrait; use RZ\TreeWalker\WalkerContextInterface; @@ -15,42 +15,51 @@ final class MultiTypeChildrenDefinition use ContextualDefinitionTrait; /** - * @param WalkerContextInterface $context * @param array $types - * @param bool $onlyVisible */ public function __construct( private readonly WalkerContextInterface $context, private readonly array $types, - private readonly bool $onlyVisible = true + private readonly bool $onlyVisible = true, ) { } /** - * @param NodesSources $source - * @return array|Paginator + * @return array */ - public function __invoke(NodesSources $source) + public function __invoke(NodesSources $source): array { if (!($this->context instanceof NodeSourceWalkerContext)) { - throw new \InvalidArgumentException('Context should be instance of ' . NodeSourceWalkerContext::class); + throw new \InvalidArgumentException('Context should be instance of '.NodeSourceWalkerContext::class); } $this->context->getStopwatch()->start(self::class); $bag = $this->context->getNodeTypesBag(); + /** @var NodeType[] $nodeTypes */ + $nodeTypes = array_map(function (string $singleType) use ($bag) { + return $bag->get($singleType); + }, $this->types); $criteria = [ 'node.parent' => $source->getNode(), 'translation' => $source->getTranslation(), - 'node.nodeType' => array_map(function (string $singleType) use ($bag) { - return $bag->get($singleType); - }, $this->types) + 'node.nodeType' => $nodeTypes, ]; if ($this->onlyVisible) { $criteria['node.visible'] = true; } - $children = $this->context->getNodeSourceApi()->getBy($criteria, [ - 'node.position' => 'ASC', - ]); + if (1 === count($nodeTypes)) { + $entityName = $nodeTypes[0]->getSourceEntityFullQualifiedClassName(); + } else { + $entityName = NodesSources::class; + } + // @phpstan-ignore-next-line + $children = $this->context + ->getManagerRegistry() + ->getRepository($entityName) + ->findBy($criteria, [ + 'node.position' => 'ASC', + ]); + $this->context->getStopwatch()->stop(self::class); return $children; diff --git a/src/Api/TreeWalker/Definition/NonReachableNodeSourceBlockDefinition.php b/src/Api/TreeWalker/Definition/NonReachableNodeSourceBlockDefinition.php index 64df42ec..91da32fc 100644 --- a/src/Api/TreeWalker/Definition/NonReachableNodeSourceBlockDefinition.php +++ b/src/Api/TreeWalker/Definition/NonReachableNodeSourceBlockDefinition.php @@ -4,9 +4,6 @@ namespace RZ\Roadiz\CoreBundle\Api\TreeWalker\Definition; -use ArrayIterator; -use Doctrine\ORM\Tools\Pagination\Paginator; -use Exception; use RZ\Roadiz\CoreBundle\Api\TreeWalker\NodeSourceWalkerContext; use RZ\Roadiz\CoreBundle\Entity\NodesSources; use RZ\TreeWalker\Definition\ContextualDefinitionTrait; @@ -18,17 +15,17 @@ final class NonReachableNodeSourceBlockDefinition public function __construct( private readonly WalkerContextInterface $context, - private readonly bool $onlyVisible = true + private readonly bool $onlyVisible = true, ) { } /** - * @throws Exception + * @throws \Exception */ public function __invoke(NodesSources $source): array { if (!($this->context instanceof NodeSourceWalkerContext)) { - throw new \InvalidArgumentException('Context should be instance of ' . NodeSourceWalkerContext::class); + throw new \InvalidArgumentException('Context should be instance of '.NodeSourceWalkerContext::class); } $this->context->getStopwatch()->start(self::class); @@ -40,19 +37,14 @@ public function __invoke(NodesSources $source): array if ($this->onlyVisible) { $criteria['node.visible'] = true; } - $children = $this->context->getNodeSourceApi()->getBy($criteria, [ - 'node.position' => 'ASC', - ]); + // @phpstan-ignore-next-line + $children = $this->context->getManagerRegistry() + ->getRepository(NodesSources::class) + ->findBy($criteria, [ + 'node.position' => 'ASC', + ]); $this->context->getStopwatch()->stop(self::class); - if ($children instanceof Paginator) { - $iterator = $children->getIterator(); - if ($iterator instanceof ArrayIterator) { - return $iterator->getArrayCopy(); - } - // @phpstan-ignore-next-line - return iterator_to_array($iterator); - } return $children; } } diff --git a/src/Api/TreeWalker/Definition/ReachableNodeSourceDefinition.php b/src/Api/TreeWalker/Definition/ReachableNodeSourceDefinition.php index 5eecf6b3..f50e947f 100644 --- a/src/Api/TreeWalker/Definition/ReachableNodeSourceDefinition.php +++ b/src/Api/TreeWalker/Definition/ReachableNodeSourceDefinition.php @@ -4,9 +4,6 @@ namespace RZ\Roadiz\CoreBundle\Api\TreeWalker\Definition; -use ArrayIterator; -use Doctrine\ORM\Tools\Pagination\Paginator; -use Exception; use RZ\Roadiz\CoreBundle\Api\TreeWalker\NodeSourceWalkerContext; use RZ\Roadiz\CoreBundle\Entity\NodesSources; use RZ\TreeWalker\Definition\ContextualDefinitionTrait; @@ -18,17 +15,17 @@ final class ReachableNodeSourceDefinition public function __construct( private readonly WalkerContextInterface $context, - private readonly bool $onlyVisible = true + private readonly bool $onlyVisible = true, ) { } /** - * @throws Exception + * @throws \Exception */ public function __invoke(NodesSources $source): array { if (!($this->context instanceof NodeSourceWalkerContext)) { - throw new \InvalidArgumentException('Context should be instance of ' . NodeSourceWalkerContext::class); + throw new \InvalidArgumentException('Context should be instance of '.NodeSourceWalkerContext::class); } $this->context->getStopwatch()->start(self::class); @@ -40,19 +37,14 @@ public function __invoke(NodesSources $source): array if ($this->onlyVisible) { $criteria['node.visible'] = true; } - $children = $this->context->getNodeSourceApi()->getBy($criteria, [ - 'node.position' => 'ASC', - ]); + // @phpstan-ignore-next-line + $children = $this->context->getManagerRegistry() + ->getRepository(NodesSources::class) + ->findBy($criteria, [ + 'node.position' => 'ASC', + ]); $this->context->getStopwatch()->stop(self::class); - if ($children instanceof Paginator) { - $iterator = $children->getIterator(); - if ($iterator instanceof ArrayIterator) { - return $iterator->getArrayCopy(); - } - // @phpstan-ignore-next-line - return iterator_to_array($iterator); - } return $children; } } diff --git a/src/Api/TreeWalker/NodeSourceWalkerContext.php b/src/Api/TreeWalker/NodeSourceWalkerContext.php index 164154ac..d5bd25ac 100644 --- a/src/Api/TreeWalker/NodeSourceWalkerContext.php +++ b/src/Api/TreeWalker/NodeSourceWalkerContext.php @@ -18,54 +18,44 @@ use Symfony\Component\Stopwatch\Stopwatch; #[Exclude] -class NodeSourceWalkerContext implements WalkerContextInterface +readonly class NodeSourceWalkerContext implements WalkerContextInterface { public function __construct( - private readonly Stopwatch $stopwatch, - private readonly NodeTypes $nodeTypesBag, - private readonly NodeSourceApi $nodeSourceApi, - private readonly RequestStack $requestStack, - private readonly ManagerRegistry $managerRegistry, - private readonly CacheItemPoolInterface $cacheAdapter, - private readonly NodeTypeResolver $nodeTypeResolver, - private readonly PreviewResolverInterface $previewResolver + private Stopwatch $stopwatch, + private NodeTypes $nodeTypesBag, + private NodeSourceApi $nodeSourceApi, + private RequestStack $requestStack, + private ManagerRegistry $managerRegistry, + private CacheItemPoolInterface $cacheAdapter, + private NodeTypeResolver $nodeTypeResolver, + private PreviewResolverInterface $previewResolver, ) { } - /** - * @return Stopwatch - */ public function getStopwatch(): Stopwatch { return $this->stopwatch; } - /** - * @return NodeTypes - */ public function getNodeTypesBag(): NodeTypes { return $this->nodeTypesBag; } /** - * @return NodeSourceApi + * @deprecated Use getManagerRegistry */ public function getNodeSourceApi(): NodeSourceApi { return $this->nodeSourceApi; } - /** - * @return RequestStack - */ public function getRequestStack(): RequestStack { return $this->requestStack; } /** - * @return Request|null * @deprecated Use getMainRequest */ public function getMasterRequest(): ?Request @@ -73,49 +63,31 @@ public function getMasterRequest(): ?Request return $this->requestStack->getMainRequest(); } - /** - * @return Request|null - */ public function getMainRequest(): ?Request { return $this->requestStack->getMainRequest(); } - /** - * @return ManagerRegistry - */ public function getManagerRegistry(): ManagerRegistry { return $this->managerRegistry; } - /** - * @return ObjectManager - */ public function getEntityManager(): ObjectManager { return $this->getManagerRegistry()->getManager(); } - /** - * @return CacheItemPoolInterface - */ public function getCacheAdapter(): CacheItemPoolInterface { return $this->cacheAdapter; } - /** - * @return NodeTypeResolver - */ public function getNodeTypeResolver(): NodeTypeResolver { return $this->nodeTypeResolver; } - /** - * @return PreviewResolverInterface - */ public function getPreviewResolver(): PreviewResolverInterface { return $this->previewResolver; diff --git a/src/Api/TreeWalker/NodeSourceWalkerContextFactory.php b/src/Api/TreeWalker/NodeSourceWalkerContextFactory.php index 2c5099c6..35253742 100644 --- a/src/Api/TreeWalker/NodeSourceWalkerContextFactory.php +++ b/src/Api/TreeWalker/NodeSourceWalkerContextFactory.php @@ -14,17 +14,17 @@ use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Stopwatch\Stopwatch; -final class NodeSourceWalkerContextFactory implements WalkerContextFactoryInterface +final readonly class NodeSourceWalkerContextFactory implements WalkerContextFactoryInterface { public function __construct( - private readonly Stopwatch $stopwatch, - private readonly NodeTypes $nodeTypesBag, - private readonly NodeSourceApi $nodeSourceApi, - private readonly RequestStack $requestStack, - private readonly ManagerRegistry $managerRegistry, - private readonly CacheItemPoolInterface $cacheAdapter, - private readonly NodeTypeResolver $nodeTypeResolver, - private readonly PreviewResolverInterface $previewResolver + private Stopwatch $stopwatch, + private NodeTypes $nodeTypesBag, + private NodeSourceApi $nodeSourceApi, + private RequestStack $requestStack, + private ManagerRegistry $managerRegistry, + private CacheItemPoolInterface $cacheAdapter, + private NodeTypeResolver $nodeTypeResolver, + private PreviewResolverInterface $previewResolver, ) { } diff --git a/src/Api/TreeWalker/TreeWalkerGenerator.php b/src/Api/TreeWalker/TreeWalkerGenerator.php index b456f2db..6d995b16 100644 --- a/src/Api/TreeWalker/TreeWalkerGenerator.php +++ b/src/Api/TreeWalker/TreeWalkerGenerator.php @@ -27,22 +27,20 @@ public function __construct( private readonly NodeSourceApi $nodeSourceApi, private readonly NodeTypes $nodeTypesBag, private readonly WalkerContextInterface $walkerContext, - private readonly CacheItemPoolInterface $cacheItemPool + private readonly CacheItemPoolInterface $cacheItemPool, ) { } /** - * @param string $nodeType * @param class-string $walkerClass - * @param TranslationInterface $translation - * @param int $maxLevel + * * @return array */ public function getTreeWalkersForTypeAtRoot( string $nodeType, string $walkerClass, TranslationInterface $translation, - int $maxLevel = 3 + int $maxLevel = 3, ): array { $walkers = []; /** @var NodesSources[] $roots */ @@ -53,7 +51,7 @@ public function getTreeWalkersForTypeAtRoot( ]); foreach ($roots as $root) { - $walkerName = (new UnicodeString($root->getNode()->getNodeName() . ' walker')) + $walkerName = (new UnicodeString($root->getNode()->getNodeName().' walker')) ->trim() ->camel() ->toString(); @@ -71,19 +69,14 @@ public function getTreeWalkersForTypeAtRoot( } /** - * @param object $root * @param class-string $walkerClass - * @param WalkerContextInterface $walkerContext - * @param int $maxLevel - * @param CacheItemPoolInterface $cacheItemPool - * @return WalkerInterface */ public function buildForRoot( object $root, string $walkerClass, WalkerContextInterface $walkerContext, int $maxLevel, - CacheItemPoolInterface $cacheItemPool + CacheItemPoolInterface $cacheItemPool, ): WalkerInterface { /** @var callable $callable */ $callable = [$walkerClass, 'build']; @@ -104,6 +97,7 @@ public function buildForRoot( ) ); } + return $walker; } @@ -112,14 +106,11 @@ public function buildForRoot( * using `roadiz_core.tree_walker_definition_factory` tag. * * @param class-string $classname - * @param DefinitionFactoryInterface $definitionFactory - * @param bool $onlyVisible - * @return void */ public function addDefinitionFactoryConfiguration( string $classname, DefinitionFactoryInterface $definitionFactory, - bool $onlyVisible + bool $onlyVisible, ): void { $this->walkerDefinitionFactories[$classname] = new DefinitionFactoryConfiguration( $classname, diff --git a/src/Bag/NodeTypes.php b/src/Bag/NodeTypes.php index fbaf9dd5..410a5db3 100644 --- a/src/Bag/NodeTypes.php +++ b/src/Bag/NodeTypes.php @@ -24,6 +24,7 @@ public function getRepository(): NodeTypeRepository if (null === $this->repository) { $this->repository = $this->managerRegistry->getRepository(NodeType::class); } + return $this->repository; } diff --git a/src/Bag/Roles.php b/src/Bag/Roles.php index e98d7e14..b2b25044 100644 --- a/src/Bag/Roles.php +++ b/src/Bag/Roles.php @@ -23,6 +23,7 @@ public function getRepository(): RoleRepository if (null === $this->repository) { $this->repository = $this->managerRegistry->getRepository(Role::class); } + return $this->repository; } @@ -44,10 +45,7 @@ protected function populateParameters(): void /** * Get role by name or create it if non-existent. * - * @param string $key - * @param null $default - * - * @return Role + * @param null $default */ public function get(string $key, $default = null): Role { diff --git a/src/Bag/Settings.php b/src/Bag/Settings.php index 4760721b..3599c596 100644 --- a/src/Bag/Settings.php +++ b/src/Bag/Settings.php @@ -17,7 +17,7 @@ class Settings extends LazyParameterBag public function __construct( private readonly ManagerRegistry $managerRegistry, - private readonly Stopwatch $stopwatch + private readonly Stopwatch $stopwatch, ) { parent::__construct(); } @@ -27,6 +27,7 @@ public function getRepository(): SettingRepository if (null === $this->repository) { $this->repository = $this->managerRegistry->getRepository(Setting::class); } + return $this->repository; } @@ -47,11 +48,6 @@ protected function populateParameters(): void $this->stopwatch->stop('settings'); } - /** - * @param string $key - * @param mixed $default - * @return mixed - */ public function get(string $key, $default = false): mixed { return parent::get($key, $default); @@ -59,14 +55,12 @@ public function get(string $key, $default = false): mixed /** * Get a document from its setting name. - * - * @param string $key - * @return Document|null */ public function getDocument(string $key): ?Document { try { $id = $this->getInt($key); + return $this->managerRegistry ->getRepository(Document::class) ->findOneById($id); diff --git a/src/Cache/Clearer/ClearerInterface.php b/src/Cache/Clearer/ClearerInterface.php index 3b76c801..d4dd9615 100644 --- a/src/Cache/Clearer/ClearerInterface.php +++ b/src/Cache/Clearer/ClearerInterface.php @@ -6,18 +6,12 @@ interface ClearerInterface { - /** - * @return bool - */ public function clear(): bool; - /** - * @return string - */ + public function getOutput(): string; + /** * Get global cache directory. - * - * @return string */ public function getCacheDir(): string; } diff --git a/src/Cache/Clearer/FileClearer.php b/src/Cache/Clearer/FileClearer.php index 955e348f..c1a5e037 100644 --- a/src/Cache/Clearer/FileClearer.php +++ b/src/Cache/Clearer/FileClearer.php @@ -24,8 +24,6 @@ public function getOutput(): string /** * Get global cache directory. - * - * @return string */ public function getCacheDir(): string { diff --git a/src/Cache/Clearer/NodesSourcesUrlsCacheClearer.php b/src/Cache/Clearer/NodesSourcesUrlsCacheClearer.php index a7018fe0..8cd5d7a2 100644 --- a/src/Cache/Clearer/NodesSourcesUrlsCacheClearer.php +++ b/src/Cache/Clearer/NodesSourcesUrlsCacheClearer.php @@ -19,8 +19,10 @@ public function clear(): bool if ($this->cacheProvider->clear()) { $this->output .= 'cleared'; + return true; } + return false; } } diff --git a/src/Cache/Clearer/OPCacheClearer.php b/src/Cache/Clearer/OPCacheClearer.php index 9d165804..c9a8cadd 100644 --- a/src/Cache/Clearer/OPCacheClearer.php +++ b/src/Cache/Clearer/OPCacheClearer.php @@ -16,10 +16,11 @@ public function clear(): bool \apcu_clear_cache(); } if ( - \function_exists('opcache_reset') && - true === \opcache_reset() + \function_exists('opcache_reset') + && true === \opcache_reset() ) { $this->output = 'PHP OPCache has been reset.'; + return true; } else { $this->output = 'PHP OPCache is disabled.'; diff --git a/src/Cache/CloudflareProxyCache.php b/src/Cache/CloudflareProxyCache.php index 93485e54..ef602313 100644 --- a/src/Cache/CloudflareProxyCache.php +++ b/src/Cache/CloudflareProxyCache.php @@ -4,70 +4,49 @@ namespace RZ\Roadiz\CoreBundle\Cache; -final class CloudflareProxyCache +final readonly class CloudflareProxyCache { public function __construct( - private readonly string $name, - private readonly string $zone, - private readonly string $version, - private readonly string $bearer, - private readonly string $email, - private readonly string $key, - private readonly int $timeout + private string $name, + private string $zone, + private string $version, + private string $bearer, + private string $email, + private string $key, + private int $timeout, ) { } - /** - * @return string - */ public function getName(): string { return $this->name; } - /** - * @return string - */ public function getZone(): string { return $this->zone; } - /** - * @return string - */ public function getVersion(): string { return $this->version; } - /** - * @return string - */ public function getBearer(): string { return $this->bearer; } - /** - * @return string - */ public function getEmail(): string { return $this->email; } - /** - * @return string - */ public function getKey(): string { return $this->key; } - /** - * @return int - */ public function getTimeout(): int { return $this->timeout; diff --git a/src/Cache/ReverseProxyCache.php b/src/Cache/ReverseProxyCache.php index 8aa36611..c7683f6d 100644 --- a/src/Cache/ReverseProxyCache.php +++ b/src/Cache/ReverseProxyCache.php @@ -4,35 +4,26 @@ namespace RZ\Roadiz\CoreBundle\Cache; -final class ReverseProxyCache +final readonly class ReverseProxyCache { public function __construct( - private readonly string $name, - private readonly string $host, - private readonly string $domainName, - private readonly int $timeout + private string $name, + private string $host, + private string $domainName, + private int $timeout, ) { } - /** - * @return string - */ public function getName(): string { return $this->name; } - /** - * @return string - */ public function getHost(): string { return $this->host; } - /** - * @return string - */ public function getDomainName(): string { return $this->domainName; diff --git a/src/Cache/ReverseProxyCacheLocator.php b/src/Cache/ReverseProxyCacheLocator.php index b3f4b963..1fd879d3 100644 --- a/src/Cache/ReverseProxyCacheLocator.php +++ b/src/Cache/ReverseProxyCacheLocator.php @@ -4,15 +4,14 @@ namespace RZ\Roadiz\CoreBundle\Cache; -final class ReverseProxyCacheLocator +final readonly class ReverseProxyCacheLocator { /** * @param ReverseProxyCache[] $frontends - * @param CloudflareProxyCache|null $cloudflareProxyCache */ public function __construct( - private readonly array $frontends, - private readonly ?CloudflareProxyCache $cloudflareProxyCache = null + private array $frontends, + private ?CloudflareProxyCache $cloudflareProxyCache = null, ) { } @@ -24,9 +23,6 @@ public function getFrontends(): array return $this->frontends; } - /** - * @return CloudflareProxyCache|null - */ public function getCloudflareProxyCache(): ?CloudflareProxyCache { return $this->cloudflareProxyCache; diff --git a/src/Configuration/CollectionFieldConfiguration.php b/src/Configuration/CollectionFieldConfiguration.php index faf08a15..1208b608 100644 --- a/src/Configuration/CollectionFieldConfiguration.php +++ b/src/Configuration/CollectionFieldConfiguration.php @@ -9,9 +9,6 @@ class CollectionFieldConfiguration implements ConfigurationInterface { - /** - * @return TreeBuilder - */ public function getConfigTreeBuilder(): TreeBuilder { $builder = new TreeBuilder('collection'); diff --git a/src/Configuration/JoinNodeTypeFieldConfiguration.php b/src/Configuration/JoinNodeTypeFieldConfiguration.php index 952c6447..9a68111e 100644 --- a/src/Configuration/JoinNodeTypeFieldConfiguration.php +++ b/src/Configuration/JoinNodeTypeFieldConfiguration.php @@ -9,9 +9,6 @@ class JoinNodeTypeFieldConfiguration implements ConfigurationInterface { - /** - * @return TreeBuilder - */ public function getConfigTreeBuilder(): TreeBuilder { $builder = new TreeBuilder('join'); diff --git a/src/Configuration/ProviderFieldConfiguration.php b/src/Configuration/ProviderFieldConfiguration.php index c9a5d00f..8da8645d 100644 --- a/src/Configuration/ProviderFieldConfiguration.php +++ b/src/Configuration/ProviderFieldConfiguration.php @@ -9,9 +9,6 @@ class ProviderFieldConfiguration implements ConfigurationInterface { - /** - * @return TreeBuilder - */ public function getConfigTreeBuilder(): TreeBuilder { $builder = new TreeBuilder('provider'); diff --git a/src/Console/AppInstallCommand.php b/src/Console/AppInstallCommand.php index e1023ba7..d47ebdd2 100644 --- a/src/Console/AppInstallCommand.php +++ b/src/Console/AppInstallCommand.php @@ -18,6 +18,7 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\HttpFoundation\File\File; use Symfony\Component\Yaml\Yaml; @@ -27,6 +28,7 @@ final class AppInstallCommand extends Command private bool $dryRun = false; public function __construct( + #[Autowire('%kernel.project_dir%')] private readonly string $projectDir, private readonly ManagerRegistry $managerRegistry, private readonly NodeTypesImporter $nodeTypesImporter, @@ -35,7 +37,7 @@ public function __construct( private readonly RolesImporter $rolesImporter, private readonly GroupsImporter $groupsImporter, private readonly AttributeImporter $attributeImporter, - ?string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -62,17 +64,19 @@ protected function execute(InputInterface $input, OutputInterface $output): int /* * Test if Classname is not a valid yaml file before using Theme */ - $configPath = $this->projectDir . '/src/Resources/config.yml'; + $configPath = $this->projectDir.'/src/Resources/config.yml'; $realConfigPath = realpath($configPath); if (false !== $realConfigPath && file_exists($realConfigPath)) { - $this->io->note('Install assets directly from file: ' . $realConfigPath); + $this->io->note('Install assets directly from file: '.$realConfigPath); $themeConfigPath = $realConfigPath; } else { - $this->io->error($configPath . ' configuration file is not readable.'); + $this->io->error($configPath.' configuration file is not readable.'); + return 1; } $this->importAppData($themeConfigPath); + return 0; } @@ -80,89 +84,92 @@ protected function importAppData(string $themeConfigPath): void { $data = $this->getAppConfig($themeConfigPath); - if (isset($data["importFiles"])) { - if (isset($data["importFiles"]['groups'])) { - foreach ($data["importFiles"]['groups'] as $filename) { - $this->importFile($filename, $this->groupsImporter); - } + if (!isset($data['importFiles']) || !is_array($data['importFiles'])) { + $this->io->warning('Config file "'.$themeConfigPath.'" has no data to import.'); + + return; + } + + if (isset($data['importFiles']['groups'])) { + foreach ($data['importFiles']['groups'] as $filename) { + $this->importFile($filename, $this->groupsImporter); } - if (isset($data["importFiles"]['roles'])) { - foreach ($data["importFiles"]['roles'] as $filename) { - $this->importFile($filename, $this->rolesImporter); - } + } + if (isset($data['importFiles']['roles'])) { + foreach ($data['importFiles']['roles'] as $filename) { + $this->importFile($filename, $this->rolesImporter); } - if (isset($data["importFiles"]['settings'])) { - foreach ($data["importFiles"]['settings'] as $filename) { - $this->importFile($filename, $this->settingsImporter); - } + } + if (isset($data['importFiles']['settings'])) { + foreach ($data['importFiles']['settings'] as $filename) { + $this->importFile($filename, $this->settingsImporter); } - if (isset($data["importFiles"]['nodetypes'])) { - foreach ($data["importFiles"]['nodetypes'] as $filename) { - $this->importFile($filename, $this->nodeTypesImporter); - } + } + if (isset($data['importFiles']['nodetypes'])) { + foreach ($data['importFiles']['nodetypes'] as $filename) { + $this->importFile($filename, $this->nodeTypesImporter); } - if (isset($data["importFiles"]['tags'])) { - foreach ($data["importFiles"]['tags'] as $filename) { - $this->importFile($filename, $this->tagsImporter); - } + } + if (isset($data['importFiles']['tags'])) { + foreach ($data['importFiles']['tags'] as $filename) { + $this->importFile($filename, $this->tagsImporter); } - if (isset($data["importFiles"]['attributes'])) { - foreach ($data["importFiles"]['attributes'] as $filename) { - $this->importFile($filename, $this->attributeImporter); - } + } + if (isset($data['importFiles']['attributes'])) { + foreach ($data['importFiles']['attributes'] as $filename) { + $this->importFile($filename, $this->attributeImporter); } - } else { - $this->io->warning('Config file "' . $themeConfigPath . '" has no data to import.'); } } - /** - * @param string $filename - * @param EntityImporterInterface $importer - */ protected function importFile(string $filename, EntityImporterInterface $importer): void { if (false !== $realFilename = realpath($filename)) { $file = new File($realFilename); } else { - throw new \RuntimeException($filename . ' is not a valid file'); + throw new \RuntimeException($filename.' is not a valid file'); } - if (!$this->dryRun) { - try { - if (false === $fileContent = file_get_contents($file->getPathname())) { - throw new \RuntimeException($file->getPathname() . ' file is not readable'); - } - $importer->import($fileContent); - $this->managerRegistry->getManager()->flush(); - $this->io->writeln( - '* ' . $file->getPathname() . ' file has been imported.' - ); - return; - } catch (EntityAlreadyExistsException $e) { - $this->io->writeln( - '* ' . $file->getPathname() . '' . - ' has NOT been imported (' . $e->getMessage() . ').' - ); + if ($this->dryRun) { + $this->io->writeln( + '* '.$file->getPathname().' file would be imported.' + ); + + return; + } + + try { + if (false === $fileContent = file_get_contents($file->getPathname())) { + throw new \RuntimeException($file->getPathname().' file is not readable'); } + $importer->import($fileContent); + $this->managerRegistry->getManager()->flush(); + $this->io->writeln( + '* '.$file->getPathname().' file has been imported.' + ); + + return; + } catch (EntityAlreadyExistsException $e) { + $this->io->writeln( + '* '.$file->getPathname().''. + ' has NOT been imported ('.$e->getMessage().').' + ); } + $this->io->writeln( - '* ' . $file->getPathname() . ' file has been imported.' + '* '.$file->getPathname().' file has been imported.' ); } - /** - * @param string $appConfigPath - * @return array - */ protected function getAppConfig(string $appConfigPath): array { if (false === $fileContent = file_get_contents($appConfigPath)) { - throw new \RuntimeException($appConfigPath . ' file is not readable'); + throw new \RuntimeException($appConfigPath.' file is not readable'); } $data = Yaml::parse($fileContent); if (!\is_array($data)) { - throw new \RuntimeException($appConfigPath . ' file is not a valid YAML file'); + throw new \RuntimeException($appConfigPath.' file is not a valid YAML file'); } + return $data; } } diff --git a/src/Console/AppMigrateCommand.php b/src/Console/AppMigrateCommand.php index e8949486..6340f3ef 100644 --- a/src/Console/AppMigrateCommand.php +++ b/src/Console/AppMigrateCommand.php @@ -11,18 +11,26 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\Console\Style\SymfonyStyle; -use Symfony\Component\Process\Process; +use Symfony\Component\DependencyInjection\Attribute\Autowire; final class AppMigrateCommand extends Command { + use RunningCommandsTrait; + public function __construct( private readonly SchemaUpdater $schemaUpdater, + #[Autowire('%kernel.project_dir%')] private readonly string $projectDir, - ?string $name = null + ?string $name = null, ) { parent::__construct($name); } + public function getProjectDir(): string + { + return $this->projectDir; + } + protected function configure(): void { $this->setName('app:migrate') @@ -43,8 +51,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int 'Are you sure to migrate against app config.yml file? This will generate new Doctrine Migrations and execute them. If you just want to import node-types run `bin/console app:install` instead', !$input->isInteractive() ); - if ($io->askQuestion($question) === false) { + if (false === $io->askQuestion($question)) { $io->note('Nothing was done…'); + return 0; } @@ -57,70 +66,37 @@ protected function execute(InputInterface $input, OutputInterface $output): int $output->isQuiet(), ); } else { - $this->runCommand( + 0 === $this->runCommand( 'app:install', '', null, $input->isInteractive(), $output->isQuiet() - ) === 0 ? $io->success('app:install') : $io->error('app:install'); + ) ? $io->success('app:install') : $io->error('app:install'); - $this->runCommand( + 0 === $this->runCommand( 'generate:nsentities', '', null, $input->isInteractive(), $output->isQuiet() - ) === 0 ? $io->success('generate:nsentities') : $io->error('generate:nsentities'); + ) ? $io->success('generate:nsentities') : $io->error('generate:nsentities'); - $this->schemaUpdater->updateNodeTypesSchema(); - $this->schemaUpdater->updateSchema(); - $io->success('doctrine-migrations'); - - $this->runCommand( - 'doctrine:cache:clear-metadata', + 0 === $this->runCommand( + 'generate:api-resources', '', null, - false, - true - ) === 0 ? $io->success('doctrine:cache:clear-metadata') : $io->error('doctrine:cache:clear-metadata'); + $input->isInteractive(), + $output->isQuiet() + ) ? $io->success('generate:api-resources') : $io->error('generate:api-resources'); - $this->runCommand( - 'cache:clear', - '', - null, - false, - true - ) === 0 ? $io->success('cache:clear') : $io->error('cache:clear'); + $this->schemaUpdater->updateNodeTypesSchema(); + $this->schemaUpdater->updateSchema(); + $io->success('doctrine-migrations'); - $this->runCommand( - 'cache:pool:clear', - 'cache.global_clearer', - null, - false, - true - ) === 0 ? $io->success('cache:pool:clear') : $io->error('cache:pool:clear'); + $this->clearCaches($io); } - return 0; - } - protected function runCommand( - string $command, - string $args = '', - ?string $environment = null, - bool $interactive = true, - bool $quiet = false - ): int { - $args .= $interactive ? '' : ' --no-interaction '; - $args .= $quiet ? ' --quiet ' : ' -v '; - $args .= is_string($environment) ? (' --env ' . $environment) : ''; - - $process = Process::fromShellCommandline( - 'php bin/console ' . $command . ' ' . $args - ); - $process->setWorkingDirectory($this->projectDir); - $process->setTty($interactive); - $process->run(); - return $process->wait(); + return 0; } } diff --git a/src/Console/CustomFormAnswerPurgeCommand.php b/src/Console/CustomFormAnswerPurgeCommand.php index 07270a01..a84d5cc3 100644 --- a/src/Console/CustomFormAnswerPurgeCommand.php +++ b/src/Console/CustomFormAnswerPurgeCommand.php @@ -23,7 +23,7 @@ public function __construct( private readonly ManagerRegistry $managerRegistry, private readonly EventDispatcherInterface $eventDispatcher, private readonly LoggerInterface $logger, - string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -44,74 +44,85 @@ protected function execute(InputInterface $input, OutputInterface $output): int ->findAllWithRetentionTime(); foreach ($customForms as $customForm) { - if (null !== $interval = $customForm->getRetentionTimeInterval()) { - $purgeBefore = (new \DateTime())->sub($interval); - $customFormAnswers = $this->managerRegistry - ->getRepository(CustomFormAnswer::class) - ->findByCustomFormSubmittedBefore($customForm, $purgeBefore); - $count = count($customFormAnswers); - - $documents = $this->managerRegistry - ->getRepository(Document::class) - ->findByCustomFormSubmittedBefore($customForm, $purgeBefore); - $documentsCount = count($documents); + $this->purgeCustomFormAnswers($customForm, $input, $output); + } - if ($output->isVeryVerbose()) { - $io->info(\sprintf( - 'Checking if “%s” custom-form has answers before %s', - $customForm->getName(), - $purgeBefore->format('Y-m-d H:i') - )); - } + return 0; + } + + protected function purgeCustomFormAnswers(CustomForm $customForm, InputInterface $input, OutputInterface $output): void + { + $io = new SymfonyStyle($input, $output); + + if (null === $interval = $customForm->getRetentionTimeInterval()) { + return; + } - if ($count > 0) { + $purgeBefore = (new \DateTime())->sub($interval); + $customFormAnswers = $this->managerRegistry + ->getRepository(CustomFormAnswer::class) + ->findByCustomFormSubmittedBefore($customForm, $purgeBefore); + $count = count($customFormAnswers); + + $documents = $this->managerRegistry + ->getRepository(Document::class) + ->findByCustomFormSubmittedBefore($customForm, $purgeBefore); + $documentsCount = count($documents); + + if ($output->isVeryVerbose()) { + $io->info(\sprintf( + 'Checking if “%s” custom-form has answers before %s', + $customForm->getName(), + $purgeBefore->format('Y-m-d H:i') + )); + } + + if ($count <= 0) { + return; + } + + $io->info(\sprintf( + 'Purge %d custom-form answer(s) with %d documents(s) from “%s” before %s', + $count, + $documentsCount, + $customForm->getName(), + $purgeBefore->format('Y-m-d H:i') + )); + + if ( + !$input->getOption('dry-run') + && (!$input->isInteractive() || $io->confirm(\sprintf( + 'Are you sure you want to delete %d custom-form answer(s) and %d document(s) from “%s” before %s', + $count, + $documentsCount, + $customForm->getName(), + $purgeBefore->format('Y-m-d H:i') + ), false)) + ) { + $this->managerRegistry + ->getRepository(CustomFormAnswer::class) + ->deleteByCustomFormSubmittedBefore($customForm, $purgeBefore); + + foreach ($documents as $document) { + $this->eventDispatcher->dispatch( + new DocumentDeletedEvent($document) + ); + if ($output->isVeryVerbose()) { $io->info(\sprintf( - 'Purge %d custom-form answer(s) with %d documents(s) from “%s” before %s', - $count, - $documentsCount, - $customForm->getName(), - $purgeBefore->format('Y-m-d H:i') + '“%s” document has been deleted', + $document->getRelativePath() )); - - if ( - !$input->getOption('dry-run') && - (!$input->isInteractive() || $io->confirm(\sprintf( - 'Are you sure you want to delete %d custom-form answer(s) and %d document(s) from “%s” before %s', - $count, - $documentsCount, - $customForm->getName(), - $purgeBefore->format('Y-m-d H:i') - ), false)) - ) { - $this->managerRegistry - ->getRepository(CustomFormAnswer::class) - ->deleteByCustomFormSubmittedBefore($customForm, $purgeBefore); - - foreach ($documents as $document) { - $this->eventDispatcher->dispatch( - new DocumentDeletedEvent($document) - ); - if ($output->isVeryVerbose()) { - $io->info(\sprintf( - '“%s” document has been deleted', - $document->getRelativePath() - )); - } - $this->managerRegistry->getManager()->remove($document); - } - $this->managerRegistry->getManager()->flush(); - $this->logger->info(\sprintf( - '%d answer(s) and %d document(s) were deleted from “%s” custom-form before %s', - $count, - $documentsCount, - $customForm->getName(), - $purgeBefore->format('Y-m-d H:i') - )); - } } + $this->managerRegistry->getManager()->remove($document); } + $this->managerRegistry->getManager()->flush(); + $this->logger->info(\sprintf( + '%d answer(s) and %d document(s) were deleted from “%s” custom-form before %s', + $count, + $documentsCount, + $customForm->getName(), + $purgeBefore->format('Y-m-d H:i') + )); } - - return 0; } } diff --git a/src/Console/FilesCommandTrait.php b/src/Console/FilesCommandTrait.php index 15d73514..b745da54 100644 --- a/src/Console/FilesCommandTrait.php +++ b/src/Console/FilesCommandTrait.php @@ -6,25 +6,16 @@ trait FilesCommandTrait { - /** - * @return string - */ protected function getPublicFolderName(): string { return '/exported_public'; } - /** - * @return string - */ protected function getPrivateFolderName(): string { return '/exported_private'; } - /** - * @return string - */ protected function getFontsFolderName(): string { return '/exported_fonts'; diff --git a/src/Console/FilesExportCommand.php b/src/Console/FilesExportCommand.php index adf93e2d..49c4267e 100644 --- a/src/Console/FilesExportCommand.php +++ b/src/Console/FilesExportCommand.php @@ -12,7 +12,6 @@ use Symfony\Component\Finder\Finder; use Symfony\Component\Finder\SplFileInfo; use Symfony\Component\String\Slugger\AsciiSlugger; -use ZipArchive; final class FilesExportCommand extends Command { @@ -22,7 +21,7 @@ public function __construct( private readonly FileAwareInterface $fileAware, private readonly string $exportDir, private readonly string $appNamespace, - ?string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -34,20 +33,11 @@ protected function configure(): void ->setDescription('Export public files, private files and fonts into a single ZIP archive at root dir.'); } - /** - * @param string $appName - * @return string - */ - protected function getArchiveFileName(string $appName = "files_export"): string + protected function getArchiveFileName(string $appName = 'files_export'): string { - return $appName . '_' . date('Y-m-d') . '.zip'; + return $appName.'_'.date('Y-m-d').'.zip'; } - /** - * @param InputInterface $input - * @param OutputInterface $output - * @return int - */ protected function execute(InputInterface $input, OutputInterface $output): int { $fs = new Filesystem(); @@ -57,14 +47,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int $fontFileFolder = $this->fileAware->getFontsFilesPath(); $archiveName = $this->getArchiveFileName((new AsciiSlugger())->slug($this->appNamespace, '_')->toString()); - $archivePath = $this->exportDir . DIRECTORY_SEPARATOR . $archiveName; + $archivePath = $this->exportDir.DIRECTORY_SEPARATOR.$archiveName; if (!$fs->exists($this->exportDir)) { - throw new \RuntimeException($archivePath . ': directory does not exist or is not writable'); + throw new \RuntimeException($archivePath.': directory does not exist or is not writable'); } - $zip = new ZipArchive(); - $zip->open($archivePath, ZipArchive::CREATE | ZipArchive::OVERWRITE); + $zip = new \ZipArchive(); + $zip->open($archivePath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE); if ($fs->exists($publicFileFolder)) { $this->zipFolder($zip, $publicFileFolder, $this->getPublicFolderName()); @@ -78,16 +68,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int // Zip archive will be created only after closing object $zip->close(); + return 0; } - - /** - * @param ZipArchive $zip - * @param string $folder - * @param string $prefix - */ - protected function zipFolder(ZipArchive $zip, string $folder, string $prefix = "/public"): void + protected function zipFolder(\ZipArchive $zip, string $folder, string $prefix = '/public'): void { $finder = new Finder(); $files = $finder->files() @@ -100,14 +85,15 @@ protected function zipFolder(ZipArchive $zip, string $folder, string $prefix = " */ foreach ($files as $file) { // Skip directories (they would be added automatically) - if (!$file->isDir()) { - // Get real and relative path for current file - $filePath = $file->getRealPath(); - $relativePath = \mb_substr($filePath, \mb_strlen($folder) + 1); - - // Add current file to archive - $zip->addFile($filePath, $prefix . '/' . $relativePath); + if ($file->isDir()) { + continue; } + // Get real and relative path for current file + $filePath = $file->getRealPath(); + $relativePath = \mb_substr($filePath, \mb_strlen($folder) + 1); + + // Add current file to archive + $zip->addFile($filePath, $prefix.'/'.$relativePath); } } } diff --git a/src/Console/FilesImportCommand.php b/src/Console/FilesImportCommand.php index 4b910575..67783b6e 100644 --- a/src/Console/FilesImportCommand.php +++ b/src/Console/FilesImportCommand.php @@ -13,7 +13,6 @@ use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\String\Slugger\AsciiSlugger; -use ZipArchive; final class FilesImportCommand extends Command { @@ -22,7 +21,7 @@ final class FilesImportCommand extends Command public function __construct( private readonly FileAwareInterface $fileAware, private readonly string $appNamespace, - ?string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -37,11 +36,6 @@ protected function configure(): void ]); } - /** - * @param InputInterface $input - * @param OutputInterface $output - * @return int - */ protected function execute(InputInterface $input, OutputInterface $output): int { $io = new SymfonyStyle($input, $output); @@ -52,7 +46,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int ); $appNamespace = (new AsciiSlugger())->slug($this->appNamespace, '_'); - $tempDir = tempnam(sys_get_temp_dir(), $appNamespace . '_files'); + $tempDir = tempnam(sys_get_temp_dir(), $appNamespace.'_files'); if (false === $tempDir) { throw new \RuntimeException('Cannot create temporary directory.'); } @@ -62,35 +56,35 @@ protected function execute(InputInterface $input, OutputInterface $output): int mkdir($tempDir); $zipArchivePath = $input->getArgument('input'); - $zip = new ZipArchive(); - if (true === $zip->open($zipArchivePath)) { - if ( - $io->askQuestion( - $confirmation - ) - ) { - $zip->extractTo($tempDir); - - $fs = new Filesystem(); - if ($fs->exists($tempDir . $this->getPublicFolderName())) { - $fs->mirror($tempDir . $this->getPublicFolderName(), $this->fileAware->getPublicFilesPath()); - $io->success('Public files have been imported.'); - } - if ($fs->exists($tempDir . $this->getPrivateFolderName())) { - $fs->mirror($tempDir . $this->getPrivateFolderName(), $this->fileAware->getPrivateFilesPath()); - $io->success('Private files have been imported.'); - } - if ($fs->exists($tempDir . $this->getFontsFolderName())) { - $fs->mirror($tempDir . $this->getFontsFolderName(), $this->fileAware->getFontsFilesPath()); - $io->success('Font files have been imported.'); - } - - $fs->remove($tempDir); - } - return 0; - } else { + $zip = new \ZipArchive(); + if (true !== $zip->open($zipArchivePath)) { $io->error('Zip archive does not exist or is invalid.'); + return 1; } + + if (!$io->askQuestion($confirmation)) { + return 0; + } + + $zip->extractTo($tempDir); + + $fs = new Filesystem(); + if ($fs->exists($tempDir.$this->getPublicFolderName())) { + $fs->mirror($tempDir.$this->getPublicFolderName(), $this->fileAware->getPublicFilesPath()); + $io->success('Public files have been imported.'); + } + if ($fs->exists($tempDir.$this->getPrivateFolderName())) { + $fs->mirror($tempDir.$this->getPrivateFolderName(), $this->fileAware->getPrivateFilesPath()); + $io->success('Private files have been imported.'); + } + if ($fs->exists($tempDir.$this->getFontsFolderName())) { + $fs->mirror($tempDir.$this->getFontsFolderName(), $this->fileAware->getFontsFilesPath()); + $io->success('Font files have been imported.'); + } + + $fs->remove($tempDir); + + return 0; } } diff --git a/src/Console/GenerateApiResourceCommand.php b/src/Console/GenerateApiResourceCommand.php index 87ae30e3..d1b68475 100644 --- a/src/Console/GenerateApiResourceCommand.php +++ b/src/Console/GenerateApiResourceCommand.php @@ -17,7 +17,7 @@ final class GenerateApiResourceCommand extends Command public function __construct( private readonly ManagerRegistry $managerRegistry, private readonly ApiResourceGenerator $apiResourceGenerator, - ?string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -38,17 +38,19 @@ protected function execute(InputInterface $input, OutputInterface $output): int ->getRepository(NodeType::class) ->findAll(); - if (count($nodeTypes) > 0) { - foreach ($nodeTypes as $nt) { - $resourcePath = $this->apiResourceGenerator->generate($nt); - if (null !== $resourcePath) { - $io->writeln("* API resource " . $resourcePath . " has been generated."); - } - } - return 0; - } else { + if (0 === count($nodeTypes)) { $io->error('No available node-types…'); + return 1; } + + foreach ($nodeTypes as $nt) { + $resourcePath = $this->apiResourceGenerator->generate($nt); + if (null !== $resourcePath) { + $io->writeln('* API resource '.$resourcePath.' has been generated.'); + } + } + + return 0; } } diff --git a/src/Console/GenerateNodeSourceEntitiesCommand.php b/src/Console/GenerateNodeSourceEntitiesCommand.php index 04c3b8dc..22192299 100644 --- a/src/Console/GenerateNodeSourceEntitiesCommand.php +++ b/src/Console/GenerateNodeSourceEntitiesCommand.php @@ -20,7 +20,7 @@ final class GenerateNodeSourceEntitiesCommand extends Command public function __construct( private readonly ManagerRegistry $managerRegistry, private readonly HandlerFactory $handlerFactory, - ?string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -39,27 +39,29 @@ protected function execute(InputInterface $input, OutputInterface $output): int { $io = new SymfonyStyle($input, $output); - $nodetypes = $this->managerRegistry + $nodeTypes = $this->managerRegistry ->getRepository(NodeType::class) ->findAll(); - if (count($nodetypes) > 0) { - /** @var NodeType $nt */ - foreach ($nodetypes as $nt) { - /** @var NodeTypeHandler $handler */ - $handler = $this->handlerFactory->getHandler($nt); - $handler->removeSourceEntityClass(); - $handler->generateSourceEntityClass(); - $io->writeln("* Source class " . $nt->getSourceEntityClassName() . " has been generated."); - - if ($output->isVeryVerbose()) { - $io->writeln("\t" . $handler->getSourceClassPath() . ""); - } - } - return 0; - } else { + if (0 === count($nodeTypes)) { $io->error('No available node-types…'); + return 1; } + + /** @var NodeType $nt */ + foreach ($nodeTypes as $nt) { + /** @var NodeTypeHandler $handler */ + $handler = $this->handlerFactory->getHandler($nt); + $handler->removeSourceEntityClass(); + $handler->generateSourceEntityClass(); + $io->writeln('* Source class '.$nt->getSourceEntityClassName().' has been generated.'); + + if ($output->isVeryVerbose()) { + $io->writeln("\t".$handler->getSourceClassPath().''); + } + } + + return 0; } } diff --git a/src/Console/GetCronLastExecDateCommand.php b/src/Console/GetCronLastExecDateCommand.php index e090c16d..9cc65f30 100644 --- a/src/Console/GetCronLastExecDateCommand.php +++ b/src/Console/GetCronLastExecDateCommand.php @@ -1,5 +1,7 @@ settingRepository->findOneByName('cron_last_exec_date'); if (!($setting instanceof Setting)) { $io->warning('Last execution date of cron job has not been persisted yet.'); + return Command::FAILURE; } diff --git a/src/Console/InstallCommand.php b/src/Console/InstallCommand.php index 913de1ca..a79e84ce 100644 --- a/src/Console/InstallCommand.php +++ b/src/Console/InstallCommand.php @@ -4,8 +4,6 @@ namespace RZ\Roadiz\CoreBundle\Console; -use Doctrine\Common\Cache\CacheProvider; -use Doctrine\ORM\EntityManagerInterface; use Doctrine\Persistence\ManagerRegistry; use RZ\Roadiz\CoreBundle\Entity\Translation; use RZ\Roadiz\CoreBundle\Importer\GroupsImporter; @@ -16,86 +14,106 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\Yaml\Yaml; final class InstallCommand extends Command { + use RunningCommandsTrait; + public function __construct( private readonly ManagerRegistry $managerRegistry, private readonly RolesImporter $rolesImporter, private readonly GroupsImporter $groupsImporter, private readonly SettingsImporter $settingsImporter, - ?string $name = null + #[Autowire('%kernel.project_dir%')] + private readonly string $projectDir, + ?string $name = null, ) { parent::__construct($name); } + public function getProjectDir(): string + { + return $this->projectDir; + } + protected function configure(): void { $this ->setName('install') - ->setDescription('Install Roadiz roles, settings, translations and default backend theme'); + ->setDescription('Perform Doctrine migrations, install default Roadiz roles, settings and translation.'); } protected function execute(InputInterface $input, OutputInterface $output): int { $io = new SymfonyStyle($input, $output); - $io->note('Before installing Roadiz, did you create database schema? ' . PHP_EOL . - 'If not execute: bin/console doctrine:migrations:migrate'); $question = new ConfirmationQuestion( 'Are you sure to perform installation?', false ); if ( - $input->getOption('no-interaction') || - $io->askQuestion($question) + $input->getOption('no-interaction') + || $io->askQuestion($question) ) { - $fixturesRoot = dirname(__DIR__) . '/../config'; - $fixtureFile = file_get_contents($fixturesRoot . "/fixtures.yaml"); + 0 === $this->runCommand( + 'doctrine:migrations:migrate', + '', + null, + false, + true + ) ? $io->success('doctrine:migrations:migrate') : $io->error('doctrine:migrations:migrate'); + + $fixturesRoot = dirname(__DIR__).'/../config'; + $fixtureFile = file_get_contents($fixturesRoot.'/fixtures.yaml'); if (false === $fixtureFile) { - $io->error('No fixtures.yaml file found in ' . $fixturesRoot); + $io->error('No fixtures.yaml file found in '.$fixturesRoot); + return 1; } $data = Yaml::parse($fixtureFile); - if (isset($data["importFiles"]['roles'])) { - foreach ($data["importFiles"]['roles'] as $filename) { - $filePath = $fixturesRoot . "/" . $filename; + if (isset($data['importFiles']['roles'])) { + foreach ($data['importFiles']['roles'] as $filename) { + $filePath = $fixturesRoot.'/'.$filename; $fileContents = file_get_contents($filePath); if (false === $fileContents) { - $io->error('No file found in ' . $filePath); + $io->error('No file found in '.$filePath); + return 1; } $this->rolesImporter->import($fileContents); - $io->success('Theme file “' . $filePath . '” has been imported.'); + $io->success('Theme file “'.$filePath.'” has been imported.'); } } - if (isset($data["importFiles"]['groups'])) { - foreach ($data["importFiles"]['groups'] as $filename) { - $filePath = $fixturesRoot . "/" . $filename; + if (isset($data['importFiles']['groups'])) { + foreach ($data['importFiles']['groups'] as $filename) { + $filePath = $fixturesRoot.'/'.$filename; $fileContents = file_get_contents($filePath); if (false === $fileContents) { - $io->error('No file found in ' . $filePath); + $io->error('No file found in '.$filePath); + return 1; } $this->groupsImporter->import($fileContents); - $io->success('Theme file “' . $filePath . '” has been imported.'); + $io->success('Theme file “'.$filePath.'” has been imported.'); } } - if (isset($data["importFiles"]['settings'])) { - foreach ($data["importFiles"]['settings'] as $filename) { - $filePath = $fixturesRoot . "/" . $filename; + if (isset($data['importFiles']['settings'])) { + foreach ($data['importFiles']['settings'] as $filename) { + $filePath = $fixturesRoot.'/'.$filename; $fileContents = file_get_contents($filePath); if (false === $fileContents) { - $io->error('No file found in ' . $filePath); + $io->error('No file found in '.$filePath); + return 1; } $this->settingsImporter->import($fileContents); - $io->success('Theme files “' . $filePath . '” has been imported.'); + $io->success('Theme files “'.$filePath.'” has been imported.'); } } $manager = $this->managerRegistry->getManagerForClass(Translation::class); @@ -106,8 +124,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int $defaultTrans = new Translation(); $defaultTrans ->setDefaultTranslation(true) - ->setLocale("en") - ->setName("Default translation"); + ->setLocale('en') + ->setName('Default translation'); $manager->persist($defaultTrans); @@ -117,25 +135,17 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $manager->flush(); - if ($manager instanceof EntityManagerInterface) { - // Clear result cache - $cacheDriver = $manager->getConfiguration()->getResultCacheImpl(); - if ($cacheDriver instanceof CacheProvider) { - $cacheDriver->deleteAll(); - } - } + $this->clearCaches($io); } + return 0; } /** * Tell if there is any translation. - * - * @return boolean */ public function hasDefaultTranslation(): bool { - $default = $this->managerRegistry->getRepository(Translation::class)->findOneBy([]); - return $default !== null; + return null !== $this->managerRegistry->getRepository(Translation::class)->findDefault(); } } diff --git a/src/Console/LogsCleanupCommand.php b/src/Console/LogsCleanupCommand.php index 56fd662a..66517c82 100644 --- a/src/Console/LogsCleanupCommand.php +++ b/src/Console/LogsCleanupCommand.php @@ -19,7 +19,7 @@ final class LogsCleanupCommand extends Command { public function __construct( private readonly ManagerRegistry $managerRegistry, - ?string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -34,15 +34,12 @@ protected function configure(): void ; } - /** - * @inheritDoc - */ protected function execute(InputInterface $input, OutputInterface $output): int { $now = new \DateTime('now'); $since = '-3 months'; if (\is_string($input->getOption('since'))) { - $since = '-' . $input->getOption('since'); + $since = '-'.$input->getOption('since'); } $interval = \DateInterval::createFromDateString($since); if (false === $interval) { @@ -65,7 +62,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $logs = 0; } - $io->note($logs . ' log entries found before ' . $now->format('Y-m-d H:i:s') . '.'); + $io->note($logs.' log entries found before '.$now->format('Y-m-d H:i:s').'.'); if ($input->getOption('erase') && $logs > 0) { $qb2 = $logRepository->createQueryBuilder('l'); @@ -75,11 +72,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int ; try { $numDeleted = $qb2->getQuery()->execute(); - $io->success($numDeleted . ' log entries were deleted.'); + $io->success($numDeleted.' log entries were deleted.'); } catch (NoResultException $e) { $io->writeln('No log entries were deleted.'); } } + return 0; } } diff --git a/src/Console/MailerTestCommand.php b/src/Console/MailerTestCommand.php index 5a5d4eec..0269ee96 100644 --- a/src/Console/MailerTestCommand.php +++ b/src/Console/MailerTestCommand.php @@ -17,7 +17,7 @@ final class MailerTestCommand extends Command { public function __construct( private readonly EmailManagerFactory $emailManagerFactory, - ?string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -46,11 +46,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int ->setEmailTemplate('@RoadizCore/email/base_email.html.twig') ->setAssignation([ 'title' => $title, - 'content' => 'This is a test email send to *' . $to->getAddress() . '* from `mailer:send:test` CLI command.', - 'mailContact' => $from->getAddress() + 'content' => 'This is a test email send to *'.$to->getAddress().'* from `mailer:send:test` CLI command.', + 'mailContact' => $from->getAddress(), ]) ->send(); (new SymfonyStyle($input, $output))->success('Email sent.'); + return 0; } } diff --git a/src/Console/NodeApplyUniversalFieldsCommand.php b/src/Console/NodeApplyUniversalFieldsCommand.php index 942e2541..645fb4d3 100644 --- a/src/Console/NodeApplyUniversalFieldsCommand.php +++ b/src/Console/NodeApplyUniversalFieldsCommand.php @@ -20,7 +20,7 @@ final class NodeApplyUniversalFieldsCommand extends Command public function __construct( private readonly ManagerRegistry $managerRegistry, private readonly UniversalDataDuplicator $universalDataDuplicator, - ?string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -39,7 +39,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $manager = $this->managerRegistry->getManagerForClass(NodesSources::class); if (null === $manager) { - throw new \RuntimeException('No manager found for ' . NodesSources::class); + throw new \RuntimeException('No manager found for '.NodesSources::class); } $qb = $manager->createQueryBuilder(); @@ -54,7 +54,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int ->setParameter(':translation', $translation); try { $sources = $qb->getQuery()->getResult(); - $io->note(count($sources) . ' node(s) with universal fields were found.'); + $io->note(count($sources).' node(s) with universal fields were found.'); $question = new ConfirmationQuestion( 'Are you sure to force every universal fields?', @@ -78,6 +78,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } catch (NoResultException $e) { $io->warning('No node with universal fields were found.'); } + return 0; } } diff --git a/src/Console/NodeClearTagCommand.php b/src/Console/NodeClearTagCommand.php index e7e775f7..9a0db025 100644 --- a/src/Console/NodeClearTagCommand.php +++ b/src/Console/NodeClearTagCommand.php @@ -19,7 +19,7 @@ final class NodeClearTagCommand extends Command { public function __construct( private readonly ManagerRegistry $managerRegistry, - ?string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -35,6 +35,7 @@ protected function configure(): void protected function getNodeQueryBuilder(Tag $tag): QueryBuilder { $qb = $this->managerRegistry->getRepository(Node::class)->createQueryBuilder('n'); + return $qb->innerJoin('n.nodesTags', 'ntg') ->andWhere($qb->expr()->eq('ntg.tag', ':tagId')) ->setParameter(':tagId', $tag); @@ -51,7 +52,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } /** @var Tag|null $tag */ $tag = $em->find(Tag::class, $tagId); - if ($tag === null) { + if (null === $tag) { throw new \InvalidArgumentException(sprintf('Tag #%d does not exist.', $tagId)); } @@ -65,6 +66,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($count <= 0) { $io->warning('No nodes were found linked with this tag.'); + return 0; } diff --git a/src/Console/NodeTypesAddFieldCommand.php b/src/Console/NodeTypesAddFieldCommand.php index e8651e30..f5643271 100644 --- a/src/Console/NodeTypesAddFieldCommand.php +++ b/src/Console/NodeTypesAddFieldCommand.php @@ -38,23 +38,25 @@ protected function execute(InputInterface $input, OutputInterface $output): int ->getRepository(NodeType::class) ->findOneBy(['name' => $name]); - if ($nodeType !== null) { - $latestPosition = $this->managerRegistry - ->getRepository(NodeTypeField::class) - ->findLatestPositionInNodeType($nodeType); - $this->addNodeTypeField($nodeType, $latestPosition + 1, $io); - $this->managerRegistry->getManagerForClass(NodeTypeField::class)->flush(); - - /** @var NodeTypeHandler $handler */ - $handler = $this->handlerFactory->getHandler($nodeType); - $handler->regenerateEntityClass(); - $this->schemaUpdater->updateNodeTypesSchema(); - - $io->success('Node type ' . $nodeType->getName() . ' has been updated.'); - return 0; - } else { - $io->error('Node-type "' . $name . '" does not exist.'); + if (null === $nodeType) { + $io->error('Node-type "'.$name.'" does not exist.'); + return 1; } + + $latestPosition = $this->managerRegistry + ->getRepository(NodeTypeField::class) + ->findLatestPositionInNodeType($nodeType); + $this->addNodeTypeField($nodeType, $latestPosition + 1, $io); + $this->managerRegistry->getManagerForClass(NodeTypeField::class)->flush(); + + /** @var NodeTypeHandler $handler */ + $handler = $this->handlerFactory->getHandler($nodeType); + $handler->regenerateEntityClass(); + $this->schemaUpdater->updateNodeTypesSchema(); + + $io->success('Node type '.$nodeType->getName().' has been updated.'); + + return 0; } } diff --git a/src/Console/NodeTypesCommand.php b/src/Console/NodeTypesCommand.php index 262bcaa6..b5275ab5 100644 --- a/src/Console/NodeTypesCommand.php +++ b/src/Console/NodeTypesCommand.php @@ -17,7 +17,7 @@ final class NodeTypesCommand extends Command { public function __construct( private readonly ManagerRegistry $managerRegistry, - ?string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -43,51 +43,52 @@ protected function execute(InputInterface $input, OutputInterface $output): int ->getRepository(NodeType::class) ->findOneByName($name); - if ($nodetype !== null) { - /** @var array $fields */ - $fields = $this->managerRegistry->getRepository(NodeTypeField::class) - ->findBy([ - 'nodeType' => $nodetype, - ], ['position' => 'ASC']); + if (null === $nodetype) { + $io->note($name.' node type does not exist.'); - $tableContent = []; - foreach ($fields as $field) { - $tableContent[] = [ - $field->getId(), - $field->getLabel(), - $field->getName(), - str_replace('.type', '', $field->getTypeName()), - ($field->isVisible() ? 'X' : ''), - ($field->isIndexed() ? 'X' : ''), - ]; - } - $io->table(['Id', 'Label', 'Name', 'Type', 'Visible', 'Index'], $tableContent); - } else { - $io->note($name . ' node type does not exist.'); return 0; } + /** @var array $fields */ + $fields = $this->managerRegistry->getRepository(NodeTypeField::class) + ->findBy([ + 'nodeType' => $nodetype, + ], ['position' => 'ASC']); + + $tableContent = []; + foreach ($fields as $field) { + $tableContent[] = [ + $field->getId(), + $field->getLabel(), + $field->getName(), + str_replace('.type', '', $field->getTypeName()), + $field->isVisible() ? 'X' : '', + $field->isIndexed() ? 'X' : '', + ]; + } + $io->table(['Id', 'Label', 'Name', 'Type', 'Visible', 'Index'], $tableContent); } else { /** @var array $nodetypes */ $nodetypes = $this->managerRegistry ->getRepository(NodeType::class) ->findBy([], ['name' => 'ASC']); - if (count($nodetypes) > 0) { - $tableContent = []; + if (0 === count($nodetypes)) { + $io->note('No available node-types…'); + } - foreach ($nodetypes as $nt) { - $tableContent[] = [ - $nt->getId(), - $nt->getName(), - ($nt->isVisible() ? 'X' : ''), - ]; - } + $tableContent = []; - $io->table(['Id', 'Title', 'Visible'], $tableContent); - } else { - $io->note('No available node-types…'); + foreach ($nodetypes as $nt) { + $tableContent[] = [ + $nt->getId(), + $nt->getName(), + $nt->isVisible() ? 'X' : '', + ]; } + + $io->table(['Id', 'Title', 'Visible'], $tableContent); } + return 0; } } diff --git a/src/Console/NodeTypesCreationCommand.php b/src/Console/NodeTypesCreationCommand.php index 25788fec..af1577ef 100644 --- a/src/Console/NodeTypesCreationCommand.php +++ b/src/Console/NodeTypesCreationCommand.php @@ -27,7 +27,7 @@ public function __construct( protected readonly ManagerRegistry $managerRegistry, protected readonly HandlerFactory $handlerFactory, protected readonly SchemaUpdater $schemaUpdater, - ?string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -57,12 +57,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int ->getRepository(NodeType::class) ->findOneBy(['name' => $name]); - if ($nodeType !== null) { - $io->error('Node-type "' . $name . '" already exists.'); + if (null !== $nodeType) { + $io->error('Node-type "'.$name.'" already exists.'); + return 1; } else { $this->executeCreation($input, $output); } + return 0; } @@ -73,7 +75,7 @@ private function executeCreation(InputInterface $input, OutputInterface $output) $nt = new NodeType(); $nt->setName($name); - $io->note('OK! Let’s create that "' . $nt->getName() . '" node-type together!'); + $io->note('OK! Let’s create that "'.$nt->getName().'" node-type together!'); $question0 = new Question('Enter your node-type display name', ucwords($name)); $displayName = $io->askQuestion($question0); @@ -94,7 +96,7 @@ private function executeCreation(InputInterface $input, OutputInterface $output) $handler->regenerateEntityClass(); $this->schemaUpdater->updateNodeTypesSchema(); - $io->success('Node type ' . $nt->getName() . ' has been created.'); + $io->success('Node type '.$nt->getName().' has been created.'); } protected function addNodeTypeField(NodeType $nodeType, int|float|string $position, SymfonyStyle $io): void @@ -103,15 +105,15 @@ protected function addNodeTypeField(NodeType $nodeType, int|float|string $positi $position = floatval($position); $field->setPosition($position); - $questionfName = new Question('[Field ' . $position . '] Enter field name', 'content'); + $questionfName = new Question('[Field '.$position.'] Enter field name', 'content'); $fName = $io->askQuestion($questionfName); $field->setName($fName); - $questionfLabel = new Question('[Field ' . $position . '] Enter field label', 'Your content'); + $questionfLabel = new Question('[Field '.$position.'] Enter field label', 'Your content'); $fLabel = $io->askQuestion($questionfLabel); $field->setLabel($fLabel); - $questionfType = new Question('[Field ' . $position . '] Enter field type', 'STRING_T'); + $questionfType = new Question('[Field '.$position.'] Enter field type', 'STRING_T'); $questionfType->setAutocompleterValues([ 'STRING_T', 'DATETIME_T', @@ -136,10 +138,10 @@ protected function addNodeTypeField(NodeType $nodeType, int|float|string $positi ]); $fType = $io->askQuestion($questionfType); - $fType = constant(NodeTypeField::class . '::' . $fType); + $fType = constant(NodeTypeField::class.'::'.$fType); $field->setType($fType); - $questionIndexed = new ConfirmationQuestion('[Field ' . $position . '] Must this field be indexed?', false); + $questionIndexed = new ConfirmationQuestion('[Field '.$position.'] Must this field be indexed?', false); if ($io->askQuestion($questionIndexed)) { $field->setIndexed(true); } diff --git a/src/Console/NodeTypesDefaultValuesCommand.php b/src/Console/NodeTypesDefaultValuesCommand.php index 2c4c3ec7..5fdc67d1 100644 --- a/src/Console/NodeTypesDefaultValuesCommand.php +++ b/src/Console/NodeTypesDefaultValuesCommand.php @@ -19,7 +19,7 @@ final class NodeTypesDefaultValuesCommand extends Command public function __construct( private readonly DefaultValuesResolverInterface $defaultValuesResolver, private readonly ManagerRegistry $managerRegistry, - string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -57,7 +57,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int throw new \InvalidArgumentException('Field name must be a valid field name.'); } if (!$oneField->isEnum()) { - throw new \InvalidArgumentException('Field name must be an enum field. Valid fields names are: ' . implode(', ', $enumFieldsNames)); + throw new \InvalidArgumentException('Field name must be an enum field. Valid fields names are: '.implode(', ', $enumFieldsNames)); } $defaultValues = $this->defaultValuesResolver->getDefaultValuesAmongAllFields($oneField); @@ -70,9 +70,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int $oneField->getLabel(), $oneField->getDescription(), implode(', ', array_unique($defaultValues)), - $maxDefaultValuesLength + $maxDefaultValuesLength, ], ]); + return 0; } } diff --git a/src/Console/NodeTypesDeleteCommand.php b/src/Console/NodeTypesDeleteCommand.php index 6e9d47c0..f312ecc0 100644 --- a/src/Console/NodeTypesDeleteCommand.php +++ b/src/Console/NodeTypesDeleteCommand.php @@ -25,7 +25,7 @@ public function __construct( private readonly ManagerRegistry $managerRegistry, private readonly HandlerFactory $handlerFactory, private readonly SchemaUpdater $schemaUpdater, - ?string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -55,33 +55,35 @@ protected function execute(InputInterface $input, OutputInterface $output): int ->getRepository(NodeType::class) ->findOneByName($name); - if ($nodeType !== null) { - $io->note('///////////////////////////////' . PHP_EOL . - '/////////// WARNING ///////////' . PHP_EOL . - '///////////////////////////////' . PHP_EOL . - 'This operation cannot be undone.' . PHP_EOL . - 'Deleting a node-type, you will automatically delete every nodes of this type.'); - $question = new ConfirmationQuestion( - 'Are you sure to delete ' . $nodeType->getName() . ' node-type?', - false - ); - if ( - $io->askQuestion( - $question - ) - ) { - /** @var NodeTypeHandler $handler */ - $handler = $this->handlerFactory->getHandler($nodeType); - $handler->removeSourceEntityClass(); - $this->managerRegistry->getManagerForClass(NodeType::class)->remove($nodeType); - $this->managerRegistry->getManagerForClass(NodeType::class)->flush(); - $this->schemaUpdater->updateNodeTypesSchema(); - $io->success('Node-type deleted.'); - } - } else { - $io->error('"' . $name . '" node type does not exist'); + if (null === $nodeType) { + $io->error('"'.$name.'" node type does not exist'); + return 1; } + + $io->note('///////////////////////////////'.PHP_EOL. + '/////////// WARNING ///////////'.PHP_EOL. + '///////////////////////////////'.PHP_EOL. + 'This operation cannot be undone.'.PHP_EOL. + 'Deleting a node-type, you will automatically delete every nodes of this type.'); + $question = new ConfirmationQuestion( + 'Are you sure to delete '.$nodeType->getName().' node-type?', + false + ); + if ( + $io->askQuestion( + $question + ) + ) { + /** @var NodeTypeHandler $handler */ + $handler = $this->handlerFactory->getHandler($nodeType); + $handler->removeSourceEntityClass(); + $this->managerRegistry->getManagerForClass(NodeType::class)->remove($nodeType); + $this->managerRegistry->getManagerForClass(NodeType::class)->flush(); + $this->schemaUpdater->updateNodeTypesSchema(); + $io->success('Node-type deleted.'); + } + return 0; } } diff --git a/src/Console/NodesCleanNamesCommand.php b/src/Console/NodesCleanNamesCommand.php index 394a55de..4f60243d 100644 --- a/src/Console/NodesCleanNamesCommand.php +++ b/src/Console/NodesCleanNamesCommand.php @@ -20,7 +20,7 @@ final class NodesCleanNamesCommand extends Command public function __construct( private readonly ManagerRegistry $managerRegistry, private readonly NodeNamePolicyInterface $nodeNamePolicy, - ?string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -65,84 +65,83 @@ protected function execute(InputInterface $input, OutputInterface $output): int ]); $io->note( - 'This command will rename EVERY nodes (except for locked and not dynamic ones) names according to their node-source for current default translation.' . PHP_EOL . - count($nodes) . ' nodes might be affected.' + 'This command will rename EVERY nodes (except for locked and not dynamic ones) names according to their node-source for current default translation.'.PHP_EOL. + count($nodes).' nodes might be affected.' ); $question1 = new ConfirmationQuestion('Are you sure to proceed? This could break many page URLs!', false); - if ($io->askQuestion($question1)) { - $io->note('Renaming ' . count($nodes) . ' nodes…'); - $renameCount = 0; - $names = []; - - /** @var Node $node */ - foreach ($nodes as $node) { - $nodeSource = $node->getNodeSources()->first() ?: null; - if ($nodeSource !== null) { - $prefixName = $nodeSource->getTitle() != "" ? - $nodeSource->getTitle() : - $node->getNodeName(); - - $prefixNameSlug = $this->nodeNamePolicy->getCanonicalNodeName($nodeSource); - /* - * Proceed to rename only if best name is not the current - * node-name AND if it is not ALREADY suffixed with a unique ID. - */ + if (!$io->askQuestion($question1)) { + $io->warning('Renaming cancelled…'); + + return 1; + } + + $io->note('Renaming '.count($nodes).' nodes…'); + $renameCount = 0; + $names = []; + + /** @var Node $node */ + foreach ($nodes as $node) { + $nodeSource = $node->getNodeSources()->first() ?: null; + if (null === $nodeSource) { + continue; + } + + $prefixNameSlug = $this->nodeNamePolicy->getCanonicalNodeName($nodeSource); + /* + * Proceed to rename only if best name is not the current + * node-name AND if it is not ALREADY suffixed with a unique ID. + */ + if ( + $prefixNameSlug != $node->getNodeName() + && $this->nodeNamePolicy->isNodeNameValid($prefixNameSlug) + && !$this->nodeNamePolicy->isNodeNameWithUniqId($prefixNameSlug, $nodeSource->getNode()->getNodeName()) + ) { + $alreadyUsed = $this->nodeNamePolicy->isNodeNameAlreadyUsed($prefixNameSlug); + if (!$alreadyUsed) { + $names[] = [ + $node->getNodeName(), + $prefixNameSlug, + ]; + $node->setNodeName($prefixNameSlug); + } else { if ( - $prefixNameSlug != $node->getNodeName() && - $this->nodeNamePolicy->isNodeNameValid($prefixNameSlug) && - !$this->nodeNamePolicy->isNodeNameWithUniqId($prefixNameSlug, $nodeSource->getNode()->getNodeName()) + $input->getOption('use-date') + && null !== $nodeSource->getPublishedAt() ) { - $alreadyUsed = $this->nodeNamePolicy->isNodeNameAlreadyUsed($prefixNameSlug); - if (!$alreadyUsed) { - $names[] = [ - $node->getNodeName(), - $prefixNameSlug - ]; - $node->setNodeName($prefixNameSlug); - } else { - if ( - $input->getOption('use-date') && - null !== $nodeSource->getPublishedAt() - ) { - $suffixedNameSlug = $this->nodeNamePolicy->getDatestampedNodeName($nodeSource); - } else { - $suffixedNameSlug = $this->nodeNamePolicy->getSafeNodeName($nodeSource); - } - if (!$this->nodeNamePolicy->isNodeNameAlreadyUsed($suffixedNameSlug)) { - $names[] = [ - $node->getNodeName(), - $suffixedNameSlug - ]; - $node->setNodeName($suffixedNameSlug); - } else { - $suffixedNameSlug = $this->nodeNamePolicy->getSafeNodeName($nodeSource); - $names[] = [ - $node->getNodeName(), - $suffixedNameSlug - ]; - $node->setNodeName($suffixedNameSlug); - } - } - if (!$input->getOption('dry-run')) { - $entityManager->flush(); - } - $renameCount++; + $suffixedNameSlug = $this->nodeNamePolicy->getDatestampedNodeName($nodeSource); + } else { + $suffixedNameSlug = $this->nodeNamePolicy->getSafeNodeName($nodeSource); + } + if (!$this->nodeNamePolicy->isNodeNameAlreadyUsed($suffixedNameSlug)) { + $names[] = [ + $node->getNodeName(), + $suffixedNameSlug, + ]; + $node->setNodeName($suffixedNameSlug); + } else { + $suffixedNameSlug = $this->nodeNamePolicy->getSafeNodeName($nodeSource); + $names[] = [ + $node->getNodeName(), + $suffixedNameSlug, + ]; + $node->setNodeName($suffixedNameSlug); } } + if (!$input->getOption('dry-run')) { + $entityManager->flush(); + } + ++$renameCount; } + } - $io->table(['Old name', 'New name'], $names); + $io->table(['Old name', 'New name'], $names); - if (!$input->getOption('dry-run')) { - $io->success('Renaming done! ' . $renameCount . ' nodes have been affected. Do not forget to reindex your Solr documents if you are using it.'); - } else { - $io->success($renameCount . ' nodes would have been affected. Nothing was saved to database.'); - } + if (!$input->getOption('dry-run')) { + $io->success('Renaming done! '.$renameCount.' nodes have been affected. Do not forget to reindex your Solr documents if you are using it.'); } else { - $io->warning('Renaming cancelled…'); - return 1; + $io->success($renameCount.' nodes would have been affected. Nothing was saved to database.'); } } diff --git a/src/Console/NodesCommand.php b/src/Console/NodesCommand.php index cd5e56a0..f3210b5e 100644 --- a/src/Console/NodesCommand.php +++ b/src/Console/NodesCommand.php @@ -17,7 +17,7 @@ final class NodesCommand extends Command { public function __construct( private readonly ManagerRegistry $managerRegistry, - ?string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -63,12 +63,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int $node->getId(), $node->getNodeName(), $node->getNodeType()->getName(), - (!$node->isVisible() ? 'X' : ''), - ($node->isPublished() ? 'X' : ''), + !$node->isVisible() ? 'X' : '', + $node->isPublished() ? 'X' : '', ]; } $io->table(['Id', 'Name', 'Type', 'Hidden', 'Published'], $tableContent); + return 0; } } diff --git a/src/Console/NodesDetailsCommand.php b/src/Console/NodesDetailsCommand.php index 53515526..e2dc827a 100644 --- a/src/Console/NodesDetailsCommand.php +++ b/src/Console/NodesDetailsCommand.php @@ -18,7 +18,7 @@ final class NodesDetailsCommand extends Command { public function __construct( private readonly ManagerRegistry $managerRegistry, - ?string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -41,6 +41,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int /** * @var NodesSources|null $source + * * @phpstan-ignore-next-line */ $source = $this->managerRegistry->getRepository(NodesSources::class) @@ -78,8 +79,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } else { $io->error('No node found.'); + return 1; } + return 0; } } diff --git a/src/Console/NodesEmptyTrashCommand.php b/src/Console/NodesEmptyTrashCommand.php index 8e21028b..3084bc0b 100644 --- a/src/Console/NodesEmptyTrashCommand.php +++ b/src/Console/NodesEmptyTrashCommand.php @@ -9,6 +9,7 @@ use RZ\Roadiz\CoreBundle\Entity\Node; use RZ\Roadiz\CoreBundle\EntityHandler\HandlerFactory; use RZ\Roadiz\CoreBundle\EntityHandler\NodeHandler; +use RZ\Roadiz\CoreBundle\Enum\NodeStatus; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -20,7 +21,7 @@ final class NodesEmptyTrashCommand extends Command public function __construct( private readonly ManagerRegistry $managerRegistry, private readonly HandlerFactory $handlerFactory, - ?string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -40,48 +41,55 @@ protected function execute(InputInterface $input, OutputInterface $output): int $em = $this->managerRegistry->getManagerForClass(Node::class); $countQb = $this->createNodeQueryBuilder(); $countQuery = $countQb->select($countQb->expr()->count('n')) - ->andWhere($countQb->expr()->eq('n.status', Node::DELETED)) + ->andWhere($countQb->expr()->eq('n.status', ':status')) + ->setParameter('status', NodeStatus::DELETED) ->getQuery(); $emptiedCount = $countQuery->getSingleScalarResult(); - if ($emptiedCount > 0) { - $confirmation = new ConfirmationQuestion( - sprintf('Are you sure to empty nodes trashcan, %d nodes will be lost forever? [y/N]: ', $emptiedCount), - false - ); - if ($io->askQuestion($confirmation) || !$input->isInteractive()) { - $i = 0; - $batchSize = 100; - $io->progressStart((int) $emptiedCount); - - $qb = $this->createNodeQueryBuilder(); - $q = $qb->select('n') - ->andWhere($countQb->expr()->eq('n.status', Node::DELETED)) - ->getQuery(); - - foreach ($q->toIterable() as $row) { - /** @var NodeHandler $nodeHandler */ - $nodeHandler = $this->handlerFactory->getHandler($row); - $nodeHandler->removeWithChildrenAndAssociations(); - $io->progressAdvance(); - ++$i; - // Call flush time to times - if (($i % $batchSize) === 0) { - $em->flush(); - $em->clear(); - } - } - - /* - * Final flush - */ + if (0 == $emptiedCount) { + $io->success('Nodes trashcan is already empty.'); + + return 0; + } + + $confirmation = new ConfirmationQuestion( + sprintf('Are you sure to empty nodes trashcan, %d nodes will be lost forever? [y/N]: ', $emptiedCount), + false + ); + + if ($input->isInteractive() && !$io->askQuestion($confirmation)) { + return 0; + } + + $i = 0; + $batchSize = 100; + $io->progressStart((int) $emptiedCount); + + $qb = $this->createNodeQueryBuilder(); + $q = $qb->select('n') + ->andWhere($countQb->expr()->eq('n.status', ':status')) + ->setParameter('status', NodeStatus::DELETED) + ->getQuery(); + + foreach ($q->toIterable() as $row) { + /** @var NodeHandler $nodeHandler */ + $nodeHandler = $this->handlerFactory->getHandler($row); + $nodeHandler->removeWithChildrenAndAssociations(); + $io->progressAdvance(); + ++$i; + // Call flush time to times + if (($i % $batchSize) === 0) { $em->flush(); - $io->progressFinish(); - $io->success('Nodes trashcan has been emptied.'); + $em->clear(); } - } else { - $io->success('Nodes trashcan is already empty.'); } + /* + * Final flush + */ + $em->flush(); + $io->progressFinish(); + $io->success('Nodes trashcan has been emptied.'); + return 0; } diff --git a/src/Console/NodesOrphansCommand.php b/src/Console/NodesOrphansCommand.php index e3a68598..bdfb3f41 100644 --- a/src/Console/NodesOrphansCommand.php +++ b/src/Console/NodesOrphansCommand.php @@ -17,7 +17,7 @@ final class NodesOrphansCommand extends Command { public function __construct( private readonly ManagerRegistry $managerRegistry, - ?string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -35,10 +35,6 @@ protected function configure(): void } /** - * @param InputInterface $input - * @param OutputInterface $output - * - * @return int * @throws \Doctrine\ORM\ORMException * @throws \Doctrine\ORM\OptimisticLockException */ @@ -59,37 +55,40 @@ protected function execute(InputInterface $input, OutputInterface $output): int } catch (NoResultException $e) { } - if (count($orphans) > 0) { - $io->note(sprintf('You have %s orphan node(s)!', count($orphans))); - $tableContent = []; + if (0 === count($orphans)) { + $io->success('That’s OK, you don’t have any orphan node.'); - /** @var Node $node */ - foreach ($orphans as $node) { - $tableContent[] = [ - $node->getId(), - $node->getNodeName(), - null !== $node->getNodeType() ? $node->getNodeType()->getName() : '', - (!$node->isVisible() ? 'X' : ''), - ($node->isPublished() ? 'X' : ''), - ]; - } + return 0; + } + + $io->note(sprintf('You have %s orphan node(s)!', count($orphans))); + $tableContent = []; - $io->table(['Id', 'Name', 'Type', 'Hidden', 'Published'], $tableContent); + /** @var Node $node */ + foreach ($orphans as $node) { + $tableContent[] = [ + $node->getId(), + $node->getNodeName(), + null !== $node->getNodeType() ? $node->getNodeType()->getName() : '', + !$node->isVisible() ? 'X' : '', + $node->isPublished() ? 'X' : '', + ]; + } - if ($input->getOption('delete')) { - /** @var Node $orphan */ - foreach ($orphans as $orphan) { - $entityManager->remove($orphan); - } - $entityManager->flush(); + $io->table(['Id', 'Name', 'Type', 'Hidden', 'Published'], $tableContent); - $io->success('Orphan nodes have been removed from your database.'); - } else { - $io->note('Use --delete option to actually remove these nodes.'); + if ($input->getOption('delete')) { + /** @var Node $orphan */ + foreach ($orphans as $orphan) { + $entityManager->remove($orphan); } + $entityManager->flush(); + + $io->success('Orphan nodes have been removed from your database.'); } else { - $io->success('That’s OK, you don’t have any orphan node.'); + $io->note('Use --delete option to actually remove these nodes.'); } + return 0; } } diff --git a/src/Console/RegisterCronLastExecDateCommand.php b/src/Console/RegisterCronLastExecDateCommand.php index 20bed441..8ebf77f1 100644 --- a/src/Console/RegisterCronLastExecDateCommand.php +++ b/src/Console/RegisterCronLastExecDateCommand.php @@ -1,5 +1,7 @@ setWorkingDirectory($this->getProjectDir()); + $process->setTty($interactive); + $process->run(); + + return $process->wait(); + } + + protected function clearCaches(SymfonyStyle $io): void + { + 0 === $this->runCommand( + 'doctrine:cache:clear-metadata', + '', + null, + false, + true + ) ? $io->success('doctrine:cache:clear-metadata') : $io->error('doctrine:cache:clear-metadata'); + + 0 === $this->runCommand( + 'cache:clear', + '', + null, + false, + true + ) ? $io->success('cache:clear') : $io->error('cache:clear'); + + 0 === $this->runCommand( + 'cache:pool:clear', + 'cache.global_clearer', + null, + false, + true + ) ? $io->success('cache:pool:clear') : $io->error('cache:pool:clear'); + } +} diff --git a/src/Console/SolrCommand.php b/src/Console/SolrCommand.php index 32396f2b..0372582e 100644 --- a/src/Console/SolrCommand.php +++ b/src/Console/SolrCommand.php @@ -5,6 +5,7 @@ namespace RZ\Roadiz\CoreBundle\Console; use RZ\Roadiz\CoreBundle\SearchEngine\ClientRegistry; +use Solarium\Core\Client\Client; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -16,7 +17,7 @@ class SolrCommand extends Command public function __construct( protected readonly ClientRegistry $clientRegistry, - ?string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -27,31 +28,47 @@ protected function configure(): void ->setDescription('Check Solr search engine server'); } - protected function execute(InputInterface $input, OutputInterface $output): int + protected function validateSolrState(SymfonyStyle $io): ?Client { $client = $this->clientRegistry->getClient(); - $this->io = new SymfonyStyle($input, $output); - if (null !== $client) { - if (true === $this->clientRegistry->isClientReady($client)) { - $this->io->writeln('Solr search engine server is running…'); - } else { - $this->io->error('Solr search engine server does not respond…'); - $this->io->note('See your config.yml file to correct your Solr connexion settings.'); - return 1; - } - } else { + if (null === $client) { $this->displayBasicConfig(); + + return null; + } + + if (true !== $this->clientRegistry->isClientReady($client)) { + $io->error('Solr search engine server does not respond…'); + $io->note('See your `config/packages/roadiz_core.yaml` file to correct your Solr connection settings.'); + + return null; + } + + return $client; + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $this->io = new SymfonyStyle($input, $output); + if (null === $this->validateSolrState($this->io)) { + return 1; } + + $this->io->success('Solr search engine server is running.'); + return 0; } protected function displayBasicConfig(): void { - if (null !== $this->io) { - $this->io->error('No Solr search engine server has been configured…'); - $this->io->note(<<io) { + return; + } + + $this->io->error('No Solr search engine server has been configured…'); + $this->io->note(<<clientRegistry->getClient(); $this->io = new SymfonyStyle($input, $output); - if (null !== $solr) { - if (true === $this->clientRegistry->isClientReady($solr)) { - $documentIndexer = $this->indexerFactory->getIndexerFor(Document::class); - if ($documentIndexer instanceof CliAwareIndexer) { - $documentIndexer->setIo($this->io); - } - $documentIndexer->optimizeSolr(); - $this->io->success('Solr core has been optimized.'); - } else { - $this->io->error('Solr search engine server does not respond…'); - $this->io->note('See your config.yml file to correct your Solr connexion settings.'); - return 1; - } - } else { - $this->displayBasicConfig(); + if (null === $this->validateSolrState($this->io)) { + return 1; } + + $documentIndexer = $this->indexerFactory->getIndexerFor(Document::class); + if ($documentIndexer instanceof CliAwareIndexer) { + $documentIndexer->setIo($this->io); + } + $documentIndexer->optimizeSolr(); + $this->io->success('Solr core has been optimized.'); + return 0; } } diff --git a/src/Console/SolrReindexCommand.php b/src/Console/SolrReindexCommand.php index 041a22fb..cbfef2a6 100644 --- a/src/Console/SolrReindexCommand.php +++ b/src/Console/SolrReindexCommand.php @@ -23,7 +23,7 @@ class SolrReindexCommand extends SolrCommand implements ThemeAwareCommandInterfa public function __construct( protected readonly IndexerFactoryInterface $indexerFactory, ClientRegistry $clientRegistry, - ?string $name = null + ?string $name = null, ) { parent::__construct($clientRegistry, $name); } @@ -40,38 +40,32 @@ protected function configure(): void protected function execute(InputInterface $input, OutputInterface $output): int { - $solr = $this->clientRegistry->getClient(); $this->io = new SymfonyStyle($input, $output); - if (null !== $solr) { - if (true === $this->clientRegistry->isClientReady($solr)) { - if ( - $this->io->confirm( - 'Are you sure to reindex your Node and Document database?', - !$input->isInteractive() - ) - ) { - $stopwatch = new Stopwatch(); - $stopwatch->start('global'); - - if ($input->getOption('documents')) { - $this->executeForDocuments($stopwatch); - } elseif ($input->getOption('nodes')) { - $batchCount = (int) ($input->getOption('batch-count') ?? 1); - $batchNumber = (int) ($input->getOption('batch-number') ?? 0); - $this->executeForNodes($stopwatch, $batchCount, $batchNumber); - } else { - $this->executeForAll($stopwatch); - } - } + if (null === $this->validateSolrState($this->io)) { + return 1; + } + + if ( + $this->io->confirm( + 'Are you sure to reindex your Node and Document database?', + !$input->isInteractive() + ) + ) { + $stopwatch = new Stopwatch(); + $stopwatch->start('global'); + + if ($input->getOption('documents')) { + $this->executeForDocuments($stopwatch); + } elseif ($input->getOption('nodes')) { + $batchCount = (int) ($input->getOption('batch-count') ?? 1); + $batchNumber = (int) ($input->getOption('batch-number') ?? 0); + $this->executeForNodes($stopwatch, $batchCount, $batchNumber); } else { - $this->io->error('Solr search engine server does not respond…'); - $this->io->note('See your config.yml file to correct your Solr connexion settings.'); - return 1; + $this->executeForAll($stopwatch); } - } else { - $this->displayBasicConfig(); } + return 0; } @@ -116,7 +110,7 @@ protected function executeForNodes(Stopwatch $stopwatch, int $batchCount, int $b $nodesSourcesIndexer->setIo($this->io); } // Empty first ONLY if one batch or first batch. - if ($batchNumber === 0) { + if (0 === $batchNumber) { $nodesSourcesIndexer->emptySolr(SolariumNodeSource::DOCUMENT_TYPE); } diff --git a/src/Console/SolrResetCommand.php b/src/Console/SolrResetCommand.php index ac48d1f3..2789e2bc 100644 --- a/src/Console/SolrResetCommand.php +++ b/src/Console/SolrResetCommand.php @@ -18,7 +18,7 @@ final class SolrResetCommand extends SolrCommand public function __construct( private readonly IndexerFactoryInterface $indexerFactory, ClientRegistry $clientRegistry, - ?string $name = null + ?string $name = null, ) { parent::__construct($clientRegistry, $name); } @@ -31,31 +31,24 @@ protected function configure(): void protected function execute(InputInterface $input, OutputInterface $output): int { - $solr = $this->clientRegistry->getClient(); $this->io = new SymfonyStyle($input, $output); - if (null !== $solr) { - if (true === $this->clientRegistry->isClientReady($solr)) { - $confirmation = new ConfirmationQuestion( - 'Are you sure to reset Solr index?', - false - ); - if ($this->io->askQuestion($confirmation)) { - $indexer = $this->indexerFactory->getIndexerFor(NodesSources::class); - if ($indexer instanceof CliAwareIndexer) { - $indexer->setIo($this->io); - } - $indexer->emptySolr(); - $this->io->success('Solr index resetted.'); - } - } else { - $this->io->error('Solr search engine server does not respond…'); - $this->io->note('See your config.yml file to correct your Solr connexion settings.'); - return 1; + if (null === $this->validateSolrState($this->io)) { + return 1; + } + $confirmation = new ConfirmationQuestion( + 'Are you sure to reset Solr index?', + false + ); + if ($this->io->askQuestion($confirmation)) { + $indexer = $this->indexerFactory->getIndexerFor(NodesSources::class); + if ($indexer instanceof CliAwareIndexer) { + $indexer->setIo($this->io); } - } else { - $this->displayBasicConfig(); + $indexer->emptySolr(); + $this->io->success('Solr index resetted.'); } + return 0; } } diff --git a/src/Console/TranslationsCommand.php b/src/Console/TranslationsCommand.php index e3781525..61fd990e 100644 --- a/src/Console/TranslationsCommand.php +++ b/src/Console/TranslationsCommand.php @@ -15,7 +15,7 @@ class TranslationsCommand extends Command { public function __construct( protected readonly ManagerRegistry $managerRegistry, - ?string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -33,22 +33,25 @@ protected function execute(InputInterface $input, OutputInterface $output): int ->getRepository(Translation::class) ->findAll(); - if (count($translations) > 0) { - $tableContent = []; - /** @var Translation $trans */ - foreach ($translations as $trans) { - $tableContent[] = [ - $trans->getId(), - $trans->getName(), - $trans->getLocale(), - (!$trans->isAvailable() ? 'X' : ''), - ($trans->isDefaultTranslation() ? 'X' : ''), - ]; - } - $io->table(['Id', 'Name', 'Locale', 'Disabled', 'Default'], $tableContent); - } else { + if (0 === count($translations)) { $io->error('No available translations.'); + + return 1; + } + + $tableContent = []; + /** @var Translation $trans */ + foreach ($translations as $trans) { + $tableContent[] = [ + $trans->getId(), + $trans->getName(), + $trans->getLocale(), + !$trans->isAvailable() ? 'X' : '', + $trans->isDefaultTranslation() ? 'X' : '', + ]; } + $io->table(['Id', 'Name', 'Locale', 'Disabled', 'Default'], $tableContent); + return 0; } } diff --git a/src/Console/TranslationsCreationCommand.php b/src/Console/TranslationsCreationCommand.php index 9d0f8b90..52f5b679 100644 --- a/src/Console/TranslationsCreationCommand.php +++ b/src/Console/TranslationsCreationCommand.php @@ -12,7 +12,7 @@ use Symfony\Component\Console\Style\SymfonyStyle; /** - * Command line utils for managing translations + * Command line utils for managing translations. */ final class TranslationsCreationCommand extends TranslationsCommand { @@ -38,42 +38,47 @@ protected function execute(InputInterface $input, OutputInterface $output): int $name = $input->getArgument('name'); $locale = $input->getArgument('locale'); - if ($name) { - $translationByName = $this->managerRegistry - ->getRepository(Translation::class) - ->findOneByName($name); - $translationByLocale = $this->managerRegistry - ->getRepository(Translation::class) - ->findOneByLocale($locale); + if (!$name) { + return 1; + } - $confirmation = new ConfirmationQuestion( - 'Are you sure to create ' . $name . ' (' . $locale . ') translation?', - false - ); + $translationByName = $this->managerRegistry + ->getRepository(Translation::class) + ->findOneByName($name); + $translationByLocale = $this->managerRegistry + ->getRepository(Translation::class) + ->findOneByLocale($locale); + + $confirmation = new ConfirmationQuestion( + 'Are you sure to create '.$name.' ('.$locale.') translation?', + false + ); - if (null !== $translationByName) { - $io->error('Translation ' . $name . ' already exists.'); - return 1; - } elseif (null !== $translationByLocale) { - $io->error('Translation locale ' . $locale . ' is already used.'); - return 1; - } else { - if ( - $io->askQuestion( - $confirmation - ) - ) { - $newTrans = new Translation(); - $newTrans->setName($name) - ->setLocale($locale); + if (null !== $translationByName) { + $io->error('Translation '.$name.' already exists.'); - $this->managerRegistry->getManagerForClass(Translation::class)->persist($newTrans); - $this->managerRegistry->getManagerForClass(Translation::class)->flush(); + return 1; + } elseif (null !== $translationByLocale) { + $io->error('Translation locale '.$locale.' is already used.'); - $io->success('New ' . $newTrans->getName() . ' translation for ' . $newTrans->getLocale() . ' locale.'); - } - } + return 1; } + + if ( + $io->askQuestion( + $confirmation + ) + ) { + $newTrans = new Translation(); + $newTrans->setName($name) + ->setLocale($locale); + + $this->managerRegistry->getManagerForClass(Translation::class)->persist($newTrans); + $this->managerRegistry->getManagerForClass(Translation::class)->flush(); + + $io->success('New '.$newTrans->getName().' translation for '.$newTrans->getLocale().' locale.'); + } + return 0; } } diff --git a/src/Console/TranslationsDeleteCommand.php b/src/Console/TranslationsDeleteCommand.php index 60f54562..a12097c3 100644 --- a/src/Console/TranslationsDeleteCommand.php +++ b/src/Console/TranslationsDeleteCommand.php @@ -41,30 +41,35 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($translationCount < 2) { $io->error('You cannot delete the only one available translation!'); + return 1; - } elseif ($translation !== null) { - $io->note('///////////////////////////////' . PHP_EOL . - '/////////// WARNING ///////////' . PHP_EOL . - '///////////////////////////////' . PHP_EOL . - 'This operation cannot be undone.' . PHP_EOL . - 'Deleting a translation, you will automatically delete every translated tags, node-sources, url-aliases and documents.'); - $confirmation = new ConfirmationQuestion( - 'Are you sure to delete ' . $translation->getName() . ' (' . $translation->getLocale() . ') translation?', - false - ); - if ( - $io->askQuestion( - $confirmation - ) - ) { - $this->managerRegistry->getManagerForClass(Translation::class)->remove($translation); - $this->managerRegistry->getManagerForClass(Translation::class)->flush(); - $io->success('Translation deleted.'); - } - } else { - $io->error('Translation for locale ' . $locale . ' does not exist.'); + } + + if (null === $translation) { + $io->error('Translation for locale '.$locale.' does not exist.'); + return 1; } + + $io->note('///////////////////////////////'.PHP_EOL. + '/////////// WARNING ///////////'.PHP_EOL. + '///////////////////////////////'.PHP_EOL. + 'This operation cannot be undone.'.PHP_EOL. + 'Deleting a translation, you will automatically delete every translated tags, node-sources, url-aliases and documents.'); + $confirmation = new ConfirmationQuestion( + 'Are you sure to delete '.$translation->getName().' ('.$translation->getLocale().') translation?', + false + ); + if ( + $io->askQuestion( + $confirmation + ) + ) { + $this->managerRegistry->getManagerForClass(Translation::class)->remove($translation); + $this->managerRegistry->getManagerForClass(Translation::class)->flush(); + $io->success('Translation deleted.'); + } + return 0; } } diff --git a/src/Console/TranslationsDisableCommand.php b/src/Console/TranslationsDisableCommand.php index 164b7422..124039e4 100644 --- a/src/Console/TranslationsDisableCommand.php +++ b/src/Console/TranslationsDisableCommand.php @@ -36,24 +36,26 @@ protected function execute(InputInterface $input, OutputInterface $output): int ->getRepository(Translation::class) ->findOneByLocale($locale); - if ($translation !== null) { - $confirmation = new ConfirmationQuestion( - 'Are you sure to disable ' . $translation->getName() . ' (' . $translation->getLocale() . ') translation?', - false - ); - if ( - $io->askQuestion( - $confirmation - ) - ) { - $translation->setAvailable(false); - $this->managerRegistry->getManagerForClass(Translation::class)->flush(); - $io->success('Translation disabled.'); - } - } else { - $io->error('Translation for locale ' . $locale . ' does not exist.'); + if (null === $translation) { + $io->error('Translation for locale '.$locale.' does not exist.'); + return 1; } + + $confirmation = new ConfirmationQuestion( + 'Are you sure to disable '.$translation->getName().' ('.$translation->getLocale().') translation?', + false + ); + if ( + $io->askQuestion( + $confirmation + ) + ) { + $translation->setAvailable(false); + $this->managerRegistry->getManagerForClass(Translation::class)->flush(); + $io->success('Translation disabled.'); + } + return 0; } } diff --git a/src/Console/TranslationsEnableCommand.php b/src/Console/TranslationsEnableCommand.php index f6656694..c196b97a 100644 --- a/src/Console/TranslationsEnableCommand.php +++ b/src/Console/TranslationsEnableCommand.php @@ -36,24 +36,26 @@ protected function execute(InputInterface $input, OutputInterface $output): int ->getRepository(Translation::class) ->findOneByLocale($locale); - if ($translation !== null) { - $confirmation = new ConfirmationQuestion( - 'Are you sure to enable ' . $translation->getName() . ' (' . $translation->getLocale() . ') translation?', - false - ); - if ( - $io->askQuestion( - $confirmation - ) - ) { - $translation->setAvailable(true); - $this->managerRegistry->getManagerForClass(Translation::class)->flush(); - $io->success('Translation enabled.'); - } - } else { - $io->error('Translation for locale ' . $locale . ' does not exist.'); + if (null === $translation) { + $io->error('Translation for locale '.$locale.' does not exist.'); + return 1; } + + $confirmation = new ConfirmationQuestion( + 'Are you sure to enable '.$translation->getName().' ('.$translation->getLocale().') translation?', + false + ); + if ( + $io->askQuestion( + $confirmation + ) + ) { + $translation->setAvailable(true); + $this->managerRegistry->getManagerForClass(Translation::class)->flush(); + $io->success('Translation enabled.'); + } + return 0; } } diff --git a/src/Console/UsersCommand.php b/src/Console/UsersCommand.php index 2309ff8d..36de8d56 100644 --- a/src/Console/UsersCommand.php +++ b/src/Console/UsersCommand.php @@ -18,7 +18,7 @@ class UsersCommand extends Command { public function __construct( protected readonly ManagerRegistry $managerRegistry, - string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -58,8 +58,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int ->getRepository(User::class) ->findOneBy(['username' => $name]); - if ($user === null) { - $io->error('User “' . $name . '” does not exist… use users:create to add a new user.'); + if (null === $user) { + $io->error('User “'.$name.'” does not exist… use users:create to add a new user.'); } else { $tableContent = [ $this->getUserTableRow($user), @@ -88,6 +88,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $io->warning('No available users.'); } } + return 0; } @@ -105,7 +106,7 @@ protected function getUserForInput(InputInterface $input): User ->findOneBy(['username' => $name]); if (!($user instanceof User)) { - throw new InvalidArgumentException('User “' . $name . '” does not exist.'); + throw new InvalidArgumentException('User “'.$name.'” does not exist.'); } return $user; @@ -113,9 +114,6 @@ protected function getUserForInput(InputInterface $input): User /** * Get role by name, and create it if it does not exist. - * - * @param string $roleName - * @return Role */ public function getRole(string $roleName = Role::ROLE_SUPERADMIN): Role { @@ -123,7 +121,7 @@ public function getRole(string $roleName = Role::ROLE_SUPERADMIN): Role ->getRepository(Role::class) ->findOneBy(['name' => $roleName]); - if ($role === null) { + if (null === $role) { $role = new Role($roleName); $this->managerRegistry->getManagerForClass(Role::class)->persist($role); $this->managerRegistry->getManagerForClass(Role::class)->flush(); diff --git a/src/Console/UsersCreationCommand.php b/src/Console/UsersCreationCommand.php index 2373093e..9d3723e5 100644 --- a/src/Console/UsersCreationCommand.php +++ b/src/Console/UsersCreationCommand.php @@ -48,7 +48,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int ->findOneBy(['username' => $name]); if ($user instanceof User) { - $io->warning('User “' . $name . '” already exists.'); + $io->warning('User “'.$name.'” already exists.'); + return 1; } @@ -60,20 +61,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int 'username' => $user->getUsername(), ]; $passwordInput = new ArrayInput($arguments); + return $command->run($passwordInput, $output); } - /** - * @param string $username - * @param InputInterface $input - * @param OutputInterface $output - * - * @return User - */ private function executeUserCreation( string $username, InputInterface $input, - OutputInterface $output + OutputInterface $output, ): User { $user = new User(); $io = new SymfonyStyle($input, $output); @@ -94,8 +89,8 @@ private function executeUserCreation( $questionEmail ); } while ( - !filter_var($email, FILTER_VALIDATE_EMAIL) || - $this->managerRegistry->getRepository(User::class)->emailExists($email) + !filter_var($email, FILTER_VALIDATE_EMAIL) + || $this->managerRegistry->getRepository(User::class)->emailExists($email) ); } else { /* @@ -124,7 +119,7 @@ private function executeUserCreation( ) { $user->addRoleEntity($this->getRole(Role::ROLE_BACKEND_USER)); } - } elseif ($input->getOption('back-end') === true) { + } elseif (true === $input->getOption('back-end')) { $user->addRoleEntity($this->getRole(Role::ROLE_BACKEND_USER)); } @@ -140,7 +135,7 @@ private function executeUserCreation( ) { $user->addRoleEntity($this->getRole(Role::ROLE_SUPERADMIN)); } - } elseif ($input->getOption('super-admin') === true) { + } elseif (true === $input->getOption('super-admin')) { $user->addRoleEntity($this->getRole(Role::ROLE_SUPERADMIN)); } @@ -155,7 +150,8 @@ private function executeUserCreation( $this->managerRegistry->getManagerForClass(User::class)->persist($user); $this->managerRegistry->getManagerForClass(User::class)->flush(); - $io->success('User “' . $username . '”<' . $email . '> created no password.'); + $io->success('User “'.$username.'”<'.$email.'> created no password.'); + return $user; } } diff --git a/src/Console/UsersDeleteCommand.php b/src/Console/UsersDeleteCommand.php index 2e8c3062..0f2007fa 100644 --- a/src/Console/UsersDeleteCommand.php +++ b/src/Console/UsersDeleteCommand.php @@ -31,7 +31,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $user = $this->getUserForInput($input); $confirmation = new ConfirmationQuestion( - 'Do you really want to delete user “' . $user->getUsername() . '”?', + 'Do you really want to delete user “'.$user->getUsername().'”?', false ); if ( @@ -41,10 +41,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int ) { $this->managerRegistry->getManagerForClass(User::class)->remove($user); $this->managerRegistry->getManagerForClass(User::class)->flush(); - $io->success('User “' . $name . '” deleted.'); + $io->success('User “'.$name.'” deleted.'); + return 0; } else { - $io->warning('User “' . $name . '” was not deleted.'); + $io->warning('User “'.$name.'” was not deleted.'); + return 1; } } diff --git a/src/Console/UsersDisableCommand.php b/src/Console/UsersDisableCommand.php index 97b0062a..587e8ecf 100644 --- a/src/Console/UsersDisableCommand.php +++ b/src/Console/UsersDisableCommand.php @@ -31,7 +31,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $user = $this->getUserForInput($input); $confirmation = new ConfirmationQuestion( - 'Do you really want to disable user “' . $user->getUsername() . '”?', + 'Do you really want to disable user “'.$user->getUsername().'”?', false ); if ( @@ -41,10 +41,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int ) { $user->setEnabled(false); $this->managerRegistry->getManagerForClass(User::class)->flush(); - $io->success('User “' . $name . '” disabled.'); + $io->success('User “'.$name.'” disabled.'); + return 0; } else { - $io->warning('User “' . $name . '” was not disabled.'); + $io->warning('User “'.$name.'” was not disabled.'); + return 1; } } diff --git a/src/Console/UsersEnableCommand.php b/src/Console/UsersEnableCommand.php index b9092656..11488c5e 100644 --- a/src/Console/UsersEnableCommand.php +++ b/src/Console/UsersEnableCommand.php @@ -31,7 +31,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $user = $this->getUserForInput($input); $confirmation = new ConfirmationQuestion( - 'Do you really want to enable user “' . $user->getUsername() . '”?', + 'Do you really want to enable user “'.$user->getUsername().'”?', false ); if ( @@ -41,10 +41,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int ) { $user->setEnabled(true); $this->managerRegistry->getManagerForClass(User::class)->flush(); - $io->success('User “' . $name . '” was enabled.'); + $io->success('User “'.$name.'” was enabled.'); + return 0; } else { - $io->warning('User “' . $name . '” was not enabled'); + $io->warning('User “'.$name.'” was not enabled'); + return 1; } } diff --git a/src/Console/UsersExpireCommand.php b/src/Console/UsersExpireCommand.php index f8aafd30..c9d865e5 100644 --- a/src/Console/UsersExpireCommand.php +++ b/src/Console/UsersExpireCommand.php @@ -49,10 +49,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int ) { $user->setExpiresAt($expirationDate); $this->managerRegistry->getManagerForClass(User::class)->flush(); - $io->success('User “' . $name . '” expiration date was set on ' . $expirationDate->format('c') . '.'); + $io->success('User “'.$name.'” expiration date was set on '.$expirationDate->format('c').'.'); + return 0; } else { - $io->warning('User “' . $name . '” was not updated.'); + $io->warning('User “'.$name.'” was not updated.'); + return 1; } } diff --git a/src/Console/UsersInactiveCommand.php b/src/Console/UsersInactiveCommand.php new file mode 100644 index 00000000..37e0f086 --- /dev/null +++ b/src/Console/UsersInactiveCommand.php @@ -0,0 +1,142 @@ +setName('users:inactive') + ->setDescription('List users that did not logged-in for 30 days.') + ->addOption( + 'days', + 'd', + InputOption::VALUE_REQUIRED, + 'Number of days since last login.', + 30 + ) + ->addOption( + 'role', + 'r', + InputOption::VALUE_REQUIRED, + 'List users with a specific role.', + null + ) + ->addOption( + 'missing-role', + 'm', + InputOption::VALUE_REQUIRED, + 'List users without a specific role. Can be combined with --role.', + null + ) + ->addOption( + 'purge', + null, + InputOption::VALUE_NONE, + 'Purge and delete inactive users with a specific role, destructive action.' + ) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + + $daysCount = $input->getOption('days'); + if (!\is_numeric($daysCount) || $daysCount < 1) { + $io->error('Days option must be a positive number.'); + + return 1; + } + + $sinceDate = new \DateTimeImmutable("-$daysCount days"); + + $inactiveUsers = $this->managerRegistry + ->getRepository(User::class) + ->findAllInactiveSinceDays( + (int) $daysCount + ) + ; + + $filteringRole = $input->getOption('role'); + if (\is_string($filteringRole) && !empty(trim($filteringRole))) { + $inactiveUsers = array_filter($inactiveUsers, function (User $user) use ($filteringRole) { + return \in_array($filteringRole, $user->getRoles(), true); + }); + } + + $missingRole = $input->getOption('missing-role'); + if (\is_string($missingRole) && !empty(trim($missingRole))) { + $inactiveUsers = array_filter($inactiveUsers, function (User $user) use ($missingRole) { + return !\in_array($missingRole, $user->getRoles(), true); + }); + } + + $io->success(sprintf( + '%d inactive users since %s.', + count($inactiveUsers), + $sinceDate->format('Y-m-d') + )); + + if ($output->isVerbose() && count($inactiveUsers) > 0) { + $io->table( + ['ID', 'Username', 'Last login', 'Created at'], + array_map(function (User $user) { + return [ + $user->getId(), + $user->getUsername(), + $user->getLastLogin()?->format('Y-m-d H:i:s') ?? 'Never', + $user->getCreatedAt()?->format('Y-m-d H:i:s') ?? 'Never', + ]; + }, $inactiveUsers) + ); + } + + $purge = $input->getOption('purge'); + if (!$purge || 0 === count($inactiveUsers)) { + return 0; + } + + if (!\is_string($filteringRole) || empty(trim($filteringRole))) { + $io->error(sprintf( + 'You cannot purge inactive users since %s without filtering them by a ROLE name.', + $sinceDate->format('Y-m-d') + )); + + return 1; + } + + if ($input->isInteractive() && !$io->confirm('Do you want to delete these users?')) { + $io->comment('No user has been deleted.'); + + return 0; + } + + foreach ($inactiveUsers as $user) { + $this->managerRegistry->getManager()->remove($user); + } + $this->managerRegistry->getManager()->flush(); + $io->success(sprintf( + '%d inactive users have been deleted.', + count($inactiveUsers) + )); + + return 0; + } +} diff --git a/src/Console/UsersLockCommand.php b/src/Console/UsersLockCommand.php index 03e9b9dc..7df7055d 100644 --- a/src/Console/UsersLockCommand.php +++ b/src/Console/UsersLockCommand.php @@ -31,7 +31,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $user = $this->getUserForInput($input); $confirmation = new ConfirmationQuestion( - 'Do you really want to lock user “' . $user->getUsername() . '”?', + 'Do you really want to lock user “'.$user->getUsername().'”?', false ); if ( @@ -41,10 +41,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int ) { $user->setLocked(true); $this->managerRegistry->getManagerForClass(User::class)->flush(); - $io->success('User “' . $name . '” locked.'); + $io->success('User “'.$name.'” locked.'); + return 0; } else { - $io->warning('User “' . $name . '” was not locked.'); + $io->warning('User “'.$name.'” was not locked.'); + return 1; } } diff --git a/src/Console/UsersPasswordCommand.php b/src/Console/UsersPasswordCommand.php index 9d265e1f..76dd9d3e 100644 --- a/src/Console/UsersPasswordCommand.php +++ b/src/Console/UsersPasswordCommand.php @@ -6,7 +6,7 @@ use Doctrine\Persistence\ManagerRegistry; use RZ\Roadiz\CoreBundle\Entity\User; -use RZ\Roadiz\Random\PasswordGenerator; +use RZ\Roadiz\Random\PasswordGeneratorInterface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -16,9 +16,9 @@ final class UsersPasswordCommand extends UsersCommand { public function __construct( - private readonly PasswordGenerator $passwordGenerator, + private readonly PasswordGeneratorInterface $passwordGenerator, ManagerRegistry $managerRegistry, - ?string $name = null + ?string $name = null, ) { parent::__construct($managerRegistry, $name); } @@ -31,6 +31,11 @@ protected function configure(): void 'username', InputArgument::REQUIRED, 'Username' + )->addOption( + 'length', + 'l', + InputArgument::OPTIONAL, + default: 16, ); } @@ -41,7 +46,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $user = $this->getUserForInput($input); $confirmation = new ConfirmationQuestion( - 'Do you really want to regenerate user “' . $user->getUsername() . '” password?', + 'Do you really want to regenerate user “'.$user->getUsername().'” password?', false ); if ( @@ -49,12 +54,16 @@ protected function execute(InputInterface $input, OutputInterface $output): int $confirmation ) ) { - $user->setPlainPassword($this->passwordGenerator->generatePassword(12)); + $user->setPlainPassword($this->passwordGenerator->generatePassword( + (int) $input->getOption('length') + )); $this->managerRegistry->getManagerForClass(User::class)->flush(); - $io->success('A new password was regenerated for ' . $name . ': ' . $user->getPlainPassword()); + $io->success('A new password was regenerated for '.$name.': '.$user->getPlainPassword()); + return 0; } else { $io->warning('User password was not changed.'); + return 1; } } diff --git a/src/Console/UsersRolesCommand.php b/src/Console/UsersRolesCommand.php index 047a2d5b..304998db 100644 --- a/src/Console/UsersRolesCommand.php +++ b/src/Console/UsersRolesCommand.php @@ -23,7 +23,7 @@ final class UsersRolesCommand extends UsersCommand public function __construct( private readonly Roles $rolesBag, ManagerRegistry $managerRegistry, - ?string $name = null + ?string $name = null, ) { parent::__construct($managerRegistry, $name); } @@ -68,12 +68,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int do { $role = $io->askQuestion($question); - if ($role != "") { + if ('' != $role) { $user->addRoleEntity($this->rolesBag->get($role)); $this->managerRegistry->getManagerForClass(User::class)->flush(); - $io->success('Role: ' . $role . ' added.'); + $io->success('Role: '.$role.' added.'); } - } while ($role != ""); + } while ('' != $role); } elseif ($input->getOption('remove')) { do { $roles = $user->getRoles(); @@ -86,9 +86,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int if (in_array($role, $roles)) { $user->removeRoleEntity($this->rolesBag->get($role)); $this->managerRegistry->getManagerForClass(User::class)->flush(); - $io->success('Role: ' . $role . ' removed.'); + $io->success('Role: '.$role.' removed.'); } - } while ($role != ""); + } while ('' != $role); } return 0; diff --git a/src/Console/UsersUnexpireCommand.php b/src/Console/UsersUnexpireCommand.php index 0430a728..a3dd5055 100644 --- a/src/Console/UsersUnexpireCommand.php +++ b/src/Console/UsersUnexpireCommand.php @@ -31,7 +31,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $user = $this->getUserForInput($input); $confirmation = new ConfirmationQuestion( - 'Do you really want to remove user “' . $user->getUsername() . '” expiration date?', + 'Do you really want to remove user “'.$user->getUsername().'” expiration date?', false ); if ( @@ -41,10 +41,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int ) { $user->setExpiresAt(null); $this->managerRegistry->getManagerForClass(User::class)->flush(); - $io->success('User “' . $name . '” unexpired.'); + $io->success('User “'.$name.'” unexpired.'); + return 0; } else { - $io->warning('User “' . $name . '” was not updated.'); + $io->warning('User “'.$name.'” was not updated.'); + return 1; } } diff --git a/src/Console/UsersUnlockCommand.php b/src/Console/UsersUnlockCommand.php index 0fd4be6a..bd4684cb 100644 --- a/src/Console/UsersUnlockCommand.php +++ b/src/Console/UsersUnlockCommand.php @@ -31,7 +31,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $user = $this->getUserForInput($input); $confirmation = new ConfirmationQuestion( - 'Do you really want to unlock user “' . $user->getUsername() . '”?', + 'Do you really want to unlock user “'.$user->getUsername().'”?', false ); if ( @@ -41,10 +41,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int ) { $user->setLocked(false); $this->managerRegistry->getManagerForClass(User::class)->flush(); - $io->success('User “' . $name . '” unlocked.'); + $io->success('User “'.$name.'” unlocked.'); + return 0; } else { - $io->warning('User “' . $name . '” was not unlocked.'); + $io->warning('User “'.$name.'” was not unlocked.'); + return 1; } } diff --git a/src/Console/VersionsPurgeCommand.php b/src/Console/VersionsPurgeCommand.php index 8891e472..d7531d84 100644 --- a/src/Console/VersionsPurgeCommand.php +++ b/src/Console/VersionsPurgeCommand.php @@ -20,7 +20,7 @@ final class VersionsPurgeCommand extends Command { public function __construct( private readonly ManagerRegistry $managerRegistry, - ?string $name = null + ?string $name = null, ) { parent::__construct($name); } @@ -54,7 +54,7 @@ protected function configure(): void protected function execute(InputInterface $input, OutputInterface $output): int { - if ($input->hasOption('before') && $input->getOption('before') != '') { + if ($input->hasOption('before') && '' != $input->getOption('before')) { $this->purgeByDate($input, $output); } elseif ($input->hasOption('count')) { if ((int) $input->getOption('count') < 2) { @@ -64,6 +64,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } else { throw new \InvalidArgumentException('Choose an option between --before or --count'); } + return 0; } @@ -79,7 +80,6 @@ private function getRepository(): UserLogEntryRepository private function purgeByDate(InputInterface $input, OutputInterface $output): void { $io = new SymfonyStyle($input, $output); - $em = $this->managerRegistry->getManagerForClass(UserLogEntry::class); $dateTime = new \DateTime($input->getOption('before')); if ($dateTime >= new \DateTime()) { @@ -105,7 +105,6 @@ private function purgeByCount(InputInterface $input, OutputInterface $output): v { $io = new SymfonyStyle($input, $output); $count = (int) $input->getOption('count'); - $em = $this->managerRegistry->getManagerForClass(UserLogEntry::class); $question = new ConfirmationQuestion(sprintf( 'Do you want to purge all entities versions and to keep only the latest %s?', diff --git a/src/Controller/CustomFormController.php b/src/Controller/CustomFormController.php index 179d96cf..f878a43d 100644 --- a/src/Controller/CustomFormController.php +++ b/src/Controller/CustomFormController.php @@ -5,7 +5,6 @@ namespace RZ\Roadiz\CoreBundle\Controller; use Doctrine\Persistence\ManagerRegistry; -use Exception; use League\Flysystem\FilesystemException; use Limenius\Liform\LiformInterface; use Psr\Log\LoggerInterface; @@ -22,7 +21,6 @@ use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException; @@ -47,7 +45,7 @@ public function __construct( ) { } - protected function validateCustomForm(?CustomForm $customForm): void + private function validateCustomForm(?CustomForm $customForm): void { if (null === $customForm) { throw new NotFoundHttpException('Custom form not found'); @@ -57,11 +55,6 @@ protected function validateCustomForm(?CustomForm $customForm): void } } - /** - * @param Request $request - * @param int $id - * @return JsonResponse - */ public function definitionAction(Request $request, int $id): JsonResponse { /** @var CustomForm|null $customForm */ @@ -80,10 +73,7 @@ public function definitionAction(Request $request, int $id): JsonResponse } /** - * @param Request $request - * @param int $id - * @return Response - * @throws Exception|FilesystemException + * @throws \Exception|FilesystemException */ public function postAction(Request $request, int $id): Response { @@ -115,6 +105,7 @@ public function postAction(Request $request, int $id): Response if ($mixed instanceof Response) { $mixed->prepare($request); + return $mixed; } @@ -122,8 +113,9 @@ public function postAction(Request $request, int $id): Response if ($mixed['formObject']->isSubmitted()) { $errorPayload = [ 'status' => Response::HTTP_BAD_REQUEST, - 'errorsPerForm' => $this->formErrorSerializer->getErrorsAsArray($mixed['formObject']) + 'errorsPerForm' => $this->formErrorSerializer->getErrorsAsArray($mixed['formObject']), ]; + return new JsonResponse( $this->serializer->serialize($errorPayload, 'json'), Response::HTTP_BAD_REQUEST, @@ -137,14 +129,11 @@ public function postAction(Request $request, int $id): Response } /** - * @param Request $request - * @param int $customFormId - * @return Response * @throws FilesystemException */ public function addAction(Request $request, int $customFormId): Response { - /** @var CustomForm $customForm */ + /** @var CustomForm|null $customForm */ $customForm = $this->registry->getRepository(CustomForm::class)->find($customFormId); $this->validateCustomForm($customForm); @@ -154,7 +143,7 @@ public function addAction(Request $request, int $customFormId): Response new RedirectResponse( $this->generateUrl( 'customFormSentAction', - ["customFormId" => $customFormId] + ['customFormId' => $customFormId] ) ) ); @@ -166,11 +155,6 @@ public function addAction(Request $request, int $customFormId): Response } } - /** - * @param Request $request - * @param int $customFormId - * @return Response - */ public function sentAction(Request $request, int $customFormId): Response { $assignation = []; @@ -179,6 +163,7 @@ public function sentAction(Request $request, int $customFormId): Response $this->validateCustomForm($customForm); $assignation['customForm'] = $customForm; + return $this->render('@RoadizCore/customForm/customFormSent.html.twig', $assignation); } @@ -191,30 +176,24 @@ public function sentAction(Request $request, int $customFormId): Response * * form * * If form is validated, **RedirectResponse** will be returned. * - * @param Request $request - * @param CustomForm $customFormsEntity - * @param Response $response - * @param boolean $forceExpanded - * @param string|null $emailSender - * @param bool $prefix * @return array|Response + * * @throws FilesystemException */ - public function prepareAndHandleCustomFormAssignation( + private function prepareAndHandleCustomFormAssignation( Request $request, CustomForm $customFormsEntity, Response $response, bool $forceExpanded = false, ?string $emailSender = null, - bool $prefix = true + bool $prefix = true, ) { $assignation = [ 'customForm' => $customFormsEntity, 'fields' => $customFormsEntity->getFields(), 'head' => [ 'siteTitle' => $this->settingsBag->get('site_name'), - 'mainColor' => $this->settingsBag->get('main_color'), - ] + ], ]; $helper = $this->customFormHelperFactory->createHelper($customFormsEntity); $form = $helper->getForm( @@ -258,13 +237,6 @@ public function prepareAndHandleCustomFormAssignation( ['%name%' => $customFormsEntity->getDisplayName()] ); - if (!$request->attributes->getBoolean('_stateless') && $request->hasPreviousSession()) { - $session = $request->getSession(); - if ($session instanceof Session) { - $session->getFlashBag()->add('confirm', $msg); - } - } - $this->logger->info($msg); return $response; @@ -275,6 +247,7 @@ public function prepareAndHandleCustomFormAssignation( $assignation['form'] = $form->createView(); $assignation['formObject'] = $form; + return $assignation; } } diff --git a/src/Controller/DefaultNodeSourceController.php b/src/Controller/DefaultNodeSourceController.php index 541668b2..007ae0ad 100644 --- a/src/Controller/DefaultNodeSourceController.php +++ b/src/Controller/DefaultNodeSourceController.php @@ -8,12 +8,12 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; -class DefaultNodeSourceController extends AbstractController +final class DefaultNodeSourceController extends AbstractController { public function indexAction(NodesSources $nodeSource): Response { return $this->render('@RoadizCore/nodeSource/default.html.twig', [ - 'nodeSource' => $nodeSource + 'nodeSource' => $nodeSource, ]); } } diff --git a/src/Controller/HealthCheckController.php b/src/Controller/HealthCheckController.php index 952f17f1..1129a866 100644 --- a/src/Controller/HealthCheckController.php +++ b/src/Controller/HealthCheckController.php @@ -9,21 +9,21 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -final class HealthCheckController +final readonly class HealthCheckController { public function __construct( - private readonly ?string $healthCheckToken, - private readonly ?string $appVersion, - private readonly ?string $cmsVersion, - private readonly ?string $cmsVersionPrefix + private ?string $healthCheckToken, + private ?string $appVersion, + private ?string $cmsVersion, + private ?string $cmsVersionPrefix, ) { } public function __invoke(Request $request): JsonResponse { if ( - !empty($this->healthCheckToken) && - $request->headers->get('x-health-check') !== $this->healthCheckToken + !empty($this->healthCheckToken) + && $request->headers->get('x-health-check') !== $this->healthCheckToken ) { throw new NotFoundHttpException(); } @@ -34,10 +34,10 @@ public function __invoke(Request $request): JsonResponse 'notes' => [ 'roadiz_version' => $this->cmsVersion ?? '', 'roadiz_channel' => $this->cmsVersionPrefix ?? '', - ] + ], ], Response::HTTP_OK, [ 'Content-type' => 'application/health+json', - 'Cache-Control' => 'public, max-age=10' + 'Cache-Control' => 'public, max-age=10', ]); } } diff --git a/src/Controller/RedirectionController.php b/src/Controller/RedirectionController.php index 6ede96a6..7d2d2cc3 100644 --- a/src/Controller/RedirectionController.php +++ b/src/Controller/RedirectionController.php @@ -12,9 +12,9 @@ use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -final class RedirectionController +final readonly class RedirectionController { - public function __construct(private readonly UrlGeneratorInterface $urlGenerator) + public function __construct(private UrlGeneratorInterface $urlGenerator) { } @@ -31,8 +31,8 @@ public function redirectAction(Request $request, Redirection $redirection): Redi } if ( - null !== $redirection->getRedirectUri() && - \mb_strlen($redirection->getRedirectUri()) > 0 + null !== $redirection->getRedirectUri() + && \mb_strlen($redirection->getRedirectUri()) > 0 ) { return new RedirectResponse($redirection->getRedirectUri(), $redirection->getType()); } @@ -62,7 +62,7 @@ public function redirectToRouteAction( Request $request, string $route, bool $permanent = false, - $ignoreAttributes = false + bool|array $ignoreAttributes = false, ): RedirectResponse { if ('' == $route) { throw new HttpException($permanent ? 410 : 404); @@ -75,6 +75,7 @@ public function redirectToRouteAction( $attributes = array_diff_key($attributes, array_flip($ignoreAttributes)); } } + return new RedirectResponse( $this->urlGenerator->generate( $route, diff --git a/src/CustomForm/CustomFormAnswerSerializer.php b/src/CustomForm/CustomFormAnswerSerializer.php index cdf08b8e..6456ab6d 100644 --- a/src/CustomForm/CustomFormAnswerSerializer.php +++ b/src/CustomForm/CustomFormAnswerSerializer.php @@ -9,17 +9,20 @@ use RZ\Roadiz\CoreBundle\Entity\Document; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -class CustomFormAnswerSerializer +final readonly class CustomFormAnswerSerializer { - public function __construct(protected readonly UrlGeneratorInterface $urlGenerator) + public function __construct(private UrlGeneratorInterface $urlGenerator) { } + /** + * @throws \Exception + */ public function toSimpleArray(CustomFormAnswer $answer): array { $answers = [ 'ip' => $answer->getIp(), - 'submitted.date' => $answer->getSubmittedAt() + 'submitted.date' => $answer->getSubmittedAt(), ]; /** @var CustomFormFieldAttribute $answerAttr */ foreach ($answer->getAnswerFields() as $answerAttr) { @@ -27,13 +30,14 @@ public function toSimpleArray(CustomFormAnswer $answer): array if ($field->isDocuments()) { $answers[$field->getLabel()] = implode(PHP_EOL, $answerAttr->getDocuments()->map(function (Document $document) { return $this->urlGenerator->generate('documentsDownloadPage', [ - 'documentId' => $document->getId() + 'documentId' => $document->getId(), ], UrlGeneratorInterface::ABSOLUTE_URL); })->toArray()); } else { $answers[$field->getLabel()] = $answerAttr->getValue(); } } + return $answers; } } diff --git a/src/CustomForm/CustomFormHelper.php b/src/CustomForm/CustomFormHelper.php index 1a2dcb27..9c84c496 100644 --- a/src/CustomForm/CustomFormHelper.php +++ b/src/CustomForm/CustomFormHelper.php @@ -6,7 +6,6 @@ use Doctrine\Persistence\ObjectManager; use League\Flysystem\FilesystemException; -use RZ\Roadiz\CoreBundle\Bag\Settings; use RZ\Roadiz\CoreBundle\Entity\CustomForm; use RZ\Roadiz\CoreBundle\Entity\CustomFormAnswer; use RZ\Roadiz\CoreBundle\Entity\CustomFormField; @@ -26,30 +25,23 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; #[Exclude] -class CustomFormHelper +final class CustomFormHelper { public const ARRAY_SEPARATOR = ', '; public function __construct( - protected readonly ObjectManager $em, - protected readonly CustomForm $customForm, - protected readonly AbstractDocumentFactory $documentFactory, - protected readonly FormFactoryInterface $formFactory, - protected readonly Settings $settingsBag, - protected readonly EventDispatcherInterface $eventDispatcher + private readonly ObjectManager $em, + private readonly CustomForm $customForm, + private readonly AbstractDocumentFactory $documentFactory, + private readonly FormFactoryInterface $formFactory, + private readonly EventDispatcherInterface $eventDispatcher, ) { } - /** - * @param Request $request - * @param boolean $forceExpanded - * @param bool $prefix - * @return FormInterface - */ public function getForm( Request $request, bool $forceExpanded = false, - bool $prefix = true + bool $prefix = true, ): FormInterface { $defaults = $request->query->all(); if ($prefix) { @@ -57,6 +49,7 @@ public function getForm( } else { $name = ''; } + return $this->formFactory->createNamed($name, CustomFormsType::class, $defaults, [ 'customForm' => $this->customForm, 'forceExpanded' => $forceExpanded, @@ -67,16 +60,12 @@ public function getForm( * Create or update custom-form answer and its attributes from * a submitted form data. * - * @param FormInterface $form - * @param CustomFormAnswer|null $answer - * @param string $ipAddress - * @return CustomFormAnswer * @throws FilesystemException */ public function parseAnswerFormData( FormInterface $form, - CustomFormAnswer $answer = null, - string $ipAddress = "" + ?CustomFormAnswer $answer = null, + string $ipAddress = '', ): CustomFormAnswer { if (!$form->isSubmitted()) { throw new \InvalidArgumentException('Form must be submitted before begin parsing.'); @@ -105,7 +94,7 @@ public function parseAnswerFormData( /* * Get data in form groups */ - if ($customFormField->getGroupName() != '') { + if ('' != $customFormField->getGroupName()) { $groupCanonical = StringHandler::slugify($customFormField->getGroupName()); $formGroup = $form->get($groupCanonical); if ($formGroup->has($customFormField->getName())) { @@ -159,22 +148,21 @@ public function parseAnswerFormData( } /** - * @param UploadedFile $file - * @param CustomFormFieldAttribute $fieldAttr - * @return DocumentInterface|null * @throws FilesystemException + * @throws \Exception */ protected function handleUploadedFile( UploadedFile $file, - CustomFormFieldAttribute $fieldAttr + CustomFormFieldAttribute $fieldAttr, ): ?DocumentInterface { $this->documentFactory->setFile($file); $this->documentFactory->setFolder($this->getDocumentFolderForCustomForm()); $document = $this->documentFactory->getDocument(); if (null !== $document) { $fieldAttr->getDocuments()->add($document); - $fieldAttr->setValue($fieldAttr->getValue() . ', ' . $file->getPathname()); + $fieldAttr->setValue($fieldAttr->getValue().', '.$file->getPathname()); } + return $document; } @@ -182,8 +170,8 @@ protected function getDocumentFolderForCustomForm(): ?Folder { return $this->em->getRepository(Folder::class) ->findOrCreateByPath( - 'custom_forms/' . - $this->customForm->getCreatedAt()->format('Ymd') . '_' . + 'custom_forms/'. + $this->customForm->getCreatedAt()->format('Ymd').'_'. \mb_substr($this->customForm->getDisplayName(), 0, 30) ); } @@ -196,17 +184,13 @@ private function formValueToString(mixed $rawValue): string $values = $rawValue; $values = array_map('trim', $values); $values = array_map('strip_tags', $values); + return implode(static::ARRAY_SEPARATOR, $values); } else { return strip_tags((string) $rawValue); } } - /** - * @param CustomFormAnswer $answer - * @param CustomFormField $field - * @return CustomFormFieldAttribute|null - */ private function getAttribute(CustomFormAnswer $answer, CustomFormField $field): ?CustomFormFieldAttribute { return $this->em->getRepository(CustomFormFieldAttribute::class)->findOneBy([ diff --git a/src/CustomForm/CustomFormHelperFactory.php b/src/CustomForm/CustomFormHelperFactory.php index a04deb5e..6a947f7f 100644 --- a/src/CustomForm/CustomFormHelperFactory.php +++ b/src/CustomForm/CustomFormHelperFactory.php @@ -5,20 +5,18 @@ namespace RZ\Roadiz\CoreBundle\CustomForm; use Doctrine\Persistence\ObjectManager; -use RZ\Roadiz\CoreBundle\Bag\Settings; use RZ\Roadiz\CoreBundle\Document\PrivateDocumentFactory; use RZ\Roadiz\CoreBundle\Entity\CustomForm; use Symfony\Component\Form\FormFactoryInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; -final class CustomFormHelperFactory +final readonly class CustomFormHelperFactory { public function __construct( - private readonly PrivateDocumentFactory $privateDocumentFactory, - private readonly ObjectManager $em, - private readonly FormFactoryInterface $formFactory, - private readonly Settings $settingsBag, - private readonly EventDispatcherInterface $eventDispatcher + private PrivateDocumentFactory $privateDocumentFactory, + private ObjectManager $em, + private FormFactoryInterface $formFactory, + private EventDispatcherInterface $eventDispatcher, ) { } @@ -29,7 +27,6 @@ public function createHelper(CustomForm $customForm): CustomFormHelper $customForm, $this->privateDocumentFactory, $this->formFactory, - $this->settingsBag, $this->eventDispatcher ); } diff --git a/src/CustomForm/Message/CustomFormAnswerNotifyMessage.php b/src/CustomForm/Message/CustomFormAnswerNotifyMessage.php index ce56e283..9caec19f 100644 --- a/src/CustomForm/Message/CustomFormAnswerNotifyMessage.php +++ b/src/CustomForm/Message/CustomFormAnswerNotifyMessage.php @@ -6,13 +6,13 @@ use RZ\Roadiz\CoreBundle\Message\AsyncMessage; -final class CustomFormAnswerNotifyMessage implements AsyncMessage +final readonly class CustomFormAnswerNotifyMessage implements AsyncMessage { public function __construct( - private readonly int $customFormAnswerId, - private readonly string $title, - private readonly string $senderAddress, - private readonly string $locale + private int $customFormAnswerId, + private string $title, + private string $senderAddress, + private string $locale, ) { } diff --git a/src/CustomForm/Message/Handler/CustomFormAnswerNotifyMessageHandler.php b/src/CustomForm/Message/Handler/CustomFormAnswerNotifyMessageHandler.php index 5e8d9a1c..7a72f1df 100644 --- a/src/CustomForm/Message/Handler/CustomFormAnswerNotifyMessageHandler.php +++ b/src/CustomForm/Message/Handler/CustomFormAnswerNotifyMessageHandler.php @@ -14,21 +14,22 @@ use RZ\Roadiz\CoreBundle\Mailer\EmailManagerFactory; use RZ\Roadiz\Documents\Models\DocumentInterface; use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Messenger\Attribute\AsMessageHandler; use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; -use Symfony\Component\Messenger\Handler\MessageHandlerInterface; use Symfony\Component\Mime\Address; use Twig\Error\LoaderError; use Twig\Error\RuntimeError; use Twig\Error\SyntaxError; -final class CustomFormAnswerNotifyMessageHandler implements MessageHandlerInterface +#[AsMessageHandler] +final readonly class CustomFormAnswerNotifyMessageHandler { public function __construct( - private readonly ManagerRegistry $managerRegistry, - private readonly EmailManagerFactory $emailManagerFactory, - private readonly Settings $settingsBag, - private readonly FilesystemOperator $documentsStorage, - private readonly LoggerInterface $messengerLogger, + private ManagerRegistry $managerRegistry, + private EmailManagerFactory $emailManagerFactory, + private Settings $settingsBag, + private FilesystemOperator $documentsStorage, + private LoggerInterface $messengerLogger, ) { } @@ -43,8 +44,8 @@ public function __invoke(CustomFormAnswerNotifyMessage $message): void } $emailFields = [ - ["name" => "ip.address", "value" => $answer->getIp()], - ["name" => "submittedAt", "value" => $answer->getSubmittedAt()->format('Y-m-d H:i:s')], + ['name' => 'ip.address', 'value' => $answer->getIp()], + ['name' => 'submittedAt', 'value' => $answer->getSubmittedAt()->format('Y-m-d H:i:s')], ]; $emailFields = array_merge( $emailFields, @@ -71,6 +72,7 @@ private function getCustomFormReceivers(CustomFormAnswer $answer): array $receiver = array_filter( array_map('trim', explode(',', $answer->getCustomForm()->getEmail() ?? '')) ); + return array_map(function (string $email) { return new Address($email); }, $receiver); @@ -79,8 +81,6 @@ private function getCustomFormReceivers(CustomFormAnswer $answer): array /** * Send an answer form by Email. * - * @param CustomFormAnswer $answer - * @param array $assignation * @throws TransportExceptionInterface * @throws LoaderError * @throws RuntimeError @@ -88,7 +88,7 @@ private function getCustomFormReceivers(CustomFormAnswer $answer): array */ private function sendAnswer( CustomFormAnswer $answer, - array $assignation + array $assignation, ): void { $defaultSender = $this->settingsBag->get('email_sender'); $defaultSender = filter_var($defaultSender, FILTER_VALIDATE_EMAIL) ? $defaultSender : 'sender@roadiz.io'; @@ -120,7 +120,7 @@ private function sendAnswer( } } catch (FilesystemException $exception) { $this->messengerLogger->error($exception->getMessage(), [ - 'entity' => $answer + 'entity' => $answer, ]); } diff --git a/src/DataCollector/RequestDataCollector.php b/src/DataCollector/RequestDataCollector.php index 38ed74f9..28a170f5 100644 --- a/src/DataCollector/RequestDataCollector.php +++ b/src/DataCollector/RequestDataCollector.php @@ -5,47 +5,41 @@ namespace RZ\Roadiz\CoreBundle\DataCollector; use Symfony\Bundle\FrameworkBundle\DataCollector\AbstractDataCollector; +use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; +use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +#[AutoconfigureTag('data_collector', [ + 'template' => '@RoadizCore/DataCollector/request.html.twig', + // must match the value returned by the getName() method + 'id' => 'roadiz.data_collector.request', + 'priority' => 400, +])] final class RequestDataCollector extends AbstractDataCollector { public function __construct( + #[Autowire('%roadiz_core.cms_version%')] private readonly string $cmsVersion, - private readonly string $cmsVersionPrefix + #[Autowire('%roadiz_core.cms_version_prefix%')] + private readonly string $cmsVersionPrefix, ) { } - /** - * {@inheritdoc} - */ - public function collect(Request $request, Response $response, \Throwable $exception = null): void + public function collect(Request $request, Response $response, ?\Throwable $exception = null): void { $this->data = [ - 'version' => implode(' - ', array_filter([$this->cmsVersionPrefix, $this->cmsVersion])), + 'version' => implode(' - ', [$this->cmsVersionPrefix, $this->cmsVersion]), ]; } public function getVersion(): string { - return $this->data['version']; + return $this->data['version'] ?? ''; } - public static function getTemplate(): ?string - { - return '@RoadizCore/DataCollector/request.html.twig'; - } - - /** - * {@inheritdoc} - */ public function getName(): string { return 'roadiz.data_collector.request'; } - - public function reset(): void - { - $this->data = []; - } } diff --git a/src/SearchEngine/SolariumLogger.php b/src/DataCollector/SolariumLogger.php similarity index 88% rename from src/SearchEngine/SolariumLogger.php rename to src/DataCollector/SolariumLogger.php index fb0f7e19..555396e7 100644 --- a/src/SearchEngine/SolariumLogger.php +++ b/src/DataCollector/SolariumLogger.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace RZ\Roadiz\CoreBundle\SearchEngine; +namespace RZ\Roadiz\CoreBundle\DataCollector; use Psr\Log\LoggerInterface; use Solarium\Core\Client\Endpoint as SolariumEndpoint; @@ -13,6 +13,7 @@ use Solarium\Core\Event\PreExecuteRequest as SolariumPreExecuteRequestEvent; use Solarium\Core\Plugin\AbstractPlugin as SolariumPlugin; use Symfony\Bundle\FrameworkBundle\DataCollector\TemplateAwareDataCollectorInterface; +use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request as HttpRequest; use Symfony\Component\HttpFoundation\Response as HttpResponse; @@ -22,6 +23,14 @@ /** * @see https://github.com/nelmio/NelmioSolariumBundle */ +#[AutoconfigureTag('data_collector', [ + 'template' => '@RoadizCore/DataCollector/solarium.html.twig', + // must match the value returned by the getName() method + 'id' => 'solarium', +])] +#[AutoconfigureTag('monolog.logger', [ + 'channel' => 'solr', +])] final class SolariumLogger extends SolariumPlugin implements DataCollectorInterface, \Serializable, EventSubscriberInterface, TemplateAwareDataCollectorInterface { private array $data = []; @@ -32,7 +41,7 @@ final class SolariumLogger extends SolariumPlugin implements DataCollectorInterf public function __construct( private readonly LoggerInterface $searchEngineLogger, - private readonly Stopwatch $stopwatch + private readonly Stopwatch $stopwatch, ) { parent::__construct(); } @@ -49,17 +58,17 @@ public function log( SolariumRequest $request, ?SolariumResponse $response, SolariumEndpoint $endpoint, - float $duration + float $duration, ): void { - $this->queries[] = array( + $this->queries[] = [ 'request' => $request, 'response' => $response, 'duration' => $duration, 'base_uri' => $this->getEndpointBaseUrl($endpoint), - ); + ]; } - public function collect(HttpRequest $request, HttpResponse $response, \Throwable $exception = null): void + public function collect(HttpRequest $request, HttpResponse $response, ?\Throwable $exception = null): void { if (isset($this->currentRequest)) { $this->failCurrentRequest(); @@ -69,10 +78,10 @@ public function collect(HttpRequest $request, HttpResponse $response, \Throwable foreach ($this->queries as $queryStruct) { $time += $queryStruct['duration']; } - $this->data = array( - 'queries' => $this->queries, - 'total_time' => $time, - ); + $this->data = [ + 'queries' => $this->queries, + 'total_time' => $time, + ]; } public function getName(): string @@ -105,7 +114,7 @@ public function preExecuteRequest(SolariumPreExecuteRequestEvent $event): void $this->currentRequest = $event->getRequest(); $this->currentEndpoint = $event->getEndpoint(); - $this->searchEngineLogger->debug($this->getEndpointBaseUrl($this->currentEndpoint) . $this->currentRequest->getUri()); + $this->searchEngineLogger->debug($this->getEndpointBaseUrl($this->currentEndpoint).$this->currentRequest->getUri()); $this->currentStartTime = microtime(true); } diff --git a/src/DependencyInjection/Compiler/CommonMarkCompilerPass.php b/src/DependencyInjection/Compiler/CommonMarkCompilerPass.php index fc540e8c..7c24a3d2 100644 --- a/src/DependencyInjection/Compiler/CommonMarkCompilerPass.php +++ b/src/DependencyInjection/Compiler/CommonMarkCompilerPass.php @@ -10,9 +10,6 @@ class CommonMarkCompilerPass implements CompilerPassInterface { - /** - * @inheritDoc - */ public function process(ContainerBuilder $container): void { if ($container->has('roadiz_core.markdown.environments.text_converter')) { @@ -40,7 +37,7 @@ public function process(ContainerBuilder $container): void foreach ($taggedServices as $id => $tags) { $definition->addMethodCall( 'addExtension', - array(new Reference($id)) + [new Reference($id)] ); } } @@ -55,7 +52,7 @@ public function process(ContainerBuilder $container): void foreach ($taggedServices as $id => $tags) { $definition->addMethodCall( 'addExtension', - array(new Reference($id)) + [new Reference($id)] ); } } diff --git a/src/DependencyInjection/Compiler/DoctrineMigrationCompilerPass.php b/src/DependencyInjection/Compiler/DoctrineMigrationCompilerPass.php index 4a4a5a29..7609a4ee 100644 --- a/src/DependencyInjection/Compiler/DoctrineMigrationCompilerPass.php +++ b/src/DependencyInjection/Compiler/DoctrineMigrationCompilerPass.php @@ -4,15 +4,11 @@ namespace RZ\Roadiz\CoreBundle\DependencyInjection\Compiler; -use RuntimeException; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; class DoctrineMigrationCompilerPass implements CompilerPassInterface { - /** - * @inheritDoc - */ public function process(ContainerBuilder $container): void { if ($container->hasDefinition('doctrine.migrations.configuration')) { @@ -27,11 +23,12 @@ public function process(ContainerBuilder $container): void private function checkIfBundleRelativePath(string $path, ContainerBuilder $container): string { - if (isset($path[0]) && $path[0] === '@') { - $pathParts = explode('/', $path); + if (isset($path[0]) && '@' === $path[0]) { + $pathParts = explode('/', $path); $bundleName = \mb_substr($pathParts[0], 1); $bundlePath = $this->getBundlePath($bundleName, $container); - return $bundlePath . \mb_substr($path, \mb_strlen('@' . $bundleName)); + + return $bundlePath.\mb_substr($path, \mb_strlen('@'.$bundleName)); } return $path; @@ -42,12 +39,8 @@ private function getBundlePath(string $bundleName, ContainerBuilder $container): $bundleMetadata = $container->getParameter('kernel.bundles_metadata'); assert(is_array($bundleMetadata)); - if (! isset($bundleMetadata[$bundleName])) { - throw new RuntimeException(sprintf( - 'The bundle "%s" has not been registered, available bundles: %s', - $bundleName, - implode(', ', array_keys($bundleMetadata)) - )); + if (!isset($bundleMetadata[$bundleName])) { + throw new \RuntimeException(sprintf('The bundle "%s" has not been registered, available bundles: %s', $bundleName, implode(', ', array_keys($bundleMetadata)))); } return $bundleMetadata[$bundleName]['path']; diff --git a/src/DependencyInjection/Compiler/DocumentRendererCompilerPass.php b/src/DependencyInjection/Compiler/DocumentRendererCompilerPass.php index 80542056..ecf0ac81 100644 --- a/src/DependencyInjection/Compiler/DocumentRendererCompilerPass.php +++ b/src/DependencyInjection/Compiler/DocumentRendererCompilerPass.php @@ -13,9 +13,6 @@ class DocumentRendererCompilerPass implements CompilerPassInterface { use PriorityTaggedServiceTrait; - /** - * @inheritDoc - */ public function process(ContainerBuilder $container): void { if ($container->has(ChainRenderer::class)) { diff --git a/src/DependencyInjection/Compiler/FlysystemStorageCompilerPass.php b/src/DependencyInjection/Compiler/FlysystemStorageCompilerPass.php index b4f53aae..7e833e8f 100644 --- a/src/DependencyInjection/Compiler/FlysystemStorageCompilerPass.php +++ b/src/DependencyInjection/Compiler/FlysystemStorageCompilerPass.php @@ -19,11 +19,11 @@ protected function getStorageReference( ContainerBuilder $container, string $storageName, array $storageConfig, - ?string $publicUrl = null + ?string $publicUrl = null, ): Reference { if (!$container->hasDefinition($storageName)) { $definitionFactory = new AdapterDefinitionFactory(); - $adapterName = 'flysystem.adapter.' . $storageName; + $adapterName = 'flysystem.adapter.'.$storageName; if ($adapter = $definitionFactory->createDefinition('local', $storageConfig['options'])) { $container->setDefinition($adapterName, $adapter)->setPublic(false); $container->setDefinition( @@ -32,6 +32,7 @@ protected function getStorageReference( ); } } + return new Reference($storageName); } @@ -54,9 +55,6 @@ protected function getDocumentPrivateStorage(ContainerBuilder $container): Refer ); } - /** - * @inheritDoc - */ public function process(ContainerBuilder $container): void { $container->setDefinition( diff --git a/src/DependencyInjection/Compiler/ImporterCompilerPass.php b/src/DependencyInjection/Compiler/ImporterCompilerPass.php index b2de17cc..08fed012 100644 --- a/src/DependencyInjection/Compiler/ImporterCompilerPass.php +++ b/src/DependencyInjection/Compiler/ImporterCompilerPass.php @@ -11,9 +11,6 @@ class ImporterCompilerPass implements CompilerPassInterface { - /** - * @inheritDoc - */ public function process(ContainerBuilder $container): void { if ($container->has(ChainImporter::class)) { diff --git a/src/DependencyInjection/Compiler/MediaFinderCompilerPass.php b/src/DependencyInjection/Compiler/MediaFinderCompilerPass.php index ee69f857..38344fb6 100644 --- a/src/DependencyInjection/Compiler/MediaFinderCompilerPass.php +++ b/src/DependencyInjection/Compiler/MediaFinderCompilerPass.php @@ -9,9 +9,6 @@ class MediaFinderCompilerPass implements CompilerPassInterface { - /** - * @inheritDoc - */ public function process(ContainerBuilder $container): void { if ($container->hasParameter('roadiz_core.medias.supported_platforms')) { diff --git a/src/DependencyInjection/Compiler/NodeWorkflowCompilerPass.php b/src/DependencyInjection/Compiler/NodeWorkflowCompilerPass.php index e2216544..1053e6ca 100644 --- a/src/DependencyInjection/Compiler/NodeWorkflowCompilerPass.php +++ b/src/DependencyInjection/Compiler/NodeWorkflowCompilerPass.php @@ -4,7 +4,7 @@ namespace RZ\Roadiz\CoreBundle\DependencyInjection\Compiler; -use RZ\Roadiz\CoreBundle\Entity\Node; +use RZ\Roadiz\Core\AbstractEntities\NodeInterface; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; @@ -23,7 +23,7 @@ public function process(ContainerBuilder $container): void $workflowId = 'state_machine.node'; $registryDefinition = $container->getDefinition('workflow.registry'); - $strategyDefinition = new Definition(InstanceOfSupportStrategy::class, [Node::class]); + $strategyDefinition = new Definition(InstanceOfSupportStrategy::class, [NodeInterface::class]); $strategyDefinition->setPublic(false); $registryDefinition->addMethodCall('addWorkflow', [new Reference($workflowId), $strategyDefinition]); } diff --git a/src/DependencyInjection/Compiler/NodesSourcesEntitiesPathCompilerPass.php b/src/DependencyInjection/Compiler/NodesSourcesEntitiesPathCompilerPass.php index 037afe46..849facef 100644 --- a/src/DependencyInjection/Compiler/NodesSourcesEntitiesPathCompilerPass.php +++ b/src/DependencyInjection/Compiler/NodesSourcesEntitiesPathCompilerPass.php @@ -9,17 +9,14 @@ class NodesSourcesEntitiesPathCompilerPass implements CompilerPassInterface { - /** - * @inheritDoc - */ public function process(ContainerBuilder $container): void { $projectDir = $container->getParameter('kernel.project_dir'); if (!\is_string($projectDir)) { throw new \RuntimeException('kernel.project_dir parameter must be a string.'); } - $container->setParameter('roadiz_core.generated_entities_dir', $projectDir . '/src/GeneratedEntity'); - $container->setParameter('roadiz_core.serialized_node_types_dir', $projectDir . '/src/Resources/node-types'); - $container->setParameter('roadiz_core.import_files_config_path', $projectDir . '/src/Resources/config.yml'); + $container->setParameter('roadiz_core.generated_entities_dir', $projectDir.'/src/GeneratedEntity'); + $container->setParameter('roadiz_core.serialized_node_types_dir', $projectDir.'/src/Resources/node-types'); + $container->setParameter('roadiz_core.import_files_config_path', $projectDir.'/src/Resources/config.yml'); } } diff --git a/src/DependencyInjection/Compiler/PathResolverCompilerPass.php b/src/DependencyInjection/Compiler/PathResolverCompilerPass.php index aff479f2..d94474cd 100644 --- a/src/DependencyInjection/Compiler/PathResolverCompilerPass.php +++ b/src/DependencyInjection/Compiler/PathResolverCompilerPass.php @@ -6,16 +6,13 @@ use RZ\Roadiz\CoreBundle\Routing\ChainResourcePathResolver; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; -use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait; +use Symfony\Component\DependencyInjection\ContainerBuilder; class PathResolverCompilerPass implements CompilerPassInterface { use PriorityTaggedServiceTrait; - /** - * @inheritDoc - */ public function process(ContainerBuilder $container): void { if ($container->has(ChainResourcePathResolver::class)) { diff --git a/src/DependencyInjection/Compiler/RateLimitersCompilerPass.php b/src/DependencyInjection/Compiler/RateLimitersCompilerPass.php index d619971c..bdd67acb 100644 --- a/src/DependencyInjection/Compiler/RateLimitersCompilerPass.php +++ b/src/DependencyInjection/Compiler/RateLimitersCompilerPass.php @@ -26,14 +26,14 @@ public function process(ContainerBuilder $container): void 'cache_pool' => 'cache.rate_limiter', 'policy' => 'token_bucket', 'limit' => 1, - 'rate' => [ 'interval' => '10 seconds'], + 'rate' => ['interval' => '10 seconds'], ]; $limiter = $container->setDefinition( - $limiterId = 'limiter.' . $name, + $limiterId = 'limiter.'.$name, new ChildDefinition('limiter') ); $container->register( - $storageId = 'limiter.storage.' . $name, + $storageId = 'limiter.storage.'.$name, CacheStorage::class )->addArgument(new Reference($limiterConfig['cache_pool'])); @@ -41,6 +41,6 @@ public function process(ContainerBuilder $container): void unset($limiterConfig['cache_pool']); $limiterConfig['id'] = $name; $limiter->replaceArgument(0, $limiterConfig); - $container->registerAliasForArgument($limiterId, RateLimiterFactory::class, $name . '.limiter'); + $container->registerAliasForArgument($limiterId, RateLimiterFactory::class, $name.'.limiter'); } } diff --git a/src/DependencyInjection/Compiler/TreeWalkerDefinitionFactoryCompilerPass.php b/src/DependencyInjection/Compiler/TreeWalkerDefinitionFactoryCompilerPass.php index b8c0d188..1a142ee7 100644 --- a/src/DependencyInjection/Compiler/TreeWalkerDefinitionFactoryCompilerPass.php +++ b/src/DependencyInjection/Compiler/TreeWalkerDefinitionFactoryCompilerPass.php @@ -11,9 +11,6 @@ class TreeWalkerDefinitionFactoryCompilerPass implements CompilerPassInterface { - /** - * @inheritDoc - */ public function process(ContainerBuilder $container): void { if ($container->has(TreeWalkerGenerator::class)) { @@ -32,7 +29,7 @@ public function process(ContainerBuilder $container): void [ $tag['classname'], new Reference($serviceId), - $tag['onlyVisible'] ?? true + $tag['onlyVisible'] ?? true, ] ); } diff --git a/src/DependencyInjection/Compiler/TwigLoaderCompilerPass.php b/src/DependencyInjection/Compiler/TwigLoaderCompilerPass.php index a59480e1..ab0b250f 100644 --- a/src/DependencyInjection/Compiler/TwigLoaderCompilerPass.php +++ b/src/DependencyInjection/Compiler/TwigLoaderCompilerPass.php @@ -12,16 +12,13 @@ class TwigLoaderCompilerPass implements CompilerPassInterface { use PriorityTaggedServiceTrait; - /** - * @inheritDoc - */ public function process(ContainerBuilder $container): void { if ($container->has('twig.loader.native_filesystem')) { $definition = $container->findDefinition('twig.loader.native_filesystem'); $definition->addMethodCall( 'prependPath', - [ realpath(dirname(__DIR__) . '/../../templates/ApiPlatformBundle'), 'ApiPlatform' ] + [realpath(dirname(__DIR__).'/../../templates/ApiPlatformBundle'), 'ApiPlatform'] ); } } diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 7f5e8948..1cbf4f65 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -81,6 +81,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->append($this->addReverseProxyCacheNode()) ->append($this->addMediasNode()) ; + return $builder; } @@ -105,12 +106,13 @@ classes table(s). BE CAREFUL, if you change this ->validate() ->ifNotInArray([ static::INHERITANCE_TYPE_JOINED, - static::INHERITANCE_TYPE_SINGLE_TABLE + static::INHERITANCE_TYPE_SINGLE_TABLE, ]) ->thenInvalid('The %s inheritance type is not supported ("joined", "single_table" are accepted).') ->end() ->end() ; + return $node; } diff --git a/src/DependencyInjection/RoadizCoreExtension.php b/src/DependencyInjection/RoadizCoreExtension.php index dce12f58..de82ceec 100644 --- a/src/DependencyInjection/RoadizCoreExtension.php +++ b/src/DependencyInjection/RoadizCoreExtension.php @@ -9,6 +9,7 @@ use RZ\Roadiz\CoreBundle\Cache\CloudflareProxyCache; use RZ\Roadiz\CoreBundle\Cache\ReverseProxyCache; use RZ\Roadiz\CoreBundle\Cache\ReverseProxyCacheLocator; +use RZ\Roadiz\CoreBundle\DataCollector\SolariumLogger; use RZ\Roadiz\CoreBundle\Entity\CustomForm; use RZ\Roadiz\CoreBundle\Entity\Document; use RZ\Roadiz\CoreBundle\Entity\Node; @@ -18,10 +19,9 @@ use RZ\Roadiz\CoreBundle\Entity\NodeType; use RZ\Roadiz\CoreBundle\Entity\Translation; use RZ\Roadiz\CoreBundle\Repository\NodesSourcesRepository; -use RZ\Roadiz\CoreBundle\SearchEngine\SolariumLogger; -use RZ\Roadiz\CoreBundle\Webhook\Message\GenericJsonPostMessage; -use RZ\Roadiz\CoreBundle\Webhook\Message\GitlabPipelineTriggerMessage; -use RZ\Roadiz\CoreBundle\Webhook\Message\NetlifyBuildHookMessage; +use RZ\Roadiz\CoreBundle\Webhook\Message\GenericJsonPostMessageInterface; +use RZ\Roadiz\CoreBundle\Webhook\Message\GitlabPipelineTriggerMessageInterface; +use RZ\Roadiz\CoreBundle\Webhook\Message\NetlifyBuildHookMessageInterface; use RZ\Roadiz\Markdown\CommonMark; use RZ\Roadiz\Markdown\MarkdownInterface; use Solarium\Core\Client\Adapter\Curl; @@ -44,12 +44,9 @@ public function getAlias(): string return 'roadiz_core'; } - /** - * @inheritDoc - */ public function load(array $configs, ContainerBuilder $container): void { - $loader = new YamlFileLoader($container, new FileLocator(dirname(__DIR__) . '/../config')); + $loader = new YamlFileLoader($container, new FileLocator(dirname(__DIR__).'/../config')); $loader->load('services.yaml'); $configuration = new Configuration(); @@ -84,7 +81,7 @@ public function load(array $configs, ContainerBuilder $container): void $projectDir = $container->getParameter('kernel.project_dir'); $container->setParameter( 'roadiz_core.documents_lib_dir', - $projectDir . DIRECTORY_SEPARATOR . trim($config['documentsLibDir'], "/ \t\n\r\0\x0B") + $projectDir.DIRECTORY_SEPARATOR.trim($config['documentsLibDir'], "/ \t\n\r\0\x0B") ); /* * Media config @@ -116,9 +113,9 @@ public function load(array $configs, ContainerBuilder $container): void $container->setParameter('roadiz_core.medias.supported_platforms', []); $container->setParameter('roadiz_core.webhook.message_types', [ - 'webhook.type.generic_json_post' => GenericJsonPostMessage::class, - 'webhook.type.gitlab_pipeline' => GitlabPipelineTriggerMessage::class, - 'webhook.type.netlify_build_hook' => NetlifyBuildHookMessage::class, + 'webhook.type.generic_json_post' => GenericJsonPostMessageInterface::class, + 'webhook.type.gitlab_pipeline' => GitlabPipelineTriggerMessageInterface::class, + 'webhook.type.netlify_build_hook' => NetlifyBuildHookMessageInterface::class, ]); $this->registerEntityGenerator($config, $container); @@ -132,7 +129,7 @@ private function registerReverseProxyCache(array $config, ContainerBuilder $cont $reverseProxyCacheFrontendsReferences = []; if (isset($config['reverseProxyCache'])) { foreach ($config['reverseProxyCache']['frontend'] as $name => $frontend) { - $definitionName = 'roadiz_core.reverse_proxy_cache.frontends.' . $name; + $definitionName = 'roadiz_core.reverse_proxy_cache.frontends.'.$name; $container->setDefinition( $definitionName, (new Definition()) @@ -149,8 +146,8 @@ private function registerReverseProxyCache(array $config, ContainerBuilder $cont } if ( - isset($config['reverseProxyCache']['cloudflare']) && - isset($config['reverseProxyCache']['cloudflare']['bearer']) + isset($config['reverseProxyCache']['cloudflare']) + && isset($config['reverseProxyCache']['cloudflare']['bearer']) ) { $container->setDefinition( 'roadiz_core.reverse_proxy_cache.cloudflare', @@ -180,7 +177,7 @@ private function registerReverseProxyCache(array $config, ContainerBuilder $cont new Reference( 'roadiz_core.reverse_proxy_cache.cloudflare', ContainerInterface::NULL_ON_INVALID_REFERENCE - ) + ), ]) ); } @@ -217,16 +214,16 @@ private function registerSolr(array $config, ContainerBuilder $container): void if (isset($config['solr'])) { foreach ($config['solr']['endpoints'] as $name => $endpoint) { $container->setDefinition( - 'roadiz_core.solr.endpoints.' . $name, + 'roadiz_core.solr.endpoints.'.$name, (new Definition()) ->setClass(Endpoint::class) ->setPublic(true) ->setArguments([ - $endpoint + $endpoint, ]) ->addMethodCall('setKey', [$name]) ); - $solrEndpoints[] = 'roadiz_core.solr.endpoints.' . $name; + $solrEndpoints[] = 'roadiz_core.solr.endpoints.'.$name; } } if (count($solrEndpoints) > 0) { @@ -240,7 +237,7 @@ private function registerSolr(array $config, ContainerBuilder $container): void ->setShared(true) ->setArguments([ new Reference('roadiz_core.solr.adapter'), - new Reference(EventDispatcherInterface::class) + new Reference(EventDispatcherInterface::class), ]) ->addMethodCall('registerPlugin', ['roadiz_core.solr.client.logger', $logger]) ->addMethodCall('setEndpoints', [array_map(function (string $endpointId) { @@ -258,26 +255,26 @@ private function registerMarkdown(array $config, ContainerBuilder $container): v 'open_in_new_window' => true, 'noopener' => 'external', 'noreferrer' => 'external', - ] + ], ]); /** @var array $defaultConfig */ $defaultConfig = $container->getParameter('roadiz_core.markdown_config_default'); $container->setParameter( 'roadiz_core.markdown_config_text_converter', array_merge($defaultConfig, [ - 'html_input' => 'allow' + 'html_input' => 'allow', ]) ); $container->setParameter( 'roadiz_core.markdown_config_text_extra_converter', array_merge($defaultConfig, [ - 'html_input' => 'allow' + 'html_input' => 'allow', ]) ); $container->setParameter( 'roadiz_core.markdown_config_line_converter', array_merge($defaultConfig, [ - 'html_input' => 'escape' + 'html_input' => 'escape', ]) ); @@ -299,7 +296,7 @@ private function registerMarkdown(array $config, ContainerBuilder $container): v ->setShared(true) ->setPublic(true) ->setArguments([ - new Reference('roadiz_core.markdown.environments.text_converter') + new Reference('roadiz_core.markdown.environments.text_converter'), ]) ); @@ -321,7 +318,7 @@ private function registerMarkdown(array $config, ContainerBuilder $container): v ->setShared(true) ->setPublic(true) ->setArguments([ - new Reference('roadiz_core.markdown.environments.text_extra_converter') + new Reference('roadiz_core.markdown.environments.text_extra_converter'), ]) ); @@ -343,7 +340,7 @@ private function registerMarkdown(array $config, ContainerBuilder $container): v ->setShared(true) ->setPublic(true) ->setArguments([ - new Reference('roadiz_core.markdown.environments.line_converter') + new Reference('roadiz_core.markdown.environments.line_converter'), ]) ); diff --git a/src/Doctrine/Event/FilterNodesSourcesQueryBuilderCriteriaEvent.php b/src/Doctrine/Event/FilterNodesSourcesQueryBuilderCriteriaEvent.php index ee8da9b0..5337a9d1 100644 --- a/src/Doctrine/Event/FilterNodesSourcesQueryBuilderCriteriaEvent.php +++ b/src/Doctrine/Event/FilterNodesSourcesQueryBuilderCriteriaEvent.php @@ -5,28 +5,26 @@ namespace RZ\Roadiz\CoreBundle\Doctrine\Event; use Doctrine\ORM\QueryBuilder; -use RZ\Roadiz\CoreBundle\Entity\NodesSources; use RZ\Roadiz\CoreBundle\Doctrine\Event\QueryBuilder\QueryBuilderBuildEvent; +use RZ\Roadiz\CoreBundle\Entity\NodesSources; -/** - * @package RZ\Roadiz\CoreBundle\Doctrine\Event - */ abstract class FilterNodesSourcesQueryBuilderCriteriaEvent extends QueryBuilderBuildEvent { /** - * @inheritDoc + * @param class-string $actualEntityName */ - public function __construct(QueryBuilder $queryBuilder, $property, $value, $actualEntityName) - { + public function __construct( + QueryBuilder $queryBuilder, + string $property, + mixed $value, + string $actualEntityName, + ) { parent::__construct($queryBuilder, NodesSources::class, $property, $value, $actualEntityName); } - /** - * @inheritDoc - */ public function supports(): bool { - if ($this->actualEntityName === NodesSources::class) { + if (NodesSources::class === $this->actualEntityName) { return true; } diff --git a/src/Doctrine/Event/FilterQueryBuilderCriteriaEvent.php b/src/Doctrine/Event/FilterQueryBuilderCriteriaEvent.php index 974ff248..3e056d90 100644 --- a/src/Doctrine/Event/FilterQueryBuilderCriteriaEvent.php +++ b/src/Doctrine/Event/FilterQueryBuilderCriteriaEvent.php @@ -7,88 +7,49 @@ use Doctrine\ORM\QueryBuilder; use Symfony\Contracts\EventDispatcher\Event; -/** - * @package RZ\Roadiz\CoreBundle\Doctrine\Event - */ abstract class FilterQueryBuilderCriteriaEvent extends Event { - protected string $property; /** - * @var mixed - */ - protected $value; - protected QueryBuilder $queryBuilder; - /** - * @var class-string - */ - protected string $entityClass; - /** - * @var class-string - */ - protected string $actualEntityName; - - /** - * @param QueryBuilder $queryBuilder * @param class-string $entityClass - * @param string $property - * @param mixed $value * @param class-string $actualEntityName */ - public function __construct(QueryBuilder $queryBuilder, string $entityClass, string $property, $value, string $actualEntityName) - { - $this->queryBuilder = $queryBuilder; - $this->entityClass = $entityClass; - $this->property = $property; - $this->value = $value; - $this->actualEntityName = $actualEntityName; + public function __construct( + protected QueryBuilder $queryBuilder, + protected string $entityClass, + protected string $property, + protected mixed $value, + protected string $actualEntityName, + ) { } - /** - * @return QueryBuilder - */ public function getQueryBuilder(): QueryBuilder { return $this->queryBuilder; } - /** - * @param QueryBuilder $queryBuilder - * @return FilterQueryBuilderCriteriaEvent - */ public function setQueryBuilder(QueryBuilder $queryBuilder): self { $this->queryBuilder = $queryBuilder; + return $this; } - /** - * @return string - */ - public function getProperty() + public function supports(): bool { - return $this->property; + return $this->entityClass === $this->actualEntityName; } - /** - * @return mixed - */ - public function getValue() + public function getProperty(): string { - return $this->value; + return $this->property; } - /** - * @return bool - */ - public function supports(): bool + public function getValue(): mixed { - return $this->entityClass === $this->actualEntityName; + return $this->value; } - /** - * @return string - */ - public function getActualEntityName() + public function getActualEntityName(): string { return $this->actualEntityName; } diff --git a/src/Doctrine/Event/FilterQueryBuilderEvent.php b/src/Doctrine/Event/FilterQueryBuilderEvent.php index 202811ca..a3aa4c20 100644 --- a/src/Doctrine/Event/FilterQueryBuilderEvent.php +++ b/src/Doctrine/Event/FilterQueryBuilderEvent.php @@ -7,52 +7,32 @@ use Doctrine\ORM\QueryBuilder; use Symfony\Contracts\EventDispatcher\Event; -/** - * @package RZ\Roadiz\CoreBundle\Doctrine\Event - */ abstract class FilterQueryBuilderEvent extends Event { /** - * @var QueryBuilder - */ - private QueryBuilder $queryBuilder; - /** - * @var class-string - */ - private string $entityClass; - - /** - * @param QueryBuilder $queryBuilder * @param class-string $entityClass */ - public function __construct(QueryBuilder $queryBuilder, string $entityClass) + public function __construct(private QueryBuilder $queryBuilder, private readonly string $entityClass) { - $this->queryBuilder = $queryBuilder; - $this->entityClass = $entityClass; } - /** - * @return QueryBuilder - */ public function getQueryBuilder(): QueryBuilder { return $this->queryBuilder; } /** - * @param QueryBuilder $queryBuilder * @return FilterQueryBuilderEvent */ public function setQueryBuilder(QueryBuilder $queryBuilder) { $this->queryBuilder = $queryBuilder; + return $this; } - /** * @param class-string $entityClass - * @return bool */ public function supports(string $entityClass): bool { diff --git a/src/Doctrine/Event/FilterQueryCriteriaEvent.php b/src/Doctrine/Event/FilterQueryCriteriaEvent.php index baa4f5c5..23b761e4 100644 --- a/src/Doctrine/Event/FilterQueryCriteriaEvent.php +++ b/src/Doctrine/Event/FilterQueryCriteriaEvent.php @@ -10,78 +10,46 @@ abstract class FilterQueryCriteriaEvent extends Event { /** - * @var string - */ - protected string $property; - /** - * @var mixed - */ - protected $value; - /** - * @var class-string - */ - protected string $entityClass; - /** - * @var Query - */ - protected Query $query; - - /** - * @param Query $query * @param class-string $entityClass - * @param string $property - * @param mixed $value */ - public function __construct(Query $query, string $entityClass, string $property, $value) + public function __construct(protected Query $query, protected string $entityClass, protected string $property, protected mixed $value) { - $this->entityClass = $entityClass; - $this->property = $property; - $this->value = $value; - $this->query = $query; } - /** - * @return Query - */ public function getQuery(): Query { return $this->query; } /** - * @param Query $query - * - * @return FilterQueryCriteriaEvent + * @return $this */ - public function setQuery(Query $query) + public function setQuery(Query $query): self { $this->query = $query; return $this; } - /** - * @return string - */ - public function getProperty() + public function getEntityClass(): string + { + return $this->entityClass; + } + + public function getProperty(): string { return $this->property; } - /** - * @return mixed - */ - public function getValue() + public function getValue(): mixed { return $this->value; } - /** - * @param string $entityClass - * @return bool + * @param class-string $entityClass */ - public function supports($entityClass): bool + public function supports(string $entityClass): bool { return $this->entityClass === $entityClass; } diff --git a/src/Doctrine/Event/QueryEvent.php b/src/Doctrine/Event/QueryEvent.php index dc85f161..ce966683 100644 --- a/src/Doctrine/Event/QueryEvent.php +++ b/src/Doctrine/Event/QueryEvent.php @@ -9,26 +9,13 @@ class QueryEvent extends Event { - protected Query $query; - - /** - * @var class-string - */ - protected string $entityClass; - /** - * @param Query $query * @param class-string $entityClass */ - public function __construct(Query $query, string $entityClass) + public function __construct(protected Query $query, protected string $entityClass) { - $this->query = $query; - $this->entityClass = $entityClass; } - /** - * @return Query - */ public function getQuery(): Query { return $this->query; diff --git a/src/Doctrine/Event/QueryNodesSourcesEvent.php b/src/Doctrine/Event/QueryNodesSourcesEvent.php index 07999c22..8ec8187f 100644 --- a/src/Doctrine/Event/QueryNodesSourcesEvent.php +++ b/src/Doctrine/Event/QueryNodesSourcesEvent.php @@ -10,7 +10,6 @@ final class QueryNodesSourcesEvent extends QueryEvent { /** - * @param Query $query * @param class-string $actualEntityName */ public function __construct(Query $query, private readonly string $actualEntityName) @@ -27,12 +26,11 @@ public function getActualEntityName(): string } /** - * @return bool * @throws \ReflectionException */ public function supports(): bool { - if ($this->actualEntityName === NodesSources::class) { + if (NodesSources::class === $this->actualEntityName) { return true; } diff --git a/src/Doctrine/EventSubscriber/AttributeValueLifeCycleSubscriber.php b/src/Doctrine/EventSubscriber/AttributeValueLifeCycleSubscriber.php index 4e7ada54..96c1fdd2 100644 --- a/src/Doctrine/EventSubscriber/AttributeValueLifeCycleSubscriber.php +++ b/src/Doctrine/EventSubscriber/AttributeValueLifeCycleSubscriber.php @@ -4,37 +4,23 @@ namespace RZ\Roadiz\CoreBundle\Doctrine\EventSubscriber; -use ArrayIterator; -use Doctrine\Common\EventSubscriber; -use Doctrine\Persistence\Event\LifecycleEventArgs; +use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener; use Doctrine\ORM\Event\OnFlushEventArgs; -use Doctrine\ORM\Events; -use RZ\Roadiz\CoreBundle\Model\AttributeValueInterface; +use Doctrine\Persistence\Event\LifecycleEventArgs; use RZ\Roadiz\CoreBundle\Entity\AttributeValue; +use RZ\Roadiz\CoreBundle\Model\AttributeValueInterface; -final class AttributeValueLifeCycleSubscriber implements EventSubscriber +#[AsDoctrineListener('prePersist')] +#[AsDoctrineListener('onFlush')] +final class AttributeValueLifeCycleSubscriber { - /** - * {@inheritdoc} - */ - public function getSubscribedEvents(): array - { - return [ - Events::prePersist, - Events::onFlush, - ]; - } - - /** - * @param LifecycleEventArgs $event - */ public function prePersist(LifecycleEventArgs $event): void { $entity = $event->getObject(); if ($entity instanceof AttributeValueInterface) { if ( - null !== $entity->getAttribute() && - null !== $entity->getAttribute()->getDefaultRealm() + null !== $entity->getAttribute() + && null !== $entity->getAttribute()->getDefaultRealm() ) { $entity->setRealm($entity->getAttribute()->getDefaultRealm()); } @@ -42,7 +28,7 @@ public function prePersist(LifecycleEventArgs $event): void /* * Automatically set position only if not manually set before. */ - if ($entity->getPosition() === 0.0) { + if (0.0 === $entity->getPosition()) { /* * Get the last index after last node in parent */ @@ -50,7 +36,7 @@ public function prePersist(LifecycleEventArgs $event): void $lastPosition = 1; foreach ($nodeAttributes as $nodeAttribute) { $nodeAttribute->setPosition($lastPosition); - $lastPosition++; + ++$lastPosition; } $entity->setPosition($lastPosition); @@ -59,8 +45,6 @@ public function prePersist(LifecycleEventArgs $event): void } /** - * @param OnFlushEventArgs $eventArgs - * * @throws \Exception */ public function onFlush(OnFlushEventArgs $eventArgs): void @@ -72,13 +56,13 @@ public function onFlush(OnFlushEventArgs $eventArgs): void if ($entity instanceof AttributeValueInterface) { $classMetadata = $em->getClassMetadata(AttributeValue::class); foreach ($uow->getEntityChangeSet($entity) as $keyField => $field) { - if ($keyField === 'position') { + if ('position' === $keyField) { $nodeAttributes = $entity->getAttributable()->getAttributeValues(); /* * Need to resort collection based on updated position. */ $iterator = $nodeAttributes->getIterator(); - if ($iterator instanceof ArrayIterator) { + if ($iterator instanceof \ArrayIterator) { // define ordering closure, using preferred comparison method/field $iterator->uasort(function (AttributeValueInterface $first, AttributeValueInterface $second) { return $first->getPosition() > $second->getPosition() ? 1 : -1; @@ -90,7 +74,7 @@ public function onFlush(OnFlushEventArgs $eventArgs): void foreach ($iterator as $nodeAttribute) { $nodeAttribute->setPosition($lastPosition); $uow->computeChangeSet($classMetadata, $nodeAttribute); - $lastPosition++; + ++$lastPosition; } } } diff --git a/src/Doctrine/EventSubscriber/CustomFormFieldLifeCycleSubscriber.php b/src/Doctrine/EventSubscriber/CustomFormFieldLifeCycleSubscriber.php index 37b42b22..15c56304 100644 --- a/src/Doctrine/EventSubscriber/CustomFormFieldLifeCycleSubscriber.php +++ b/src/Doctrine/EventSubscriber/CustomFormFieldLifeCycleSubscriber.php @@ -4,31 +4,18 @@ namespace RZ\Roadiz\CoreBundle\Doctrine\EventSubscriber; -use Doctrine\Common\EventSubscriber; +use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener; use Doctrine\Persistence\Event\LifecycleEventArgs; -use Doctrine\ORM\Events; use RZ\Roadiz\CoreBundle\Entity\CustomFormField; use RZ\Roadiz\CoreBundle\EntityHandler\CustomFormFieldHandler; -final class CustomFormFieldLifeCycleSubscriber implements EventSubscriber +#[AsDoctrineListener('prePersist')] +final class CustomFormFieldLifeCycleSubscriber { public function __construct(private readonly CustomFormFieldHandler $customFormFieldHandler) { } - /** - * {@inheritdoc} - */ - public function getSubscribedEvents(): array - { - return [ - Events::prePersist, - ]; - } - - /** - * @param LifecycleEventArgs $event - */ public function prePersist(LifecycleEventArgs $event): void { $field = $event->getObject(); @@ -36,7 +23,7 @@ public function prePersist(LifecycleEventArgs $event): void /* * Automatically set position only if not manually set before. */ - if ($field->getPosition() === 0.0) { + if (0.0 === $field->getPosition()) { /* * Get the last index after last node in parent */ diff --git a/src/Doctrine/EventSubscriber/NodesSourcesInheritanceSubscriber.php b/src/Doctrine/EventSubscriber/NodesSourcesInheritanceSubscriber.php index 0f1b7c4b..d5256b85 100644 --- a/src/Doctrine/EventSubscriber/NodesSourcesInheritanceSubscriber.php +++ b/src/Doctrine/EventSubscriber/NodesSourcesInheritanceSubscriber.php @@ -4,9 +4,9 @@ namespace RZ\Roadiz\CoreBundle\Doctrine\EventSubscriber; -use Doctrine\Common\EventSubscriber; -use Doctrine\Persistence\Event\LifecycleEventArgs; +use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener; use Doctrine\ORM\Event\LoadClassMetadataEventArgs; +use Doctrine\ORM\Event\PostLoadEventArgs; use Doctrine\ORM\Events; use Doctrine\ORM\Mapping\ClassMetadataInfo; use Psr\Log\LoggerInterface; @@ -15,38 +15,29 @@ use RZ\Roadiz\CoreBundle\DependencyInjection\Configuration; use RZ\Roadiz\CoreBundle\Entity\NodesSources; use RZ\Roadiz\CoreBundle\Entity\NodeType; +use Symfony\Component\Stopwatch\Stopwatch; -final class NodesSourcesInheritanceSubscriber implements EventSubscriber +#[AsDoctrineListener(event: Events::postLoad)] +#[AsDoctrineListener(event: Events::loadClassMetadata)] +final class NodesSourcesInheritanceSubscriber { public function __construct( private readonly NodeTypes $nodeTypes, private readonly string $inheritanceType, - private readonly LoggerInterface $logger + private readonly LoggerInterface $logger, + private readonly Stopwatch $stopwatch, ) { } - /** - * @inheritDoc - */ - public function getSubscribedEvents(): array - { - return [ - Events::loadClassMetadata, - Events::postLoad - ]; - } - - public function postLoad(LifecycleEventArgs $event): void + public function postLoad(PostLoadEventArgs $event): void { $object = $event->getObject(); - if ($object instanceof NodesSources) { - $object->injectObjectManager($event->getObjectManager()); + if (!$object instanceof NodesSources) { + return; } + $object->injectObjectManager($event->getObjectManager()); } - /** - * @param LoadClassMetadataEventArgs $eventArgs - */ public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs): void { // the $metadata is all the mapping info for this class @@ -55,7 +46,8 @@ public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs): void // obtained from the $metadata $class = $metadata->getReflectionClass(); - if ($class->getName() === NodesSources::class) { + if (NodesSources::class === $class->getName()) { + $this->stopwatch->start('NodesSources loadClassMetadata'); try { /** @var NodeType[] $nodeTypes */ $nodeTypes = $this->nodeTypes->all(); @@ -82,6 +74,7 @@ public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs): void ['columns' => ['discr']], ['columns' => ['title']], ['columns' => ['published_at']], + 'ns_no_index' => ['columns' => ['no_index']], 'ns_node_translation_published' => ['columns' => ['node_id', 'translation_id', 'published_at']], 'ns_node_discr_translation' => ['columns' => ['node_id', 'discr', 'translation_id']], 'ns_node_discr_translation_published' => ['columns' => ['node_id', 'discr', 'translation_id', 'published_at']], @@ -92,13 +85,13 @@ public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs): void 'ns_title_translation_published' => ['columns' => ['title', 'translation_id', 'published_at']], ], 'uniqueConstraints' => [ - ['columns' => ["node_id", "translation_id"]] - ] + ['columns' => ['node_id', 'translation_id']], + ], ]; - if ($this->inheritanceType === Configuration::INHERITANCE_TYPE_JOINED) { + if (Configuration::INHERITANCE_TYPE_JOINED === $this->inheritanceType) { $metadata->setInheritanceType(ClassMetadataInfo::INHERITANCE_TYPE_JOINED); - } elseif ($this->inheritanceType === Configuration::INHERITANCE_TYPE_SINGLE_TABLE) { + } elseif (Configuration::INHERITANCE_TYPE_SINGLE_TABLE === $this->inheritanceType) { $metadata->setInheritanceType(ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_TABLE); /* * If inheritance type is single table, we need to set indexes on parent class: NodesSources @@ -109,13 +102,13 @@ public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs): void }); /** @var NodeTypeFieldInterface $indexedField */ foreach ($indexedFields as $indexedField) { - $nodeSourceTableAnnotation['indexes']['nsapp_' . $indexedField->getName()] = [ + $nodeSourceTableAnnotation['indexes']['nsapp_'.$indexedField->getName()] = [ 'columns' => [$indexedField->getName()], ]; } } } else { - throw new \RuntimeException('Inheritance type not supported: ' . $this->inheritanceType); + throw new \RuntimeException('Inheritance type not supported: '.$this->inheritanceType); } $metadata->setPrimaryTable($nodeSourceTableAnnotation); } catch (\Exception $e) { @@ -124,6 +117,8 @@ public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs): void * Need Install */ } + + $this->stopwatch->stop('NodesSources loadClassMetadata'); } } } diff --git a/src/Doctrine/EventSubscriber/UserLifeCycleSubscriber.php b/src/Doctrine/EventSubscriber/UserLifeCycleSubscriber.php index 0e3b98f8..80d085fa 100644 --- a/src/Doctrine/EventSubscriber/UserLifeCycleSubscriber.php +++ b/src/Doctrine/EventSubscriber/UserLifeCycleSubscriber.php @@ -4,10 +4,10 @@ namespace RZ\Roadiz\CoreBundle\Doctrine\EventSubscriber; -use Doctrine\Common\EventSubscriber; -use Doctrine\Persistence\Event\LifecycleEventArgs; +use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener; use Doctrine\ORM\Event\PreUpdateEventArgs; use Doctrine\ORM\Events; +use Doctrine\Persistence\Event\LifecycleEventArgs; use Psr\Log\LoggerInterface; use RZ\Roadiz\CoreBundle\Entity\User; use RZ\Roadiz\CoreBundle\Event\User\UserCreatedEvent; @@ -22,51 +22,38 @@ use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; -final class UserLifeCycleSubscriber implements EventSubscriber +#[AsDoctrineListener(event: Events::preUpdate)] +#[AsDoctrineListener(event: Events::prePersist)] +#[AsDoctrineListener(event: Events::postPersist)] +#[AsDoctrineListener(event: Events::postUpdate)] +#[AsDoctrineListener(event: Events::postRemove)] +final readonly class UserLifeCycleSubscriber { public function __construct( - private readonly UserViewer $userViewer, - private readonly EventDispatcherInterface $dispatcher, - private readonly PasswordHasherFactoryInterface $passwordHasherFactory, - private readonly LoggerInterface $logger, - private readonly bool $useGravatar + private UserViewer $userViewer, + private EventDispatcherInterface $dispatcher, + private PasswordHasherFactoryInterface $passwordHasherFactory, + private FacebookPictureFinder $facebookPictureFinder, + private LoggerInterface $logger, + private bool $useGravatar, ) { } - /** - * {@inheritdoc} - */ - public function getSubscribedEvents(): array - { - return [ - Events::preUpdate, - Events::prePersist, - Events::postPersist, - Events::postUpdate, - Events::postRemove, - ]; - } - - /** - * @param PreUpdateEventArgs $event - * @return void - * @throws \GuzzleHttp\Exception\GuzzleException - */ public function preUpdate(PreUpdateEventArgs $event): void { - $user = $event->getEntity(); + $user = $event->getObject(); if ($user instanceof User) { if ( - $event->hasChangedField('enabled') && - true === $event->getNewValue('enabled') + $event->hasChangedField('enabled') + && true === $event->getNewValue('enabled') ) { $userEvent = new UserEnabledEvent($user); $this->dispatcher->dispatch($userEvent); } if ( - $event->hasChangedField('enabled') && - false === $event->getNewValue('enabled') + $event->hasChangedField('enabled') + && false === $event->getNewValue('enabled') ) { $userEvent = new UserDisabledEvent($user); $this->dispatcher->dispatch($userEvent); @@ -75,8 +62,7 @@ public function preUpdate(PreUpdateEventArgs $event): void if ($event->hasChangedField('facebookName')) { if ('' != $event->getNewValue('facebookName')) { try { - $facebook = new FacebookPictureFinder($user->getFacebookName()); - $url = $facebook->getPictureUrl(); + $url = $this->facebookPictureFinder->getPictureUrl($user->getFacebookName()); $user->setPictureUrl($url); } catch (\Exception $e) { $user->setFacebookName(''); @@ -92,9 +78,9 @@ public function preUpdate(PreUpdateEventArgs $event): void * Encode user password */ if ( - $event->hasChangedField('password') && - null !== $user->getPlainPassword() && - '' !== $user->getPlainPassword() + $event->hasChangedField('password') + && null !== $user->getPlainPassword() + && '' !== $user->getPlainPassword() ) { $this->setPassword($user, $user->getPlainPassword()); $userEvent = new UserPasswordChangedEvent($user); @@ -103,10 +89,6 @@ public function preUpdate(PreUpdateEventArgs $event): void } } - /** - * @param User $user - * @param string|null $plainPassword - */ protected function setPassword(User $user, ?string $plainPassword): void { if (null !== $plainPassword) { @@ -116,9 +98,6 @@ protected function setPassword(User $user, ?string $plainPassword): void } } - /** - * @param LifecycleEventArgs $event - */ public function postUpdate(LifecycleEventArgs $event): void { $user = $event->getObject(); @@ -128,9 +107,6 @@ public function postUpdate(LifecycleEventArgs $event): void } } - /** - * @param LifecycleEventArgs $event - */ public function postRemove(LifecycleEventArgs $event): void { $user = $event->getObject(); @@ -141,8 +117,6 @@ public function postRemove(LifecycleEventArgs $event): void } /** - * @param LifecycleEventArgs $event - * * @throws \Exception */ public function postPersist(LifecycleEventArgs $event): void @@ -155,7 +129,6 @@ public function postPersist(LifecycleEventArgs $event): void } /** - * @param LifecycleEventArgs $event * @throws \Throwable */ public function prePersist(LifecycleEventArgs $event): void @@ -163,9 +136,9 @@ public function prePersist(LifecycleEventArgs $event): void $user = $event->getObject(); if ($user instanceof User) { if ( - $user->willSendCreationConfirmationEmail() && - (null === $user->getPlainPassword() || - $user->getPlainPassword() === '') + $user->willSendCreationConfirmationEmail() + && (null === $user->getPlainPassword() + || '' === $user->getPlainPassword()) ) { /* * Do not generate password for new users diff --git a/src/Doctrine/ORM/Filter/ANodesFilter.php b/src/Doctrine/ORM/Filter/ANodesFilter.php index ebfcb49e..5e654e85 100644 --- a/src/Doctrine/ORM/Filter/ANodesFilter.php +++ b/src/Doctrine/ORM/Filter/ANodesFilter.php @@ -4,50 +4,38 @@ namespace RZ\Roadiz\CoreBundle\Doctrine\ORM\Filter; -use RZ\Roadiz\CoreBundle\Entity\Node; use RZ\Roadiz\CoreBundle\Doctrine\Event\QueryBuilder\QueryBuilderBuildEvent; use RZ\Roadiz\CoreBundle\Doctrine\Event\QueryBuilder\QueryBuilderNodesSourcesBuildEvent; -use RZ\Roadiz\CoreBundle\Repository\EntityRepository; use RZ\Roadiz\CoreBundle\Doctrine\ORM\SimpleQueryBuilder; +use RZ\Roadiz\CoreBundle\Entity\Node; +use RZ\Roadiz\CoreBundle\Repository\EntityRepository; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -/** - * @package RZ\Roadiz\CoreBundle\Doctrine\ORM\Filter - */ class ANodesFilter implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [ QueryBuilderNodesSourcesBuildEvent::class => [['onNodesSourcesQueryBuilderBuild', 40]], - QueryBuilderBuildEvent::class => [['onNodeQueryBuilderBuild', 30]] + QueryBuilderBuildEvent::class => [['onNodeQueryBuilderBuild', 30]], ]; } - /** - * @return string - */ protected function getProperty(): string { return 'aNodes'; } - /** - * @return string - */ protected function getNodeJoinAlias(): string { return 'a_n'; } - /** - * @param QueryBuilderBuildEvent $event - */ public function onNodeQueryBuilderBuild(QueryBuilderBuildEvent $event): void { - if ($event->supports() && $event->getActualEntityName() === Node::class) { + if ($event->supports() && Node::class === $event->getActualEntityName()) { $simpleQB = new SimpleQueryBuilder($event->getQueryBuilder()); - if (str_contains($event->getProperty(), $this->getProperty() . '.')) { + if (str_contains($event->getProperty(), $this->getProperty().'.')) { // Prevent other query builder filters to execute $event->stopPropagation(); $qb = $event->getQueryBuilder(); @@ -60,27 +48,24 @@ public function onNodeQueryBuilderBuild(QueryBuilderBuildEvent $event): void ) ) { $qb->innerJoin( - $simpleQB->getRootAlias() . '.' . $this->getProperty(), + $simpleQB->getRootAlias().'.'.$this->getProperty(), $this->getNodeJoinAlias() ); } - $prefix = $this->getNodeJoinAlias() . '.'; - $key = str_replace($this->getProperty() . '.', '', $event->getProperty()); + $prefix = $this->getNodeJoinAlias().'.'; + $key = str_replace($this->getProperty().'.', '', $event->getProperty()); $qb->andWhere($simpleQB->buildExpressionWithoutBinding($event->getValue(), $prefix, $key, $baseKey)); } } } - /** - * @param QueryBuilderNodesSourcesBuildEvent $event - */ public function onNodesSourcesQueryBuilderBuild(QueryBuilderNodesSourcesBuildEvent $event): void { if ($event->supports()) { $simpleQB = new SimpleQueryBuilder($event->getQueryBuilder()); - if (str_contains($event->getProperty(), 'node.' . $this->getProperty() . '.')) { + if (str_contains($event->getProperty(), 'node.'.$this->getProperty().'.')) { // Prevent other query builder filters to execute $event->stopPropagation(); $qb = $event->getQueryBuilder(); @@ -93,7 +78,7 @@ public function onNodesSourcesQueryBuilderBuild(QueryBuilderNodesSourcesBuildEve ) ) { $qb->innerJoin( - $simpleQB->getRootAlias() . '.node', + $simpleQB->getRootAlias().'.node', EntityRepository::NODE_ALIAS ); } @@ -105,13 +90,13 @@ public function onNodesSourcesQueryBuilderBuild(QueryBuilderNodesSourcesBuildEve ) ) { $qb->innerJoin( - EntityRepository::NODE_ALIAS . '.' . $this->getProperty(), + EntityRepository::NODE_ALIAS.'.'.$this->getProperty(), $this->getNodeJoinAlias() ); } - $prefix = $this->getNodeJoinAlias() . '.'; - $key = str_replace('node.' . $this->getProperty() . '.', '', $event->getProperty()); + $prefix = $this->getNodeJoinAlias().'.'; + $key = str_replace('node.'.$this->getProperty().'.', '', $event->getProperty()); $qb->andWhere($simpleQB->buildExpressionWithoutBinding($event->getValue(), $prefix, $key, $baseKey)); } diff --git a/src/Doctrine/ORM/Filter/BNodesFilter.php b/src/Doctrine/ORM/Filter/BNodesFilter.php index 8cb6f894..4b15cb47 100644 --- a/src/Doctrine/ORM/Filter/BNodesFilter.php +++ b/src/Doctrine/ORM/Filter/BNodesFilter.php @@ -7,30 +7,21 @@ use RZ\Roadiz\CoreBundle\Doctrine\Event\QueryBuilder\QueryBuilderBuildEvent; use RZ\Roadiz\CoreBundle\Doctrine\Event\QueryBuilder\QueryBuilderNodesSourcesBuildEvent; -/** - * @package RZ\Roadiz\CoreBundle\Doctrine\ORM\Filter - */ class BNodesFilter extends ANodesFilter { public static function getSubscribedEvents(): array { return [ QueryBuilderNodesSourcesBuildEvent::class => [['onNodesSourcesQueryBuilderBuild', 40]], - QueryBuilderBuildEvent::class => [['onNodeQueryBuilderBuild', 30]] + QueryBuilderBuildEvent::class => [['onNodeQueryBuilderBuild', 30]], ]; } - /** - * @return string - */ protected function getProperty(): string { return 'bNodes'; } - /** - * @return string - */ protected function getNodeJoinAlias(): string { return 'b_n'; diff --git a/src/Doctrine/ORM/Filter/NodeTranslationFilter.php b/src/Doctrine/ORM/Filter/NodeTranslationFilter.php index 5f86e660..d7d22312 100644 --- a/src/Doctrine/ORM/Filter/NodeTranslationFilter.php +++ b/src/Doctrine/ORM/Filter/NodeTranslationFilter.php @@ -4,16 +4,14 @@ namespace RZ\Roadiz\CoreBundle\Doctrine\ORM\Filter; -use RZ\Roadiz\CoreBundle\Entity\Node; use RZ\Roadiz\CoreBundle\Doctrine\Event\QueryBuilder\QueryBuilderBuildEvent; -use RZ\Roadiz\CoreBundle\Repository\EntityRepository; use RZ\Roadiz\CoreBundle\Doctrine\ORM\SimpleQueryBuilder; +use RZ\Roadiz\CoreBundle\Entity\Node; +use RZ\Roadiz\CoreBundle\Repository\EntityRepository; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** * Filter on translation fields when criteria contains translation. prefix. - * - * @package RZ\Roadiz\CoreBundle\Doctrine\ORM\Filter */ class NodeTranslationFilter implements EventSubscriberInterface { @@ -24,25 +22,17 @@ public static function getSubscribedEvents(): array // This event must be the last to perform ['onTranslationPrefixFilter', 0], ['onTranslationFilter', -10], - ] + ], ]; } - /** - * @param QueryBuilderBuildEvent $event - * - * @return bool - */ protected function supports(QueryBuilderBuildEvent $event): bool { - return $event->supports() && - $event->getActualEntityName() === Node::class && - str_contains($event->getProperty(), 'translation'); + return $event->supports() + && Node::class === $event->getActualEntityName() + && str_contains($event->getProperty(), 'translation'); } - /** - * @param QueryBuilderBuildEvent $event - */ public function onTranslationPrefixFilter(QueryBuilderBuildEvent $event): void { if ($this->supports($event)) { @@ -60,7 +50,7 @@ public function onTranslationPrefixFilter(QueryBuilderBuildEvent $event): void ) ) { $qb->innerJoin( - $simpleQB->getRootAlias() . '.nodeSources', + $simpleQB->getRootAlias().'.nodeSources', EntityRepository::NODESSOURCES_ALIAS ); } @@ -72,26 +62,23 @@ public function onTranslationPrefixFilter(QueryBuilderBuildEvent $event): void ) ) { $qb->innerJoin( - EntityRepository::NODESSOURCES_ALIAS . '.translation', + EntityRepository::NODESSOURCES_ALIAS.'.translation', EntityRepository::TRANSLATION_ALIAS ); } - $prefix = EntityRepository::TRANSLATION_ALIAS . '.'; + $prefix = EntityRepository::TRANSLATION_ALIAS.'.'; $key = str_replace('translation.', '', $event->getProperty()); $qb->andWhere($simpleQB->buildExpressionWithoutBinding($event->getValue(), $prefix, $key, $baseKey)); } } } - /** - * @param QueryBuilderBuildEvent $event - */ public function onTranslationFilter(QueryBuilderBuildEvent $event): void { if ($this->supports($event)) { $simpleQB = new SimpleQueryBuilder($event->getQueryBuilder()); - if ($event->getProperty() === 'translation') { + if ('translation' === $event->getProperty()) { // Prevent other query builder filters to execute $event->stopPropagation(); $qb = $event->getQueryBuilder(); @@ -104,12 +91,12 @@ public function onTranslationFilter(QueryBuilderBuildEvent $event): void ) ) { $qb->innerJoin( - $simpleQB->getRootAlias() . '.nodeSources', + $simpleQB->getRootAlias().'.nodeSources', EntityRepository::NODESSOURCES_ALIAS ); } - $prefix = EntityRepository::NODESSOURCES_ALIAS . '.'; + $prefix = EntityRepository::NODESSOURCES_ALIAS.'.'; $key = $event->getProperty(); $qb->andWhere($simpleQB->buildExpressionWithoutBinding($event->getValue(), $prefix, $key, $baseKey)); } diff --git a/src/Doctrine/ORM/Filter/NodeTypeFilter.php b/src/Doctrine/ORM/Filter/NodeTypeFilter.php index 561797e7..3da315da 100644 --- a/src/Doctrine/ORM/Filter/NodeTypeFilter.php +++ b/src/Doctrine/ORM/Filter/NodeTypeFilter.php @@ -6,14 +6,12 @@ use RZ\Roadiz\CoreBundle\Doctrine\Event\QueryBuilder\QueryBuilderBuildEvent; use RZ\Roadiz\CoreBundle\Doctrine\Event\QueryBuilder\QueryBuilderNodesSourcesBuildEvent; -use RZ\Roadiz\CoreBundle\Repository\EntityRepository; use RZ\Roadiz\CoreBundle\Doctrine\ORM\SimpleQueryBuilder; +use RZ\Roadiz\CoreBundle\Repository\EntityRepository; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** * Filter on nodeType fields when criteria contains nodeType. prefix. - * - * @package RZ\Roadiz\CoreBundle\Doctrine\ORM\Filter */ class NodeTypeFilter implements EventSubscriberInterface { @@ -23,7 +21,7 @@ public static function getSubscribedEvents(): array QueryBuilderNodesSourcesBuildEvent::class => [['onNodesSourcesQueryBuilderBuild', 40]], QueryBuilderBuildEvent::class => [ ['onNodeQueryBuilderBuild', 30], - ] + ], ]; } @@ -32,9 +30,6 @@ protected function supports(QueryBuilderBuildEvent $event): bool return $event->supports() && str_contains($event->getProperty(), 'nodeType.'); } - /** - * @param QueryBuilderBuildEvent $event - */ public function onNodeQueryBuilderBuild(QueryBuilderBuildEvent $event): void { if ($this->supports($event)) { @@ -52,20 +47,17 @@ public function onNodeQueryBuilderBuild(QueryBuilderBuildEvent $event): void ) { $qb->addSelect(EntityRepository::NODETYPE_ALIAS); $qb->innerJoin( - $simpleQB->getRootAlias() . '.nodeType', + $simpleQB->getRootAlias().'.nodeType', EntityRepository::NODETYPE_ALIAS ); } - $prefix = EntityRepository::NODETYPE_ALIAS . '.'; + $prefix = EntityRepository::NODETYPE_ALIAS.'.'; $key = str_replace('nodeType.', '', $event->getProperty()); $qb->andWhere($simpleQB->buildExpressionWithoutBinding($event->getValue(), $prefix, $key, $baseKey)); } } - /** - * @param QueryBuilderNodesSourcesBuildEvent $event - */ public function onNodesSourcesQueryBuilderBuild(QueryBuilderNodesSourcesBuildEvent $event): void { if ($this->supports($event)) { @@ -83,7 +75,7 @@ public function onNodesSourcesQueryBuilderBuild(QueryBuilderNodesSourcesBuildEve ) ) { $qb->innerJoin( - $simpleQB->getRootAlias() . '.node', + $simpleQB->getRootAlias().'.node', EntityRepository::NODE_ALIAS ); } @@ -95,12 +87,12 @@ public function onNodesSourcesQueryBuilderBuild(QueryBuilderNodesSourcesBuildEve ) { $qb->addSelect(EntityRepository::NODETYPE_ALIAS); $qb->innerJoin( - EntityRepository::NODE_ALIAS . '.nodeType', + EntityRepository::NODE_ALIAS.'.nodeType', EntityRepository::NODETYPE_ALIAS ); } - $prefix = EntityRepository::NODETYPE_ALIAS . '.'; + $prefix = EntityRepository::NODETYPE_ALIAS.'.'; $key = str_replace('node.nodeType.', '', $event->getProperty()); $qb->andWhere($simpleQB->buildExpressionWithoutBinding($event->getValue(), $prefix, $key, $baseKey)); } diff --git a/src/Doctrine/ORM/Filter/NodesSourcesNodeFilter.php b/src/Doctrine/ORM/Filter/NodesSourcesNodeFilter.php index 3a4f3310..18ffc69f 100644 --- a/src/Doctrine/ORM/Filter/NodesSourcesNodeFilter.php +++ b/src/Doctrine/ORM/Filter/NodesSourcesNodeFilter.php @@ -5,14 +5,12 @@ namespace RZ\Roadiz\CoreBundle\Doctrine\ORM\Filter; use RZ\Roadiz\CoreBundle\Doctrine\Event\QueryBuilder\QueryBuilderNodesSourcesBuildEvent; -use RZ\Roadiz\CoreBundle\Repository\EntityRepository; use RZ\Roadiz\CoreBundle\Doctrine\ORM\SimpleQueryBuilder; +use RZ\Roadiz\CoreBundle\Repository\EntityRepository; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** * Filter on nodeType fields when criteria contains nodeType. prefix. - * - * @package RZ\Roadiz\CoreBundle\Doctrine\ORM\Filter */ class NodesSourcesNodeFilter implements EventSubscriberInterface { @@ -23,19 +21,11 @@ public static function getSubscribedEvents(): array ]; } - /** - * @param QueryBuilderNodesSourcesBuildEvent $event - * - * @return bool - */ protected function supports(QueryBuilderNodesSourcesBuildEvent $event): bool { return $event->supports() && str_contains($event->getProperty(), 'node.'); } - /** - * @param QueryBuilderNodesSourcesBuildEvent $event - */ public function onNodesSourcesQueryBuilderBuild(QueryBuilderNodesSourcesBuildEvent $event): void { if ($this->supports($event)) { @@ -52,12 +42,12 @@ public function onNodesSourcesQueryBuilderBuild(QueryBuilderNodesSourcesBuildEve ) ) { $qb->innerJoin( - $simpleQB->getRootAlias() . '.node', + $simpleQB->getRootAlias().'.node', EntityRepository::NODE_ALIAS ); } - $prefix = EntityRepository::NODE_ALIAS . '.'; + $prefix = EntityRepository::NODE_ALIAS.'.'; $key = str_replace('node.', '', $event->getProperty()); $qb->andWhere($simpleQB->buildExpressionWithoutBinding($event->getValue(), $prefix, $key, $baseKey)); } diff --git a/src/Doctrine/ORM/Filter/NodesSourcesNodeTypeFilter.php b/src/Doctrine/ORM/Filter/NodesSourcesNodeTypeFilter.php index 62d943e5..974709ff 100644 --- a/src/Doctrine/ORM/Filter/NodesSourcesNodeTypeFilter.php +++ b/src/Doctrine/ORM/Filter/NodesSourcesNodeTypeFilter.php @@ -4,16 +4,13 @@ namespace RZ\Roadiz\CoreBundle\Doctrine\ORM\Filter; -use RZ\Roadiz\CoreBundle\Entity\NodeType; use RZ\Roadiz\CoreBundle\Doctrine\Event\FilterNodesSourcesQueryBuilderCriteriaEvent; use RZ\Roadiz\CoreBundle\Doctrine\Event\QueryBuilder\QueryBuilderNodesSourcesApplyEvent; use RZ\Roadiz\CoreBundle\Doctrine\Event\QueryBuilder\QueryBuilderNodesSourcesBuildEvent; use RZ\Roadiz\CoreBundle\Doctrine\ORM\SimpleQueryBuilder; +use RZ\Roadiz\CoreBundle\Entity\NodeType; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -/** - * @package RZ\Roadiz\CoreBundle\Doctrine\ORM\Filter - */ final class NodesSourcesNodeTypeFilter implements EventSubscriberInterface { public static function getSubscribedEvents(): array @@ -24,26 +21,18 @@ public static function getSubscribedEvents(): array ]; } - /** - * @param FilterNodesSourcesQueryBuilderCriteriaEvent $event - * - * @return bool - */ protected function supports(FilterNodesSourcesQueryBuilderCriteriaEvent $event): bool { - return $event->supports() && - $event->getProperty() === 'node.nodeType' && - ( - $event->getValue() instanceof NodeType || - (is_array($event->getValue()) && - count($event->getValue()) > 0 && - $event->getValue()[0] instanceof NodeType) + return $event->supports() + && 'node.nodeType' === $event->getProperty() + && ( + $event->getValue() instanceof NodeType + || (is_array($event->getValue()) + && count($event->getValue()) > 0 + && $event->getValue()[0] instanceof NodeType) ); } - /** - * @param QueryBuilderNodesSourcesBuildEvent $event - */ public function onNodesSourcesQueryBuilderBuild(QueryBuilderNodesSourcesBuildEvent $event): void { if ($this->supports($event)) { diff --git a/src/Doctrine/ORM/Filter/NodesSourcesReachableFilter.php b/src/Doctrine/ORM/Filter/NodesSourcesReachableFilter.php index 6f524f5c..9a038091 100644 --- a/src/Doctrine/ORM/Filter/NodesSourcesReachableFilter.php +++ b/src/Doctrine/ORM/Filter/NodesSourcesReachableFilter.php @@ -13,14 +13,11 @@ use RZ\Roadiz\CoreBundle\Entity\NodeType; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -/** - * @package RZ\Roadiz\CoreBundle\Doctrine\ORM\Filter - */ final class NodesSourcesReachableFilter implements EventSubscriberInterface { public const PARAMETER = [ 'node.nodeType.reachable', - 'reachable' + 'reachable', ]; public function __construct(private readonly NodeTypes $nodeTypesBag) @@ -36,21 +33,13 @@ public static function getSubscribedEvents(): array ]; } - /** - * @param FilterNodesSourcesQueryBuilderCriteriaEvent $event - * - * @return bool - */ protected function supports(FilterNodesSourcesQueryBuilderCriteriaEvent $event): bool { - return $event->supports() && - in_array($event->getProperty(), self::PARAMETER) && - is_bool($event->getValue()); + return $event->supports() + && in_array($event->getProperty(), self::PARAMETER) + && is_bool($event->getValue()); } - /** - * @param QueryBuilderNodesSourcesBuildEvent $event - */ public function onNodesSourcesQueryBuilderBuild(QueryBuilderNodesSourcesBuildEvent $event): void { if ($this->supports($event)) { diff --git a/src/Doctrine/ORM/SimpleQueryBuilder.php b/src/Doctrine/ORM/SimpleQueryBuilder.php index 90c7713b..38d54ce4 100644 --- a/src/Doctrine/ORM/SimpleQueryBuilder.php +++ b/src/Doctrine/ORM/SimpleQueryBuilder.php @@ -5,59 +5,37 @@ namespace RZ\Roadiz\CoreBundle\Doctrine\ORM; use Doctrine\ORM\Query\Expr\Comparison; -use Doctrine\ORM\Query\Expr\Func; use Doctrine\ORM\Query\Expr\From; +use Doctrine\ORM\Query\Expr\Func; use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\QueryBuilder; use RZ\Roadiz\Core\AbstractEntities\PersistableInterface; use Scienta\DoctrineJsonFunctions\Query\AST\Functions\Mysql\JsonContains; -class SimpleQueryBuilder +final readonly class SimpleQueryBuilder { - protected QueryBuilder $queryBuilder; - - /** - * @param QueryBuilder $queryBuilder - */ - public function __construct(QueryBuilder $queryBuilder) + public function __construct(private QueryBuilder $queryBuilder) { - $this->queryBuilder = $queryBuilder; } - /** - * @param string $key - * - * @return string - */ public function getParameterKey(string $key): string { return \mb_strtolower(str_replace('.', '_', $key)); } /** - * @param mixed $value * @param string $prefix Property prefix including DOT - * @param string $key - * - * @return QueryBuilder */ - public function buildExpressionWithBinding($value, string $prefix, string $key): QueryBuilder + public function buildExpressionWithBinding(mixed $value, string $prefix, string $key): QueryBuilder { $this->buildExpressionWithoutBinding($value, $prefix, $key); + return $this->bindValue($key, $value); } - /** - * @param mixed $value - * @param string $prefix - * @param string $key - * @param string|null $baseKey - * - * @return Comparison|Func|string - */ - public function buildExpressionWithoutBinding(mixed $value, string $prefix, string $key, string $baseKey = null) + public function buildExpressionWithoutBinding(mixed $value, string $prefix, string $key, ?string $baseKey = null): Comparison|Func|string { - if (\mb_strlen($prefix) > 0 && \mb_substr($prefix, -\mb_strlen('.')) !== '.') { + if (\mb_strlen($prefix) > 0 && '.' !== \mb_substr($prefix, -\mb_strlen('.'))) { $prefix .= '.'; } @@ -65,10 +43,10 @@ public function buildExpressionWithoutBinding(mixed $value, string $prefix, stri $baseKey = $this->getParameterKey($key); } if (is_bool($value)) { - return $this->queryBuilder->expr()->eq($prefix . $key, ':' . $baseKey); + return $this->queryBuilder->expr()->eq($prefix.$key, ':'.$baseKey); } if ('NOT NULL' === $value) { - return $this->queryBuilder->expr()->isNotNull($prefix . $key); + return $this->queryBuilder->expr()->isNotNull($prefix.$key); } if (is_array($value)) { /* @@ -87,64 +65,60 @@ public function buildExpressionWithoutBinding(mixed $value, string $prefix, stri if (count($value) > 1) { switch ($value[0]) { case '!=': - # neq - return $this->queryBuilder->expr()->neq($prefix . $key, ':' . $baseKey); + // neq + return $this->queryBuilder->expr()->neq($prefix.$key, ':'.$baseKey); case '<=': - # lte - return $this->queryBuilder->expr()->lte($prefix . $key, ':' . $baseKey); + // lte + return $this->queryBuilder->expr()->lte($prefix.$key, ':'.$baseKey); case '<': - # lt - return $this->queryBuilder->expr()->lt($prefix . $key, ':' . $baseKey); + // lt + return $this->queryBuilder->expr()->lt($prefix.$key, ':'.$baseKey); case '>=': - # gte - return $this->queryBuilder->expr()->gte($prefix . $key, ':' . $baseKey); + // gte + return $this->queryBuilder->expr()->gte($prefix.$key, ':'.$baseKey); case '>': - # gt - return $this->queryBuilder->expr()->gt($prefix . $key, ':' . $baseKey); + // gt + return $this->queryBuilder->expr()->gt($prefix.$key, ':'.$baseKey); case 'BETWEEN': return $this->queryBuilder->expr()->between( - $prefix . $key, - ':' . $baseKey . '_1', - ':' . $baseKey . '_2' + $prefix.$key, + ':'.$baseKey.'_1', + ':'.$baseKey.'_2' ); case 'LIKE': - $fullKey = sprintf('LOWER(%s)', $prefix . $key); + $fullKey = sprintf('LOWER(%s)', $prefix.$key); + return $this->queryBuilder->expr()->like( $fullKey, $this->queryBuilder->expr()->literal(\mb_strtolower($value[1] ?? '')) ); case 'NOT IN': - return $this->queryBuilder->expr()->notIn($prefix . $key, ':' . $baseKey); + return $this->queryBuilder->expr()->notIn($prefix.$key, ':'.$baseKey); case JsonContains::FUNCTION_NAME: // Json flat array/object contains a given value - return JsonContains::FUNCTION_NAME . '(' . $prefix . $key . ', :' . $baseKey . ', \'$\') = 1'; + return JsonContains::FUNCTION_NAME.'('.$prefix.$key.', :'.$baseKey.', \'$\') = 1'; case 'INSTANCE OF': - return $this->queryBuilder->expr()->isInstanceOf($prefix . $key, ':' . $baseKey); + return $this->queryBuilder->expr()->isInstanceOf($prefix.$key, ':'.$baseKey); } } - return $this->queryBuilder->expr()->in($prefix . $key, ':' . $baseKey); + + return $this->queryBuilder->expr()->in($prefix.$key, ':'.$baseKey); } if ($value instanceof PersistableInterface) { - return $this->queryBuilder->expr()->eq($prefix . $key, ':' . $baseKey); + return $this->queryBuilder->expr()->eq($prefix.$key, ':'.$baseKey); } if (null === $value) { - return $this->queryBuilder->expr()->isNull($prefix . $key); + return $this->queryBuilder->expr()->isNull($prefix.$key); } - return $this->queryBuilder->expr()->eq($prefix . $key, ':' . $baseKey); + return $this->queryBuilder->expr()->eq($prefix.$key, ':'.$baseKey); } - /** - * @param string $key - * @param mixed $value - * - * @return QueryBuilder - */ - public function bindValue(string $key, $value): QueryBuilder + public function bindValue(string $key, mixed $value): QueryBuilder { $key = $this->getParameterKey($key); - if (is_bool($value) || $value === 0) { + if (is_bool($value) || 0 === $value) { return $this->queryBuilder->setParameter($key, $value); } if ('NOT NULL' == $value) { @@ -163,16 +137,17 @@ public function bindValue(string $key, $value): QueryBuilder case 'NOT IN': return $this->queryBuilder->setParameter($key, $value[1]); case 'BETWEEN': - return $this->queryBuilder->setParameter($key . '_1', $value[1]) - ->setParameter($key . '_2', $value[2]); + return $this->queryBuilder->setParameter($key.'_1', $value[1]) + ->setParameter($key.'_2', $value[2]); case JsonContains::FUNCTION_NAME: // Need to quote Json value - return $this->queryBuilder->setParameter($key, '"' . $value[1] . '"'); + return $this->queryBuilder->setParameter($key, '"'.$value[1].'"'); case 'LIKE': // param is set in filterBy return $this->queryBuilder; } } + return $this->queryBuilder->setParameter($key, $value); } if ($value instanceof PersistableInterface) { @@ -185,20 +160,13 @@ public function bindValue(string $key, $value): QueryBuilder return $this->queryBuilder->setParameter($key, $value); } - /** - * @param string $rootAlias - * @param string $joinAlias - * - * @return bool - */ public function joinExists(string $rootAlias, string $joinAlias): bool { if (isset($this->queryBuilder->getDQLPart('join')[$rootAlias])) { foreach ($this->queryBuilder->getDQLPart('join')[$rootAlias] as $join) { if ( - null !== $join && - $join instanceof Join && - $join->getAlias() === $joinAlias + $join instanceof Join + && $join->getAlias() === $joinAlias ) { return true; } @@ -208,17 +176,11 @@ public function joinExists(string $rootAlias, string $joinAlias): bool return false; } - /** - * @return QueryBuilder - */ public function getQueryBuilder(): QueryBuilder { return $this->queryBuilder; } - /** - * @return string|null - */ public function getRootAlias(): ?string { $fromArray = $this->getQueryBuilder()->getDQLPart('from'); diff --git a/src/Doctrine/SchemaUpdater.php b/src/Doctrine/SchemaUpdater.php index bd1ccdeb..e00257f1 100644 --- a/src/Doctrine/SchemaUpdater.php +++ b/src/Doctrine/SchemaUpdater.php @@ -15,7 +15,7 @@ public function __construct( private readonly CacheClearerInterface $cacheClearer, private readonly OPCacheClearer $opCacheClearer, private readonly LoggerInterface $logger, - private readonly string $projectDir + private readonly string $projectDir, ) { } @@ -29,10 +29,10 @@ public function clearMetadata(): void ); $process->run(); - if ($process->wait() === 0) { + if (0 === $process->wait()) { $this->logger->info('Cleared Doctrine metadata cache.'); } else { - throw new \RuntimeException('Cannot clear Doctrine metadata cache. ' . $process->getErrorOutput()); + throw new \RuntimeException('Cannot clear Doctrine metadata cache. '.$process->getErrorOutput()); } $process = $this->runCommand( @@ -40,10 +40,10 @@ public function clearMetadata(): void ); $process->run(); - if ($process->wait() === 0) { + if (0 === $process->wait()) { $this->logger->info('Stop any running messenger worker to force them to restart'); } else { - throw new \RuntimeException('Cannot stop messenger workers. ' . $process->getErrorOutput()); + throw new \RuntimeException('Cannot stop messenger workers. '.$process->getErrorOutput()); } } @@ -56,10 +56,10 @@ public function clearAllCaches(): void ); $process->run(); - if ($process->wait() === 0) { + if (0 === $process->wait()) { $this->logger->info('Cleared all caches.'); } else { - throw new \RuntimeException('Cannot clear cache. ' . $process->getErrorOutput()); + throw new \RuntimeException('Cannot clear cache. '.$process->getErrorOutput()); } } @@ -77,10 +77,10 @@ public function updateSchema(): void ); $process->run(); - if ($process->wait() === 0) { + if (0 === $process->wait()) { $this->logger->info('Executed pending migrations.'); } else { - throw new \RuntimeException('Migrations failed. ' . $process->getErrorOutput()); + throw new \RuntimeException('Migrations failed. '.$process->getErrorOutput()); } } @@ -95,26 +95,27 @@ public function updateNodeTypesSchema(): void '--namespace=DoctrineMigrations --quiet --allow-empty-diff', ); $process->run(); - if ($process->wait() === 0) { + if (0 === $process->wait()) { $this->logger->info('New migration has been generated.'); $this->updateSchema(); } else { - throw new \RuntimeException('DB schema update failed. ' . $process->getErrorOutput()); + throw new \RuntimeException('DB schema update failed. '.$process->getErrorOutput()); } } private function runCommand( string $command, - string $args = '' + string $args = '', ): Process { $args .= ' --no-interaction'; $args .= ' --quiet'; $process = Process::fromShellCommandline( - 'php bin/console ' . $command . ' ' . $args + 'php bin/console '.$command.' '.$args ); $process->setWorkingDirectory($this->projectDir); $process->setTty(false); + return $process; } } diff --git a/src/Document/DocumentFactory.php b/src/Document/DocumentFactory.php index 91f6f612..7ff20cb1 100644 --- a/src/Document/DocumentFactory.php +++ b/src/Document/DocumentFactory.php @@ -23,7 +23,7 @@ public function __construct( private readonly ManagerRegistry $managerRegistry, FilesystemOperator $documentsStorage, DocumentFinderInterface $documentFinder, - ?LoggerInterface $logger = null + ?LoggerInterface $logger = null, ) { parent::__construct($documentsStorage, $documentFinder, $logger); } @@ -33,9 +33,6 @@ protected function persistDocument(DocumentInterface $document): void $this->managerRegistry->getManagerForClass(Document::class)->persist($document); } - /** - * @inheritDoc - */ protected function createDocument(): DocumentInterface { return new Document(); diff --git a/src/Document/DocumentFinder.php b/src/Document/DocumentFinder.php index 7de00596..cb542b1d 100644 --- a/src/Document/DocumentFinder.php +++ b/src/Document/DocumentFinder.php @@ -16,42 +16,30 @@ public function __construct(private readonly ManagerRegistry $managerRegistry) { } - /** - * @inheritDoc - */ public function findAllByFilenames(array $fileNames): iterable { return $this->getRepository()->findBy([ - "filename" => $fileNames, - "raw" => false, + 'filename' => $fileNames, + 'raw' => false, ]); } - /** - * @inheritDoc - */ public function findOneByFilenames(array $fileNames): ?DocumentInterface { return $this->getRepository()->findOneBy([ - "filename" => $fileNames, - "raw" => false, + 'filename' => $fileNames, + 'raw' => false, ]); } - /** - * @inheritDoc - */ public function findOneByHashAndAlgorithm(string $hash, string $algorithm): ?DocumentInterface { return $this->getRepository()->findOneBy([ - "fileHash" => $hash, - "fileHashAlgorithm" => $algorithm, + 'fileHash' => $hash, + 'fileHashAlgorithm' => $algorithm, ]); } - /** - * @return DocumentRepository - */ protected function getRepository(): DocumentRepository { return $this->managerRegistry->getRepository(Document::class); diff --git a/src/Document/EventSubscriber/DocumentMessageDispatchSubscriber.php b/src/Document/EventSubscriber/DocumentMessageDispatchSubscriber.php index cf6a6844..217e0eb4 100644 --- a/src/Document/EventSubscriber/DocumentMessageDispatchSubscriber.php +++ b/src/Document/EventSubscriber/DocumentMessageDispatchSubscriber.php @@ -20,21 +20,18 @@ use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\MessageBusInterface; -final class DocumentMessageDispatchSubscriber implements EventSubscriberInterface +final readonly class DocumentMessageDispatchSubscriber implements EventSubscriberInterface { - public function __construct(private readonly MessageBusInterface $bus) + public function __construct(private MessageBusInterface $bus) { } - /** - * @inheritDoc - */ public static function getSubscribedEvents(): array { return [ // Only dispatch async message when document files are updated or created - DocumentCreatedEvent::class => ['onFilterDocumentEvent', 0], - DocumentFileUpdatedEvent::class => ['onFilterDocumentEvent', 0], + DocumentCreatedEvent::class => ['onFilterDocumentEvent', 0], + DocumentFileUpdatedEvent::class => ['onFilterDocumentEvent', 0], ]; } @@ -42,10 +39,10 @@ public function onFilterDocumentEvent(FilterDocumentEvent $event): void { $document = $event->getDocument(); if ( - $document instanceof Document && - \is_numeric($document->getId()) && - $document->isLocal() && - null !== $document->getRelativePath() + $document instanceof Document + && \is_numeric($document->getId()) + && $document->isLocal() + && null !== $document->getRelativePath() ) { $id = (int) $document->getId(); $this->bus->dispatch(new Envelope(new DocumentRawMessage($id))); diff --git a/src/Document/MediaFinder/DailymotionEmbedFinder.php b/src/Document/MediaFinder/DailymotionEmbedFinder.php index 71385a08..c322ded7 100644 --- a/src/Document/MediaFinder/DailymotionEmbedFinder.php +++ b/src/Document/MediaFinder/DailymotionEmbedFinder.php @@ -6,9 +6,6 @@ use RZ\Roadiz\Documents\MediaFinders\AbstractDailymotionEmbedFinder; -/** - * Dailymotion tools class. - */ class DailymotionEmbedFinder extends AbstractDailymotionEmbedFinder { use EmbedFinderTrait; diff --git a/src/Document/MediaFinder/EmbedFinderTrait.php b/src/Document/MediaFinder/EmbedFinderTrait.php index 66dfee7b..07d2e011 100644 --- a/src/Document/MediaFinder/EmbedFinderTrait.php +++ b/src/Document/MediaFinder/EmbedFinderTrait.php @@ -5,19 +5,16 @@ namespace RZ\Roadiz\CoreBundle\Document\MediaFinder; use Doctrine\Persistence\ObjectManager; -use GuzzleHttp\Exception\ClientException; use RZ\Roadiz\CoreBundle\Entity\Document; use RZ\Roadiz\CoreBundle\Entity\DocumentTranslation; use RZ\Roadiz\CoreBundle\Entity\Translation; use RZ\Roadiz\Documents\Exceptions\APINeedsAuthentificationException; use RZ\Roadiz\Documents\Models\DocumentInterface; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; trait EmbedFinderTrait { - /** - * @inheritDoc - */ - protected function documentExists(ObjectManager $objectManager, $embedId, $embedPlatform): bool + protected function documentExists(ObjectManager $objectManager, string $embedId, ?string $embedPlatform): bool { $existingDocument = $objectManager->getRepository(Document::class) ->findOneBy([ @@ -28,9 +25,6 @@ protected function documentExists(ObjectManager $objectManager, $embedId, $embed return null !== $existingDocument; } - /** - * @inheritDoc - */ protected function injectMetaInDocument(ObjectManager $objectManager, DocumentInterface $document): DocumentInterface { $translations = $objectManager->getRepository(Translation::class)->findAll(); @@ -56,9 +50,9 @@ protected function injectMetaInDocument(ObjectManager $objectManager, DocumentIn } } } catch (APINeedsAuthentificationException $exception) { - // do no prevent from creating document if credentials are not provided. - } catch (ClientException $exception) { - // do no prevent from creating document if platform has errors, such as + // do not prevent from creating document if credentials are not provided. + } catch (ClientExceptionInterface $exception) { + // do not prevent from creating document if platform has errors, such as // too much API usage. } diff --git a/src/Document/MediaFinder/PodcastFinder.php b/src/Document/MediaFinder/PodcastFinder.php index bc10601d..384373bb 100644 --- a/src/Document/MediaFinder/PodcastFinder.php +++ b/src/Document/MediaFinder/PodcastFinder.php @@ -5,11 +5,11 @@ namespace RZ\Roadiz\CoreBundle\Document\MediaFinder; use Doctrine\Persistence\ObjectManager; -use GuzzleHttp\Exception\ClientException; use RZ\Roadiz\CoreBundle\Entity\DocumentTranslation; use RZ\Roadiz\CoreBundle\Entity\Translation; use RZ\Roadiz\Documents\MediaFinders\AbstractPodcastFinder; use RZ\Roadiz\Documents\Models\DocumentInterface; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; class PodcastFinder extends AbstractPodcastFinder { @@ -18,7 +18,7 @@ class PodcastFinder extends AbstractPodcastFinder protected function injectMetaFromPodcastItem( ObjectManager $objectManager, DocumentInterface $document, - \SimpleXMLElement $item + \SimpleXMLElement $item, ): void { $translations = $objectManager->getRepository(Translation::class)->findAll(); @@ -33,8 +33,8 @@ protected function injectMetaFromPodcastItem( $documentTr->setCopyright($this->getPodcastItemCopyright($item)); $objectManager->persist($documentTr); } - } catch (ClientException $exception) { - // do no prevent from creating document if platform has errors, such as + } catch (ClientExceptionInterface $exception) { + // do not prevent from creating document if platform has errors, such as // too much API usage. } } diff --git a/src/Document/MediaFinder/SoundcloudEmbedFinder.php b/src/Document/MediaFinder/SoundcloudEmbedFinder.php index 30daf162..ef7b3330 100644 --- a/src/Document/MediaFinder/SoundcloudEmbedFinder.php +++ b/src/Document/MediaFinder/SoundcloudEmbedFinder.php @@ -6,9 +6,6 @@ use RZ\Roadiz\Documents\MediaFinders\AbstractSoundcloudEmbedFinder; -/** - * Soundcloud tools class. - */ class SoundcloudEmbedFinder extends AbstractSoundcloudEmbedFinder { use EmbedFinderTrait; diff --git a/src/Document/MediaFinder/TwitchEmbedFinder.php b/src/Document/MediaFinder/TwitchEmbedFinder.php deleted file mode 100644 index de8ef24c..00000000 --- a/src/Document/MediaFinder/TwitchEmbedFinder.php +++ /dev/null @@ -1,12 +0,0 @@ -documentId = $documentId; } - /** - * @return int - */ public function getDocumentId(): int { return $this->documentId; diff --git a/src/Document/MessageHandler/AbstractDocumentMessageHandler.php b/src/Document/MessageHandler/AbstractDocumentMessageHandler.php index e9747f8b..311b6358 100644 --- a/src/Document/MessageHandler/AbstractDocumentMessageHandler.php +++ b/src/Document/MessageHandler/AbstractDocumentMessageHandler.php @@ -10,15 +10,16 @@ use Psr\Log\LoggerInterface; use RZ\Roadiz\CoreBundle\Document\Message\AbstractDocumentMessage; use RZ\Roadiz\Documents\Models\DocumentInterface; +use Symfony\Component\Messenger\Attribute\AsMessageHandler; use Symfony\Component\Messenger\Exception\RecoverableMessageHandlingException; -use Symfony\Component\Messenger\Handler\MessageHandlerInterface; -abstract class AbstractDocumentMessageHandler implements MessageHandlerInterface +#[AsMessageHandler] +abstract class AbstractDocumentMessageHandler { public function __construct( protected readonly ManagerRegistry $managerRegistry, protected readonly LoggerInterface $messengerLogger, - protected readonly FilesystemOperator $documentsStorage + protected readonly FilesystemOperator $documentsStorage, ) { } diff --git a/src/Document/MessageHandler/AbstractLockingDocumentMessageHandler.php b/src/Document/MessageHandler/AbstractLockingDocumentMessageHandler.php index e15c6139..1a78fba5 100644 --- a/src/Document/MessageHandler/AbstractLockingDocumentMessageHandler.php +++ b/src/Document/MessageHandler/AbstractLockingDocumentMessageHandler.php @@ -30,10 +30,7 @@ public function __invoke(AbstractDocumentMessage $message): void $this->managerRegistry->getManager()->flush(); @\flock($resource, \LOCK_UN); } else { - throw new RecoverableMessageHandlingException(sprintf( - '%s file is currently locked', - $documentPath - )); + throw new RecoverableMessageHandlingException(sprintf('%s file is currently locked', $documentPath)); } } else { $this->processMessage($message, $document); @@ -48,7 +45,7 @@ public function __invoke(AbstractDocumentMessage $message): void protected function isFileLocal(DocumentInterface $document): bool { return - $document->isPrivate() || - str_starts_with($this->documentsStorage->publicUrl($document->getMountPath()), '/'); + $document->isPrivate() + || str_starts_with($this->documentsStorage->publicUrl($document->getMountPath()), '/'); } } diff --git a/src/Document/MessageHandler/DocumentAudioVideoMessageHandler.php b/src/Document/MessageHandler/DocumentAudioVideoMessageHandler.php index 056f2f8b..0b841c53 100644 --- a/src/Document/MessageHandler/DocumentAudioVideoMessageHandler.php +++ b/src/Document/MessageHandler/DocumentAudioVideoMessageHandler.php @@ -25,6 +25,7 @@ * * Detect Audio and Video files metadata using https://github.com/JamesHeinrich/getID3 lib * And extract video thumbnail using local ffmpeg. + * * @see https://github.com/JamesHeinrich/getID3 */ final class DocumentAudioVideoMessageHandler extends AbstractLockingDocumentMessageHandler @@ -35,23 +36,19 @@ public function __construct( private readonly ?string $ffmpegPath, ManagerRegistry $managerRegistry, LoggerInterface $messengerLogger, - FilesystemOperator $documentsStorage + FilesystemOperator $documentsStorage, ) { parent::__construct($managerRegistry, $messengerLogger, $documentsStorage); } - /** - * @param DocumentInterface $document - * @return bool - */ protected function supports(DocumentInterface $document): bool { /* * If none of AV tool are available, do not stream media for nothing. */ - return $document->isLocal() && - ($document->isVideo() || $document->isAudio()) && - (\class_exists('getID3') || is_string($this->ffmpegPath)); + return $document->isLocal() + && ($document->isVideo() || $document->isAudio()) + && (\class_exists('getID3') || is_string($this->ffmpegPath)); } protected function processMessage(AbstractDocumentMessage $message, DocumentInterface $document): void @@ -135,13 +132,7 @@ protected function extractMediaThumbnail(DocumentInterface $document, string $lo $this->eventDispatcher->dispatch(new DocumentCreatedEvent($thumbnailDocument)); } } catch (ProcessFailedException $exception) { - throw new UnrecoverableMessageHandlingException( - sprintf( - 'Cannot extract thumbnail from %s video file : %s', - $localMediaPath, - $exception->getMessage() - ), - ); + throw new UnrecoverableMessageHandlingException(sprintf('Cannot extract thumbnail from %s video file : %s', $localMediaPath, $exception->getMessage())); } } } diff --git a/src/Document/MessageHandler/DocumentAverageColorMessageHandler.php b/src/Document/MessageHandler/DocumentAverageColorMessageHandler.php index 6c251078..e2e9c8b7 100644 --- a/src/Document/MessageHandler/DocumentAverageColorMessageHandler.php +++ b/src/Document/MessageHandler/DocumentAverageColorMessageHandler.php @@ -17,27 +17,20 @@ final class DocumentAverageColorMessageHandler extends AbstractLockingDocumentMessageHandler { public function __construct( + private readonly ImageManager $imageManager, ManagerRegistry $managerRegistry, LoggerInterface $messengerLogger, FilesystemOperator $documentsStorage, - private readonly ImageManager $imageManager ) { parent::__construct($managerRegistry, $messengerLogger, $documentsStorage); } - /** - * @param DocumentInterface $document - * @return bool - */ protected function supports(DocumentInterface $document): bool { return $document->isLocal() && $document->isProcessable(); } /** - * @param AbstractDocumentMessage $message - * @param DocumentInterface $document - * @return void * @throws \League\Flysystem\FilesystemException */ protected function processMessage(AbstractDocumentMessage $message, DocumentInterface $document): void @@ -54,7 +47,7 @@ protected function processMessage(AbstractDocumentMessage $message, DocumentInte 'Document file is not a readable image.', [ 'path' => $document->getMountPath(), - 'message' => $exception->getMessage() + 'message' => $exception->getMessage(), ] ); } diff --git a/src/Document/MessageHandler/DocumentExifMessageHandler.php b/src/Document/MessageHandler/DocumentExifMessageHandler.php index 5983a7b3..94b38602 100644 --- a/src/Document/MessageHandler/DocumentExifMessageHandler.php +++ b/src/Document/MessageHandler/DocumentExifMessageHandler.php @@ -12,21 +12,17 @@ final class DocumentExifMessageHandler extends AbstractLockingDocumentMessageHandler { - /** - * @param DocumentInterface $document - * @return bool - */ protected function supports(DocumentInterface $document): bool { if (!$document->isLocal()) { return false; } - if ($document->getEmbedPlatform() !== "") { + if ('' !== $document->getEmbedPlatform()) { return false; } - if ($document->getMimeType() == 'image/jpeg' || $document->getMimeType() == 'image/tiff') { + if ('image/jpeg' == $document->getMimeType() || 'image/tiff' == $document->getMimeType()) { return true; } @@ -39,8 +35,8 @@ protected function processMessage(AbstractDocumentMessage $message, DocumentInte return; } if ( - function_exists('exif_read_data') && - $document->getDocumentTranslations()->count() === 0 + function_exists('exif_read_data') + && 0 === $document->getDocumentTranslations()->count() ) { $fileStream = $this->documentsStorage->readStream($document->getMountPath()); $exif = @\exif_read_data($fileStream, 'FILE,COMPUTED,ANY_TAG,EXIF,COMMENT'); @@ -53,7 +49,7 @@ function_exists('exif_read_data') && $this->messengerLogger->debug( 'EXIF information available for document.', [ - 'document' => (string)$document + 'document' => (string) $document, ] ); $manager = $this->managerRegistry->getManagerForClass(DocumentTranslation::class); @@ -73,16 +69,12 @@ function_exists('exif_read_data') && } } - /** - * @param array $exif - * @return string|null - */ private function getCopyright(array $exif): ?string { foreach ($exif as $key => $section) { if (is_array($section)) { foreach ($section as $skey => $value) { - if (\mb_strtolower($skey) === 'copyright') { + if ('copyright' === \mb_strtolower($skey)) { return $value; } } @@ -92,25 +84,22 @@ private function getCopyright(array $exif): ?string return null; } - /** - * @param array $exif - * @return string|null - */ private function getDescription(array $exif): ?string { foreach ($exif as $key => $section) { - if (is_string($section) && \mb_strtolower($key) === 'imagedescription') { + if (is_string($section) && 'imagedescription' === \mb_strtolower($key)) { return $section; } elseif (is_array($section)) { - if (\mb_strtolower($key) == 'comment') { + if ('comment' == \mb_strtolower($key)) { $comment = ''; foreach ($section as $value) { - $comment .= $value . PHP_EOL; + $comment .= $value.PHP_EOL; } + return $comment; } else { foreach ($section as $skey => $value) { - if (\mb_strtolower($skey) == 'comment') { + if ('comment' == \mb_strtolower($skey)) { return $value; } } diff --git a/src/Document/MessageHandler/DocumentFilesizeMessageHandler.php b/src/Document/MessageHandler/DocumentFilesizeMessageHandler.php index 14600d04..5a5a96a5 100644 --- a/src/Document/MessageHandler/DocumentFilesizeMessageHandler.php +++ b/src/Document/MessageHandler/DocumentFilesizeMessageHandler.php @@ -11,10 +11,6 @@ final class DocumentFilesizeMessageHandler extends AbstractLockingDocumentMessageHandler { - /** - * @param DocumentInterface $document - * @return bool - */ protected function supports(DocumentInterface $document): bool { return $document->isLocal() && null !== $document->getRelativePath(); diff --git a/src/Document/MessageHandler/DocumentPdfMessageHandler.php b/src/Document/MessageHandler/DocumentPdfMessageHandler.php index 2a6453ff..54ade391 100644 --- a/src/Document/MessageHandler/DocumentPdfMessageHandler.php +++ b/src/Document/MessageHandler/DocumentPdfMessageHandler.php @@ -23,21 +23,17 @@ public function __construct( private readonly EventDispatcherInterface $eventDispatcher, ManagerRegistry $managerRegistry, LoggerInterface $messengerLogger, - FilesystemOperator $documentsStorage + FilesystemOperator $documentsStorage, ) { parent::__construct($managerRegistry, $messengerLogger, $documentsStorage); } - /** - * @param DocumentInterface $document - * @return bool - */ protected function supports(DocumentInterface $document): bool { - return $document->isLocal() && - $document->isPdf() && - \class_exists('\Imagick') && - \class_exists('\ImagickException'); + return $document->isLocal() + && $document->isPdf() + && \class_exists('\Imagick') + && \class_exists('\ImagickException'); } protected function processMessage(AbstractDocumentMessage $message, DocumentInterface $document): void @@ -79,13 +75,13 @@ protected function extractPdfThumbnail(DocumentInterface $document, string $loca if (false === $thumbnailPath) { throw new UnrecoverableMessageHandlingException('Cannot create temporary file for PDF thumbnail.'); } - \rename($thumbnailPath, $thumbnailPath .= $document->getFilename() . '.jpg'); + \rename($thumbnailPath, $thumbnailPath .= $document->getFilename().'.jpg'); try { $im = new \Imagick(); $im->setResolution(144, 144); // Use [0] to get first page of PDF. - if ($im->readImage($localPdfPath . '[0]')) { + if ($im->readImage($localPdfPath.'[0]')) { $im->writeImages($thumbnailPath, false); $thumbnailDocument = $this->documentFactory diff --git a/src/Document/MessageHandler/DocumentRawMessageHandler.php b/src/Document/MessageHandler/DocumentRawMessageHandler.php index dc2c1588..fcb658db 100644 --- a/src/Document/MessageHandler/DocumentRawMessageHandler.php +++ b/src/Document/MessageHandler/DocumentRawMessageHandler.php @@ -16,16 +16,12 @@ final class DocumentRawMessageHandler extends AbstractLockingDocumentMessageHand public function __construct( private readonly DownscaleImageManager $downscaleImageManager, ManagerRegistry $managerRegistry, - LoggerInterface $logger, - FilesystemOperator $documentsStorage + LoggerInterface $messengerLogger, + FilesystemOperator $documentsStorage, ) { - parent::__construct($managerRegistry, $logger, $documentsStorage); + parent::__construct($managerRegistry, $messengerLogger, $documentsStorage); } - /** - * @param DocumentInterface $document - * @return bool - */ protected function supports(DocumentInterface $document): bool { return $document->isLocal() && null !== $document->getRelativePath() && $document->isProcessable(); diff --git a/src/Document/MessageHandler/DocumentSizeMessageHandler.php b/src/Document/MessageHandler/DocumentSizeMessageHandler.php index b337463f..ab917f95 100644 --- a/src/Document/MessageHandler/DocumentSizeMessageHandler.php +++ b/src/Document/MessageHandler/DocumentSizeMessageHandler.php @@ -16,18 +16,14 @@ final class DocumentSizeMessageHandler extends AbstractLockingDocumentMessageHandler { public function __construct( + private readonly ImageManager $imageManager, ManagerRegistry $managerRegistry, LoggerInterface $messengerLogger, FilesystemOperator $documentsStorage, - private readonly ImageManager $imageManager ) { parent::__construct($managerRegistry, $messengerLogger, $documentsStorage); } - /** - * @param DocumentInterface $document - * @return bool - */ protected function supports(DocumentInterface $document): bool { return $document->isLocal() && $document->isImage(); @@ -47,7 +43,7 @@ protected function processMessage(AbstractDocumentMessage $message, DocumentInte 'Document file is not a readable image.', [ 'path' => $document->getMountPath(), - 'message' => $exception->getMessage() + 'message' => $exception->getMessage(), ] ); } diff --git a/src/Document/MessageHandler/DocumentSvgMessageHandler.php b/src/Document/MessageHandler/DocumentSvgMessageHandler.php index b833a3d3..240f389c 100644 --- a/src/Document/MessageHandler/DocumentSvgMessageHandler.php +++ b/src/Document/MessageHandler/DocumentSvgMessageHandler.php @@ -12,10 +12,6 @@ final class DocumentSvgMessageHandler extends AbstractLockingDocumentMessageHandler { - /** - * @param DocumentInterface $document - * @return bool - */ protected function supports(DocumentInterface $document): bool { return $document->isLocal() && null !== $document->getRelativePath() && $document->isSvg(); diff --git a/src/Document/PrivateDocumentFactory.php b/src/Document/PrivateDocumentFactory.php index 68713ac9..e29f9454 100644 --- a/src/Document/PrivateDocumentFactory.php +++ b/src/Document/PrivateDocumentFactory.php @@ -25,7 +25,7 @@ public function __construct( ManagerRegistry $managerRegistry, FilesystemOperator $documentsStorage, DocumentFinderInterface $documentFinder, - ?LoggerInterface $logger = null + ?LoggerInterface $logger = null, ) { parent::__construct($documentsStorage, $documentFinder, $logger); $this->managerRegistry = $managerRegistry; @@ -36,13 +36,11 @@ protected function persistDocument(DocumentInterface $document): void $this->managerRegistry->getManagerForClass(Document::class)->persist($document); } - /** - * @inheritDoc - */ protected function createDocument(): DocumentInterface { $document = new Document(); $document->setPrivate(true); + return $document; } } diff --git a/src/Entity/AbstractDateTimedPositioned.php b/src/Entity/AbstractDateTimedPositioned.php index 9f33830a..5151807a 100644 --- a/src/Entity/AbstractDateTimedPositioned.php +++ b/src/Entity/AbstractDateTimedPositioned.php @@ -22,19 +22,19 @@ ORM\MappedSuperclass, ORM\HasLifecycleCallbacks, ORM\Table, - ORM\Index(columns: ["position"]), - ORM\Index(columns: ["created_at"]), - ORM\Index(columns: ["updated_at"]) + ORM\Index(columns: ['position']), + ORM\Index(columns: ['created_at']), + ORM\Index(columns: ['updated_at']) ] abstract class AbstractDateTimedPositioned extends AbstractDateTimed implements PositionedInterface, Comparable { use PositionedTrait; #[ - ORM\Column(type: "float"), - Serializer\Groups(["position"]), - Serializer\Type("float"), - SymfonySerializer\Groups(["position"]), + ORM\Column(type: 'float'), + Serializer\Groups(['position']), + Serializer\Type('float'), + SymfonySerializer\Groups(['position']), ApiFilter(RangeFilter::class), ApiFilter(NumericFilter::class) ] diff --git a/src/Entity/Attribute.php b/src/Entity/Attribute.php index 04657460..7edc8776 100644 --- a/src/Entity/Attribute.php +++ b/src/Entity/Attribute.php @@ -20,20 +20,17 @@ use Symfony\Component\Validator\Constraints\NotNull; use Symfony\Component\Validator\Constraints\Range; -/** - * @package RZ\Roadiz\CoreBundle\Entity - */ #[ ORM\Entity(repositoryClass: AttributeRepository::class), - ORM\Table(name: "attributes"), - ORM\Index(columns: ["code"]), - ORM\Index(columns: ["type"]), - ORM\Index(columns: ["searchable"]), - ORM\Index(columns: ["weight"]), - ORM\Index(columns: ["color"]), - ORM\Index(columns: ["group_id"]), + ORM\Table(name: 'attributes'), + ORM\Index(columns: ['code']), + ORM\Index(columns: ['type']), + ORM\Index(columns: ['searchable']), + ORM\Index(columns: ['weight']), + ORM\Index(columns: ['color']), + ORM\Index(columns: ['group_id']), ORM\HasLifecycleCallbacks, - UniqueEntity(fields: ["code"]), + UniqueEntity(fields: ['code']), ] class Attribute extends AbstractEntity implements AttributeInterface { @@ -44,12 +41,12 @@ class Attribute extends AbstractEntity implements AttributeInterface */ #[ ORM\OneToMany( - mappedBy: "attribute", + mappedBy: 'attribute', targetEntity: AttributeDocuments::class, - cascade: ["persist", "merge"], + cascade: ['persist', 'merge'], orphanRemoval: true ), - ORM\OrderBy(["position" => "ASC"]), + ORM\OrderBy(['position' => 'ASC']), Serializer\Exclude, Serializer\Type("ArrayCollection"), SymfonySerializer\Ignore @@ -69,13 +66,13 @@ class Attribute extends AbstractEntity implements AttributeInterface private ?RealmInterface $defaultRealm = null; /** - * @var int Absolute weight for sorting attributes in filtered lists. + * @var int absolute weight for sorting attributes in filtered lists */ #[ - ORM\Column(type: "integer", nullable: false, options: ["default" => 0]), - Serializer\Type("integer"), - Serializer\Groups(["attribute", "node", "nodes_sources"]), - SymfonySerializer\Groups(["attribute", "node", "nodes_sources"]), + ORM\Column(type: 'integer', nullable: false, options: ['default' => 0]), + Serializer\Type('integer'), + Serializer\Groups(['attribute', 'node', 'nodes_sources']), + SymfonySerializer\Groups(['attribute', 'node', 'nodes_sources']), ApiFilter(OrderFilter::class), Range(min: 0, max: 9999), NotNull, @@ -97,11 +94,6 @@ public function getAttributeDocuments(): Collection return $this->attributeDocuments; } - /** - * @param Collection $attributeDocuments - * - * @return Attribute - */ public function setAttributeDocuments(Collection $attributeDocuments): Attribute { $this->attributeDocuments = $attributeDocuments; @@ -117,6 +109,7 @@ public function getDefaultRealm(): ?RealmInterface public function setDefaultRealm(?RealmInterface $defaultRealm): Attribute { $this->defaultRealm = $defaultRealm; + return $this; } @@ -128,6 +121,7 @@ public function getWeight(): int public function setWeight(?int $weight): Attribute { $this->weight = $weight ?? 0; + return $this; } @@ -136,8 +130,8 @@ public function setWeight(?int $weight): Attribute */ #[ Serializer\VirtualProperty(), - Serializer\Groups(["attribute", "node", "nodes_sources"]), - SymfonySerializer\Groups(["attribute", "node", "nodes_sources"]), + Serializer\Groups(['attribute', 'node', 'nodes_sources']), + SymfonySerializer\Groups(['attribute', 'node', 'nodes_sources']), ] public function getDocuments(): Collection { @@ -147,6 +141,7 @@ public function getDocuments(): Collection })->filter(function (?Document $document) { return null !== $document; }); + return $values; // phpstan does not understand filtering null values } } diff --git a/src/Entity/AttributeDocuments.php b/src/Entity/AttributeDocuments.php index 596a3947..fad0ebce 100644 --- a/src/Entity/AttributeDocuments.php +++ b/src/Entity/AttributeDocuments.php @@ -5,8 +5,8 @@ namespace RZ\Roadiz\CoreBundle\Entity; use Doctrine\ORM\Mapping as ORM; -use RZ\Roadiz\Core\AbstractEntities\AbstractPositioned; use JMS\Serializer\Annotation as Serializer; +use RZ\Roadiz\Core\AbstractEntities\AbstractPositioned; use RZ\Roadiz\CoreBundle\Repository\AttributeDocumentsRepository; use Symfony\Component\Serializer\Annotation as SymfonySerializer; @@ -16,24 +16,24 @@ */ #[ ORM\Entity(repositoryClass: AttributeDocumentsRepository::class), - ORM\Table(name: "attributes_documents"), - ORM\Index(columns: ["position"]), - ORM\Index(columns: ["attribute_id", "position"]) + ORM\Table(name: 'attributes_documents'), + ORM\Index(columns: ['position']), + ORM\Index(columns: ['attribute_id', 'position']) ] class AttributeDocuments extends AbstractPositioned { #[ ORM\ManyToOne( targetEntity: Attribute::class, - cascade: ["persist", "merge"], - fetch: "EAGER", - inversedBy: "attributeDocuments" + cascade: ['persist', 'merge'], + fetch: 'EAGER', + inversedBy: 'attributeDocuments' ), ORM\JoinColumn( - name: "attribute_id", - referencedColumnName: "id", + name: 'attribute_id', + referencedColumnName: 'id', nullable: false, - onDelete: "CASCADE" + onDelete: 'CASCADE' ), Serializer\Exclude(), SymfonySerializer\Ignore() @@ -43,18 +43,18 @@ class AttributeDocuments extends AbstractPositioned #[ ORM\ManyToOne( targetEntity: Document::class, - cascade: ["persist", "merge"], - fetch: "EAGER", - inversedBy: "attributeDocuments" + cascade: ['persist', 'merge'], + fetch: 'EAGER', + inversedBy: 'attributeDocuments' ), ORM\JoinColumn( - name: "document_id", - referencedColumnName: "id", + name: 'document_id', + referencedColumnName: 'id', nullable: false, - onDelete: "CASCADE" + onDelete: 'CASCADE' ), - Serializer\Groups(["attribute"]), - SymfonySerializer\Groups(["attribute"]), + Serializer\Groups(['attribute']), + SymfonySerializer\Groups(['attribute']), Serializer\Type(Document::class) ] protected Document $document; @@ -80,6 +80,7 @@ public function getDocument(): Document public function setDocument(Document $document): AttributeDocuments { $this->document = $document; + return $this; } @@ -91,6 +92,7 @@ public function getAttribute(): Attribute public function setAttribute(Attribute $attribute): AttributeDocuments { $this->attribute = $attribute; + return $this; } } diff --git a/src/Entity/AttributeGroup.php b/src/Entity/AttributeGroup.php index a0601959..cd56cac5 100644 --- a/src/Entity/AttributeGroup.php +++ b/src/Entity/AttributeGroup.php @@ -6,19 +6,19 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; +use RZ\Roadiz\Core\AbstractEntities\AbstractEntity; use RZ\Roadiz\CoreBundle\Model\AttributeGroupInterface; use RZ\Roadiz\CoreBundle\Model\AttributeGroupTrait; use RZ\Roadiz\CoreBundle\Model\AttributeGroupTranslationInterface; -use RZ\Roadiz\Core\AbstractEntities\AbstractEntity; use RZ\Roadiz\CoreBundle\Repository\AttributeGroupRepository; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; #[ ORM\Entity(repositoryClass: AttributeGroupRepository::class), - ORM\Table(name: "attribute_groups"), - ORM\Index(columns: ["canonical_name"]), + ORM\Table(name: 'attribute_groups'), + ORM\Index(columns: ['canonical_name']), ORM\HasLifecycleCallbacks, - UniqueEntity(fields: ["canonicalName"]) + UniqueEntity(fields: ['canonicalName']) ] class AttributeGroup extends AbstractEntity implements AttributeGroupInterface { diff --git a/src/Entity/AttributeGroupTranslation.php b/src/Entity/AttributeGroupTranslation.php index 502e2ea7..299e70d7 100644 --- a/src/Entity/AttributeGroupTranslation.php +++ b/src/Entity/AttributeGroupTranslation.php @@ -5,21 +5,21 @@ namespace RZ\Roadiz\CoreBundle\Entity; use Doctrine\ORM\Mapping as ORM; -use RZ\Roadiz\CoreBundle\Model\AttributeGroupTranslationInterface; use RZ\Roadiz\Core\AbstractEntities\AbstractEntity; +use RZ\Roadiz\CoreBundle\Model\AttributeGroupTranslationInterface; use RZ\Roadiz\CoreBundle\Model\AttributeGroupTranslationTrait; use RZ\Roadiz\CoreBundle\Repository\AttributeGroupTranslationRepository; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; #[ ORM\Entity(repositoryClass: AttributeGroupTranslationRepository::class), - ORM\Table(name: "attribute_group_translations"), - ORM\Index(columns: ["name"]), - ORM\UniqueConstraint(columns: ["attribute_group_id", "translation_id"]), - ORM\UniqueConstraint(columns: ["name", "translation_id"]), + ORM\Table(name: 'attribute_group_translations'), + ORM\Index(columns: ['name']), + ORM\UniqueConstraint(columns: ['attribute_group_id', 'translation_id']), + ORM\UniqueConstraint(columns: ['name', 'translation_id']), ORM\HasLifecycleCallbacks, - UniqueEntity(fields: ["attributeGroup", "translation"]), - UniqueEntity(fields: ["name", "translation"]) + UniqueEntity(fields: ['attributeGroup', 'translation']), + UniqueEntity(fields: ['name', 'translation']) ] class AttributeGroupTranslation extends AbstractEntity implements AttributeGroupTranslationInterface { diff --git a/src/Entity/AttributeTranslation.php b/src/Entity/AttributeTranslation.php index ef55c991..780ed7fd 100644 --- a/src/Entity/AttributeTranslation.php +++ b/src/Entity/AttributeTranslation.php @@ -5,19 +5,19 @@ namespace RZ\Roadiz\CoreBundle\Entity; use Doctrine\ORM\Mapping as ORM; +use RZ\Roadiz\Core\AbstractEntities\AbstractEntity; use RZ\Roadiz\CoreBundle\Model\AttributeTranslationInterface; use RZ\Roadiz\CoreBundle\Model\AttributeTranslationTrait; -use RZ\Roadiz\Core\AbstractEntities\AbstractEntity; use RZ\Roadiz\CoreBundle\Repository\AttributeTranslationRepository; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; #[ ORM\Entity(repositoryClass: AttributeTranslationRepository::class), - ORM\Table(name: "attribute_translations"), - ORM\Index(columns: ["label"]), - ORM\UniqueConstraint(columns: ["attribute_id", "translation_id"]), + ORM\Table(name: 'attribute_translations'), + ORM\Index(columns: ['label']), + ORM\UniqueConstraint(columns: ['attribute_id', 'translation_id']), ORM\HasLifecycleCallbacks, - UniqueEntity(fields: ["attribute", "translation"], errorPath: "translation") + UniqueEntity(fields: ['attribute', 'translation'], errorPath: 'translation') ] class AttributeTranslation extends AbstractEntity implements AttributeTranslationInterface { diff --git a/src/Entity/AttributeValue.php b/src/Entity/AttributeValue.php index f5df8d02..1bc3488d 100644 --- a/src/Entity/AttributeValue.php +++ b/src/Entity/AttributeValue.php @@ -21,14 +21,14 @@ #[ ORM\Entity(repositoryClass: AttributeValueRepository::class), - ORM\Table(name: "attribute_values"), - ORM\Index(columns: ["attribute_id", "node_id"]), - ORM\Index(columns: ["node_id", "position"], name: "idx_attribute_value_node_position"), - ORM\Index(columns: ["position"], name: "idx_attribute_value_position"), + ORM\Table(name: 'attribute_values'), + ORM\Index(columns: ['attribute_id', 'node_id']), + ORM\Index(columns: ['node_id', 'position'], name: 'idx_attribute_value_node_position'), + ORM\Index(columns: ['position'], name: 'idx_attribute_value_position'), ORM\HasLifecycleCallbacks, ApiFilter(PropertyFilter::class), ApiFilter(BaseFilter\OrderFilter::class, properties: [ - "position", + 'position', ]), ] class AttributeValue extends AbstractPositioned implements AttributeValueInterface @@ -36,20 +36,20 @@ class AttributeValue extends AbstractPositioned implements AttributeValueInterfa use AttributeValueTrait; #[ - ORM\ManyToOne(targetEntity: Node::class, inversedBy: "attributeValues"), - ORM\JoinColumn(name: "node_id", referencedColumnName: "id", nullable: false, onDelete: "CASCADE"), - Serializer\Groups(["attribute_node"]), - SymfonySerializer\Groups(["attribute_node"]), + ORM\ManyToOne(targetEntity: Node::class, inversedBy: 'attributeValues'), + ORM\JoinColumn(name: 'node_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE'), + Serializer\Groups(['attribute_node']), + SymfonySerializer\Groups(['attribute_node']), SymfonySerializer\MaxDepth(1), ApiFilter(BaseFilter\SearchFilter::class, properties: [ - "node" => "exact", - "node.id" => "exact", - "node.nodeName" => "exact", - "node.nodeType" => "exact", - "node.nodeType.name" => "exact" + 'node' => 'exact', + 'node.id' => 'exact', + 'node.nodeName' => 'exact', + 'node.nodeType' => 'exact', + 'node.nodeType.name' => 'exact', ]), ApiFilter(BaseFilter\BooleanFilter::class, properties: [ - "node.visible" + 'node.visible', ]) ] protected Node $node; @@ -88,12 +88,13 @@ public function getAttributable(): Node } /** - * @inheritDoc + * @return $this */ - public function setAttributable(?AttributableInterface $attributable) + public function setAttributable(?AttributableInterface $attributable): self { if ($attributable instanceof Node) { $this->node = $attributable; + return $this; } throw new \InvalidArgumentException('Attributable have to be an instance of Node.'); @@ -119,6 +120,7 @@ public function getRealm(): ?RealmInterface public function setRealm(?RealmInterface $realm): AttributeValue { $this->realm = $realm; + return $this; } diff --git a/src/Entity/AttributeValueTranslation.php b/src/Entity/AttributeValueTranslation.php index 83ed9f1d..180144d7 100644 --- a/src/Entity/AttributeValueTranslation.php +++ b/src/Entity/AttributeValueTranslation.php @@ -5,16 +5,16 @@ namespace RZ\Roadiz\CoreBundle\Entity; use Doctrine\ORM\Mapping as ORM; +use RZ\Roadiz\Core\AbstractEntities\AbstractEntity; use RZ\Roadiz\CoreBundle\Model\AttributeValueTranslationInterface; use RZ\Roadiz\CoreBundle\Model\AttributeValueTranslationTrait; -use RZ\Roadiz\Core\AbstractEntities\AbstractEntity; use RZ\Roadiz\CoreBundle\Repository\AttributeValueTranslationRepository; #[ ORM\Entity(repositoryClass: AttributeValueTranslationRepository::class), - ORM\Table(name: "attribute_value_translations"), - ORM\Index(columns: ["value"]), - ORM\Index(columns: ["translation_id", "attribute_value"]), + ORM\Table(name: 'attribute_value_translations'), + ORM\Index(columns: ['value']), + ORM\Index(columns: ['translation_id', 'attribute_value']), ORM\HasLifecycleCallbacks ] class AttributeValueTranslation extends AbstractEntity implements AttributeValueTranslationInterface diff --git a/src/Entity/CustomForm.php b/src/Entity/CustomForm.php index b4f9be4e..6fd474c0 100644 --- a/src/Entity/CustomForm.php +++ b/src/Entity/CustomForm.php @@ -5,17 +5,16 @@ namespace RZ\Roadiz\CoreBundle\Entity; use ApiPlatform\Metadata\ApiFilter; -use DateTime; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation as Serializer; +use RZ\Roadiz\Core\AbstractEntities\AbstractDateTimed; +use RZ\Roadiz\CoreBundle\Api\Filter as RoadizFilter; use RZ\Roadiz\CoreBundle\Repository\CustomFormRepository; +use RZ\Roadiz\Utils\StringHandler; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Serializer\Annotation as SymfonySerializer; -use RZ\Roadiz\Core\AbstractEntities\AbstractDateTimed; -use RZ\Roadiz\Utils\StringHandler; -use RZ\Roadiz\CoreBundle\Api\Filter as RoadizFilter; use Symfony\Component\Validator\Constraints as Assert; /** @@ -24,26 +23,26 @@ */ #[ ORM\Entity(repositoryClass: CustomFormRepository::class), - ORM\Table(name: "custom_forms"), + ORM\Table(name: 'custom_forms'), ORM\HasLifecycleCallbacks, - UniqueEntity(fields: ["name"]), - ORM\Index(columns: ["created_at"], name: "custom_form_created_at"), - ORM\Index(columns: ["updated_at"], name: "custom_form_updated_at"), + UniqueEntity(fields: ['name']), + ORM\Index(columns: ['created_at'], name: 'custom_form_created_at'), + ORM\Index(columns: ['updated_at'], name: 'custom_form_updated_at'), ] class CustomForm extends AbstractDateTimed { #[ - ORM\Column(name: "color", type: "string", length: 7, unique: false, nullable: true), - Serializer\Groups(["custom_form", "nodes_sources"]), + ORM\Column(name: 'color', type: 'string', length: 7, unique: false, nullable: true), + Serializer\Groups(['custom_form', 'nodes_sources']), Assert\Length(max: 7), SymfonySerializer\Ignore() ] protected ?string $color = '#000000'; #[ - ORM\Column(type: "string", length: 250, unique: true), - Serializer\Groups(["custom_form", "nodes_sources"]), - SymfonySerializer\Groups(["custom_form", "nodes_sources"]), + ORM\Column(type: 'string', length: 250, unique: true), + Serializer\Groups(['custom_form', 'nodes_sources']), + SymfonySerializer\Groups(['custom_form', 'nodes_sources']), Assert\NotNull(), Assert\NotBlank(), Assert\Length(max: 250), @@ -52,9 +51,9 @@ class CustomForm extends AbstractDateTimed private string $name = 'Untitled'; #[ - ORM\Column(name: "display_name", type: "string", length: 250), - Serializer\Groups(["custom_form", "nodes_sources"]), - SymfonySerializer\Groups(["custom_form", "nodes_sources"]), + ORM\Column(name: 'display_name', type: 'string', length: 250), + Serializer\Groups(['custom_form', 'nodes_sources']), + SymfonySerializer\Groups(['custom_form', 'nodes_sources']), Assert\NotNull(), Assert\NotBlank(), Assert\Length(max: 250), @@ -63,60 +62,60 @@ class CustomForm extends AbstractDateTimed private string $displayName = 'Untitled'; #[ - ORM\Column(type: "text", nullable: true), - Serializer\Groups(["custom_form", "nodes_sources"]), - SymfonySerializer\Groups(["custom_form", "nodes_sources"]), + ORM\Column(type: 'text', nullable: true), + Serializer\Groups(['custom_form', 'nodes_sources']), + SymfonySerializer\Groups(['custom_form', 'nodes_sources']), SymfonySerializer\Ignore() ] private ?string $description = null; #[ - ORM\Column(type: "text", nullable: true), - Serializer\Groups(["custom_form"]), - SymfonySerializer\Groups(["custom_form"]), + ORM\Column(type: 'text', nullable: true), + Serializer\Groups(['custom_form']), + SymfonySerializer\Groups(['custom_form']), SymfonySerializer\Ignore() ] private ?string $email = null; #[ - ORM\Column(type: "string", length: 15, nullable: true), - Serializer\Groups(["custom_form"]), - SymfonySerializer\Groups(["custom_form"]), + ORM\Column(type: 'string', length: 15, nullable: true), + Serializer\Groups(['custom_form']), + SymfonySerializer\Groups(['custom_form']), Assert\Length(max: 15), SymfonySerializer\Ignore() ] private ?string $retentionTime = null; #[ - ORM\Column(type: "boolean", nullable: false, options: ["default" => true]), - Serializer\Groups(["custom_form", "nodes_sources"]), - SymfonySerializer\Groups(["custom_form", "nodes_sources"]), + ORM\Column(type: 'boolean', nullable: false, options: ['default' => true]), + Serializer\Groups(['custom_form', 'nodes_sources']), + SymfonySerializer\Groups(['custom_form', 'nodes_sources']), SymfonySerializer\Ignore() ] private bool $open = true; #[ ApiFilter(RoadizFilter\ArchiveFilter::class), - ORM\Column(name: "close_date", type: "datetime", nullable: true), - Serializer\Groups(["custom_form", "nodes_sources"]), - SymfonySerializer\Groups(["custom_form", "nodes_sources"]), + ORM\Column(name: 'close_date', type: 'datetime', nullable: true), + Serializer\Groups(['custom_form', 'nodes_sources']), + SymfonySerializer\Groups(['custom_form', 'nodes_sources']), SymfonySerializer\Ignore() ] - private ?DateTime $closeDate = null; + private ?\DateTime $closeDate = null; /** * @var Collection */ #[ ORM\OneToMany( - mappedBy: "customForm", + mappedBy: 'customForm', targetEntity: CustomFormField::class, - cascade: ["ALL"], + cascade: ['ALL'], orphanRemoval: true ), - ORM\OrderBy(["position" => "ASC"]), - Serializer\Groups(["custom_form"]), - SymfonySerializer\Groups(["custom_form"]), + ORM\OrderBy(['position' => 'ASC']), + Serializer\Groups(['custom_form']), + SymfonySerializer\Groups(['custom_form']), SymfonySerializer\Ignore() ] private Collection $fields; @@ -126,9 +125,9 @@ class CustomForm extends AbstractDateTimed */ #[ ORM\OneToMany( - mappedBy: "customForm", + mappedBy: 'customForm', targetEntity: CustomFormAnswer::class, - cascade: ["ALL"], + cascade: ['ALL'], orphanRemoval: true ), Serializer\Exclude, @@ -140,7 +139,7 @@ class CustomForm extends AbstractDateTimed * @var Collection */ #[ - ORM\OneToMany(mappedBy: "customForm", targetEntity: NodesCustomForms::class, fetch: "EXTRA_LAZY"), + ORM\OneToMany(mappedBy: 'customForm', targetEntity: NodesCustomForms::class, fetch: 'EXTRA_LAZY'), Serializer\Exclude, SymfonySerializer\Ignore ] @@ -154,16 +153,12 @@ public function __construct() $this->initAbstractDateTimed(); } - /** - * @return string - */ public function getDisplayName(): string { return $this->displayName; } /** - * @param string|null $displayName * @return $this */ public function setDisplayName(?string $displayName): CustomForm @@ -174,94 +169,78 @@ public function setDisplayName(?string $displayName): CustomForm return $this; } - /** - * @return string|null - */ public function getDescription(): ?string { return $this->description; } /** - * @param string $description * @return $this */ public function setDescription(string $description): CustomForm { $this->description = $description; + return $this; } - /** - * @return string|null - */ public function getEmail(): ?string { return $this->email; } /** - * @param string|null $email - * * @return $this */ public function setEmail(?string $email): CustomForm { $this->email = $email; + return $this; } /** - * @param bool $open - * * @return $this */ public function setOpen(bool $open): CustomForm { $this->open = $open; + return $this; } - /** - * @return \DateTime|null - */ public function getCloseDate(): ?\DateTime { return $this->closeDate; } /** - * @param \DateTime|null $closeDate - * * @return $this */ public function setCloseDate(?\DateTime $closeDate): CustomForm { $this->closeDate = $closeDate; + return $this; } /** * Combine open flag and closeDate to determine * if current form is still available. - * - * @return bool */ #[ - Serializer\Groups(["custom_form", "nodes_sources"]), + Serializer\Groups(['custom_form', 'nodes_sources']), Serializer\VirtualProperty, SymfonySerializer\Ignore ] public function isFormStillOpen(): bool { - return (null === $this->getCloseDate() || $this->getCloseDate() >= (new \DateTime('now'))) && - $this->open === true; + return (null === $this->getCloseDate() || $this->getCloseDate() >= (new \DateTime('now'))) + && true === $this->open; } /** * Gets the value of color. - * - * @return string */ public function getColor(): string { @@ -271,21 +250,18 @@ public function getColor(): string /** * Sets the value of color. * - * @param string $color - * * @return $this */ public function setColor(string $color): CustomForm { $this->color = $color; + return $this; } /** * Get every node-type fields names in * a simple array. - * - * @return array */ public function getFieldsNames(): array { @@ -298,9 +274,6 @@ public function getFieldsNames(): array return $namesArray; } - /** - * @return Collection - */ public function getFields(): Collection { return $this->fields; @@ -309,8 +282,6 @@ public function getFields(): Collection /** * Get every node-type fields names in * a simple array. - * - * @return array */ public function getFieldsLabels(): array { @@ -323,10 +294,6 @@ public function getFieldsLabels(): array return $namesArray; } - /** - * @param CustomFormField $field - * @return CustomForm - */ public function addField(CustomFormField $field): CustomForm { if (!$this->getFields()->contains($field)) { @@ -337,10 +304,6 @@ public function addField(CustomFormField $field): CustomForm return $this; } - /** - * @param CustomFormField $field - * @return CustomForm - */ public function removeField(CustomFormField $field): CustomForm { if ($this->getFields()->contains($field)) { @@ -358,45 +321,32 @@ public function getCustomFormAnswers(): Collection return $this->customFormAnswers; } - /** - * @return string - */ public function getOneLineSummary(): string { - return $this->getId() . " — " . $this->getName() . - " — Open : " . ($this->isOpen() ? 'true' : 'false') . PHP_EOL; + return $this->getId().' — '.$this->getName(). + ' — Open : '.($this->isOpen() ? 'true' : 'false').PHP_EOL; } - /** - * @return string - */ public function getName(): string { return $this->name; } /** - * @param string $name - * * @return $this */ public function setName(string $name): CustomForm { $this->name = StringHandler::slugify($name); + return $this; } - /** - * @return bool - */ public function isOpen(): bool { return $this->open; } - /** - * @return string|null - */ public function getRetentionTime(): ?string { return $this->retentionTime; @@ -411,13 +361,10 @@ public function getRetentionTimeInterval(): ?\DateInterval } } - /** - * @param string|null $retentionTime - * @return CustomForm - */ public function setRetentionTime(?string $retentionTime): CustomForm { $this->retentionTime = $retentionTime; + return $this; } @@ -426,17 +373,14 @@ public function setRetentionTime(?string $retentionTime): CustomForm */ public function getFieldsSummary(): string { - $text = "|" . PHP_EOL; + $text = '|'.PHP_EOL; foreach ($this->getFields() as $field) { - $text .= "|--- " . $field->getOneLineSummary(); + $text .= '|--- '.$field->getOneLineSummary(); } return $text; } - /** - * @return Collection - */ public function getNodes(): Collection { return $this->nodes; @@ -446,7 +390,7 @@ public function __clone() { if ($this->id) { $this->id = null; - $suffix = "-" . uniqid(); + $suffix = '-'.uniqid(); $this->name .= $suffix; $this->displayName .= $suffix; $this->customFormAnswers = new ArrayCollection(); diff --git a/src/Entity/CustomFormAnswer.php b/src/Entity/CustomFormAnswer.php index 3199d4d1..0ba86fcb 100644 --- a/src/Entity/CustomFormAnswer.php +++ b/src/Entity/CustomFormAnswer.php @@ -4,36 +4,36 @@ namespace RZ\Roadiz\CoreBundle\Entity; -use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation as Serializer; +use RZ\Roadiz\Core\AbstractEntities\AbstractEntity; use RZ\Roadiz\CoreBundle\Repository\CustomFormAnswerRepository; use Symfony\Component\Serializer\Annotation as SymfonySerializer; -use RZ\Roadiz\Core\AbstractEntities\AbstractEntity; use Symfony\Component\Validator\Constraints as Assert; #[ ORM\Entity(repositoryClass: CustomFormAnswerRepository::class), - ORM\Table(name: "custom_form_answers"), - ORM\Index(columns: ["ip"]), - ORM\Index(columns: ["submitted_at"]), - ORM\Index(columns: ["custom_form_id", "submitted_at"], name: "answer_customform_submitted_at") + ORM\Table(name: 'custom_form_answers'), + ORM\Index(columns: ['ip']), + ORM\Index(columns: ['submitted_at']), + ORM\Index(columns: ['custom_form_id', 'submitted_at'], name: 'answer_customform_submitted_at') ] class CustomFormAnswer extends AbstractEntity { #[ - ORM\Column(name: "ip", type: "string", length: 46, nullable: false), - Serializer\Groups(["custom_form_answer"]), - SymfonySerializer\Groups(["custom_form_answer"]), + ORM\Column(name: 'ip', type: 'string', length: 46, nullable: false), + Serializer\Groups(['custom_form_answer']), + SymfonySerializer\Groups(['custom_form_answer']), Assert\Length(max: 46) ] private string $ip = ''; #[ - ORM\Column(name: "submitted_at", type: "datetime", nullable: false), - Serializer\Groups(["custom_form_answer"]), - SymfonySerializer\Groups(["custom_form_answer"]) + ORM\Column(name: 'submitted_at', type: 'datetime', nullable: false), + Serializer\Groups(['custom_form_answer']), + SymfonySerializer\Groups(['custom_form_answer']) ] private \DateTime $submittedAt; @@ -42,22 +42,22 @@ class CustomFormAnswer extends AbstractEntity */ #[ ORM\OneToMany( - mappedBy: "customFormAnswer", + mappedBy: 'customFormAnswer', targetEntity: CustomFormFieldAttribute::class, - cascade: ["ALL"], + cascade: ['ALL'], orphanRemoval: true ), - Serializer\Groups(["custom_form_answer"]), - SymfonySerializer\Groups(["custom_form_answer"]) + Serializer\Groups(['custom_form_answer']), + SymfonySerializer\Groups(['custom_form_answer']) ] private Collection $answerFields; #[ ORM\ManyToOne( targetEntity: CustomForm::class, - inversedBy: "customFormAnswers" + inversedBy: 'customFormAnswers' ), - ORM\JoinColumn(name: "custom_form_id", referencedColumnName: "id", nullable: false, onDelete: "CASCADE"), + ORM\JoinColumn(name: 'custom_form_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE'), Serializer\Exclude, SymfonySerializer\Ignore ] @@ -70,7 +70,6 @@ public function __construct() } /** - * @param CustomFormFieldAttribute $field * @return $this */ public function addAnswerField(CustomFormFieldAttribute $field): CustomFormAnswer @@ -91,8 +90,6 @@ public function getAnswerFields(): Collection } /** - * @param CustomFormFieldAttribute $field - * * @return $this */ public function removeAnswerField(CustomFormFieldAttribute $field): CustomFormAnswer @@ -104,84 +101,68 @@ public function removeAnswerField(CustomFormFieldAttribute $field): CustomFormAn return $this; } - /** - * @return CustomForm - */ public function getCustomForm(): CustomForm { return $this->customForm; } /** - * @param CustomForm $customForm * @return $this */ public function setCustomForm(CustomForm $customForm): CustomFormAnswer { $this->customForm = $customForm; + return $this; } - /** - * @return string - */ public function __toString(): string { return (string) $this->getId(); } - /** - * @return string - */ public function getIp(): string { return $this->ip; } /** - * @param string $ip - * * @return $this */ public function setIp(string $ip): CustomFormAnswer { $this->ip = $ip; + return $this; } - /** - * @return \DateTime|null - */ public function getSubmittedAt(): ?\DateTime { return $this->submittedAt; } /** - * @param \DateTime $submittedAt - * * @return $this */ public function setSubmittedAt(\DateTime $submittedAt): CustomFormAnswer { $this->submittedAt = $submittedAt; + return $this; } - /** - * @return string|null - */ public function getEmail(): ?string { $attribute = $this->getAnswerFields()->filter(function (CustomFormFieldAttribute $attribute) { return $attribute->getCustomFormField()->isEmail(); })->first(); + return $attribute ? (string) $attribute->getValue() : null; } /** * @param bool $namesAsKeys Use fields name as key. Default: true - * @return array + * * @throws \Exception */ public function toArray(bool $namesAsKeys = true): array @@ -201,6 +182,7 @@ public function toArray(bool $namesAsKeys = true): array ]; } } + return $answers; } } diff --git a/src/Entity/CustomFormField.php b/src/Entity/CustomFormField.php index b58a6f29..f2048c53 100644 --- a/src/Entity/CustomFormField.php +++ b/src/Entity/CustomFormField.php @@ -8,10 +8,10 @@ use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation as Serializer; +use RZ\Roadiz\Core\AbstractEntities\AbstractField; use RZ\Roadiz\CoreBundle\Repository\CustomFormFieldRepository; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Serializer\Annotation as SymfonySerializer; -use RZ\Roadiz\Core\AbstractEntities\AbstractField; use Symfony\Component\Validator\Constraints\Choice; /** @@ -20,20 +20,17 @@ */ #[ ORM\Entity(repositoryClass: CustomFormFieldRepository::class), - ORM\Table(name: "custom_form_fields"), - ORM\UniqueConstraint(columns: ["name", "custom_form_id"]), - ORM\Index(columns: ["position"]), - ORM\Index(columns: ["group_name"]), - ORM\Index(columns: ["type"]), - ORM\Index(columns: ["custom_form_id", "position"], name: "cfield_customform_position"), + ORM\Table(name: 'custom_form_fields'), + ORM\UniqueConstraint(columns: ['name', 'custom_form_id']), + ORM\Index(columns: ['position']), + ORM\Index(columns: ['group_name']), + ORM\Index(columns: ['type']), + ORM\Index(columns: ['custom_form_id', 'position'], name: 'cfield_customform_position'), ORM\HasLifecycleCallbacks, - UniqueEntity(fields: ["label", "customForm"]) + UniqueEntity(fields: ['label', 'customForm']) ] class CustomFormField extends AbstractField { - /** - * @inheritdoc - */ public static array $typeToHuman = [ AbstractField::STRING_T => 'string.type', AbstractField::DATETIME_T => 'date-time.type', @@ -51,8 +48,8 @@ class CustomFormField extends AbstractField ]; #[ - ORM\ManyToOne(targetEntity: CustomForm::class, inversedBy: "fields"), - ORM\JoinColumn(name: "custom_form_id", referencedColumnName: "id", nullable: false, onDelete: "CASCADE"), + ORM\ManyToOne(targetEntity: CustomForm::class, inversedBy: 'fields'), + ORM\JoinColumn(name: 'custom_form_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE'), Serializer\Exclude, SymfonySerializer\Ignore ] @@ -62,16 +59,16 @@ class CustomFormField extends AbstractField * @var Collection */ #[ - ORM\OneToMany(mappedBy: "customFormField", targetEntity: CustomFormFieldAttribute::class), + ORM\OneToMany(mappedBy: 'customFormField', targetEntity: CustomFormFieldAttribute::class), Serializer\Exclude, SymfonySerializer\Ignore ] private Collection $customFormFieldAttributes; #[ - ORM\Column(name: "field_required", type: "boolean", nullable: false, options: ["default" => false]), - Serializer\Groups(["custom_form"]), - SymfonySerializer\Groups(["custom_form"]) + ORM\Column(name: 'field_required', type: 'boolean', nullable: false, options: ['default' => false]), + Serializer\Groups(['custom_form']), + SymfonySerializer\Groups(['custom_form']) ] private bool $required = false; @@ -79,9 +76,9 @@ class CustomFormField extends AbstractField * @var string|null https://developer.mozilla.org/fr/docs/Web/HTML/Attributes/autocomplete */ #[ - ORM\Column(name: "autocomplete", type: 'string', length:18, nullable: true), - Serializer\Groups(["custom_form"]), - SymfonySerializer\Groups(["custom_form"]), + ORM\Column(name: 'autocomplete', type: 'string', length: 18, nullable: true), + Serializer\Groups(['custom_form']), + SymfonySerializer\Groups(['custom_form']), Choice([ 'off', 'name', @@ -144,9 +141,6 @@ public function setCustomForm(CustomForm $customForm): CustomFormField return $this; } - /** - * @return Collection - */ public function getCustomFormFieldAttribute(): Collection { return $this->customFormFieldAttributes; @@ -161,13 +155,12 @@ public function isRequired(): bool } /** - * @param bool $required - * * @return $this */ public function setRequired(bool $required): CustomFormField { $this->required = $required; + return $this; } @@ -179,20 +172,15 @@ public function getAutocomplete(): ?string public function setAutocomplete(?string $autocomplete): CustomFormField { $this->autocomplete = $autocomplete; + return $this; } - /** - * @return string - */ public function getOneLineSummary(): string { - return $this->getId() . " — " . $this->getName() . " — " . $this->getLabel() . PHP_EOL; + return $this->getId().' — '.$this->getName().' — '.$this->getLabel().PHP_EOL; } - /** - * @return string - */ public function __toString(): string { return (string) $this->getId(); diff --git a/src/Entity/CustomFormFieldAttribute.php b/src/Entity/CustomFormFieldAttribute.php index b8452226..188a0d91 100644 --- a/src/Entity/CustomFormFieldAttribute.php +++ b/src/Entity/CustomFormFieldAttribute.php @@ -16,21 +16,21 @@ */ #[ ORM\Entity(repositoryClass: CustomFormFieldAttributeRepository::class), - ORM\Table(name: "custom_form_field_attributes"), - ORM\Index(columns: ["custom_form_answer_id", "custom_form_field_id"], name: "cffattribute_answer_field"), + ORM\Table(name: 'custom_form_field_attributes'), + ORM\Index(columns: ['custom_form_answer_id', 'custom_form_field_id'], name: 'cffattribute_answer_field'), ORM\HasLifecycleCallbacks ] class CustomFormFieldAttribute extends AbstractEntity { #[ - ORM\ManyToOne(targetEntity: CustomFormAnswer::class, inversedBy: "answerFields"), - ORM\JoinColumn(name: "custom_form_answer_id", referencedColumnName: "id", nullable: false, onDelete: "CASCADE") + ORM\ManyToOne(targetEntity: CustomFormAnswer::class, inversedBy: 'answerFields'), + ORM\JoinColumn(name: 'custom_form_answer_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE') ] protected CustomFormAnswer $customFormAnswer; #[ - ORM\ManyToOne(targetEntity: CustomFormField::class, inversedBy: "customFormFieldAttributes"), - ORM\JoinColumn(name: "custom_form_field_id", referencedColumnName: "id", nullable: false, onDelete: "CASCADE") + ORM\ManyToOne(targetEntity: CustomFormField::class, inversedBy: 'customFormFieldAttributes'), + ORM\JoinColumn(name: 'custom_form_field_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE') ] protected CustomFormField $customFormField; @@ -38,14 +38,14 @@ class CustomFormFieldAttribute extends AbstractEntity * @var Collection */ #[ - ORM\ManyToMany(targetEntity: Document::class, inversedBy: "customFormFieldAttributes"), - ORM\JoinTable(name: "custom_form_answers_documents"), - ORM\JoinColumn(name: "customformfieldattribute_id", onDelete: "CASCADE"), - ORM\InverseJoinColumn(name: "document_id", onDelete: "CASCADE") + ORM\ManyToMany(targetEntity: Document::class, inversedBy: 'customFormFieldAttributes'), + ORM\JoinTable(name: 'custom_form_answers_documents'), + ORM\JoinColumn(name: 'customformfieldattribute_id', onDelete: 'CASCADE'), + ORM\InverseJoinColumn(name: 'document_id', onDelete: 'CASCADE') ] protected Collection $documents; - #[ORM\Column(type: "text", nullable: true)] + #[ORM\Column(type: 'text', nullable: true)] protected ?string $value = null; public function __construct() @@ -55,6 +55,7 @@ public function __construct() /** * @return string|null $value + * * @throws \Exception */ public function getValue(): ?string @@ -70,16 +71,17 @@ public function getValue(): ?string if ($this->getCustomFormField()->isDateTime()) { return (new \DateTime($this->value))->format('Y-m-d H:i:s'); } + return $this->value; } /** - * @param string|null $value * @return $this */ public function setValue(?string $value): CustomFormFieldAttribute { $this->value = $value; + return $this; } @@ -96,7 +98,6 @@ public function setCustomFormAnswer(CustomFormAnswer $customFormAnswer): CustomF } /** - * @return string * @throws \Exception */ public function __toString(): string @@ -116,22 +117,15 @@ public function setCustomFormField(CustomFormField $customFormField): CustomForm return $this; } - /** - * @return Collection - */ public function getDocuments(): Collection { return $this->documents; } - /** - * @param Collection $documents - * - * @return CustomFormFieldAttribute - */ public function setDocuments(Collection $documents): CustomFormFieldAttribute { $this->documents = $documents; + return $this; } } diff --git a/src/Entity/Document.php b/src/Entity/Document.php index e81e5633..aefebf93 100644 --- a/src/Entity/Document.php +++ b/src/Entity/Document.php @@ -11,6 +11,7 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Criteria; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation as Serializer; use RZ\Roadiz\Core\AbstractEntities\AbstractDateTimed; @@ -34,39 +35,39 @@ */ #[ ORM\Entity(repositoryClass: DocumentRepository::class), - ORM\Table(name: "documents"), - ORM\Index(columns: ["created_at"], name: "document_created_at"), - ORM\Index(columns: ["updated_at"], name: "document_updated_at"), - ORM\Index(columns: ["raw"]), - ORM\Index(columns: ["raw", "created_at"], name: "document_raw_created_at"), - ORM\Index(columns: ["private"]), - ORM\Index(columns: ["filename"], name: "document_filename"), - ORM\Index(columns: ["file_hash"], name: "document_file_hash"), - ORM\Index(columns: ["file_hash_algorithm"], name: "document_hash_algorithm"), - ORM\Index(columns: ["file_hash", "file_hash_algorithm"], name: "document_file_hash_algorithm"), - ORM\Index(columns: ["embedId"], name: "document_embed_id"), - ORM\Index(columns: ["embedId", "embedPlatform"], name: "document_embed_platform_id"), - ORM\Index(columns: ["embedPlatform"], name: "document_embed_platform"), - ORM\Index(columns: ["raw", "private"]), - ORM\Index(columns: ["duration"], name: "document_duration"), - ORM\Index(columns: ["filesize"], name: "document_filesize"), - ORM\Index(columns: ["imageWidth"], name: "document_image_width"), - ORM\Index(columns: ["imageHeight"], name: "document_image_height"), - ORM\Index(columns: ["mime_type"]), - Serializer\ExclusionPolicy("all"), + ORM\Table(name: 'documents'), + ORM\Index(columns: ['created_at'], name: 'document_created_at'), + ORM\Index(columns: ['updated_at'], name: 'document_updated_at'), + ORM\Index(columns: ['raw']), + ORM\Index(columns: ['raw', 'created_at'], name: 'document_raw_created_at'), + ORM\Index(columns: ['private']), + ORM\Index(columns: ['filename'], name: 'document_filename'), + ORM\Index(columns: ['file_hash'], name: 'document_file_hash'), + ORM\Index(columns: ['file_hash_algorithm'], name: 'document_hash_algorithm'), + ORM\Index(columns: ['file_hash', 'file_hash_algorithm'], name: 'document_file_hash_algorithm'), + ORM\Index(columns: ['embedId'], name: 'document_embed_id'), + ORM\Index(columns: ['embedId', 'embedPlatform'], name: 'document_embed_platform_id'), + ORM\Index(columns: ['embedPlatform'], name: 'document_embed_platform'), + ORM\Index(columns: ['raw', 'private']), + ORM\Index(columns: ['duration'], name: 'document_duration'), + ORM\Index(columns: ['filesize'], name: 'document_filesize'), + ORM\Index(columns: ['imageWidth'], name: 'document_image_width'), + ORM\Index(columns: ['imageHeight'], name: 'document_image_height'), + ORM\Index(columns: ['mime_type']), + Serializer\ExclusionPolicy('all'), ApiFilter(PropertyFilter::class), ApiFilter(BaseFilter\OrderFilter::class, properties: [ - "createdAt", - "updatedAt", - "copyrightValidSince", - "copyrightValidUntil", - "filesize" + 'createdAt', + 'updatedAt', + 'copyrightValidSince', + 'copyrightValidUntil', + 'filesize', ]), ApiFilter(BaseFilter\DateFilter::class, properties: [ - "createdAt", - "updatedAt", - "copyrightValidSince" => "include_null_before", - "copyrightValidUntil" => "include_null_after" + 'createdAt', + 'updatedAt', + 'copyrightValidSince' => 'include_null_before', + 'copyrightValidUntil' => 'include_null_after', ]), ApiFilter(CopyrightValidFilter::class) ] @@ -123,7 +124,7 @@ class Document extends AbstractDateTimed implements AdvancedDocumentInterface, H 'right', 'bottom-left', 'bottom', - 'bottom-right' + 'bottom-right', ])] protected ?string $imageCropAlignment = null; @@ -140,8 +141,8 @@ class Document extends AbstractDateTimed implements AdvancedDocumentInterface, H #[ SymfonySerializer\Ignore, - Serializer\Groups(["document"]), - Serializer\Type("bool"), + Serializer\Groups(['document']), + Serializer\Type('bool'), ORM\Column(name: 'raw', type: 'boolean', nullable: false, options: ['default' => false]) ] protected bool $raw = false; @@ -149,7 +150,7 @@ class Document extends AbstractDateTimed implements AdvancedDocumentInterface, H #[ORM\Column(name: 'embedId', type: 'string', length: 250, unique: false, nullable: true)] #[SymfonySerializer\Groups(['document', 'document_display', 'nodes_sources', 'tag', 'attribute'])] #[Serializer\Groups(['document', 'document_display', 'nodes_sources', 'tag', 'attribute'])] - #[Serializer\Type("string")] + #[Serializer\Type('string')] #[ApiProperty( description: 'Embed ID on external platforms', example: 'FORSwsjtQSE', @@ -171,7 +172,7 @@ class Document extends AbstractDateTimed implements AdvancedDocumentInterface, H #[Assert\Length(max: 15)] protected ?string $fileHashAlgorithm = null; - #[ApiFilter(BaseFilter\SearchFilter::class, strategy: "exact")] + #[ApiFilter(BaseFilter\SearchFilter::class, strategy: 'exact')] #[ApiFilter(RoadizFilter\NotFilter::class)] #[ORM\Column(name: 'embedPlatform', type: 'string', length: 100, unique: false, nullable: true)] #[SymfonySerializer\Groups(['document', 'document_display', 'nodes_sources', 'tag', 'attribute'])] @@ -230,20 +231,14 @@ class Document extends AbstractDateTimed implements AdvancedDocumentInterface, H #[Serializer\Groups(['document', 'nodes_sources', 'tag', 'attribute'])] #[Serializer\Type('ArrayCollection')] protected Collection $documentTranslations; - /** - * @var string|null - */ - #[ApiFilter(BaseFilter\SearchFilter::class, strategy: "partial")] + #[ApiFilter(BaseFilter\SearchFilter::class, strategy: 'partial')] #[ORM\Column(name: 'filename', type: 'string', length: 250, nullable: true)] #[SymfonySerializer\Ignore] #[Serializer\Groups(['document', 'nodes_sources', 'tag', 'attribute'])] #[Serializer\Type('string')] #[Assert\Length(max: 250)] private ?string $filename = null; - /** - * @var string|null - */ - #[ApiFilter(BaseFilter\SearchFilter::class, strategy: "exact")] + #[ApiFilter(BaseFilter\SearchFilter::class, strategy: 'exact')] #[ApiFilter(RoadizFilter\NotFilter::class)] #[ORM\Column(name: 'mime_type', type: 'string', length: 255, nullable: true)] #[SymfonySerializer\Groups(['document', 'document_display', 'nodes_sources', 'tag', 'attribute'])] @@ -262,27 +257,18 @@ class Document extends AbstractDateTimed implements AdvancedDocumentInterface, H #[SymfonySerializer\Ignore] #[Serializer\Exclude] private Collection $downscaledDocuments; - /** - * @var string - */ #[ORM\Column(type: 'string', length: 100)] #[SymfonySerializer\Ignore] #[Assert\Length(max: 100)] #[Serializer\Groups(['document', 'nodes_sources', 'tag', 'attribute'])] #[Serializer\Type('string')] private string $folder = ''; - /** - * @var bool - */ #[ORM\Column(type: 'boolean', nullable: false, options: ['default' => false])] #[SymfonySerializer\Ignore] #[Serializer\Groups(['document', 'document_private', 'nodes_sources', 'tag', 'attribute'])] #[Serializer\Type('bool')] private bool $private = false; - /** - * @var integer - */ - #[ORM\Column(name: 'imageWidth', type: 'integer', nullable: false, options: ['default' => 0])] + #[ORM\Column(name: 'imageWidth', type: Types::SMALLINT, nullable: false, options: ['default' => 0])] #[SymfonySerializer\Groups(['document', 'document_display', 'nodes_sources', 'tag', 'attribute'])] #[Serializer\Groups(['document', 'document_display', 'nodes_sources', 'tag', 'attribute'])] #[Serializer\Type('int')] @@ -291,10 +277,7 @@ class Document extends AbstractDateTimed implements AdvancedDocumentInterface, H example: '1280', )] private int $imageWidth = 0; - /** - * @var integer - */ - #[ORM\Column(name: 'imageHeight', type: 'integer', nullable: false, options: ['default' => 0])] + #[ORM\Column(name: 'imageHeight', type: Types::SMALLINT, nullable: false, options: ['default' => 0])] #[SymfonySerializer\Groups(['document', 'document_display', 'nodes_sources', 'tag', 'attribute'])] #[Serializer\Groups(['document', 'document_display', 'nodes_sources', 'tag', 'attribute'])] #[Serializer\Type('int')] @@ -303,10 +286,7 @@ class Document extends AbstractDateTimed implements AdvancedDocumentInterface, H example: '800', )] private int $imageHeight = 0; - /** - * @var integer - */ - #[ORM\Column(name: 'duration', type: 'integer', nullable: false, options: ['default' => 0])] + #[ORM\Column(name: 'duration', type: Types::INTEGER, nullable: false, options: ['default' => 0])] #[SymfonySerializer\Groups(['document', 'document_display', 'nodes_sources', 'tag', 'attribute'])] #[Serializer\Groups(['document', 'document_display', 'nodes_sources', 'tag', 'attribute'])] #[Serializer\Type('int')] @@ -315,9 +295,6 @@ class Document extends AbstractDateTimed implements AdvancedDocumentInterface, H example: '300', )] private int $mediaDuration = 0; - /** - * @var string|null - */ #[ORM\Column(name: 'average_color', type: 'string', length: 7, unique: false, nullable: true)] #[SymfonySerializer\Groups(['document', 'document_display', 'nodes_sources', 'tag', 'attribute'])] #[Serializer\Groups(['document', 'document_display', 'nodes_sources', 'tag', 'attribute'])] @@ -329,7 +306,7 @@ class Document extends AbstractDateTimed implements AdvancedDocumentInterface, H )] private ?string $imageAverageColor = null; /** - * @var int|null The filesize in bytes. + * @var int|null the filesize in bytes */ #[ORM\Column(name: 'filesize', type: 'integer', unique: false, nullable: true)] #[SymfonySerializer\Groups(['document_filesize'])] @@ -346,9 +323,6 @@ class Document extends AbstractDateTimed implements AdvancedDocumentInterface, H #[Serializer\Type('ArrayCollection')] private Collection $thumbnails; - /** - * @var HasThumbnailInterface|null - */ #[ORM\ManyToOne(targetEntity: Document::class, fetch: 'EXTRA_LAZY', inversedBy: 'thumbnails')] #[ORM\JoinColumn(name: 'original', nullable: true, onDelete: 'SET NULL')] #[SymfonySerializer\Groups(['document_original'])] @@ -373,9 +347,6 @@ public function __construct() $this->thumbnails = new ArrayCollection(); } - /** - * @return string|null - */ public function getMimeType(): ?string { return $this->mimeType; @@ -384,12 +355,10 @@ public function getMimeType(): ?string public function setMimeType(?string $mimeType): static { $this->mimeType = $mimeType; + return $this; } - /** - * @return string - */ public function getFolder(): string { return $this->folder; @@ -398,6 +367,7 @@ public function getFolder(): string public function setFolder(string $folder): static { $this->folder = $folder; + return $this; } @@ -422,11 +392,12 @@ public function getRawDocument(): ?DocumentInterface return $this->rawDocument; } - public function setRawDocument(DocumentInterface $rawDocument = null): static + public function setRawDocument(?DocumentInterface $rawDocument = null): static { if (null === $rawDocument || $rawDocument instanceof Document) { $this->rawDocument = $rawDocument; } + return $this; } @@ -494,7 +465,6 @@ public function removeFolder(FolderInterface $folder): static } /** - * @param TranslationInterface $translation * @return Collection */ #[SymfonySerializer\Ignore] @@ -515,7 +485,6 @@ public function getDocumentTranslationsByDefaultTranslation(): ?DocumentTranslat } /** - * @param DocumentTranslation $documentTranslation * @return $this */ public function addDocumentTranslation(DocumentTranslation $documentTranslation): static @@ -535,9 +504,6 @@ public function getDocumentTranslations(): Collection return $this->documentTranslations; } - /** - * @return bool - */ #[SymfonySerializer\Ignore] public function hasTranslations(): bool { @@ -546,8 +512,6 @@ public function hasTranslations(): bool /** * Is document a raw one. - * - * @return bool */ public function isRaw(): bool { @@ -557,13 +521,12 @@ public function isRaw(): bool public function setRaw(bool $raw): static { $this->raw = $raw; + return $this; } /** * Gets the downscaledDocument. - * - * @return DocumentInterface|null */ #[SymfonySerializer\Ignore] public function getDownscaledDocument(): ?DocumentInterface @@ -571,21 +534,16 @@ public function getDownscaledDocument(): ?DocumentInterface return $this->downscaledDocuments->first() ?: null; } - /** - * @return float|null - */ #[SymfonySerializer\Ignore] public function getImageRatio(): ?float { if ($this->getImageWidth() > 0 && $this->getImageHeight() > 0) { return $this->getImageWidth() / $this->getImageHeight(); } + return null; } - /** - * @return int - */ public function getImageWidth(): int { return $this->imageWidth; @@ -598,9 +556,6 @@ public function setImageWidth(int $imageWidth): static return $this; } - /** - * @return int - */ public function getImageHeight(): int { return $this->imageHeight; @@ -613,9 +568,6 @@ public function setImageHeight(int $imageHeight): static return $this; } - /** - * @return int - */ public function getMediaDuration(): int { return $this->mediaDuration; @@ -624,12 +576,10 @@ public function getMediaDuration(): int public function setMediaDuration(int $duration): static { $this->mediaDuration = $duration; + return $this; } - /** - * @return string|null - */ public function getImageAverageColor(): ?string { return $this->imageAverageColor; @@ -638,12 +588,10 @@ public function getImageAverageColor(): ?string public function setImageAverageColor(?string $imageAverageColor): static { $this->imageAverageColor = $imageAverageColor; + return $this; } - /** - * @return int|null - */ public function getFilesize(): ?int { return $this->filesize; @@ -652,16 +600,17 @@ public function getFilesize(): ?int public function setFilesize(?int $filesize): static { $this->filesize = $filesize; + return $this; } #[ - Serializer\Groups(["document", "document_display", "nodes_sources", "tag", "attribute"]), - Serializer\Type("string"), + Serializer\Groups(['document', 'document_display', 'nodes_sources', 'tag', 'attribute']), + Serializer\Type('string'), Serializer\VirtualProperty, - Serializer\SerializedName("alt"), - SymfonySerializer\Groups(["document", "document_display", "nodes_sources", "tag", "attribute"]), - SymfonySerializer\SerializedName("alt"), + Serializer\SerializedName('alt'), + SymfonySerializer\Groups(['document', 'document_display', 'nodes_sources', 'tag', 'attribute']), + SymfonySerializer\SerializedName('alt'), ApiProperty( description: 'Document alternative text, for img HTML tag.', writable: false, @@ -670,6 +619,7 @@ public function setFilesize(?int $filesize): static public function getAlternativeText(): string { $documentTranslation = $this->getDocumentTranslations()->first(); + return $documentTranslation && !empty($documentTranslation->getName()) ? $documentTranslation->getName() : $this->getFilename(); @@ -683,20 +633,14 @@ public function __clone() } } - /** - * @return bool - */ #[SymfonySerializer\Groups(['document'])] #[Serializer\Groups(['document'])] #[Serializer\VirtualProperty] public function isThumbnail(): bool { - return $this->getOriginal() !== null; + return null !== $this->getOriginal(); } - /** - * @return HasThumbnailInterface|null - */ #[SymfonySerializer\Ignore] public function getOriginal(): ?HasThumbnailInterface { @@ -712,9 +656,6 @@ public function setOriginal(?HasThumbnailInterface $original): static return $this; } - /** - * @return bool - */ #[SymfonySerializer\Groups(['document'])] #[Serializer\Groups(['document'])] #[Serializer\VirtualProperty] @@ -723,9 +664,6 @@ public function hasThumbnails(): bool return $this->getThumbnails()->count() > 0; } - /** - * @return Collection - */ public function getThumbnails(): Collection { // Filter private thumbnails @@ -755,9 +693,6 @@ public function setThumbnails(Collection $thumbnails): static return $this; } - /** - * @return DocumentInterface|null - */ #[SymfonySerializer\Groups(['document_thumbnails'])] #[SymfonySerializer\SerializedName('thumbnail')] #[SymfonySerializer\MaxDepth(1)] @@ -767,20 +702,15 @@ public function getFirstThumbnail(): ?DocumentInterface if ($this->isEmbed() || !$this->isImage()) { return $this->getThumbnails()->first() ?: null; } + return null; } - /** - * @return bool - */ public function needsThumbnail(): bool { return !$this->isProcessable(); } - /** - * @return string|null - */ public function getFileHash(): ?string { return $this->fileHash; @@ -789,12 +719,10 @@ public function getFileHash(): ?string public function setFileHash(?string $hash): static { $this->fileHash = $hash; + return $this; } - /** - * @return string|null - */ public function getFileHashAlgorithm(): ?string { return $this->fileHashAlgorithm; @@ -803,12 +731,10 @@ public function getFileHashAlgorithm(): ?string public function setFileHashAlgorithm(?string $algorithm): static { $this->fileHashAlgorithm = $algorithm; + return $this; } - /** - * @return \DateTime|null - */ public function getCopyrightValidSince(): ?\DateTime { return $this->copyrightValidSince; @@ -817,12 +743,10 @@ public function getCopyrightValidSince(): ?\DateTime public function setCopyrightValidSince(?\DateTime $copyrightValidSince): static { $this->copyrightValidSince = $copyrightValidSince; + return $this; } - /** - * @return \DateTime|null - */ public function getCopyrightValidUntil(): ?\DateTime { return $this->copyrightValidUntil; @@ -831,12 +755,10 @@ public function getCopyrightValidUntil(): ?\DateTime public function setCopyrightValidUntil(?\DateTime $copyrightValidUntil): static { $this->copyrightValidUntil = $copyrightValidUntil; + return $this; } - /** - * @return string - */ public function __toString(): string { if (!empty($this->getFilename())) { @@ -847,14 +769,12 @@ public function __toString(): string return $translation->getName(); } if (!empty($this->getEmbedPlatform())) { - return $this->getEmbedPlatform() . ' (' . $this->getEmbedId() . ')'; + return $this->getEmbedPlatform().' ('.$this->getEmbedId().')'; } + return (string) $this->getId(); } - /** - * @return string - */ public function getFilename(): string { return $this->filename ?? ''; @@ -867,7 +787,6 @@ public function setFilename(string $filename): static return $this; } - public function getEmbedPlatform(): ?string { return $this->embedPlatform; @@ -876,6 +795,7 @@ public function getEmbedPlatform(): ?string public function setEmbedPlatform(?string $embedPlatform): static { $this->embedPlatform = $embedPlatform; + return $this; } @@ -887,6 +807,7 @@ public function getEmbedId(): ?string public function setEmbedId(?string $embedId): static { $this->embedId = $embedId; + return $this; } @@ -898,6 +819,7 @@ public function getImageCropAlignment(): ?string public function setImageCropAlignment(?string $imageCropAlignment): Document { $this->imageCropAlignment = $imageCropAlignment; + return $this; } } diff --git a/src/Entity/DocumentTranslation.php b/src/Entity/DocumentTranslation.php index e7ac1609..db4872b3 100644 --- a/src/Entity/DocumentTranslation.php +++ b/src/Entity/DocumentTranslation.php @@ -17,8 +17,8 @@ #[ ORM\Entity(repositoryClass: DocumentTranslationRepository::class), - ORM\Table(name: "documents_translations"), - ORM\UniqueConstraint(columns: ["document_id", "translation_id"]), + ORM\Table(name: 'documents_translations'), + ORM\UniqueConstraint(columns: ['document_id', 'translation_id']), Gedmo\Loggable(logEntryClass: UserLogEntry::class) ] class DocumentTranslation extends AbstractEntity implements Loggable @@ -60,22 +60,18 @@ class DocumentTranslation extends AbstractEntity implements Loggable #[Gedmo\Versioned] private ?string $copyright = null; - /** - * @return string|null - */ public function getName(): ?string { return $this->name; } /** - * @param string|null $name - * * @return $this */ public function setName(?string $name): DocumentTranslation { $this->name = $name; + return $this; } @@ -87,20 +83,16 @@ public function getDescription(): ?string public function setDescription(?string $description): DocumentTranslation { $this->description = $description; + return $this; } - /** - * @return string|null - */ public function getCopyright(): ?string { return $this->copyright; } /** - * @param string|null $copyright - * * @return $this */ public function setCopyright(?string $copyright): DocumentTranslation @@ -110,34 +102,24 @@ public function setCopyright(?string $copyright): DocumentTranslation return $this; } - /** - * @return string|null - */ public function getExternalUrl(): ?string { return $this->externalUrl; } - /** - * @param string|null $externalUrl - * @return DocumentTranslation - */ public function setExternalUrl(?string $externalUrl): DocumentTranslation { $this->externalUrl = $externalUrl; + return $this; } - /** - * @return TranslationInterface - */ public function getTranslation(): TranslationInterface { return $this->translation; } /** - * @param TranslationInterface $translation * @return $this */ public function setTranslation(TranslationInterface $translation): DocumentTranslation @@ -147,21 +129,18 @@ public function setTranslation(TranslationInterface $translation): DocumentTrans return $this; } - /** - * @return DocumentInterface - */ public function getDocument(): DocumentInterface { return $this->document; } /** - * @param DocumentInterface $document * @return $this */ public function setDocument(DocumentInterface $document): DocumentTranslation { $this->document = $document; + return $this; } } diff --git a/src/Entity/FieldAwareEntityTrait.php b/src/Entity/FieldAwareEntityTrait.php index be0611eb..db01735e 100644 --- a/src/Entity/FieldAwareEntityTrait.php +++ b/src/Entity/FieldAwareEntityTrait.php @@ -22,6 +22,7 @@ public function getFieldName(): string public function setFieldName(string $fieldName): self { $this->fieldName = $fieldName; + return $this; } @@ -31,6 +32,7 @@ public function setFieldName(string $fieldName): self public function setField(NodeTypeFieldInterface $field): self { $this->fieldName = $field->getName(); + return $this; } diff --git a/src/Entity/Folder.php b/src/Entity/Folder.php index c583b4e9..f2ff8c59 100644 --- a/src/Entity/Folder.php +++ b/src/Entity/Folder.php @@ -29,34 +29,31 @@ #[ ORM\Entity(repositoryClass: FolderRepository::class), ORM\HasLifecycleCallbacks, - ORM\Table(name: "folders"), - ORM\Index(columns: ["visible"]), - ORM\Index(columns: ["locked"]), - ORM\Index(columns: ["position"]), - ORM\Index(columns: ["created_at"]), - ORM\Index(columns: ["updated_at"]), - ORM\Index(columns: ["parent_id", "position"], name: "folder_parent_position"), - ORM\Index(columns: ["visible", "position"], name: "folder_visible_position"), - ORM\Index(columns: ["parent_id", "visible"], name: "folder_parent_visible"), - ORM\Index(columns: ["parent_id", "visible", "position"], name: "folder_parent_visible_position"), - UniqueEntity(fields: ["folderName"]), + ORM\Table(name: 'folders'), + ORM\Index(columns: ['visible']), + ORM\Index(columns: ['locked']), + ORM\Index(columns: ['position']), + ORM\Index(columns: ['created_at']), + ORM\Index(columns: ['updated_at']), + ORM\Index(columns: ['parent_id', 'position'], name: 'folder_parent_position'), + ORM\Index(columns: ['visible', 'position'], name: 'folder_visible_position'), + ORM\Index(columns: ['parent_id', 'visible'], name: 'folder_parent_visible'), + ORM\Index(columns: ['parent_id', 'visible', 'position'], name: 'folder_parent_visible_position'), + UniqueEntity(fields: ['folderName']), ApiFilter(PropertyFilter::class), ApiFilter(BaseFilter\OrderFilter::class, properties: [ - "position", - "createdAt", - "updatedAt" + 'position', + 'createdAt', + 'updatedAt', ]) ] class Folder extends AbstractDateTimedPositioned implements FolderInterface, LeafInterface { use LeafTrait; - /** - * @var Folder|null - */ #[ApiFilter(BaseFilter\SearchFilter::class, properties: [ - "parent.id" => "exact", - "parent.folderName" => "exact" + 'parent.id' => 'exact', + 'parent.folderName' => 'exact', ])] #[ORM\ManyToOne(targetEntity: Folder::class, inversedBy: 'children')] #[ORM\JoinColumn(name: 'parent_id', referencedColumnName: 'id', onDelete: 'CASCADE')] @@ -87,11 +84,6 @@ class Folder extends AbstractDateTimedPositioned implements FolderInterface, Lea /** @phpstan-ignore-next-line */ protected Collection $documents; - /** - * @var string - * @Serializer\Groups({"folder", "folder_color"}) - * @Serializer\Type("string") - */ #[ORM\Column( name: 'color', type: 'string', @@ -102,9 +94,11 @@ class Folder extends AbstractDateTimedPositioned implements FolderInterface, Lea )] #[Assert\Length(max: 7)] #[SymfonySerializer\Groups(['folder', 'folder_color'])] + #[Serializer\Groups(['folder', 'folder_color'])] + #[Serializer\Type('string')] protected string $color = '#000000'; - #[ApiFilter(BaseFilter\SearchFilter::class, strategy: "partial")] + #[ApiFilter(BaseFilter\SearchFilter::class, strategy: 'partial')] #[ORM\Column(name: 'folder_name', type: 'string', length: 250, unique: true, nullable: false)] #[Serializer\Groups(['folder', 'document_folders'])] #[SymfonySerializer\Groups(['folder', 'document_folders'])] @@ -151,7 +145,6 @@ public function __construct() } /** - * @param DocumentInterface $document * @return $this */ public function addDocument(DocumentInterface $document): static @@ -172,7 +165,6 @@ public function getDocuments(): Collection } /** - * @param DocumentInterface $document * @return $this */ public function removeDocument(DocumentInterface $document): static @@ -184,34 +176,27 @@ public function removeDocument(DocumentInterface $document): static return $this; } - /** - * @return boolean - */ public function getVisible(): bool { return $this->isVisible(); } - /** - * @return boolean - */ public function isVisible(): bool { return $this->visible; } /** - * @param bool $visible * @return $this */ public function setVisible(bool $visible): static { $this->visible = $visible; + return $this; } /** - * @param TranslationInterface $translation * @return Collection */ #[SymfonySerializer\Ignore] @@ -231,12 +216,9 @@ public function getTranslatedFoldersByDefaultTranslation(): ?FolderTranslation }); } - /** - * @return string|null - * @Serializer\VirtualProperty - * @Serializer\Groups({"folder", "document_folders"}) - */ #[SymfonySerializer\Groups(['folder', 'document_folders'])] + #[Serializer\Groups(['folder', 'document_folders'])] + #[Serializer\VirtualProperty] public function getName(): ?string { return $this->getTranslatedFolders()->first() ? @@ -254,91 +236,73 @@ public function getTranslatedFolders(): Collection /** * @param Collection $translatedFolders + * * @return $this */ public function setTranslatedFolders(Collection $translatedFolders): static { $this->translatedFolders = $translatedFolders; + return $this; } - /** - * @return string - */ public function getFolderName(): string { return $this->folderName ?? ''; } /** - * @param string $folderName * @return $this */ public function setFolderName(string $folderName): static { $this->dirtyFolderName = $folderName; $this->folderName = StringHandler::slugify($folderName); + return $this; } - /** - * @return string - */ public function getDirtyFolderName(): string { return $this->dirtyFolderName; } /** - * @param string $dirtyFolderName * @return $this */ public function setDirtyFolderName(string $dirtyFolderName): static { $this->dirtyFolderName = $dirtyFolderName; + return $this; } - /** - * @return bool - */ public function isLocked(): bool { return $this->locked; } - /** - * @param bool $locked - * @return Folder - */ public function setLocked(bool $locked): Folder { $this->locked = $locked; + return $this; } - /** - * @return string - */ public function getColor(): string { return $this->color; } - /** - * @param string $color - * @return Folder - */ public function setColor(string $color): Folder { $this->color = $color; + return $this; } /** * Get folder full path using folder names. - * - * @return string */ #[SymfonySerializer\Ignore] public function getFullPath(): string diff --git a/src/Entity/FolderTranslation.php b/src/Entity/FolderTranslation.php index 76a78b84..c9bca9c5 100644 --- a/src/Entity/FolderTranslation.php +++ b/src/Entity/FolderTranslation.php @@ -20,9 +20,9 @@ */ #[ ORM\Entity(repositoryClass: FolderTranslationRepository::class), - ORM\Table(name: "folders_translations"), - ORM\UniqueConstraint(columns: ["folder_id", "translation_id"]), - UniqueEntity(fields: ["folder", "translation"]) + ORM\Table(name: 'folders_translations'), + ORM\UniqueConstraint(columns: ['folder_id', 'translation_id']), + UniqueEntity(fields: ['folder', 'translation']) ] class FolderTranslation extends AbstractEntity { @@ -48,50 +48,38 @@ public function __construct(Folder $original, TranslationInterface $translation) { $this->setFolder($original); $this->setTranslation($translation); - $this->name = $original->getDirtyFolderName() != '' ? $original->getDirtyFolderName() : $original->getFolderName(); + $this->name = '' != $original->getDirtyFolderName() ? $original->getDirtyFolderName() : $original->getFolderName(); } - /** - * @return string - */ public function getName(): string { return $this->name ?? ''; } /** - * @param string $name * @return $this */ public function setName(string $name): FolderTranslation { $this->name = $name; + return $this; } - /** - * @return Folder - */ public function getFolder(): Folder { return $this->folder; } - /** - * @param Folder $folder - * @return FolderTranslation - */ public function setFolder(Folder $folder): FolderTranslation { $this->folder = $folder; + return $this; } - /** * Gets the value of translation. - * - * @return TranslationInterface */ public function getTranslation(): TranslationInterface { @@ -102,11 +90,11 @@ public function getTranslation(): TranslationInterface * Sets the value of translation. * * @param TranslationInterface $translation the translation - * @return self */ public function setTranslation(TranslationInterface $translation): FolderTranslation { $this->translation = $translation; + return $this; } } diff --git a/src/Entity/Group.php b/src/Entity/Group.php index 5bb7efd0..741f8a06 100644 --- a/src/Entity/Group.php +++ b/src/Entity/Group.php @@ -7,8 +7,8 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; -use RZ\Roadiz\Core\AbstractEntities\AbstractEntity; use JMS\Serializer\Annotation as Serializer; +use RZ\Roadiz\Core\AbstractEntities\AbstractEntity; use RZ\Roadiz\CoreBundle\Repository\GroupRepository; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Serializer\Annotation as SymfonySerializer; @@ -19,8 +19,8 @@ */ #[ ORM\Entity(repositoryClass: GroupRepository::class), - ORM\Table(name: "usergroups"), - UniqueEntity(fields: ["name"]) + ORM\Table(name: 'usergroups'), + UniqueEntity(fields: ['name']) ] class Group extends AbstractEntity { @@ -52,12 +52,9 @@ class Group extends AbstractEntity #[Serializer\Type("ArrayCollection")] private Collection $roleEntities; - /** - * @var array|null - * @Serializer\Groups({"group", "user"}) - * @Serializer\Type("array") - */ #[SymfonySerializer\Groups(['group', 'user'])] + #[Serializer\Groups(['group', 'user'])] + #[Serializer\Type('array')] private ?array $roles = null; public function __construct() @@ -66,17 +63,12 @@ public function __construct() $this->users = new ArrayCollection(); } - /** - * @return string - */ public function getName(): string { return $this->name; } /** - * @param string $name - * * @return $this */ public function setName(string $name) @@ -86,9 +78,6 @@ public function setName(string $name) return $this; } - /** - * @return Collection - */ public function getUsers(): Collection { return $this->users; @@ -101,7 +90,7 @@ public function getUsers(): Collection */ public function getRoles(): array { - if ($this->roles === null) { + if (null === $this->roles) { $this->roles = array_map(function (Role $role) { return $role->getRole(); }, $this->getRolesEntities()->toArray()); @@ -112,8 +101,6 @@ public function getRoles(): array /** * Get roles entities. - * - * @return Collection */ public function getRolesEntities(): ?Collection { @@ -122,10 +109,6 @@ public function getRolesEntities(): ?Collection /** * Get roles entities. - * - * @param Collection $roles - * - * @return Group */ public function setRolesEntities(Collection $roles): self { @@ -134,12 +117,13 @@ public function setRolesEntities(Collection $roles): self foreach ($this->roleEntities as $role) { $role->addGroup($this); } + return $this; } /** - * @param Role $role * @return $this + * * @deprecated Use addRoleEntity */ public function addRole(Role $role): Group @@ -148,8 +132,6 @@ public function addRole(Role $role): Group } /** - * @param Role $role - * * @return $this */ public function addRoleEntity(Role $role): Group @@ -162,8 +144,8 @@ public function addRoleEntity(Role $role): Group } /** - * @param Role $role * @return $this + * * @deprecated Use removeRoleEntity */ public function removeRole(Role $role): Group @@ -172,8 +154,6 @@ public function removeRole(Role $role): Group } /** - * @param Role $role - * * @return $this */ public function removeRoleEntity(Role $role): Group diff --git a/src/Entity/Node.php b/src/Entity/Node.php index 18b73384..c9e9e683 100644 --- a/src/Entity/Node.php +++ b/src/Entity/Node.php @@ -11,6 +11,7 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Criteria; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use Gedmo\Loggable\Loggable; use Gedmo\Mapping\Annotation as Gedmo; @@ -19,8 +20,10 @@ use RZ\Roadiz\Contracts\NodeType\NodeTypeInterface; use RZ\Roadiz\Core\AbstractEntities\LeafInterface; use RZ\Roadiz\Core\AbstractEntities\LeafTrait; +use RZ\Roadiz\Core\AbstractEntities\NodeInterface; use RZ\Roadiz\Core\AbstractEntities\TranslationInterface; use RZ\Roadiz\CoreBundle\Api\Filter as RoadizFilter; +use RZ\Roadiz\CoreBundle\Enum\NodeStatus; use RZ\Roadiz\CoreBundle\Model\AttributableInterface; use RZ\Roadiz\CoreBundle\Model\AttributableTrait; use RZ\Roadiz\CoreBundle\Repository\NodeRepository; @@ -36,26 +39,26 @@ */ #[ ORM\Entity(repositoryClass: NodeRepository::class), - ORM\Table(name: "nodes"), - ORM\Index(columns: ["visible"]), - ORM\Index(columns: ["status"]), - ORM\Index(columns: ["locked"]), - ORM\Index(columns: ["sterile"]), - ORM\Index(columns: ["position"]), - ORM\Index(columns: ["created_at"]), - ORM\Index(columns: ["updated_at"]), - ORM\Index(columns: ["hide_children"]), - ORM\Index(columns: ["home"]), - ORM\Index(columns: ["node_name", "status"]), - ORM\Index(columns: ["visible", "status"]), - ORM\Index(columns: ["visible", "status", "parent_node_id"], name: "node_visible_status_parent"), - ORM\Index(columns: ["status", "parent_node_id"], name: "node_status_parent"), - ORM\Index(columns: ["nodeType_id", "status", "parent_node_id"], name: "node_nodetype_status_parent"), - ORM\Index(columns: ["nodeType_id", "status", "parent_node_id", "position"], name: "node_nodetype_status_parent_position"), - ORM\Index(columns: ["visible", "parent_node_id"], name: "node_visible_parent"), - ORM\Index(columns: ["parent_node_id", "position"], name: "node_parent_position"), - ORM\Index(columns: ["visible", "parent_node_id", "position"], name: "node_visible_parent_position"), - ORM\Index(columns: ["status", "visible", "parent_node_id", "position"], name: "node_status_visible_parent_position"), + ORM\Table(name: 'nodes'), + ORM\Index(columns: ['visible']), + ORM\Index(columns: ['status']), + ORM\Index(columns: ['locked']), + ORM\Index(columns: ['sterile']), + ORM\Index(columns: ['position']), + ORM\Index(columns: ['created_at']), + ORM\Index(columns: ['updated_at']), + ORM\Index(columns: ['hide_children']), + ORM\Index(columns: ['home']), + ORM\Index(columns: ['node_name', 'status']), + ORM\Index(columns: ['visible', 'status']), + ORM\Index(columns: ['visible', 'status', 'parent_node_id'], name: 'node_visible_status_parent'), + ORM\Index(columns: ['status', 'parent_node_id'], name: 'node_status_parent'), + ORM\Index(columns: ['nodeType_id', 'status', 'parent_node_id'], name: 'node_nodetype_status_parent'), + ORM\Index(columns: ['nodeType_id', 'status', 'parent_node_id', 'position'], name: 'node_nodetype_status_parent_position'), + ORM\Index(columns: ['visible', 'parent_node_id'], name: 'node_visible_parent'), + ORM\Index(columns: ['parent_node_id', 'position'], name: 'node_parent_position'), + ORM\Index(columns: ['visible', 'parent_node_id', 'position'], name: 'node_visible_parent_position'), + ORM\Index(columns: ['status', 'visible', 'parent_node_id', 'position'], name: 'node_status_visible_parent_position'), ORM\HasLifecycleCallbacks, Gedmo\Loggable(logEntryClass: UserLogEntry::class), // Need to override repository method to see all nodes @@ -66,15 +69,20 @@ ), ApiFilter(PropertyFilter::class) ] -class Node extends AbstractDateTimedPositioned implements LeafInterface, AttributableInterface, Loggable +class Node extends AbstractDateTimedPositioned implements LeafInterface, AttributableInterface, Loggable, NodeInterface { use LeafTrait; use AttributableTrait; + /** @deprecated Use NodeStatus enum */ public const DRAFT = 10; + /** @deprecated Use NodeStatus enum */ public const PENDING = 20; + /** @deprecated Use NodeStatus enum */ public const PUBLISHED = 30; + /** @deprecated Use NodeStatus enum */ public const ARCHIVED = 40; + /** @deprecated Use NodeStatus enum */ public const DELETED = 50; #[SymfonySerializer\Ignore] @@ -90,7 +98,7 @@ class Node extends AbstractDateTimedPositioned implements LeafInterface, Attribu #[ORM\Column(name: 'node_name', type: 'string', length: 255, unique: true)] #[SymfonySerializer\Groups(['nodes_sources', 'nodes_sources_base', 'node', 'log_sources'])] #[Serializer\Groups(['nodes_sources', 'nodes_sources_base', 'node', 'log_sources'])] - #[Serializer\Accessor(getter: "getNodeName", setter: "setNodeName")] + #[Serializer\Accessor(getter: 'getNodeName', setter: 'setNodeName')] #[Assert\NotNull] #[Assert\NotBlank] #[Assert\Length(max: 255)] @@ -120,14 +128,23 @@ class Node extends AbstractDateTimedPositioned implements LeafInterface, Attribu private bool $visible = true; /** - * @internal You should use node Workflow to perform change on status. + * @internal you should use node Workflow to perform change on status */ - #[ORM\Column(type: 'integer')] + #[ORM\Column( + name: 'status', + type: Types::SMALLINT, + enumType: NodeStatus::class, + options: ['default' => NodeStatus::DRAFT] + )] #[Serializer\Exclude] #[SymfonySerializer\Ignore] - private int $status = Node::DRAFT; + private NodeStatus $status = NodeStatus::DRAFT; - #[ORM\Column(type: 'integer', nullable: false, options: ['default' => 0])] + #[ORM\Column( + type: Types::INTEGER, + nullable: false, + options: ['default' => 0] + )] #[Assert\GreaterThanOrEqual(value: 0)] #[Assert\NotNull] #[SymfonySerializer\Ignore] @@ -177,7 +194,7 @@ class Node extends AbstractDateTimedPositioned implements LeafInterface, Attribu schema: [ 'type' => 'string', 'enum' => ['position', 'nodeName', 'createdAt', 'updatedAt', 'publishedAt'], - 'example' => 'position' + 'example' => 'position', ], )] private string $childrenOrder = 'position'; @@ -194,13 +211,13 @@ class Node extends AbstractDateTimedPositioned implements LeafInterface, Attribu schema: [ 'type' => 'string', 'enum' => ['ASC', 'DESC'], - 'example' => 'ASC' + 'example' => 'ASC', ], )] private string $childrenOrderDirection = 'ASC'; #[ORM\ManyToOne(targetEntity: NodeTypeInterface::class)] - #[ORM\JoinColumn(name: 'nodeType_id', referencedColumnName: 'id', nullable:false, onDelete: 'CASCADE')] + #[ORM\JoinColumn(name: 'nodeType_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')] #[SymfonySerializer\Groups(['node'])] #[Serializer\Groups(['node'])] #[SymfonySerializer\Ignore] @@ -237,16 +254,16 @@ class Node extends AbstractDateTimedPositioned implements LeafInterface, Attribu #[SymfonySerializer\Ignore] #[Serializer\Exclude] #[ApiFilter(BaseFilter\SearchFilter::class, properties: [ - "nodesTags.tag" => "exact", - "nodesTags.tag.tagName" => "exact", + 'nodesTags.tag' => 'exact', + 'nodesTags.tag.tagName' => 'exact', ])] #[ApiFilter(RoadizFilter\NotFilter::class, properties: [ - "nodesTags.tag.tagName", + 'nodesTags.tag.tagName', ])] - # Use IntersectionFilter after SearchFilter! + // Use IntersectionFilter after SearchFilter! #[ApiFilter(RoadizFilter\IntersectionFilter::class, properties: [ - "nodesTags.tag", - "nodesTags.tag.tagName", + 'nodesTags.tag', + 'nodesTags.tag.tagName', ])] private Collection $nodesTags; @@ -333,24 +350,13 @@ public function __construct() } /** - * @param int $status - * @return string + * @deprecated Use NodeStatus enum getLabel method */ - public static function getStatusLabel($status): string + public static function getStatusLabel(int|string $status): string { - $nodeStatuses = [ - static::DRAFT => 'draft', - static::PENDING => 'pending', - static::PUBLISHED => 'published', - static::ARCHIVED => 'archived', - static::DELETED => 'deleted', - ]; - - if (isset($nodeStatuses[$status])) { - return $nodeStatuses[$status]; - } + $status = NodeStatus::tryFrom((int) $status); - throw new \InvalidArgumentException('Status does not exist.'); + return $status->getLabel(); } /** @@ -359,8 +365,6 @@ public static function getStatusLabel($status): string * * Disable this parameter if you need to protect your nodeName * from title changes. - * - * @return bool */ public function isDynamicNodeName(): bool { @@ -368,217 +372,189 @@ public function isDynamicNodeName(): bool } /** - * @param bool $dynamicNodeName * @return $this */ public function setDynamicNodeName(bool $dynamicNodeName): Node { $this->dynamicNodeName = (bool) $dynamicNodeName; + return $this; } - /** - * @return bool - */ public function isHome(): bool { return $this->home; } /** - * @param bool $home * @return $this */ public function setHome(bool $home): Node { $this->home = $home; + return $this; } - /** - * @return int - */ - public function getStatus(): int + public function getStatus(): NodeStatus { return $this->status; } /** - * @param int|string $status Workflow only use marking places + * @param int|string|NodeStatus $status Workflow only use marking places + * * @return $this - * @internal You should use node Workflow to perform change on status. + * + * @internal you should use node Workflow to perform change on status */ - public function setStatus(int|string $status): Node + public function setStatus(int|string|NodeStatus $status): Node + { + if ($status instanceof NodeStatus) { + $this->status = $status; + } else { + $this->status = NodeStatus::tryFrom((int) $status) ?? NodeStatus::DRAFT; + } + + return $this; + } + + public function setStatusAsString(string $name): Node { - $this->status = (int) $status; + $this->status = NodeStatus::fromName($name); + return $this; } - /** - * @return int - */ + public function getStatusAsString(): string + { + return $this->status->name; + } + public function getTtl(): int { return $this->ttl ?? 0; } - /** - * @param int|null $ttl - * - * @return Node - */ public function setTtl(?int $ttl): Node { $this->ttl = $ttl; + return $this; } - /** - * @return bool - */ public function isPublished(): bool { - return ($this->status === Node::PUBLISHED); + return $this->status->isPublished(); } - /** - * @return bool - */ public function isPending(): bool { - return ($this->status === Node::PENDING); + return $this->status->isPending(); } - /** - * @return bool - */ public function isDraft(): bool { - return ($this->status === Node::DRAFT); + return $this->status->isDraft(); } - /** - * @return bool - */ public function isDeleted(): bool { - return ($this->status === Node::DELETED); + return $this->status->isDeleted(); + } + + public function isArchived(): bool + { + return $this->status->isArchived(); } - /** - * @return bool - */ public function isLocked(): bool { return $this->locked; } /** - * @param bool $locked * @return $this */ public function setLocked(bool $locked): static { $this->locked = $locked; + return $this; } - /** - * @return bool - */ public function getHideChildren(): bool { return $this->hideChildren; } /** - * @param bool $hideChildren * @return $this */ public function setHideChildren(bool $hideChildren): static { $this->hideChildren = $hideChildren; + return $this; } - /** - * @return bool - */ public function isHidingChildren(): bool { return $this->hideChildren; } /** - * @param bool $hideChildren - * * @return $this */ public function setHidingChildren(bool $hideChildren): static { $this->hideChildren = $hideChildren; - return $this; - } - /** - * @return bool - */ - public function isArchived(): bool - { - return ($this->status === Node::ARCHIVED); + return $this; } - /** - * @return bool - */ public function isSterile(): bool { return $this->sterile; } /** - * @param bool $sterile * @return $this */ public function setSterile(bool $sterile): static { $this->sterile = $sterile; + return $this; } - /** - * @return string - */ public function getChildrenOrder(): string { return $this->childrenOrder; } /** - * @param string $childrenOrder * @return $this */ public function setChildrenOrder(string $childrenOrder): static { $this->childrenOrder = $childrenOrder; + return $this; } - /** - * @return string - */ public function getChildrenOrderDirection(): string { return $this->childrenOrderDirection; } /** - * @param string $childrenOrderDirection * @return $this */ public function setChildrenOrderDirection(string $childrenOrderDirection): static { $this->childrenOrderDirection = $childrenOrderDirection; + return $this; } @@ -592,6 +568,7 @@ public function getNodesTags(): Collection /** * @param Collection $nodesTags + * * @return $this */ public function setNodesTags(Collection $nodesTags): static @@ -631,12 +608,11 @@ public function setTags(iterable $tags): static (new NodesTags())->setNode($this)->setTag($tag)->setPosition(++$i) ); } + return $this; } /** - * @param Tag $tag - * * @return $this */ public function addTag(Tag $tag): static @@ -682,18 +658,19 @@ public function getCustomForms(): Collection /** * @param Collection $customForms + * * @return $this */ public function setCustomForms(Collection $customForms): static { $this->customForms = $customForms; + return $this; } /** * Used by generated nodes-sources. * - * @param NodesCustomForms $nodesCustomForms * @return $this */ public function addCustomForm(NodesCustomForms $nodesCustomForms): static @@ -701,12 +678,11 @@ public function addCustomForm(NodesCustomForms $nodesCustomForms): static if (!$this->customForms->contains($nodesCustomForms)) { $this->customForms->add($nodesCustomForms); } + return $this; } /** - * @param NodeType $stackType - * * @return $this */ public function removeStackType(NodeType $stackType): static @@ -727,8 +703,6 @@ public function getStackTypes(): Collection } /** - * @param NodeType $stackType - * * @return $this */ public function addStackType(NodeType $stackType): static @@ -743,7 +717,6 @@ public function addStackType(NodeType $stackType): static /** * Get node-sources using a given translation. * - * @param TranslationInterface $translation * @return Collection */ #[SymfonySerializer\Ignore] @@ -755,8 +728,6 @@ public function getNodeSourcesByTranslation(TranslationInterface $translation): } /** - * @param NodesSources $ns - * * @return $this */ public function removeNodeSources(NodesSources $ns): static @@ -777,8 +748,6 @@ public function getNodeSources(): Collection } /** - * @param NodesSources $ns - * * @return $this */ public function addNodeSources(NodesSources $ns): static @@ -801,6 +770,7 @@ public function getBNodesByField(NodeTypeFieldInterface $field): Collection $criteria = Criteria::create(); $criteria->andWhere(Criteria::expr()->eq('fieldName', $field->getName())); $criteria->orderBy(['position' => 'ASC']); + return $this->getBNodes()->matching($criteria); } @@ -816,6 +786,7 @@ public function getBNodes(): Collection /** * @param Collection $bNodes + * * @return $this */ public function setBNodes(Collection $bNodes): static @@ -826,20 +797,20 @@ public function setBNodes(Collection $bNodes): static $this->addBNode($bNode); } } + return $this; } public function hasBNode(NodesToNodes $bNode): bool { return $this->getBNodes()->exists(function ($key, NodesToNodes $element) use ($bNode) { - return $bNode->getNodeB()->getId() !== null && - $element->getNodeB()->getId() === $bNode->getNodeB()->getId() && - $element->getFieldName() === $bNode->getFieldName(); + return null !== $bNode->getNodeB()->getId() + && $element->getNodeB()->getId() === $bNode->getNodeB()->getId() + && $element->getFieldName() === $bNode->getFieldName(); }); } /** - * @param NodesToNodes $bNode * @return $this */ public function addBNode(NodesToNodes $bNode): static @@ -848,6 +819,7 @@ public function addBNode(NodesToNodes $bNode): static $this->getBNodes()->add($bNode); $bNode->setNodeA($this); } + return $this; } @@ -860,6 +832,7 @@ public function clearBNodesForField(NodeTypeFieldInterface $field): Node foreach ($toRemoveCollection as $toRemove) { $this->getBNodes()->removeElement($toRemove); } + return $this; } @@ -873,31 +846,18 @@ public function getANodes(): Collection return $this->aNodes; } - /** - * @return string - */ - #[SymfonySerializer\Ignore] - public function getOneLineSummary(): string - { - return $this->getId() . " — " . $this->getNodeName() . " — " . $this->getNodeType()->getName() . - " — Visible : " . ($this->isVisible() ? 'true' : 'false') . PHP_EOL; - } - - /** - * @return string - */ public function getNodeName(): string { return $this->nodeName; } /** - * @param string $nodeName * @return $this */ public function setNodeName(string $nodeName): static { $this->nodeName = StringHandler::slugify($nodeName); + return $this; } @@ -909,49 +869,23 @@ public function getNodeType(): NodeTypeInterface public function setNodeType(NodeTypeInterface $nodeType): Node { $this->nodeType = $nodeType; + return $this; } - /** - * @return bool - */ public function isVisible(): bool { return $this->visible; } /** - * @param bool $visible * @return $this */ public function setVisible(bool $visible): Node { $this->visible = $visible; - return $this; - } - - /** - * @return string - */ - #[SymfonySerializer\Ignore] - public function getOneLineSourceSummary(): string - { - $text = "Source " . - ( - $this->getNodeSources()->first() ? - $this->getNodeSources()->first()->getId() : - '' - ) . - PHP_EOL; - - foreach ($this->getNodeType()->getFields() as $field) { - $getterName = $field->getGetterName(); - $text .= '[' . $field->getLabel() . ']: ' . - ($this->getNodeSources()->first() ? $this->getNodeSources()->first()->$getterName() : '') . - PHP_EOL; - } - return $text; + return $this; } /** @@ -964,6 +898,7 @@ public function __clone() if ($this->id) { $this->id = null; $this->home = false; + /** @var Collection $children */ $children = $this->getChildren(); $this->children = new ArrayCollection(); foreach ($children as $child) { @@ -973,7 +908,7 @@ public function __clone() /** @var NodesTags[] $nodesTags */ $nodesTags = $this->nodesTags->toArray(); - if ($nodesTags !== null) { + if (null !== $nodesTags) { $this->nodesTags = new ArrayCollection(); foreach ($nodesTags as $nodesTag) { $this->addTag($nodesTag->getTag()); @@ -1000,14 +935,14 @@ public function __clone() // This is for safety reasons // NodeDuplicator service will override it $nodeSource = $this->getNodeSources()->first(); - if ($nodeSource !== false) { - $namePrefix = $nodeSource->getTitle() != "" ? + if (false !== $nodeSource) { + $namePrefix = '' != $nodeSource->getTitle() ? $nodeSource->getTitle() : $this->nodeName; } else { $namePrefix = $this->nodeName; } - $this->setNodeName($namePrefix . "-" . uniqid()); + $this->setNodeName($namePrefix.'-'.uniqid()); $this->setCreatedAt(new \DateTime()); $this->setUpdatedAt(new \DateTime()); } @@ -1027,9 +962,6 @@ public function setParent(?LeafInterface $parent = null): static return $this; } - /** - * @return string - */ public function __toString(): string { return (string) $this->getId(); diff --git a/src/Entity/NodeType.php b/src/Entity/NodeType.php index 53ab01ff..e41f85ad 100644 --- a/src/Entity/NodeType.php +++ b/src/Entity/NodeType.php @@ -24,33 +24,33 @@ */ #[ ORM\Entity(repositoryClass: NodeTypeRepository::class), - ORM\Table(name: "node_types"), - ORM\Index(columns: ["name"], name: "node_type_name"), - ORM\Index(columns: ["visible"]), - ORM\Index(columns: ["publishable"]), - ORM\Index(columns: ["attributable"]), - ORM\Index(columns: ["hiding_nodes"]), - ORM\Index(columns: ["hiding_non_reachable_nodes"]), - ORM\Index(columns: ["reachable"]), - ORM\Index(columns: ["searchable"], name: "nt_searchable"), - UniqueEntity(fields: ["name"]), - UniqueEntity(fields: ["displayName"]) + ORM\Table(name: 'node_types'), + ORM\Index(columns: ['name'], name: 'node_type_name'), + ORM\Index(columns: ['visible']), + ORM\Index(columns: ['publishable']), + ORM\Index(columns: ['attributable']), + ORM\Index(columns: ['hiding_nodes']), + ORM\Index(columns: ['hiding_non_reachable_nodes']), + ORM\Index(columns: ['reachable']), + ORM\Index(columns: ['searchable'], name: 'nt_searchable'), + UniqueEntity(fields: ['name']), + UniqueEntity(fields: ['displayName']) ] class NodeType extends AbstractEntity implements NodeTypeInterface { #[ - ORM\Column(name: "color", type: "string", length: 7, unique: false, nullable: true), - Serializer\Groups(["node_type", "color"]), - SymfonySerializer\Groups(["node_type", "color"]), - Serializer\Type("string"), + ORM\Column(name: 'color', type: 'string', length: 7, unique: false, nullable: true), + Serializer\Groups(['node_type', 'color']), + SymfonySerializer\Groups(['node_type', 'color']), + Serializer\Type('string'), Assert\Length(max: 7), ] protected ?string $color = '#000000'; #[ - ORM\Column(type: "string", length: 30, unique: true), - Serializer\Groups(["node_type", "node"]), - SymfonySerializer\Groups(["node_type", "node"]), - Serializer\Type("string"), + ORM\Column(type: 'string', length: 30, unique: true), + Serializer\Groups(['node_type', 'node']), + SymfonySerializer\Groups(['node_type', 'node']), + Serializer\Type('string'), Assert\NotNull(), Assert\NotBlank(), RoadizAssert\NonSqlReservedWord(), @@ -60,52 +60,52 @@ class NodeType extends AbstractEntity implements NodeTypeInterface ] private string $name = ''; #[ - ORM\Column(name: "display_name", type: "string", length: 250), - Serializer\Groups(["node_type", "node"]), - SymfonySerializer\Groups(["node_type", "node"]), - Serializer\Type("string"), + ORM\Column(name: 'display_name', type: 'string', length: 250), + Serializer\Groups(['node_type', 'node']), + SymfonySerializer\Groups(['node_type', 'node']), + Serializer\Type('string'), Assert\NotNull(), Assert\NotBlank(), Assert\Length(max: 250) ] private string $displayName = ''; #[ - ORM\Column(type: "text", nullable: true), - Serializer\Groups(["node_type"]), - SymfonySerializer\Groups(["node_type"]), - Serializer\Type("string") + ORM\Column(type: 'text', nullable: true), + Serializer\Groups(['node_type']), + SymfonySerializer\Groups(['node_type']), + Serializer\Type('string') ] private ?string $description = null; #[ - ORM\Column(type: "boolean", nullable: false, options: ["default" => true]), - Serializer\Groups(["node_type"]), - SymfonySerializer\Groups(["node_type"]), - Serializer\Type("boolean") + ORM\Column(type: 'boolean', nullable: false, options: ['default' => true]), + Serializer\Groups(['node_type']), + SymfonySerializer\Groups(['node_type']), + Serializer\Type('boolean') ] private bool $visible = true; #[ - ORM\Column(type: "boolean", nullable: false, options: ["default" => false]), - Serializer\Groups(["node_type"]), - SymfonySerializer\Groups(["node_type"]), - Serializer\Type("boolean") + ORM\Column(type: 'boolean', nullable: false, options: ['default' => false]), + Serializer\Groups(['node_type']), + SymfonySerializer\Groups(['node_type']), + Serializer\Type('boolean') ] private bool $publishable = false; /** - * @var bool Define if this node-type produces nodes that will have attributes. + * @var bool define if this node-type produces nodes that will have attributes */ #[ - ORM\Column(type: "boolean", nullable: false, options: ["default" => true]), - Serializer\Groups(["node_type"]), - SymfonySerializer\Groups(["node_type"]), - Serializer\Type("boolean") + ORM\Column(type: 'boolean', nullable: false, options: ['default' => true]), + Serializer\Groups(['node_type']), + SymfonySerializer\Groups(['node_type']), + Serializer\Type('boolean') ] private bool $attributable = false; #[ - ORM\Column(name: "attributable_by_weight", type: "boolean", nullable: false, options: ["default" => false]), - Serializer\Groups(["node_type"]), - SymfonySerializer\Groups(["node_type"]), - Serializer\Type("boolean") + ORM\Column(name: 'attributable_by_weight', type: 'boolean', nullable: false, options: ['default' => false]), + Serializer\Groups(['node_type']), + SymfonySerializer\Groups(['node_type']), + Serializer\Type('boolean') ] private bool $sortingAttributesByWeight = false; /** @@ -115,24 +115,24 @@ class NodeType extends AbstractEntity implements NodeTypeInterface * Typically, if a node has a URL. */ #[ - ORM\Column(name: "reachable", type: "boolean", nullable: false, options: ["default" => true]), - Serializer\Groups(["node_type"]), - SymfonySerializer\Groups(["node_type"]), - Serializer\Type("boolean") + ORM\Column(name: 'reachable', type: 'boolean', nullable: false, options: ['default' => true]), + Serializer\Groups(['node_type']), + SymfonySerializer\Groups(['node_type']), + Serializer\Type('boolean') ] private bool $reachable = true; #[ - ORM\Column(name: "hiding_nodes", type: "boolean", nullable: false, options: ["default" => false]), - Serializer\Groups(["node_type"]), - SymfonySerializer\Groups(["node_type"]), - Serializer\Type("boolean") + ORM\Column(name: 'hiding_nodes', type: 'boolean', nullable: false, options: ['default' => false]), + Serializer\Groups(['node_type']), + SymfonySerializer\Groups(['node_type']), + Serializer\Type('boolean') ] private bool $hidingNodes = false; #[ - ORM\Column(name: "hiding_non_reachable_nodes", type: "boolean", nullable: false, options: ["default" => false]), - Serializer\Groups(["node_type"]), - SymfonySerializer\Groups(["node_type"]), - Serializer\Type("boolean") + ORM\Column(name: 'hiding_non_reachable_nodes', type: 'boolean', nullable: false, options: ['default' => false]), + Serializer\Groups(['node_type']), + SymfonySerializer\Groups(['node_type']), + Serializer\Type('boolean') ] private bool $hidingNonReachableNodes = false; /** @@ -140,23 +140,23 @@ class NodeType extends AbstractEntity implements NodeTypeInterface */ #[ ORM\OneToMany( - mappedBy: "nodeType", + mappedBy: 'nodeType', targetEntity: NodeTypeField::class, - cascade: ["all"], + cascade: ['all'], orphanRemoval: true ), - ORM\OrderBy(["position" => "ASC"]), - Serializer\Groups(["node_type"]), - SymfonySerializer\Groups(["node_type"]), + ORM\OrderBy(['position' => 'ASC']), + Serializer\Groups(['node_type']), + SymfonySerializer\Groups(['node_type']), Serializer\Type("ArrayCollection"), - Serializer\Accessor(getter: "getFields", setter: "setFields") + Serializer\Accessor(getter: 'getFields', setter: 'setFields') ] private Collection $fields; #[ - ORM\Column(name: "default_ttl", type: "integer", nullable: false, options: ["default" => 0]), - Serializer\Groups(["node_type"]), - SymfonySerializer\Groups(["node_type"]), - Serializer\Type("int"), + ORM\Column(name: 'default_ttl', type: 'integer', nullable: false, options: ['default' => 0]), + Serializer\Groups(['node_type']), + SymfonySerializer\Groups(['node_type']), + Serializer\Type('int'), Assert\GreaterThanOrEqual(value: 0), Assert\NotNull ] @@ -166,10 +166,10 @@ class NodeType extends AbstractEntity implements NodeTypeInterface * Define if this node-type title will be indexed during its parent indexation. */ #[ - ORM\Column(name: "searchable", type: "boolean", nullable: false, options: ["default" => true]), - Serializer\Groups(["node_type"]), - SymfonySerializer\Groups(["node_type"]), - Serializer\Type("boolean") + ORM\Column(name: 'searchable', type: 'boolean', nullable: false, options: ['default' => true]), + Serializer\Groups(['node_type']), + SymfonySerializer\Groups(['node_type']), + Serializer\Type('boolean') ] private bool $searchable = true; @@ -188,147 +188,109 @@ public function getLabel(): string return $this->getDisplayName(); } - /** - * @return string - */ public function getDisplayName(): string { return $this->displayName; } /** - * @param string|null $displayName - * * @return $this */ public function setDisplayName(?string $displayName): NodeType { $this->displayName = $displayName ?? ''; + return $this; } - /** - * @return string|null - */ public function getDescription(): ?string { return $this->description; } /** - * @param string|null $description * @return $this */ public function setDescription(?string $description = null): NodeType { $this->description = $description; + return $this; } - /** - * @return boolean - */ public function isVisible(): bool { return $this->visible; } /** - * @param boolean $visible * @return $this */ public function setVisible(bool $visible): NodeType { $this->visible = $visible; + return $this; } - /** - * @return bool - */ public function isPublishable(): bool { return $this->publishable; } - /** - * @param bool $publishable - * @return NodeType - */ public function setPublishable(bool $publishable): NodeType { $this->publishable = $publishable; + return $this; } - /** - * @return bool - */ public function getReachable(): bool { return $this->reachable; } - /** - * @return bool - */ public function isReachable(): bool { return $this->getReachable(); } - /** - * @param bool $reachable - * @return NodeType - */ public function setReachable(bool $reachable): NodeType { $this->reachable = $reachable; + return $this; } - /** - * @return boolean - */ public function isHidingNodes(): bool { return $this->hidingNodes; } /** - * @param boolean $hidingNodes - * * @return $this */ public function setHidingNodes(bool $hidingNodes): NodeType { $this->hidingNodes = $hidingNodes; + return $this; } - /** - * @return bool - */ public function isHidingNonReachableNodes(): bool { return $this->hidingNonReachableNodes; } - /** - * @param bool $hidingNonReachableNodes - * - * @return NodeType - */ public function setHidingNonReachableNodes(bool $hidingNonReachableNodes): NodeType { $this->hidingNonReachableNodes = $hidingNonReachableNodes; + return $this; } /** * Gets the value of color. - * - * @return string|null */ public function getColor(): ?string { @@ -338,8 +300,6 @@ public function getColor(): ?string /** * Sets the value of color. * - * @param string|null $color - * * @return $this */ public function setColor(?string $color): NodeType @@ -349,19 +309,11 @@ public function setColor(?string $color): NodeType return $this; } - /** - * @return int - */ public function getDefaultTtl(): int { return $this->defaultTtl ?? 0; } - /** - * @param int|null $defaultTtl - * - * @return NodeType - */ public function setDefaultTtl(?int $defaultTtl): NodeType { $this->defaultTtl = $defaultTtl; @@ -369,17 +321,13 @@ public function setDefaultTtl(?int $defaultTtl): NodeType return $this; } - /** - * @param string $name - * - * @return NodeTypeField|null - */ public function getFieldByName(string $name): ?NodeTypeField { $fieldCriteria = Criteria::create(); $fieldCriteria->andWhere(Criteria::expr()->eq('name', $name)); $fieldCriteria->setMaxResults(1); $field = $this->getFields()->matching($fieldCriteria)->first(); + return $field ?: null; } @@ -393,8 +341,6 @@ public function getFields(): Collection /** * @param Collection $fields - * - * @return NodeType */ public function setFields(Collection $fields): NodeType { @@ -409,8 +355,6 @@ public function setFields(Collection $fields): NodeType /** * Get every node-type fields names in * a simple array. - * - * @return array */ #[SymfonySerializer\Ignore] public function getFieldsNames(): array @@ -420,29 +364,21 @@ public function getFieldsNames(): array }, $this->getFields()->toArray()); } - /** - * @return string - */ public function getName(): string { return $this->name; } /** - * @param string|null $name * @return $this */ public function setName(?string $name): NodeType { $this->name = StringHandler::classify($name ?? ''); + return $this; } - /** - * @param NodeTypeField $field - * - * @return NodeType - */ public function addField(NodeTypeField $field): NodeType { if (!$this->getFields()->contains($field)) { @@ -453,11 +389,6 @@ public function addField(NodeTypeField $field): NodeType return $this; } - /** - * @param NodeTypeField $field - * - * @return NodeType - */ public function removeField(NodeTypeField $field): NodeType { if ($this->getFields()->contains($field)) { @@ -474,12 +405,9 @@ public function removeField(NodeTypeField $field): NodeType public function getSourceEntityFullQualifiedClassName(): string { // @phpstan-ignore-next-line - return static::getGeneratedEntitiesNamespace() . '\\' . $this->getSourceEntityClassName(); + return static::getGeneratedEntitiesNamespace().'\\'.$this->getSourceEntityClassName(); } - /** - * @return string - */ #[SymfonySerializer\Ignore] public static function getGeneratedEntitiesNamespace(): string { @@ -488,29 +416,22 @@ public static function getGeneratedEntitiesNamespace(): string /** * Get node-source entity class name without its namespace. - * - * @return string */ #[SymfonySerializer\Ignore] public function getSourceEntityClassName(): string { - return 'NS' . ucwords($this->getName()); + return 'NS'.ucwords($this->getName()); } /** * Get node-source entity database table name. - * - * @return string */ #[SymfonySerializer\Ignore] public function getSourceEntityTableName(): string { - return 'ns_' . \mb_strtolower($this->getName()); + return 'ns_'.\mb_strtolower($this->getName()); } - /** - * @return string - */ public function __toString(): string { return (string) $this->getId(); @@ -518,8 +439,6 @@ public function __toString(): string /** * Get every searchable node-type fields as a Doctrine ArrayCollection. - * - * @return Collection */ #[SymfonySerializer\Ignore] public function getSearchableFields(): Collection @@ -529,21 +448,15 @@ public function getSearchableFields(): Collection }); } - /** - * @return bool - */ public function isSearchable(): bool { return $this->searchable; } - /** - * @param bool $searchable - * @return NodeType - */ public function setSearchable(bool $searchable): NodeType { $this->searchable = $searchable; + return $this; } @@ -555,6 +468,7 @@ public function isAttributable(): bool public function setAttributable(bool $attributable): NodeType { $this->attributable = $attributable; + return $this; } @@ -566,6 +480,7 @@ public function isSortingAttributesByWeight(): bool public function setSortingAttributesByWeight(bool $sortingAttributesByWeight): NodeType { $this->sortingAttributesByWeight = $sortingAttributesByWeight; + return $this; } } diff --git a/src/Entity/NodeTypeField.php b/src/Entity/NodeTypeField.php index 07dd18bf..ec3b331f 100644 --- a/src/Entity/NodeTypeField.php +++ b/src/Entity/NodeTypeField.php @@ -4,6 +4,7 @@ namespace RZ\Roadiz\CoreBundle\Entity; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation as Serializer; use RZ\Roadiz\Contracts\NodeType\NodeTypeFieldInterface; @@ -22,30 +23,30 @@ */ #[ ORM\Entity(repositoryClass: NodeTypeFieldRepository::class), - ORM\Table(name: "node_type_fields"), - ORM\Index(columns: ["visible"]), - ORM\Index(columns: ["indexed"]), - ORM\Index(columns: ["position"]), - ORM\Index(columns: ["group_name"]), - ORM\Index(columns: ["group_name_canonical"]), - ORM\Index(columns: ["type"]), - ORM\Index(columns: ["name"], name: 'ntf_name'), - ORM\Index(columns: ["universal"]), - ORM\Index(columns: ["node_type_id", "position"], name: "ntf_type_position"), - ORM\UniqueConstraint(columns: ["name", "node_type_id"]), + ORM\Table(name: 'node_type_fields'), + ORM\Index(columns: ['visible']), + ORM\Index(columns: ['indexed']), + ORM\Index(columns: ['position']), + ORM\Index(columns: ['group_name']), + ORM\Index(columns: ['group_name_canonical']), + ORM\Index(columns: ['type']), + ORM\Index(columns: ['name'], name: 'ntf_name'), + ORM\Index(columns: ['universal']), + ORM\Index(columns: ['node_type_id', 'position'], name: 'ntf_type_position'), + ORM\UniqueConstraint(columns: ['name', 'node_type_id']), ORM\HasLifecycleCallbacks, - UniqueEntity(fields: ["name", "nodeType"]), + UniqueEntity(fields: ['name', 'nodeType']), RoadizAssert\NodeTypeField ] class NodeTypeField extends AbstractField implements NodeTypeFieldInterface, SerializableInterface { #[ - ORM\Column(type: "string", length: 50), + ORM\Column(type: 'string', length: 50), Serializer\Expose, - Serializer\Groups(["node_type", "setting"]), - SymfonySerializer\Groups(["node_type", "setting"]), + Serializer\Groups(['node_type', 'setting']), + SymfonySerializer\Groups(['node_type', 'setting']), Assert\Length(max: 50), - Serializer\Type("string"), + Serializer\Type('string'), RoadizAssert\NonSqlReservedWord(), RoadizAssert\SimpleLatinString() ] @@ -55,10 +56,10 @@ class NodeTypeField extends AbstractField implements NodeTypeFieldInterface, Ser * If current field data should be the same over translations or not. */ #[ - ORM\Column(name: "universal", type: "boolean", nullable: false, options: ["default" => false]), - Serializer\Groups(["node_type"]), - SymfonySerializer\Groups(["node_type"]), - Serializer\Type("bool") + ORM\Column(name: 'universal', type: 'boolean', nullable: false, options: ['default' => false]), + Serializer\Groups(['node_type']), + SymfonySerializer\Groups(['node_type']), + Serializer\Type('bool') ] private bool $universal = false; @@ -66,87 +67,87 @@ class NodeTypeField extends AbstractField implements NodeTypeFieldInterface, Ser * Exclude current field from full-text search engines. */ #[ - ORM\Column(name: "exclude_from_search", type: "boolean", nullable: false, options: ["default" => false]), - Serializer\Groups(["node_type"]), - SymfonySerializer\Groups(["node_type"]), - Serializer\Type("bool") + ORM\Column(name: 'exclude_from_search', type: 'boolean', nullable: false, options: ['default' => false]), + Serializer\Groups(['node_type']), + SymfonySerializer\Groups(['node_type']), + Serializer\Type('bool') ] private bool $excludeFromSearch = false; #[ - ORM\ManyToOne(targetEntity: NodeType::class, inversedBy: "fields"), - ORM\JoinColumn(name: "node_type_id", nullable: false, onDelete: "CASCADE"), + ORM\ManyToOne(targetEntity: NodeType::class, inversedBy: 'fields'), + ORM\JoinColumn(name: 'node_type_id', nullable: false, onDelete: 'CASCADE'), Serializer\Exclude(), SymfonySerializer\Ignore ] private NodeTypeInterface $nodeType; #[ - Serializer\Groups(["node_type"]), - SymfonySerializer\Groups(["node_type"]), - Serializer\Type("string"), - ORM\Column(name: "serialization_exclusion_expression", type: "text", nullable: true) + Serializer\Groups(['node_type']), + SymfonySerializer\Groups(['node_type']), + Serializer\Type('string'), + ORM\Column(name: 'serialization_exclusion_expression', type: 'text', nullable: true) ] private ?string $serializationExclusionExpression = null; #[ - Serializer\Groups(["node_type"]), - SymfonySerializer\Groups(["node_type"]), - Serializer\Type("array"), - ORM\Column(name: "serialization_groups", type: "json", nullable: true) + Serializer\Groups(['node_type']), + SymfonySerializer\Groups(['node_type']), + Serializer\Type('array'), + ORM\Column(name: 'serialization_groups', type: 'json', nullable: true) ] private ?array $serializationGroups = null; #[ - Serializer\Groups(["node_type"]), - SymfonySerializer\Groups(["node_type"]), - Serializer\Type("int"), - ORM\Column(name: "serialization_max_depth", type: "integer", nullable: true) + Serializer\Groups(['node_type']), + SymfonySerializer\Groups(['node_type']), + Serializer\Type('int'), + ORM\Column(name: 'serialization_max_depth', type: Types::SMALLINT, nullable: true) ] private ?int $serializationMaxDepth = null; #[ - Serializer\Groups(["node_type"]), - SymfonySerializer\Groups(["node_type"]), - Serializer\Type("bool"), - ORM\Column(name: "excluded_from_serialization", type: "boolean", nullable: false, options: ["default" => false]) + Serializer\Groups(['node_type']), + SymfonySerializer\Groups(['node_type']), + Serializer\Type('bool'), + ORM\Column(name: 'excluded_from_serialization', type: 'boolean', nullable: false, options: ['default' => false]) ] private bool $excludedFromSerialization = false; #[ - ORM\Column(name: "min_length", type: "integer", nullable: true), - Serializer\Groups(["node_type"]), - SymfonySerializer\Groups(["node_type"]), - Serializer\Type("int") + ORM\Column(name: 'min_length', type: Types::SMALLINT, nullable: true), + Serializer\Groups(['node_type']), + SymfonySerializer\Groups(['node_type']), + Serializer\Type('int') ] private ?int $minLength = null; #[ - ORM\Column(name: "max_length", type: "integer", nullable: true), - Serializer\Groups(["node_type"]), - SymfonySerializer\Groups(["node_type"]), - Serializer\Type("int") + ORM\Column(name: 'max_length', type: Types::SMALLINT, nullable: true), + Serializer\Groups(['node_type']), + SymfonySerializer\Groups(['node_type']), + Serializer\Type('int') ] private ?int $maxLength = null; #[ - ORM\Column(type: "boolean", nullable: false, options: ["default" => false]), - Serializer\Groups(["node_type"]), - SymfonySerializer\Groups(["node_type"]), - Serializer\Type("bool") + ORM\Column(type: 'boolean', nullable: false, options: ['default' => false]), + Serializer\Groups(['node_type']), + SymfonySerializer\Groups(['node_type']), + Serializer\Type('bool') ] private bool $indexed = false; #[ - ORM\Column(type: "boolean", nullable: false, options: ["default" => true]), - Serializer\Groups(["node_type"]), - SymfonySerializer\Groups(["node_type"]), - Serializer\Type("bool") + ORM\Column(type: 'boolean', nullable: false, options: ['default' => true]), + Serializer\Groups(['node_type']), + SymfonySerializer\Groups(['node_type']), + Serializer\Type('bool') ] private bool $visible = true; #[ - SymfonySerializer\Groups(["node_type"]) + SymfonySerializer\Groups(['node_type']) ] public function getNodeTypeName(): string { @@ -161,6 +162,7 @@ public function getNodeType(): NodeTypeInterface public function setNodeType(NodeTypeInterface $nodeType): NodeTypeField { $this->nodeType = $nodeType; + return $this; } @@ -172,12 +174,10 @@ public function getMinLength(): ?int public function setMinLength(?int $minLength): NodeTypeField { $this->minLength = $minLength; + return $this; } - /** - * @return int|null - */ public function getMaxLength(): ?int { return $this->maxLength; @@ -186,49 +186,43 @@ public function getMaxLength(): ?int public function setMaxLength(?int $maxLength): NodeTypeField { $this->maxLength = $maxLength; + return $this; } /** * Tell if current field can be searched and indexed in a Search engine server. - * - * @return bool */ public function isSearchable(): bool { return !$this->excludeFromSearch && in_array($this->getType(), static::$searchableTypes); } - /** - * @return string - */ #[SymfonySerializer\Ignore] public function getOneLineSummary(): string { - return $this->getId() . " — " . $this->getLabel() . ' [' . $this->getName() . ']' . - ' - ' . $this->getTypeName() . - ($this->isIndexed() ? ' - indexed' : '') . - (!$this->isVisible() ? ' - hidden' : '') . PHP_EOL; + return $this->getId().' — '.$this->getLabel().' ['.$this->getName().']'. + ' - '.$this->getTypeName(). + ($this->isIndexed() ? ' - indexed' : ''). + (!$this->isVisible() ? ' - hidden' : '').PHP_EOL; } /** - * @return boolean $isIndexed + * @return bool $isIndexed */ public function isIndexed(): bool { // JSON types cannot be indexed - return $this->indexed && $this->getDoctrineType() !== 'json'; + return $this->indexed && 'json' !== $this->getDoctrineType(); } public function setIndexed(bool $indexed): NodeTypeField { $this->indexed = $indexed; + return $this; } - /** - * @return bool - */ public function isVisible(): bool { return $this->visible; @@ -237,12 +231,10 @@ public function isVisible(): bool public function setVisible(bool $visible): NodeTypeField { $this->visible = $visible; + return $this; } - /** - * @return bool - */ public function isUniversal(): bool { return $this->universal; @@ -250,34 +242,24 @@ public function isUniversal(): bool /** * @see Same as isUniversal - * @return bool */ public function getUniversal(): bool { return $this->universal; } - /** - * @param bool $universal - * @return NodeTypeField - */ public function setUniversal(bool $universal): NodeTypeField { $this->universal = $universal; + return $this; } - /** - * @return bool - */ public function isExcludedFromSearch(): bool { return $this->getExcludeFromSearch(); } - /** - * @return bool - */ public function getExcludeFromSearch(): bool { return $this->excludeFromSearch; @@ -300,28 +282,18 @@ public function getSerializationExclusionExpression(): ?string return $this->serializationExclusionExpression; } - /** - * @param string|null $serializationExclusionExpression - * @return NodeTypeField - */ public function setSerializationExclusionExpression(?string $serializationExclusionExpression): NodeTypeField { $this->serializationExclusionExpression = $serializationExclusionExpression; + return $this; } - /** - * @return array - */ public function getSerializationGroups(): array { return array_filter($this->serializationGroups ?? []); } - /** - * @param array|null $serializationGroups - * @return NodeTypeField - */ public function setSerializationGroups(?array $serializationGroups): NodeTypeField { $this->serializationGroups = $serializationGroups; @@ -331,42 +303,31 @@ public function setSerializationGroups(?array $serializationGroups): NodeTypeFie if (empty($this->serializationGroups)) { $this->serializationGroups = null; } + return $this; } - /** - * @return int|null - */ public function getSerializationMaxDepth(): ?int { return $this->serializationMaxDepth; } - /** - * @param int|null $serializationMaxDepth - * @return NodeTypeField - */ public function setSerializationMaxDepth(?int $serializationMaxDepth): NodeTypeField { $this->serializationMaxDepth = $serializationMaxDepth; + return $this; } - /** - * @return bool - */ public function isExcludedFromSerialization(): bool { return $this->excludedFromSerialization; } - /** - * @param bool $excludedFromSerialization - * @return NodeTypeField - */ public function setExcludedFromSerialization(bool $excludedFromSerialization): NodeTypeField { $this->excludedFromSerialization = $excludedFromSerialization; + return $this; } } diff --git a/src/Entity/NodesCustomForms.php b/src/Entity/NodesCustomForms.php index 8f7d4a39..fc4a2ec8 100644 --- a/src/Entity/NodesCustomForms.php +++ b/src/Entity/NodesCustomForms.php @@ -15,10 +15,10 @@ */ #[ ORM\Entity(repositoryClass: NodesCustomFormsRepository::class), - ORM\Table(name: "nodes_custom_forms"), - ORM\Index(columns: ["position"]), - ORM\Index(columns: ["node_id", "position"], name: "customform_node_position"), - ORM\Index(columns: ["node_id", "field_name", "position"], name: "customform_node_field_position") + ORM\Table(name: 'nodes_custom_forms'), + ORM\Index(columns: ['position']), + ORM\Index(columns: ['node_id', 'position'], name: 'customform_node_position'), + ORM\Index(columns: ['node_id', 'field_name', 'position'], name: 'customform_node_field_position') ] class NodesCustomForms extends AbstractPositioned { @@ -35,8 +35,6 @@ class NodesCustomForms extends AbstractPositioned /** * Create a new relation between a Node, a CustomForm and a NodeTypeField. * - * @param Node $node - * @param CustomForm $customForm * @param NodeTypeFieldInterface|null $field NodeTypeField */ public function __construct(Node $node, CustomForm $customForm, ?NodeTypeFieldInterface $field = null) @@ -58,8 +56,6 @@ public function __clone() /** * Gets the value of node. - * - * @return Node */ public function getNode(): Node { @@ -70,19 +66,16 @@ public function getNode(): Node * Sets the value of node. * * @param Node $node the node - * - * @return self */ public function setNode(Node $node): NodesCustomForms { $this->node = $node; + return $this; } /** * Gets the value of customForm. - * - * @return CustomForm */ public function getCustomForm(): CustomForm { @@ -93,12 +86,11 @@ public function getCustomForm(): CustomForm * Sets the value of customForm. * * @param CustomForm $customForm the custom form - * - * @return self */ public function setCustomForm(CustomForm $customForm): NodesCustomForms { $this->customForm = $customForm; + return $this; } } diff --git a/src/Entity/NodesSources.php b/src/Entity/NodesSources.php index 8ebc470e..c18cc534 100644 --- a/src/Entity/NodesSources.php +++ b/src/Entity/NodesSources.php @@ -31,26 +31,26 @@ */ #[ ORM\Entity(repositoryClass: NodesSourcesRepository::class), - ORM\Table(name: "nodes_sources"), - ORM\Index(columns: ["discr"]), - ORM\Index(columns: ["title"]), - ORM\Index(columns: ["published_at"]), - ORM\Index(columns: ["no_index"]), - ORM\Index(columns: ["node_id", "translation_id", "published_at"], name: "ns_node_translation_published"), - ORM\Index(columns: ["node_id", "discr", "translation_id"], name: "ns_node_discr_translation"), - ORM\Index(columns: ["node_id", "discr", "translation_id", "published_at"], name: "ns_node_discr_translation_published"), - ORM\Index(columns: ["translation_id", "published_at"], name: "ns_translation_published"), - ORM\Index(columns: ["discr", "translation_id"], name: "ns_discr_translation"), - ORM\Index(columns: ["discr", "translation_id", "published_at"], name: "ns_discr_translation_published"), - ORM\Index(columns: ["title", "published_at"], name: "ns_title_published"), - ORM\Index(columns: ["title", "translation_id", "published_at"], name: "ns_title_translation_published"), - ORM\UniqueConstraint(columns: ["node_id", "translation_id"]), - ORM\InheritanceType("JOINED"), + ORM\Table(name: 'nodes_sources'), + ORM\Index(columns: ['discr']), + ORM\Index(columns: ['title']), + ORM\Index(columns: ['published_at']), + ORM\Index(columns: ['no_index'], name: 'ns_no_index'), + ORM\Index(columns: ['node_id', 'translation_id', 'published_at'], name: 'ns_node_translation_published'), + ORM\Index(columns: ['node_id', 'discr', 'translation_id'], name: 'ns_node_discr_translation'), + ORM\Index(columns: ['node_id', 'discr', 'translation_id', 'published_at'], name: 'ns_node_discr_translation_published'), + ORM\Index(columns: ['translation_id', 'published_at'], name: 'ns_translation_published'), + ORM\Index(columns: ['discr', 'translation_id'], name: 'ns_discr_translation'), + ORM\Index(columns: ['discr', 'translation_id', 'published_at'], name: 'ns_discr_translation_published'), + ORM\Index(columns: ['title', 'published_at'], name: 'ns_title_published'), + ORM\Index(columns: ['title', 'translation_id', 'published_at'], name: 'ns_title_translation_published'), + ORM\UniqueConstraint(columns: ['node_id', 'translation_id']), + ORM\InheritanceType('JOINED'), // Limit discriminator column to 30 characters for indexing optimization - ORM\DiscriminatorColumn(name: "discr", type: "string", length: 30), + ORM\DiscriminatorColumn(name: 'discr', type: 'string', length: 30), ORM\HasLifecycleCallbacks, Gedmo\Loggable(logEntryClass: UserLogEntry::class), - UniqueEntity(fields: ["node", "translation"]), + UniqueEntity(fields: ['node', 'translation']), ApiFilter(PropertyFilter::class), ApiFilter(RoadizFilter\LocaleFilter::class) ] @@ -68,7 +68,7 @@ class NodesSources extends AbstractEntity implements Loggable #[Serializer\Exclude] protected Collection $redirections; - #[ApiFilter(BaseFilter\SearchFilter::class, strategy: "partial")] + #[ApiFilter(BaseFilter\SearchFilter::class, strategy: 'partial')] #[ORM\Column(name: 'title', type: 'string', length: 250, unique: false, nullable: true)] #[SymfonySerializer\Groups(['nodes_sources', 'nodes_sources_base', 'log_sources'])] #[Serializer\Groups(['nodes_sources', 'nodes_sources_base', 'log_sources'])] @@ -92,7 +92,7 @@ class NodesSources extends AbstractEntity implements Loggable )] protected ?\DateTime $publishedAt = null; - #[ApiFilter(BaseFilter\SearchFilter::class, strategy: "partial")] + #[ApiFilter(BaseFilter\SearchFilter::class, strategy: 'partial')] #[ORM\Column(name: 'meta_title', type: 'string', length: 150, unique: false)] #[SymfonySerializer\Groups(['nodes_sources'])] #[Serializer\Groups(['nodes_sources'])] @@ -104,7 +104,7 @@ class NodesSources extends AbstractEntity implements Loggable )] protected string $metaTitle = ''; - #[ApiFilter(BaseFilter\SearchFilter::class, strategy: "partial")] + #[ApiFilter(BaseFilter\SearchFilter::class, strategy: 'partial')] #[ORM\Column(name: 'meta_description', type: 'text')] #[SymfonySerializer\Groups(['nodes_sources'])] #[Serializer\Groups(['nodes_sources'])] @@ -127,45 +127,45 @@ class NodesSources extends AbstractEntity implements Loggable protected bool $noIndex = false; #[ApiFilter(BaseFilter\SearchFilter::class, properties: [ - "node.id" => "exact", - "node.nodeName" => "exact", - "node.parent" => "exact", - "node.parent.nodeName" => "exact", - "node.nodesTags.tag" => "exact", - "node.nodesTags.tag.tagName" => "exact", - "node.nodeType" => "exact", - "node.nodeType.name" => "exact" + 'node.id' => 'exact', + 'node.nodeName' => 'exact', + 'node.parent' => 'exact', + 'node.parent.nodeName' => 'exact', + 'node.nodesTags.tag' => 'exact', + 'node.nodesTags.tag.tagName' => 'exact', + 'node.nodeType' => 'exact', + 'node.nodeType.name' => 'exact', ])] #[ApiFilter(BaseFilter\OrderFilter::class, properties: [ - "node.position", - "node.createdAt", - "node.updatedAt" + 'node.position', + 'node.createdAt', + 'node.updatedAt', ])] #[ApiFilter(BaseFilter\NumericFilter::class, properties: [ - "node.position", + 'node.position', ])] #[ApiFilter(BaseFilter\RangeFilter::class, properties: [ - "node.position", + 'node.position', ])] #[ApiFilter(BaseFilter\DateFilter::class, properties: [ - "node.createdAt", - "node.updatedAt" + 'node.createdAt', + 'node.updatedAt', ])] #[ApiFilter(BaseFilter\BooleanFilter::class, properties: [ - "node.visible", - "node.home", - "node.nodeType.reachable", - "node.nodeType.publishable" + 'node.visible', + 'node.home', + 'node.nodeType.reachable', + 'node.nodeType.publishable', ])] #[ApiFilter(RoadizFilter\NotFilter::class, properties: [ - "node.nodeType.name", - "node.id", - "node.nodesTags.tag.tagName", + 'node.nodeType.name', + 'node.id', + 'node.nodesTags.tag.tagName', ])] - # Use IntersectionFilter after SearchFilter! + // Use IntersectionFilter after SearchFilter! #[ApiFilter(RoadizFilter\IntersectionFilter::class, properties: [ - "node.nodesTags.tag", - "node.nodesTags.tag.tagName", + 'node.nodesTags.tag', + 'node.nodesTags.tag.tagName', ])] #[ORM\ManyToOne(targetEntity: Node::class, cascade: ['persist'], fetch: 'EAGER', inversedBy: 'nodeSources')] #[ORM\JoinColumn(name: 'node_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')] @@ -176,8 +176,8 @@ class NodesSources extends AbstractEntity implements Loggable private Node $node; #[ApiFilter(BaseFilter\SearchFilter::class, properties: [ - "translation.id" => "exact", - "translation.locale" => "exact", + 'translation.id' => 'exact', + 'translation.locale' => 'exact', ])] #[ORM\ManyToOne(targetEntity: Translation::class, inversedBy: 'nodeSources')] #[ORM\JoinColumn(name: 'translation_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')] @@ -213,9 +213,6 @@ class NodesSources extends AbstractEntity implements Loggable /** * Create a new NodeSource with its Node and Translation. - * - * @param Node $node - * @param TranslationInterface $translation */ public function __construct(Node $node, TranslationInterface $translation) { @@ -235,7 +232,7 @@ public function injectObjectManager(ObjectManager $objectManager): void #[ORM\PreUpdate] public function preUpdate(): void { - $this->getNode()->setUpdatedAt(new \DateTime("now")); + $this->getNode()->setUpdatedAt(new \DateTime('now')); } public function getNode(): Node @@ -252,7 +249,6 @@ public function setNode(Node $node): NodesSources } /** - * @param UrlAlias $urlAlias * @return $this */ public function addUrlAlias(UrlAlias $urlAlias): NodesSources @@ -290,17 +286,15 @@ public function getDocumentsByFields(): Collection /** * Get at least one document to represent this node-source as image. - * - * @return DocumentInterface|null */ #[SymfonySerializer\Ignore] public function getOneDisplayableDocument(): ?DocumentInterface { return $this->getDocumentsByFields()->filter(function (NodesSourcesDocuments $nsd) { - return null !== $nsd->getDocument() && - !$nsd->getDocument()->isPrivate() && - ($nsd->getDocument()->isImage() || $nsd->getDocument()->isSvg()) && - $nsd->getDocument()->isProcessable(); + return null !== $nsd->getDocument() + && !$nsd->getDocument()->isPrivate() + && ($nsd->getDocument()->isImage() || $nsd->getDocument()->isSvg()) + && $nsd->getDocument()->isProcessable(); })->map(function (NodesSourcesDocuments $nsd) { return $nsd->getDocument(); })->first() ?: null; @@ -308,8 +302,6 @@ public function getOneDisplayableDocument(): ?DocumentInterface /** * @param Collection $documentsByFields - * - * @return NodesSources */ public function setDocumentsByFields(Collection $documentsByFields): NodesSources { @@ -323,18 +315,14 @@ public function setDocumentsByFields(Collection $documentsByFields): NodesSource return $this; } - /** - * @param NodesSourcesDocuments $nodesSourcesDocuments - * @return bool - */ #[SymfonySerializer\Ignore] public function hasNodesSourcesDocuments(NodesSourcesDocuments $nodesSourcesDocuments): bool { return $this->getDocumentsByFields()->exists( function ($key, NodesSourcesDocuments $element) use ($nodesSourcesDocuments) { - return $nodesSourcesDocuments->getDocument()->getId() !== null && - $element->getDocument()->getId() === $nodesSourcesDocuments->getDocument()->getId() && - $element->getFieldName() === $nodesSourcesDocuments->getFieldName(); + return null !== $nodesSourcesDocuments->getDocument()->getId() + && $element->getDocument()->getId() === $nodesSourcesDocuments->getDocument()->getId() + && $element->getFieldName() === $nodesSourcesDocuments->getFieldName(); } ); } @@ -342,8 +330,6 @@ function ($key, NodesSourcesDocuments $element) use ($nodesSourcesDocuments) { /** * Used by any NSClass to add directly new documents to source. * - * @param NodesSourcesDocuments $nodesSourcesDocuments - * * @return $this */ public function addDocumentsByFields(NodesSourcesDocuments $nodesSourcesDocuments): NodesSources @@ -352,6 +338,7 @@ public function addDocumentsByFields(NodesSourcesDocuments $nodesSourcesDocument $this->getDocumentsByFields()->add($nodesSourcesDocuments); $nodesSourcesDocuments->setNodeSource($this); } + return $this; } @@ -364,6 +351,7 @@ public function getDocumentsByFieldsWithField(NodeTypeFieldInterface $field): ar { $criteria = Criteria::create(); $criteria->orderBy(['position' => 'ASC']); + return $this->getDocumentsByFields() ->matching($criteria) ->filter(function (NodesSourcesDocuments $element) use ($field) { @@ -377,13 +365,13 @@ public function getDocumentsByFieldsWithField(NodeTypeFieldInterface $field): ar } /** - * @param string $fieldName * @return Document[] */ public function getDocumentsByFieldsWithName(string $fieldName): array { $criteria = Criteria::create(); $criteria->orderBy(['position' => 'ASC']); + return $this->getDocumentsByFields() ->matching($criteria) ->filter(function (NodesSourcesDocuments $element) use ($fieldName) { @@ -406,43 +394,32 @@ public function getRedirections(): Collection /** * @param Collection $redirections - * @return NodesSources */ public function setRedirections(Collection $redirections): NodesSources { $this->redirections = $redirections; + return $this; } - /** - * @return \DateTime|null - */ public function getPublishedAt(): ?\DateTime { return $this->publishedAt; } - /** - * @param \DateTime|null $publishedAt - * @return NodesSources - */ - public function setPublishedAt(\DateTime $publishedAt = null): NodesSources + public function setPublishedAt(?\DateTime $publishedAt = null): NodesSources { $this->publishedAt = $publishedAt; + return $this; } - /** - * @return string - */ public function getMetaTitle(): string { return $this->metaTitle; } /** - * @param string|null $metaTitle - * * @return $this */ public function setMetaTitle(?string $metaTitle): NodesSources @@ -452,17 +429,12 @@ public function setMetaTitle(?string $metaTitle): NodesSources return $this; } - /** - * @return string - */ public function getMetaDescription(): string { return $this->metaDescription; } /** - * @param string|null $metaDescription - * * @return $this */ public function setMetaDescription(?string $metaDescription): NodesSources @@ -472,36 +444,27 @@ public function setMetaDescription(?string $metaDescription): NodesSources return $this; } - /** - * @return bool - */ public function isNoIndex(): bool { return $this->noIndex; } - /** - * @param bool $noIndex - * @return NodesSources - */ public function setNoIndex(bool $noIndex): NodesSources { $this->noIndex = $noIndex; + return $this; } - /** - * @return string - * @Serializer\VirtualProperty - * @Serializer\SerializedName("slug") - * @Serializer\Groups({"nodes_sources", "nodes_sources_base"}) - */ #[SymfonySerializer\SerializedName('slug')] #[SymfonySerializer\Groups(['nodes_sources', 'nodes_sources_base'])] + #[Serializer\SerializedName('slug')] + #[Serializer\VirtualProperty] + #[Serializer\Groups(['nodes_sources', 'nodes_sources_base'])] public function getIdentifier(): string { $urlAlias = $this->getUrlAliases()->first(); - if (false !== $urlAlias && $urlAlias->getAlias() !== '') { + if (false !== $urlAlias && '' !== $urlAlias->getAlias()) { return $urlAlias->getAlias(); } @@ -517,12 +480,10 @@ public function getUrlAliases(): Collection } /** - * Get parent node’ source based on the same translation. - * - * @return NodesSources|null - * @Serializer\Exclude + * Get parent node source based on the same translation. */ #[SymfonySerializer\Ignore] + #[Serializer\Exclude] public function getParent(): ?NodesSources { /** @var Node|null $parent */ @@ -530,65 +491,53 @@ public function getParent(): ?NodesSources if (null !== $parent) { /** @var NodesSources|false $nodeSources */ $nodeSources = $parent->getNodeSourcesByTranslation($this->translation)->first(); + return $nodeSources ?: null; } else { return null; } } - /** - * @return string - */ public function __toString(): string { return (string) $this->getId(); } - /** - * @return string|null - */ public function getTitle(): ?string { return $this->title; } /** - * @param string|null $title * @return $this */ public function setTitle(?string $title): NodesSources { $this->title = null !== $title ? trim($title) : null; + return $this; } - /** - * @return TranslationInterface - */ public function getTranslation(): TranslationInterface { return $this->translation; } /** - * @param TranslationInterface $translation - * * @return $this */ public function setTranslation(TranslationInterface $translation): NodesSources { $this->translation = $translation; + return $this; } - /** - * @return string - * @Serializer\VirtualProperty - * @Serializer\Groups({"nodes_sources", "nodes_sources_default"}) - * @Serializer\SerializedName("@type") - */ #[SymfonySerializer\Groups(['nodes_sources', 'nodes_sources_default'])] #[SymfonySerializer\SerializedName('@type')] + #[Serializer\Groups(['nodes_sources', 'nodes_sources_default'])] + #[Serializer\SerializedName('@type')] + #[Serializer\VirtualProperty] public function getNodeTypeName(): string { return 'NodesSources'; @@ -596,8 +545,6 @@ public function getNodeTypeName(): string /** * Overridden in NS classes. - * - * @return bool */ public function isPublishable(): bool { @@ -606,8 +553,6 @@ public function isPublishable(): bool /** * Overridden in NS classes. - * - * @return bool */ public function isReachable(): bool { @@ -616,8 +561,6 @@ public function isReachable(): bool /** * Returns current listing sort options OR parent node's if parent node is hiding children. - * - * @return array */ #[Serializer\Groups(['node_listing'])] #[SymfonySerializer\Groups(['node_listing'])] @@ -626,21 +569,22 @@ public function getListingSortOptions(): array if (null !== $this->getParent() && $this->getParent()->getNode()->isHidingChildren()) { return $this->getParent()->getListingSortOptions(); } + return match ($this->getNode()->getChildrenOrder()) { 'position' => [ - 'node.position' => $this->getNode()->getChildrenOrderDirection() + 'node.position' => $this->getNode()->getChildrenOrderDirection(), ], 'nodeName' => [ - 'node.nodeName' => $this->getNode()->getChildrenOrderDirection() + 'node.nodeName' => $this->getNode()->getChildrenOrderDirection(), ], 'createdAt' => [ - 'node.createdAt' => $this->getNode()->getChildrenOrderDirection() + 'node.createdAt' => $this->getNode()->getChildrenOrderDirection(), ], 'updatedAt' => [ - 'node.updatedAt' => $this->getNode()->getChildrenOrderDirection() + 'node.updatedAt' => $this->getNode()->getChildrenOrderDirection(), ], default => [ - 'publishedAt' => $this->getNode()->getChildrenOrderDirection() + 'publishedAt' => $this->getNode()->getChildrenOrderDirection(), ], }; } diff --git a/src/Entity/NodesSourcesDocuments.php b/src/Entity/NodesSourcesDocuments.php index 6842bba9..f0472cc2 100644 --- a/src/Entity/NodesSourcesDocuments.php +++ b/src/Entity/NodesSourcesDocuments.php @@ -16,18 +16,15 @@ */ #[ ORM\Entity(repositoryClass: NodesSourcesDocumentsRepository::class), - ORM\Table(name: "nodes_sources_documents"), - ORM\Index(columns: ["position"]), - ORM\Index(columns: ["ns_id", "field_name"], name: "nsdoc_field"), - ORM\Index(columns: ["ns_id", "field_name", "position"], name: "nsdoc_field_position") + ORM\Table(name: 'nodes_sources_documents'), + ORM\Index(columns: ['position']), + ORM\Index(columns: ['ns_id', 'field_name'], name: 'nsdoc_field'), + ORM\Index(columns: ['ns_id', 'field_name', 'position'], name: 'nsdoc_field_position') ] class NodesSourcesDocuments extends AbstractPositioned { use FieldAwareEntityTrait; - /** - * @var NodesSources - */ #[ORM\ManyToOne( targetEntity: NodesSources::class, cascade: ['persist'], @@ -38,9 +35,6 @@ class NodesSourcesDocuments extends AbstractPositioned #[ORM\JoinColumn(name: 'ns_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')] protected NodesSources $nodeSource; - /** - * @var Document - */ #[ORM\ManyToOne( targetEntity: Document::class, cascade: ['persist'], @@ -54,9 +48,9 @@ class NodesSourcesDocuments extends AbstractPositioned /** * Create a new relation between NodeSource, a Document and a NodeTypeField. * - * @param NodesSources $nodeSource NodesSources and inherited types - * @param Document $document Document to link - * @param NodeTypeFieldInterface|null $field NodeTypeField + * @param NodesSources $nodeSource NodesSources and inherited types + * @param Document $document Document to link + * @param NodeTypeFieldInterface|null $field NodeTypeField */ public function __construct(NodesSources $nodeSource, Document $document, ?NodeTypeFieldInterface $field = null) { @@ -77,8 +71,6 @@ public function __clone() /** * Gets the value of nodeSource. - * - * @return NodesSources */ public function getNodeSource(): NodesSources { @@ -89,8 +81,6 @@ public function getNodeSource(): NodesSources * Sets the value of nodeSource. * * @param NodesSources $nodeSource the node source - * - * @return self */ public function setNodeSource(NodesSources $nodeSource): NodesSourcesDocuments { @@ -101,8 +91,6 @@ public function setNodeSource(NodesSources $nodeSource): NodesSourcesDocuments /** * Gets the value of document. - * - * @return Document */ public function getDocument(): Document { @@ -113,8 +101,6 @@ public function getDocument(): Document * Sets the value of document. * * @param Document $document the document - * - * @return self */ public function setDocument(Document $document): NodesSourcesDocuments { diff --git a/src/Entity/NodesTags.php b/src/Entity/NodesTags.php index e2e82b67..746dff6d 100644 --- a/src/Entity/NodesTags.php +++ b/src/Entity/NodesTags.php @@ -14,7 +14,7 @@ #[ ORM\Entity(repositoryClass: NodesTagsRepository::class), - ORM\Table(name: "nodes_tags"), + ORM\Table(name: 'nodes_tags'), ORM\Index(columns: ['node_id', 'position'], name: 'nodes_tags_node_id_position'), ORM\Index(columns: ['tag_id', 'position'], name: 'nodes_tags_tag_id_position'), ORM\Index(columns: ['position'], name: 'nodes_tags_position'), @@ -27,17 +27,17 @@ class NodesTags implements PositionedInterface, Comparable #[ ORM\Id, - ORM\Column(type:"string", length:36), + ORM\Column(type: 'string', length: 36), SymfonySerializer\Ignore ] /** @phpstan-ignore-next-line */ protected ?string $id = null; #[ - ORM\ManyToOne(targetEntity: Node::class, inversedBy: "nodesTags"), + ORM\ManyToOne(targetEntity: Node::class, inversedBy: 'nodesTags'), ORM\JoinColumn( - name: "node_id", - referencedColumnName: "id", + name: 'node_id', + referencedColumnName: 'id', unique: false, nullable: false, onDelete: 'CASCADE' @@ -48,10 +48,10 @@ class NodesTags implements PositionedInterface, Comparable private Node $node; #[ - ORM\ManyToOne(targetEntity: Tag::class, inversedBy: "nodesTags"), + ORM\ManyToOne(targetEntity: Tag::class, inversedBy: 'nodesTags'), ORM\JoinColumn( - name: "tag_id", - referencedColumnName: "id", + name: 'tag_id', + referencedColumnName: 'id', unique: false, nullable: false, onDelete: 'CASCADE' @@ -62,7 +62,7 @@ class NodesTags implements PositionedInterface, Comparable private Tag $tag; #[ - ORM\Column(type: "float", nullable: false, options: ['default' => 1]), + ORM\Column(type: 'float', nullable: false, options: ['default' => 1]), SymfonySerializer\Ignore, Serializer\Exclude, ] @@ -73,39 +73,27 @@ public function __construct(?string $uuid = null) $this->id = $uuid ?? \Ramsey\Uuid\Uuid::uuid4()->toString(); } - /** - * @return Node - */ public function getNode(): Node { return $this->node; } - /** - * @param Node $node - * @return NodesTags - */ public function setNode(Node $node): NodesTags { $this->node = $node; + return $this; } - /** - * @return Tag - */ public function getTag(): Tag { return $this->tag; } - /** - * @param Tag $tag - * @return NodesTags - */ public function setTag(Tag $tag): NodesTags { $this->tag = $tag; + return $this; } } diff --git a/src/Entity/NodesToNodes.php b/src/Entity/NodesToNodes.php index b80836c9..6b24f4ca 100644 --- a/src/Entity/NodesToNodes.php +++ b/src/Entity/NodesToNodes.php @@ -15,12 +15,12 @@ */ #[ ORM\Entity(repositoryClass: NodesToNodesRepository::class), - ORM\Table(name: "nodes_to_nodes"), - ORM\Index(columns: ["position"]), - ORM\Index(columns: ["node_a_id", "field_name"], name: "node_a_field"), - ORM\Index(columns: ["node_a_id", "field_name", "position"], name: "node_a_field_position"), - ORM\Index(columns: ["node_b_id", "field_name"], name: "node_b_field"), - ORM\Index(columns: ["node_b_id", "field_name", "position"], name: "node_b_field_position") + ORM\Table(name: 'nodes_to_nodes'), + ORM\Index(columns: ['position']), + ORM\Index(columns: ['node_a_id', 'field_name'], name: 'node_a_field'), + ORM\Index(columns: ['node_a_id', 'field_name', 'position'], name: 'node_a_field_position'), + ORM\Index(columns: ['node_b_id', 'field_name'], name: 'node_b_field'), + ORM\Index(columns: ['node_b_id', 'field_name', 'position'], name: 'node_b_field_position') ] class NodesToNodes extends AbstractPositioned { @@ -50,8 +50,6 @@ public function __clone() /** * Gets the value of nodeA. - * - * @return Node */ public function getNodeA(): Node { @@ -62,8 +60,6 @@ public function getNodeA(): Node * Sets the value of nodeA. * * @param Node $nodeA the node - * - * @return self */ public function setNodeA(Node $nodeA): NodesToNodes { @@ -74,8 +70,6 @@ public function setNodeA(Node $nodeA): NodesToNodes /** * Gets the value of nodeB. - * - * @return Node */ public function getNodeB(): Node { @@ -86,12 +80,11 @@ public function getNodeB(): Node * Sets the value of nodeB. * * @param Node $nodeB the node - * - * @return self */ public function setNodeB(Node $nodeB): NodesToNodes { $this->nodeB = $nodeB; + return $this; } } diff --git a/src/Entity/Realm.php b/src/Entity/Realm.php index 9cf68e49..2f063c1e 100644 --- a/src/Entity/Realm.php +++ b/src/Entity/Realm.php @@ -27,15 +27,15 @@ */ #[ ORM\Entity(repositoryClass: RealmRepository::class), - ORM\Table(name: "realms"), - ORM\Index(columns: ["type"], name: "realms_type"), - ORM\Index(columns: ["behaviour"], name: "realms_behaviour"), - UniqueEntity(fields: ["name"]), + ORM\Table(name: 'realms'), + ORM\Index(columns: ['type'], name: 'realms_type'), + ORM\Index(columns: ['behaviour'], name: 'realms_behaviour'), + UniqueEntity(fields: ['name']), ApiFilter(PropertyFilter::class), ApiFilter(BaseFilter\SearchFilter::class, properties: [ - "type" => "exact", - "behaviour" => "exact", - "name" => "exact" + 'type' => 'exact', + 'behaviour' => 'exact', + 'name' => 'exact', ]) ] class Realm extends AbstractEntity implements RealmInterface @@ -61,12 +61,9 @@ class Realm extends AbstractEntity implements RealmInterface #[Assert\Regex('#^[\w\s]+$#u')] private string $name = ''; - /** - * @var string|null - * @Serializer\Exclude() - */ #[ORM\Column(name: 'plain_password', type: 'string', length: 255, unique: false, nullable: true)] #[SymfonySerializer\Ignore] + #[Serializer\Exclude] #[Assert\Length(max: 255)] private ?string $plainPassword = null; @@ -105,73 +102,53 @@ public function __construct() $this->realmNodes = new ArrayCollection(); } - /** - * @return string|null - */ public function getRole(): ?string { if (null === $this->roleEntity) { return null; } + return $this->roleEntity->getRole(); } - /** - * @return Role|null - */ public function getRoleEntity(): ?Role { return $this->roleEntity; } - /** - * @param Role|null $roleEntity - * @return Realm - */ public function setRoleEntity(?Role $roleEntity): Realm { $this->roleEntity = $roleEntity; + return $this; } - /** - * @return string|null - */ public function getSerializationGroup(): ?string { return $this->serializationGroup; } - /** - * @param string|null $serializationGroup - * @return Realm - */ public function setSerializationGroup(?string $serializationGroup): Realm { $this->serializationGroup = null !== $serializationGroup ? (new AsciiSlugger())->slug($serializationGroup, '_')->lower()->toString() : null; + return $this; } - /** - * @return string - */ public function getName(): string { return $this->name ?? ''; } - /** - * @param string $name - * @return Realm - */ public function setName(string $name): Realm { $this->name = $name; if (null === $this->serializationGroup) { $this->serializationGroup = (new AsciiSlugger())->slug($this->name, '_')->lower()->toString(); } + return $this; } @@ -185,11 +162,13 @@ public function getRealmNodes(): Collection /** * @param Collection $realmNodes + * * @return Realm */ public function setRealmNodes(Collection $realmNodes) { $this->realmNodes = $realmNodes; + return $this; } @@ -203,58 +182,45 @@ public function getUsers(): Collection /** * @param Collection $users + * * @return Realm */ public function setUsers(Collection $users) { $this->users = $users; + return $this; } - /** - * @return string|null - */ public function getPlainPassword(): ?string { return $this->plainPassword; } - /** - * @param string|null $plainPassword - * @return Realm - */ public function setPlainPassword(?string $plainPassword): Realm { $this->plainPassword = $plainPassword; + return $this; } - /** - * @return string - */ public function getBehaviour(): string { return $this->behaviour; } - /** - * @param string $behaviour - * @return Realm - */ public function setBehaviour(string $behaviour): Realm { $this->behaviour = $behaviour; + return $this; } public function getChallenge(): string { - return $this->getAuthenticationScheme() . ' realm="' . addslashes($this->getName()) . '"'; + return $this->getAuthenticationScheme().' realm="'.addslashes($this->getName()).'"'; } - /** - * @return string - */ #[SymfonySerializer\Groups(['get', 'realm', 'web_response'])] #[Serializer\Groups(['get', 'realm', 'web_response'])] public function getAuthenticationScheme(): string @@ -267,21 +233,15 @@ public function getAuthenticationScheme(): string } } - /** - * @return string - */ public function getType(): string { return $this->type; } - /** - * @param string $type - * @return Realm - */ public function setType(string $type): Realm { $this->type = $type; + return $this; } } diff --git a/src/Entity/RealmNode.php b/src/Entity/RealmNode.php index 8007a309..e0623569 100644 --- a/src/Entity/RealmNode.php +++ b/src/Entity/RealmNode.php @@ -7,21 +7,21 @@ use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation as Serializer; use RZ\Roadiz\Core\AbstractEntities\AbstractEntity; +use RZ\Roadiz\CoreBundle\Model\RealmInterface; use RZ\Roadiz\CoreBundle\Repository\RealmNodeRepository; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Serializer\Annotation as SymfonySerializer; -use RZ\Roadiz\CoreBundle\Model\RealmInterface; use Symfony\Component\Validator\Constraints as Assert; #[ ORM\Entity(repositoryClass: RealmNodeRepository::class), - ORM\Table(name: "realms_nodes"), - ORM\Index(columns: ["inheritance_type"], name: "realms_nodes_inheritance_type"), - ORM\Index(columns: ["realm_id"], name: "realms_nodes_realm"), - ORM\Index(columns: ["node_id"], name: "realms_nodes_node"), - ORM\Index(columns: ["node_id", "inheritance_type"], name: "realms_nodes_node_inheritance_type"), - ORM\UniqueConstraint(name: "realms_nodes_unique", columns: ["node_id", "realm_id"]), - UniqueEntity(fields: ["node", "realm"]) + ORM\Table(name: 'realms_nodes'), + ORM\Index(columns: ['inheritance_type'], name: 'realms_nodes_inheritance_type'), + ORM\Index(columns: ['realm_id'], name: 'realms_nodes_realm'), + ORM\Index(columns: ['node_id'], name: 'realms_nodes_node'), + ORM\Index(columns: ['node_id', 'inheritance_type'], name: 'realms_nodes_node_inheritance_type'), + ORM\UniqueConstraint(name: 'realms_nodes_unique', columns: ['node_id', 'realm_id']), + UniqueEntity(fields: ['node', 'realm']) ] class RealmNode extends AbstractEntity { @@ -55,57 +55,39 @@ class RealmNode extends AbstractEntity #[Serializer\Exclude] private string $inheritanceType = RealmInterface::INHERITANCE_AUTO; - /** - * @return Node - */ public function getNode(): Node { return $this->node; } - /** - * @param Node $node - * @return RealmNode - */ public function setNode(Node $node): RealmNode { $this->node = $node; + return $this; } - /** - * @return Realm - */ public function getRealm(): Realm { return $this->realm; } - /** - * @param Realm $realm - * @return RealmNode - */ public function setRealm(Realm $realm): RealmNode { $this->realm = $realm; + return $this; } - /** - * @return string - */ public function getInheritanceType(): string { return $this->inheritanceType; } - /** - * @param string $inheritanceType - * @return RealmNode - */ public function setInheritanceType(string $inheritanceType): RealmNode { $this->inheritanceType = $inheritanceType; + return $this; } } diff --git a/src/Entity/Redirection.php b/src/Entity/Redirection.php index 469222ef..aeedd398 100644 --- a/src/Entity/Redirection.php +++ b/src/Entity/Redirection.php @@ -4,6 +4,7 @@ namespace RZ\Roadiz\CoreBundle\Entity; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use RZ\Roadiz\Core\AbstractEntities\AbstractDateTimed; use RZ\Roadiz\CoreBundle\Repository\RedirectionRepository; @@ -16,19 +17,19 @@ */ #[ ORM\Entity(repositoryClass: RedirectionRepository::class), - ORM\Table(name: "redirections"), + ORM\Table(name: 'redirections'), ORM\HasLifecycleCallbacks, - UniqueEntity(fields: ["query"]), - ORM\Index(columns: ["use_count"], name: 'redirection_use_count'), - ORM\Index(columns: ["created_at"], name: "redirection_created_at"), - ORM\Index(columns: ["updated_at"], name: "redirection_updated_at"), + UniqueEntity(fields: ['query']), + ORM\Index(columns: ['use_count'], name: 'redirection_use_count'), + ORM\Index(columns: ['created_at'], name: 'redirection_created_at'), + ORM\Index(columns: ['updated_at'], name: 'redirection_updated_at'), ] class Redirection extends AbstractDateTimed { #[ORM\Column(type: 'string', length: 255, unique: true)] #[Assert\NotBlank] #[Assert\Length(max: 255)] - private string $query = ""; + private string $query = ''; #[ORM\Column(name: 'redirectUri', type: 'text', length: 2048, nullable: true)] #[Assert\Length(max: 2048)] @@ -38,84 +39,54 @@ class Redirection extends AbstractDateTimed #[Assert\Length(max: 2048)] private int $useCount = 0; - /** - * @var NodesSources|null - */ #[ORM\ManyToOne(targetEntity: NodesSources::class, cascade: ['persist'], inversedBy: 'redirections')] #[ORM\JoinColumn(name: 'ns_id', referencedColumnName: 'id', onDelete: 'CASCADE')] private ?NodesSources $redirectNodeSource = null; - /** - * @var int - */ - #[ORM\Column(type: 'integer')] + #[ORM\Column(type: Types::SMALLINT)] private int $type = 301; - /** - * @return string - */ public function getQuery(): string { return $this->query; } - /** - * @param string|null $query - * @return Redirection - */ public function setQuery(?string $query): Redirection { $this->query = $query ?? ''; + return $this; } - /** - * @return string|null - */ public function getRedirectUri(): ?string { return $this->redirectUri; } - /** - * @param string|null $redirectUri - * @return Redirection - */ public function setRedirectUri(?string $redirectUri): Redirection { $this->redirectUri = $redirectUri; + return $this; } - /** - * @return NodesSources|null - */ public function getRedirectNodeSource(): ?NodesSources { return $this->redirectNodeSource; } - /** - * @param NodesSources|null $redirectNodeSource - * @return Redirection - */ - public function setRedirectNodeSource(NodesSources $redirectNodeSource = null): Redirection + public function setRedirectNodeSource(?NodesSources $redirectNodeSource = null): Redirection { $this->redirectNodeSource = $redirectNodeSource; + return $this; } - /** - * @return int - */ public function getType(): int { return $this->type; } - /** - * @return string - */ public function getTypeAsString(): string { $types = [ @@ -126,13 +97,10 @@ public function getTypeAsString(): string return $types[$this->type] ?? ''; } - /** - * @param int $type - * @return Redirection - */ public function setType(int $type): Redirection { $this->type = $type; + return $this; } @@ -142,9 +110,6 @@ public function __construct() $this->initAbstractDateTimed(); } - /** - * @return int - */ public function getUseCount(): int { return $this->useCount; @@ -152,7 +117,8 @@ public function getUseCount(): int public function incrementUseCount(): self { - $this->useCount++; + ++$this->useCount; + return $this; } } diff --git a/src/Entity/Role.php b/src/Entity/Role.php index d1a03ca8..230df685 100644 --- a/src/Entity/Role.php +++ b/src/Entity/Role.php @@ -20,8 +20,8 @@ */ #[ ORM\Entity(repositoryClass: RoleRepository::class), - ORM\Table(name: "roles"), - UniqueEntity(fields: ["name"]) + ORM\Table(name: 'roles'), + UniqueEntity(fields: ['name']) ] class Role implements PersistableInterface { @@ -31,8 +31,8 @@ class Role implements PersistableInterface #[ ORM\Id, - ORM\Column(type: "integer"), - ORM\GeneratedValue(strategy: "AUTO") + ORM\Column(type: 'integer'), + ORM\GeneratedValue(strategy: 'AUTO') ] protected ?int $id = null; @@ -51,7 +51,7 @@ class Role implements PersistableInterface #[ORM\ManyToMany(targetEntity: Group::class, mappedBy: 'roleEntities', cascade: ['persist', 'merge'])] #[SymfonySerializer\Groups(['role'])] #[Serializer\Groups(['role'])] - #[Serializer\Accessor(getter: "getGroups", setter: "setGroups")] + #[Serializer\Accessor(getter: 'getGroups', setter: 'setGroups')] #[Serializer\Type("ArrayCollection")] private Collection $groups; @@ -66,26 +66,19 @@ public function __construct(string $name) $this->groups = new ArrayCollection(); } - /** - * @return int|null - */ public function getId(): ?int { return $this->id; } - /** - * @param int|null $id - * @return Role - */ public function setId(?int $id): Role { $this->id = $id; + return $this; } /** - * @return string * @deprecated Use getRole method */ public function getName(): string @@ -94,8 +87,6 @@ public function getName(): string } /** - * @param string $name - * @return Role * @deprecated Use setRole method */ public function setName(string $name): Role @@ -103,21 +94,13 @@ public function setName(string $name): Role return $this->setRole($name); } - /** - * @param string $role - * @return Role - */ public function setRole(string $role): Role { $this->name = static::cleanName($role); + return $this; } - /** - * @param string $name - * - * @return string - */ public static function cleanName(string $name): string { $string = (new UnicodeString($name)) @@ -134,7 +117,6 @@ public static function cleanName(string $name): string } /** - * @param Group $group * @return $this */ public function addGroup(Group $group): Role @@ -146,16 +128,12 @@ public function addGroup(Group $group): Role return $this; } - /** - * @return Collection - */ public function getGroups(): Collection { return $this->groups; } /** - * @param Collection $groups * @return $this */ public function setGroups(Collection $groups): Role @@ -170,7 +148,6 @@ public function setGroups(Collection $groups): Role } /** - * @param Group $group * @return $this */ public function removeGroup(Group $group): Role @@ -186,33 +163,25 @@ public function removeGroup(Group $group): Role * Get a classified version of current role name. * * It replaces underscores by dashes and lowercase. - * - * @return string - * @Serializer\Groups({"role"}) */ #[SymfonySerializer\Groups(['role'])] + #[Serializer\Groups(['role'])] public function getClassName(): string { return str_replace('_', '-', \mb_strtolower($this->getRole())); } - /** - * @return string - */ public function getRole(): string { return $this->name; } - /** - * @return bool - */ public function required(): bool { if ( - $this->getRole() == static::ROLE_DEFAULT || - $this->getRole() == static::ROLE_SUPERADMIN || - $this->getRole() == static::ROLE_BACKEND_USER + $this->getRole() == static::ROLE_DEFAULT + || $this->getRole() == static::ROLE_SUPERADMIN + || $this->getRole() == static::ROLE_BACKEND_USER ) { return true; } @@ -220,9 +189,6 @@ public function required(): bool return false; } - /** - * @return string - */ public function __toString(): string { return $this->getRole(); diff --git a/src/Entity/Setting.php b/src/Entity/Setting.php index 2670a463..21065bfc 100644 --- a/src/Entity/Setting.php +++ b/src/Entity/Setting.php @@ -4,13 +4,14 @@ namespace RZ\Roadiz\CoreBundle\Entity; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation as Serializer; +use RZ\Roadiz\Core\AbstractEntities\AbstractEntity; +use RZ\Roadiz\Core\AbstractEntities\AbstractField; use RZ\Roadiz\CoreBundle\Repository\SettingRepository; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Serializer\Annotation as SymfonySerializer; -use RZ\Roadiz\Core\AbstractEntities\AbstractEntity; -use RZ\Roadiz\Core\AbstractEntities\AbstractField; use Symfony\Component\String\UnicodeString; use Symfony\Component\Validator\Constraints as Assert; @@ -19,11 +20,11 @@ */ #[ ORM\Entity(repositoryClass: SettingRepository::class), - ORM\Table(name: "settings"), - ORM\Index(columns: ["type"]), - ORM\Index(columns: ["name"]), - ORM\Index(columns: ["visible"]), - UniqueEntity(fields: ["name"]) + ORM\Table(name: 'settings'), + ORM\Index(columns: ['type']), + ORM\Index(columns: ['name']), + ORM\Index(columns: ['visible']), + UniqueEntity(fields: ['name']) ] class Setting extends AbstractEntity { @@ -85,14 +86,14 @@ class Setting extends AbstractEntity #[SymfonySerializer\Groups(['setting'])] #[Serializer\Groups(['setting'])] #[Serializer\AccessType(type: 'public_method')] - #[Serializer\Accessor(getter: "getSettingGroup", setter: "setSettingGroup")] + #[Serializer\Accessor(getter: 'getSettingGroup', setter: 'setSettingGroup')] private ?SettingGroup $settingGroup; /** * Value types. * Use NodeTypeField types constants. */ - #[ORM\Column(type: 'integer')] + #[ORM\Column(type: Types::SMALLINT)] #[SymfonySerializer\Groups(['setting'])] #[Serializer\Groups(['setting'])] private int $type = AbstractField::STRING_T; @@ -105,17 +106,12 @@ class Setting extends AbstractEntity #[Serializer\Groups(['setting'])] private ?string $defaultValues; - /** - * @return string - */ public function getName(): string { return $this->name; } /** - * @param string|null $name - * * @return $this */ public function setName(?string $name): self @@ -129,19 +125,11 @@ public function setName(?string $name): self return $this; } - /** - * @return string|null - */ public function getDescription(): ?string { return $this->description; } - /** - * @param string|null $description - * - * @return Setting - */ public function setDescription(?string $description): Setting { $this->description = $description; @@ -149,30 +137,26 @@ public function setDescription(?string $description): Setting return $this; } - /** - * @return string|null - */ public function getRawValue(): ?string { return $this->value; } /** - * @return string|bool|\DateTime|int|null * @throws \Exception */ #[SymfonySerializer\Ignore] public function getValue(): string|bool|\DateTime|int|null { - if ($this->getType() == AbstractField::BOOLEAN_T) { + if (AbstractField::BOOLEAN_T == $this->getType()) { return (bool) $this->value; } if (null !== $this->value) { - if ($this->getType() == AbstractField::DATETIME_T) { + if (AbstractField::DATETIME_T == $this->getType()) { return new \DateTime($this->value); } - if ($this->getType() == AbstractField::DOCUMENTS_T) { + if (AbstractField::DOCUMENTS_T == $this->getType()) { return (int) $this->value; } } @@ -181,8 +165,6 @@ public function getValue(): string|bool|\DateTime|int|null } /** - * @param mixed $value - * * @return $this */ public function setValue(mixed $value): self @@ -198,17 +180,12 @@ public function setValue(mixed $value): self return $this; } - /** - * @return int - */ public function getType(): int { return $this->type; } /** - * @param int $type - * * @return $this */ public function setType(int $type): self @@ -218,17 +195,12 @@ public function setType(int $type): self return $this; } - /** - * @return boolean - */ public function isVisible(): bool { return $this->visible; } /** - * @param bool $visible - * * @return $this */ public function setVisible(bool $visible): self @@ -238,17 +210,12 @@ public function setVisible(bool $visible): self return $this; } - /** - * @return SettingGroup|null - */ public function getSettingGroup(): ?SettingGroup { return $this->settingGroup; } /** - * @param SettingGroup|null $settingGroup - * * @return $this */ public function setSettingGroup(?SettingGroup $settingGroup): self @@ -258,19 +225,11 @@ public function setSettingGroup(?SettingGroup $settingGroup): self return $this; } - /** - * @return string|null - */ public function getDefaultValues(): ?string { return $this->defaultValues; } - /** - * @param string|null $defaultValues - * - * @return Setting - */ public function setDefaultValues(?string $defaultValues): self { $this->defaultValues = $defaultValues; diff --git a/src/Entity/SettingGroup.php b/src/Entity/SettingGroup.php index a8d73195..364661b4 100644 --- a/src/Entity/SettingGroup.php +++ b/src/Entity/SettingGroup.php @@ -19,8 +19,8 @@ */ #[ ORM\Entity(repositoryClass: SettingGroupRepository::class), - ORM\Table(name: "settings_groups"), - UniqueEntity(fields: ["name"]) + ORM\Table(name: 'settings_groups'), + UniqueEntity(fields: ['name']) ] class SettingGroup extends AbstractEntity { @@ -50,35 +50,27 @@ public function __construct() $this->settings = new ArrayCollection(); } - /** - * @return string - */ public function getName(): string { return $this->name; } /** - * @param string $name - * * @return SettingGroup */ public function setName(string $name) { $this->name = $name; + return $this; } - /** - * @return bool - */ public function isInMenu(): bool { return $this->inMenu; } /** - * @param bool $newinMenu * @return SettingGroup */ public function setInMenu(bool $newinMenu) @@ -89,7 +81,6 @@ public function setInMenu(bool $newinMenu) } /** - * @param Setting $setting * @return SettingGroup */ public function addSetting(Setting $setting) @@ -97,6 +88,7 @@ public function addSetting(Setting $setting) if (!$this->getSettings()->contains($setting)) { $this->settings->add($setting); } + return $this; } @@ -110,6 +102,7 @@ public function getSettings(): Collection /** * @param Collection $settings + * * @return SettingGroup */ public function addSettings(Collection $settings) @@ -119,6 +112,7 @@ public function addSettings(Collection $settings) $this->settings->add($setting); } } + return $this; } } diff --git a/src/Entity/Tag.php b/src/Entity/Tag.php index e8503dea..9a3bd3a2 100644 --- a/src/Entity/Tag.php +++ b/src/Entity/Tag.php @@ -28,22 +28,22 @@ #[ ORM\Entity(repositoryClass: TagRepository::class), ORM\HasLifecycleCallbacks, - ORM\Table(name: "tags"), - ORM\Index(columns: ["visible"]), - ORM\Index(columns: ["locked"]), - ORM\Index(columns: ["position"]), - ORM\Index(columns: ["created_at"]), - ORM\Index(columns: ["updated_at"]), - ORM\Index(columns: ["parent_tag_id", "position"], name: "tag_parent_position"), - ORM\Index(columns: ["visible", "position"], name: "tag_visible_position"), - ORM\Index(columns: ["parent_tag_id", "visible"], name: "tag_parent_visible"), - ORM\Index(columns: ["parent_tag_id", "visible", "position"], name: "tag_parent_visible_position"), - UniqueEntity(fields: ["tagName"]), + ORM\Table(name: 'tags'), + ORM\Index(columns: ['visible']), + ORM\Index(columns: ['locked']), + ORM\Index(columns: ['position']), + ORM\Index(columns: ['created_at']), + ORM\Index(columns: ['updated_at']), + ORM\Index(columns: ['parent_tag_id', 'position'], name: 'tag_parent_position'), + ORM\Index(columns: ['visible', 'position'], name: 'tag_visible_position'), + ORM\Index(columns: ['parent_tag_id', 'visible'], name: 'tag_parent_visible'), + ORM\Index(columns: ['parent_tag_id', 'visible', 'position'], name: 'tag_parent_visible_position'), + UniqueEntity(fields: ['tagName']), ApiFilter(PropertyFilter::class), ApiFilter(BaseFilter\OrderFilter::class, properties: [ - "position", - "createdAt", - "updatedAt" + 'position', + 'createdAt', + 'updatedAt', ]) ] class Tag extends AbstractDateTimedPositioned implements LeafInterface @@ -71,12 +71,12 @@ class Tag extends AbstractDateTimedPositioned implements LeafInterface * @var Tag|null */ #[ApiFilter(BaseFilter\SearchFilter::class, properties: [ - "parent.id" => "exact", - "parent.tagName" => "exact" + 'parent.id' => 'exact', + 'parent.tagName' => 'exact', ])] #[ApiFilter(NotFilter::class, properties: [ - "parent.id", - "parent.tagName" + 'parent.id', + 'parent.tagName', ])] #[ORM\ManyToOne(targetEntity: Tag::class, fetch: 'EXTRA_LAZY', inversedBy: 'children')] #[ORM\JoinColumn(name: 'parent_tag_id', referencedColumnName: 'id', onDelete: 'CASCADE')] @@ -97,7 +97,7 @@ class Tag extends AbstractDateTimedPositioned implements LeafInterface #[ORM\OrderBy(['position' => 'ASC'])] #[SymfonySerializer\Groups(['tag_children'])] #[Serializer\Groups(['tag_children'])] - #[Serializer\AccessType(type: "public_method")] + #[Serializer\AccessType(type: 'public_method')] protected Collection $children; /** @@ -113,11 +113,11 @@ class Tag extends AbstractDateTimedPositioned implements LeafInterface #[Serializer\Groups(['translated_tag'])] protected Collection $translatedTags; - #[ApiFilter(BaseFilter\SearchFilter::class, strategy: "partial")] + #[ApiFilter(BaseFilter\SearchFilter::class, strategy: 'partial')] #[ORM\Column(name: 'tag_name', type: 'string', length: 250, unique: true)] #[SymfonySerializer\Ignore] #[Serializer\Groups(['tag'])] - #[Serializer\Accessor(getter: "getTagName", setter: "setTagName")] + #[Serializer\Accessor(getter: 'getTagName', setter: 'setTagName')] #[Assert\NotNull] #[Assert\NotBlank] #[Assert\Length(max: 250)] @@ -143,7 +143,7 @@ class Tag extends AbstractDateTimedPositioned implements LeafInterface #[ORM\Column(name: 'children_order', type: 'string', length: 60, options: ['default' => 'position'])] #[SymfonySerializer\Ignore] - #[Serializer\Groups(["tag", "tag_children_order"])] + #[Serializer\Groups(['tag', 'tag_children_order'])] #[Assert\Length(max: 60)] #[ApiProperty( description: 'This tag children will be sorted by a given field', @@ -151,14 +151,14 @@ class Tag extends AbstractDateTimedPositioned implements LeafInterface schema: [ 'type' => 'string', 'enum' => ['position', 'tagName', 'createdAt', 'updatedAt', 'publishedAt'], - 'example' => 'position' + 'example' => 'position', ], )] private string $childrenOrder = 'position'; #[ORM\Column(name: 'children_order_direction', type: 'string', length: 4, options: ['default' => 'ASC'])] #[SymfonySerializer\Ignore] - #[Serializer\Groups(["tag", "tag_children_order"])] + #[Serializer\Groups(['tag', 'tag_children_order'])] #[Assert\Length(max: 4)] #[ApiProperty( description: 'This tag children will be sorted ascendant or descendant', @@ -166,7 +166,7 @@ class Tag extends AbstractDateTimedPositioned implements LeafInterface schema: [ 'type' => 'string', 'enum' => ['ASC', 'DESC'], - 'example' => 'ASC' + 'example' => 'ASC', ], )] private string $childrenOrderDirection = 'ASC'; @@ -174,7 +174,7 @@ class Tag extends AbstractDateTimedPositioned implements LeafInterface #[ApiFilter(BaseFilter\BooleanFilter::class)] #[ORM\Column(type: 'boolean', nullable: false, options: ['default' => false])] #[SymfonySerializer\Ignore] - #[Serializer\Groups(["tag"])] + #[Serializer\Groups(['tag'])] #[ApiProperty( description: 'Is this tag locked to prevent deletion and renaming?', example: 'false', @@ -194,18 +194,18 @@ class Tag extends AbstractDateTimedPositioned implements LeafInterface #[SymfonySerializer\Ignore] #[Serializer\Exclude] #[ApiFilter(BaseFilter\SearchFilter::class, properties: [ - "nodesTags.node" => "exact", - "nodesTags.node.nodeName" => "exact", - "nodesTags.node.parent" => "exact", - "nodesTags.node.parent.nodeName" => "exact", - "nodesTags.node.nodeType" => "exact", - "nodesTags.node.nodeType.name" => "exact", - "nodesTags.node.nodesTags.tag" => "exact", - "nodesTags.node.nodesTags.tag.tagName" => "exact", + 'nodesTags.node' => 'exact', + 'nodesTags.node.nodeName' => 'exact', + 'nodesTags.node.parent' => 'exact', + 'nodesTags.node.parent.nodeName' => 'exact', + 'nodesTags.node.nodeType' => 'exact', + 'nodesTags.node.nodeType.name' => 'exact', + 'nodesTags.node.nodesTags.tag' => 'exact', + 'nodesTags.node.nodesTags.tag.tagName' => 'exact', ])] #[ApiFilter(BaseFilter\BooleanFilter::class, properties: [ - "nodesTags.node.visible", - "nodesTags.node.nodeType.reachable", + 'nodesTags.node.visible', + 'nodesTags.node.nodeType.reachable', ])] private Collection $nodesTags; @@ -222,25 +222,18 @@ public function __construct() /** * Gets the value of dirtyTagName. - * - * @return string */ public function getDirtyTagName(): string { return $this->dirtyTagName; } - /** - * @return boolean - */ public function isLocked(): bool { return $this->locked; } /** - * @param boolean $locked - * * @return $this */ public function setLocked(bool $locked): static @@ -262,8 +255,6 @@ public function getNodes(): Collection /** * Get tag full path using tag names. - * - * @return string */ public function getFullPath(): string { @@ -281,17 +272,12 @@ public function getFullPath(): string return implode('/', $path); } - /** - * @return string - */ public function getTagName(): string { return $this->tagName; } /** - * @param string $tagName - * * @return $this */ public function setTagName(string $tagName): static @@ -303,7 +289,6 @@ public function setTagName(string $tagName): static } /** - * @param TranslationInterface $translation * @return Collection */ #[SymfonySerializer\Ignore] @@ -322,38 +307,29 @@ public function getTranslatedTagsByDefaultTranslation(): ?TagTranslation }); } - /** - * @return string - */ public function getOneLineSummary(): string { - return $this->getId() . " — " . $this->getTagName() . - " — Visible : " . ($this->isVisible() ? 'true' : 'false') . PHP_EOL; + return $this->getId().' — '.$this->getTagName(). + ' — Visible : '.($this->isVisible() ? 'true' : 'false').PHP_EOL; } - /** - * @return boolean - */ public function isVisible(): bool { return $this->visible; } /** - * @param boolean $visible - * * @return $this */ public function setVisible(bool $visible): static { $this->visible = $visible; + return $this; } /** * Gets the value of color. - * - * @return string */ public function getColor(): string { @@ -364,8 +340,6 @@ public function getColor(): string * Sets the value of color. * * @param string|null $color the color - * - * @return static */ public function setColor(?string $color): static { @@ -376,8 +350,6 @@ public function setColor(?string $color): static /** * Gets the value of childrenOrder. - * - * @return string */ public function getChildrenOrder(): string { @@ -388,8 +360,6 @@ public function getChildrenOrder(): string * Sets the value of childrenOrder. * * @param string $childrenOrder the children order - * - * @return static */ public function setChildrenOrder(string $childrenOrder): static { @@ -400,8 +370,6 @@ public function setChildrenOrder(string $childrenOrder): static /** * Gets the value of childrenOrderDirection. - * - * @return string */ public function getChildrenOrderDirection(): string { @@ -412,8 +380,6 @@ public function getChildrenOrderDirection(): string * Sets the value of childrenOrderDirection. * * @param string $childrenOrderDirection the children order direction - * - * @return static */ public function setChildrenOrderDirection(string $childrenOrderDirection): static { @@ -422,22 +388,15 @@ public function setChildrenOrderDirection(string $childrenOrderDirection): stati return $this; } - /** - * @return string - */ public function __toString(): string { return (string) $this->getId(); } - /** - * @return string|null - * - * @Serializer\Groups({"tag", "tag_base", "node", "nodes_sources"}) - * @Serializer\VirtualProperty - * @Serializer\Type("string|null") - */ #[SymfonySerializer\Ignore] + #[Serializer\Groups(['tag', 'tag_base', 'node', 'nodes_sources'])] + #[Serializer\VirtualProperty] + #[Serializer\Type('string|null')] public function getName(): ?string { return $this->getTranslatedTags()->first() ? @@ -455,6 +414,7 @@ public function getTranslatedTags(): Collection /** * @param Collection $translatedTags + * * @return $this */ public function setTranslatedTags(Collection $translatedTags): static @@ -464,17 +424,14 @@ public function setTranslatedTags(Collection $translatedTags): static foreach ($this->translatedTags as $translatedTag) { $translatedTag->setTag($this); } + return $this; } - /** - * @return string|null - * - * @Serializer\Groups({"tag", "node", "nodes_sources"}) - * @Serializer\VirtualProperty - * @Serializer\Type("string|null") - */ #[SymfonySerializer\Ignore] + #[Serializer\VirtualProperty] + #[Serializer\Groups(['tag', 'node', 'nodes_sources'])] + #[Serializer\Type('string|null')] public function getDescription(): ?string { return $this->getTranslatedTags()->first() ? @@ -482,14 +439,10 @@ public function getDescription(): ?string ''; } - /** - * @return array - * - * @Serializer\Groups({"tag", "node", "nodes_sources"}) - * @Serializer\VirtualProperty - * @Serializer\Type("array") - */ #[SymfonySerializer\Ignore] + #[Serializer\VirtualProperty] + #[Serializer\Groups(['tag', 'node', 'nodes_sources'])] + #[Serializer\Type('array')] public function getDocuments(): array { return $this->getTranslatedTags()->first() ? @@ -511,7 +464,6 @@ public function setParent(?LeafInterface $parent = null): static return $this; } - #[ApiProperty( description: 'Unique tag name (slug) used to build content URL or filter queries.', example: 'this-is-a-tag-name', diff --git a/src/Entity/TagTranslation.php b/src/Entity/TagTranslation.php index 36017fe1..bb1d5125 100644 --- a/src/Entity/TagTranslation.php +++ b/src/Entity/TagTranslation.php @@ -23,10 +23,10 @@ */ #[ ORM\Entity(repositoryClass: TagTranslationRepository::class), - ORM\Table(name: "tags_translations"), - ORM\UniqueConstraint(columns: ["tag_id", "translation_id"]), + ORM\Table(name: 'tags_translations'), + ORM\UniqueConstraint(columns: ['tag_id', 'translation_id']), Gedmo\Loggable(logEntryClass: UserLogEntry::class), - UniqueEntity(fields: ["tag", "translation"]) + UniqueEntity(fields: ['tag', 'translation']) ] class TagTranslation extends AbstractEntity { @@ -58,7 +58,6 @@ class TagTranslation extends AbstractEntity /** * @var Collection - * @Serializer\Exclude */ #[ORM\OneToMany( mappedBy: 'tagTranslation', @@ -68,20 +67,18 @@ class TagTranslation extends AbstractEntity )] #[ORM\OrderBy(['position' => 'ASC'])] #[SymfonySerializer\Ignore] + #[Serializer\Exclude] protected Collection $tagTranslationDocuments; /** * Create a new TagTranslation with its origin Tag and Translation. - * - * @param Tag $original - * @param TranslationInterface $translation */ public function __construct(Tag $original, TranslationInterface $translation) { $this->setTag($original); $this->setTranslation($translation); $this->tagTranslationDocuments = new ArrayCollection(); - $this->name = $original->getDirtyTagName() != '' ? $original->getDirtyTagName() : $original->getTagName(); + $this->name = '' != $original->getDirtyTagName() ? $original->getDirtyTagName() : $original->getTagName(); } public function getName(): string @@ -116,6 +113,7 @@ public function getTag(): Tag public function setTag(Tag $tag): TagTranslation { $this->tag = $tag; + return $this; } @@ -152,14 +150,10 @@ public function __clone() } } - /** - * @return array - * - * @Serializer\Groups({"tag"}) - * @Serializer\VirtualProperty - * @Serializer\Type("array") - */ #[SymfonySerializer\Groups(['tag'])] + #[Serializer\Groups(['tag'])] + #[Serializer\VirtualProperty] + #[Serializer\Type('array')] public function getDocuments(): array { return array_map(function (TagTranslationDocuments $tagTranslationDocument) { @@ -167,21 +161,15 @@ public function getDocuments(): array }, $this->getTagTranslationDocuments()->toArray()); } - /** - * @return Collection - */ public function getTagTranslationDocuments(): Collection { return $this->tagTranslationDocuments; } - /** - * @param Collection $tagTranslationDocuments - * @return TagTranslation - */ public function setTagTranslationDocuments(Collection $tagTranslationDocuments): TagTranslation { $this->tagTranslationDocuments = $tagTranslationDocuments; + return $this; } } diff --git a/src/Entity/TagTranslationDocuments.php b/src/Entity/TagTranslationDocuments.php index d06683da..cb350fb9 100644 --- a/src/Entity/TagTranslationDocuments.php +++ b/src/Entity/TagTranslationDocuments.php @@ -5,8 +5,8 @@ namespace RZ\Roadiz\CoreBundle\Entity; use Doctrine\ORM\Mapping as ORM; -use RZ\Roadiz\Core\AbstractEntities\AbstractPositioned; use JMS\Serializer\Annotation as Serializer; +use RZ\Roadiz\Core\AbstractEntities\AbstractPositioned; use RZ\Roadiz\CoreBundle\Repository\TagTranslationDocumentsRepository; use Symfony\Component\Serializer\Annotation as SymfonySerializer; @@ -16,9 +16,9 @@ */ #[ ORM\Entity(repositoryClass: TagTranslationDocumentsRepository::class), - ORM\Table(name: "tags_translations_documents"), - ORM\Index(columns: ["position"]), - ORM\Index(columns: ["tag_translation_id", "position"], name: "tagtranslation_position") + ORM\Table(name: 'tags_translations_documents'), + ORM\Index(columns: ['position']), + ORM\Index(columns: ['tag_translation_id', 'position'], name: 'tagtranslation_position') ] class TagTranslationDocuments extends AbstractPositioned { @@ -46,9 +46,6 @@ class TagTranslationDocuments extends AbstractPositioned /** * Create a new relation between NodeSource, a Document and a NodeTypeField. - * - * @param TagTranslation $tagTranslation - * @param Document $document */ public function __construct(TagTranslation $tagTranslation, Document $document) { @@ -71,6 +68,7 @@ public function getDocument(): Document public function setDocument(Document $document): TagTranslationDocuments { $this->document = $document; + return $this; } @@ -82,6 +80,7 @@ public function getTagTranslation(): TagTranslation public function setTagTranslation(TagTranslation $tagTranslation): TagTranslationDocuments { $this->tagTranslation = $tagTranslation; + return $this; } } diff --git a/src/Entity/Theme.php b/src/Entity/Theme.php index 57d5afd6..69234999 100644 --- a/src/Entity/Theme.php +++ b/src/Entity/Theme.php @@ -22,30 +22,24 @@ class Theme extends AbstractEntity private string $routePrefix = ''; private bool $backendTheme = false; - /** - * @return boolean - */ public function isAvailable(): bool { return $this->available; } /** - * @param boolean $available - * * @return $this */ public function setAvailable(bool $available): Theme { $this->available = $available; + return $this; } /** * Static means that your theme is not suitable for responding from * nodes urls but only static routes. - * - * @return boolean */ public function isStaticTheme(): bool { @@ -53,19 +47,17 @@ public function isStaticTheme(): bool } /** - * @param boolean $staticTheme * @return $this */ public function setStaticTheme(bool $staticTheme): Theme { $this->staticTheme = (bool) $staticTheme; + return $this; } /** * Alias for getInformations. - * - * @return array */ public function getInformation(): array { @@ -79,8 +71,6 @@ public function getInformation(): array * - author * - copyright * - dir - * - * @return array */ public function getInformations(): array { @@ -91,6 +81,7 @@ public function getInformations(): array $authorCallable = [$class, 'getThemeAuthor']; $copyrightCallable = [$class, 'getThemeCopyright']; $dirCallable = [$class, 'getThemeDir']; + return [ 'name' => \is_callable($nameCallable) ? call_user_func($nameCallable) : null, 'author' => \is_callable($authorCallable) ? call_user_func($authorCallable) : null, @@ -112,67 +103,58 @@ public function getClassName(): string /** * @param class-string $className + * * @return $this */ public function setClassName(string $className): Theme { $this->className = $className; + return $this; } - /** - * @return string - */ public function getHostname(): string { return $this->hostname; } /** - * @param string $hostname - * * @return $this */ public function setHostname(string $hostname): Theme { $this->hostname = $hostname; + return $this; } - /** - * @return string - */ public function getRoutePrefix(): string { return $this->routePrefix; } /** - * @param string $routePrefix - * * @return $this */ public function setRoutePrefix(string $routePrefix): Theme { $this->routePrefix = $routePrefix; + return $this; } - /** - * @return boolean - */ public function isBackendTheme(): bool { return $this->backendTheme; } /** - * @param boolean $backendTheme * @return $this */ public function setBackendTheme(bool $backendTheme): Theme { $this->backendTheme = $backendTheme; + return $this; } } diff --git a/src/Entity/Translation.php b/src/Entity/Translation.php index 549360e8..d83812dc 100644 --- a/src/Entity/Translation.php +++ b/src/Entity/Translation.php @@ -4,10 +4,10 @@ namespace RZ\Roadiz\CoreBundle\Entity; +use ApiPlatform\Doctrine\Orm\Filter as BaseFilter; +use ApiPlatform\Metadata\ApiFilter; use ApiPlatform\Metadata\ApiProperty; use ApiPlatform\Serializer\Filter\PropertyFilter; -use ApiPlatform\Metadata\ApiFilter; -use ApiPlatform\Doctrine\Orm\Filter as BaseFilter; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; @@ -26,32 +26,32 @@ */ #[ ORM\Entity(repositoryClass: TranslationRepository::class), - ORM\Table(name: "translations"), - ORM\Index(columns: ["available"]), - ORM\Index(columns: ["default_translation"]), - ORM\Index(columns: ["created_at"]), - ORM\Index(columns: ["updated_at"]), - ORM\Index(columns: ["available", "default_translation"]), - ORM\Index(columns: ["available", "locale"]), - ORM\Index(columns: ["available", "override_locale"]), - UniqueEntity(fields: ["name"]), - UniqueEntity(fields: ["locale"]), - UniqueEntity(fields: ["overrideLocale"]), + ORM\Table(name: 'translations'), + ORM\Index(columns: ['available']), + ORM\Index(columns: ['default_translation']), + ORM\Index(columns: ['created_at']), + ORM\Index(columns: ['updated_at']), + ORM\Index(columns: ['available', 'default_translation']), + ORM\Index(columns: ['available', 'locale']), + ORM\Index(columns: ['available', 'override_locale']), + UniqueEntity(fields: ['name']), + UniqueEntity(fields: ['locale']), + UniqueEntity(fields: ['overrideLocale']), ApiFilter(PropertyFilter::class), ApiFilter(BaseFilter\OrderFilter::class, properties: [ - "createdAt", - "updatedAt", - "locale", - "available", - "defaultTranslation" + 'createdAt', + 'updatedAt', + 'locale', + 'available', + 'defaultTranslation', ]), ApiFilter(BaseFilter\BooleanFilter::class, properties: [ - "available", - "defaultTranslation" + 'available', + 'defaultTranslation', ]), ApiFilter(BaseFilter\SearchFilter::class, properties: [ - "locale" => "exact", - "name" => "exact" + 'locale' => 'exact', + 'name' => 'exact', ]) ] class Translation extends AbstractDateTimed implements TranslationInterface @@ -62,470 +62,470 @@ class Translation extends AbstractDateTimed implements TranslationInterface #[SymfonySerializer\Ignore] #[Serializer\Exclude] public static array $availableLocales = [ - 'af_NA' => "Afrikaans (Namibia)", - 'af_ZA' => "Afrikaans (South Africa)", - 'af' => "Afrikaans", - 'ak_GH' => "Akan (Ghana)", - 'ak' => "Akan", - 'sq_AL' => "Albanian (Albania)", - 'sq' => "Albanian", - 'am_ET' => "Amharic (Ethiopia)", - 'am' => "Amharic", - 'ar_DZ' => "Arabic (Algeria)", - 'ar_BH' => "Arabic (Bahrain)", - 'ar_EG' => "Arabic (Egypt)", - 'ar_IQ' => "Arabic (Iraq)", - 'ar_JO' => "Arabic (Jordan)", - 'ar_KW' => "Arabic (Kuwait)", - 'ar_LB' => "Arabic (Lebanon)", - 'ar_LY' => "Arabic (Libya)", - 'ar_MA' => "Arabic (Morocco)", - 'ar_OM' => "Arabic (Oman)", - 'ar_QA' => "Arabic (Qatar)", - 'ar_SA' => "Arabic (Saudi Arabia)", - 'ar_SD' => "Arabic (Sudan)", - 'ar_SY' => "Arabic (Syria)", - 'ar_TN' => "Arabic (Tunisia)", - 'ar_AE' => "Arabic (United Arab Emirates)", - 'ar_YE' => "Arabic (Yemen)", - 'ar' => "Arabic", - 'hy_AM' => "Armenian (Armenia)", - 'hy' => "Armenian", - 'as_IN' => "Assamese (India)", - 'as' => "Assamese", - 'asa_TZ' => "Asu (Tanzania)", - 'asa' => "Asu", - 'az_Cyrl' => "Azerbaijani (Cyrillic)", - 'az_Cyrl_AZ' => "Azerbaijani (Cyrillic, Azerbaijan)", - 'az_Latn' => "Azerbaijani (Latin)", - 'az_Latn_AZ' => "Azerbaijani (Latin, Azerbaijan)", - 'az' => "Azerbaijani", - 'bm_ML' => "Bambara (Mali)", - 'bm' => "Bambara", - 'eu_ES' => "Basque (Spain)", - 'eu' => "Basque", - 'be_BY' => "Belarusian (Belarus)", - 'be' => "Belarusian", - 'bem_ZM' => "Bemba (Zambia)", - 'bem' => "Bemba", - 'bez_TZ' => "Bena (Tanzania)", - 'bez' => "Bena", - 'bn_BD' => "Bengali (Bangladesh)", - 'bn_IN' => "Bengali (India)", - 'bn' => "Bengali", - 'bs_BA' => "Bosnian (Bosnia and Herzegovina)", - 'bs' => "Bosnian", - 'bg_BG' => "Bulgarian (Bulgaria)", - 'bg' => "Bulgarian", - 'my_MM' => "Burmese (Myanmar [Burma])", - 'my' => "Burmese", - 'ca_ES' => "Catalan (Spain)", - 'ca' => "Catalan", - 'tzm_Latn' => "Central Morocco Tamazight (Latin)", - 'tzm_Latn_MA' => "Central Morocco Tamazight (Latin, Morocco)", - 'tzm' => "Central Morocco Tamazight", - 'chr_US' => "Cherokee (United States)", - 'chr' => "Cherokee", - 'cgg_UG' => "Chiga (Uganda)", - 'cgg' => "Chiga", - 'zh_Hans' => "Chinese (Simplified Han)", - 'zh_Hans_CN' => "Chinese (Simplified Han, China)", - 'zh_Hans_HK' => "Chinese (Simplified Han, Hong Kong SAR China)", - 'zh_Hans_MO' => "Chinese (Simplified Han, Macau SAR China)", - 'zh_Hans_SG' => "Chinese (Simplified Han, Singapore)", - 'zh_Hant' => "Chinese (Traditional Han)", - 'zh_Hant_HK' => "Chinese (Traditional Han, Hong Kong SAR China)", - 'zh_Hant_MO' => "Chinese (Traditional Han, Macau SAR China)", - 'zh_Hant_TW' => "Chinese (Traditional Han, Taiwan)", - 'zh' => "Chinese", - 'kw_GB' => "Cornish (United Kingdom)", - 'kw' => "Cornish", - 'hr_HR' => "Croatian (Croatia)", - 'hr' => "Croatian", - 'cs_CZ' => "Czech (Czech Republic)", - 'cs' => "Czech", - 'da_DK' => "Danish (Denmark)", - 'da' => "Danish", - 'nl_BE' => "Dutch (Belgium)", - 'nl_NL' => "Dutch (Netherlands)", - 'nl' => "Dutch", - 'ebu_KE' => "Embu (Kenya)", - 'ebu' => "Embu", - 'en_AS' => "English (American Samoa)", - 'en_AU' => "English (Australia)", - 'en_BE' => "English (Belgium)", - 'en_BZ' => "English (Belize)", - 'en_BW' => "English (Botswana)", - 'en_CA' => "English (Canada)", - 'en_GU' => "English (Guam)", - 'en_HK' => "English (Hong Kong SAR China)", - 'en_IN' => "English (India)", - 'en_IE' => "English (Ireland)", - 'en_JM' => "English (Jamaica)", - 'en_MT' => "English (Malta)", - 'en_MH' => "English (Marshall Islands)", - 'en_MU' => "English (Mauritius)", - 'en_NA' => "English (Namibia)", - 'en_NZ' => "English (New Zealand)", - 'en_MP' => "English (Northern Mariana Islands)", - 'en_PK' => "English (Pakistan)", - 'en_PH' => "English (Philippines)", - 'en_SG' => "English (Singapore)", - 'en_ZA' => "English (South Africa)", - 'en_TT' => "English (Trinidad and Tobago)", - 'en_UM' => "English (U.S. Minor Outlying Islands)", - 'en_VI' => "English (U.S. Virgin Islands)", - 'en_GB' => "English (United Kingdom)", - 'en_US' => "English (United States)", - 'en_ZW' => "English (Zimbabwe)", - 'en' => "English", - 'eo' => "Esperanto", - 'et_EE' => "Estonian (Estonia)", - 'et' => "Estonian", - 'ee_GH' => "Ewe (Ghana)", - 'ee_TG' => "Ewe (Togo)", - 'ee' => "Ewe", - 'fo_FO' => "Faroese (Faroe Islands)", - 'fo' => "Faroese", - 'fil_PH' => "Filipino (Philippines)", - 'fil' => "Filipino", - 'fi_FI' => "Finnish (Finland)", - 'fi' => "Finnish", - 'fr_BE' => "French (Belgium)", - 'fr_BJ' => "French (Benin)", - 'fr_BF' => "French (Burkina Faso)", - 'fr_BI' => "French (Burundi)", - 'fr_CM' => "French (Cameroon)", - 'fr_CA' => "French (Canada)", - 'fr_CF' => "French (Central African Republic)", - 'fr_TD' => "French (Chad)", - 'fr_KM' => "French (Comoros)", - 'fr_CG' => "French (Congo - Brazzaville)", - 'fr_CD' => "French (Congo - Kinshasa)", - 'fr_CI' => "French (Côte d’Ivoire)", - 'fr_DJ' => "French (Djibouti)", - 'fr_GQ' => "French (Equatorial Guinea)", - 'fr_FR' => "French (France)", - 'fr_GA' => "French (Gabon)", - 'fr_GP' => "French (Guadeloupe)", - 'fr_GN' => "French (Guinea)", - 'fr_LU' => "French (Luxembourg)", - 'fr_MG' => "French (Madagascar)", - 'fr_ML' => "French (Mali)", - 'fr_MQ' => "French (Martinique)", - 'fr_MC' => "French (Monaco)", - 'fr_NE' => "French (Niger)", - 'fr_RW' => "French (Rwanda)", - 'fr_RE' => "French (Réunion)", - 'fr_BL' => "French (Saint Barthélemy)", - 'fr_MF' => "French (Saint Martin)", - 'fr_SN' => "French (Senegal)", - 'fr_CH' => "French (Switzerland)", - 'fr_TG' => "French (Togo)", - 'fr' => "French", - 'ff_SN' => "Fulah (Senegal)", - 'ff' => "Fulah", - 'gl_ES' => "Galician (Spain)", - 'gl' => "Galician", - 'lg_UG' => "Ganda (Uganda)", - 'lg' => "Ganda", - 'ka_GE' => "Georgian (Georgia)", - 'ka' => "Georgian", - 'de_AT' => "German (Austria)", - 'de_BE' => "German (Belgium)", - 'de_DE' => "German (Germany)", - 'de_LI' => "German (Liechtenstein)", - 'de_LU' => "German (Luxembourg)", - 'de_CH' => "German (Switzerland)", - 'de' => "German", - 'el_CY' => "Greek (Cyprus)", - 'el_GR' => "Greek (Greece)", - 'el' => "Greek", - 'gu_IN' => "Gujarati (India)", - 'gu' => "Gujarati", - 'guz_KE' => "Gusii (Kenya)", - 'guz' => "Gusii", - 'ha_Latn' => "Hausa (Latin)", - 'ha_Latn_GH' => "Hausa (Latin, Ghana)", - 'ha_Latn_NE' => "Hausa (Latin, Niger)", - 'ha_Latn_NG' => "Hausa (Latin, Nigeria)", - 'ha' => "Hausa", - 'haw_US' => "Hawaiian (United States)", - 'haw' => "Hawaiian", - 'he_IL' => "Hebrew (Israel)", - 'he' => "Hebrew", - 'hi_IN' => "Hindi (India)", - 'hi' => "Hindi", - 'hu_HU' => "Hungarian (Hungary)", - 'hu' => "Hungarian", - 'is_IS' => "Icelandic (Iceland)", - 'is' => "Icelandic", - 'ig_NG' => "Igbo (Nigeria)", - 'ig' => "Igbo", - 'id_ID' => "Indonesian (Indonesia)", - 'id' => "Indonesian", - 'ga_IE' => "Irish (Ireland)", - 'ga' => "Irish", - 'it_IT' => "Italian (Italy)", - 'it_CH' => "Italian (Switzerland)", - 'it' => "Italian", - 'ja_JP' => "Japanese (Japan)", - 'ja' => "Japanese", - 'kea_CV' => "Kabuverdianu (Cape Verde)", - 'kea' => "Kabuverdianu", - 'kab_DZ' => "Kabyle (Algeria)", - 'kab' => "Kabyle", - 'kl_GL' => "Kalaallisut (Greenland)", - 'kl' => "Kalaallisut", - 'kln_KE' => "Kalenjin (Kenya)", - 'kln' => "Kalenjin", - 'kam_KE' => "Kamba (Kenya)", - 'kam' => "Kamba", - 'kn_IN' => "Kannada (India)", - 'kn' => "Kannada", - 'kk_Cyrl' => "Kazakh (Cyrillic)", - 'kk_Cyrl_KZ' => "Kazakh (Cyrillic, Kazakhstan)", - 'kk' => "Kazakh", - 'km_KH' => "Khmer (Cambodia)", - 'km' => "Khmer", - 'ki_KE' => "Kikuyu (Kenya)", - 'ki' => "Kikuyu", - 'rw_RW' => "Kinyarwanda (Rwanda)", - 'rw' => "Kinyarwanda", - 'kok_IN' => "Konkani (India)", - 'kok' => "Konkani", - 'ko_KR' => "Korean (South Korea)", - 'ko' => "Korean", - 'khq_ML' => "Koyra Chiini (Mali)", - 'khq' => "Koyra Chiini", - 'ses_ML' => "Koyraboro Senni (Mali)", - 'ses' => "Koyraboro Senni", - 'lag_TZ' => "Langi (Tanzania)", - 'lag' => "Langi", - 'lv_LV' => "Latvian (Latvia)", - 'lv' => "Latvian", - 'lt_LT' => "Lithuanian (Lithuania)", - 'lt' => "Lithuanian", - 'luo_KE' => "Luo (Kenya)", - 'luo' => "Luo", - 'luy_KE' => "Luyia (Kenya)", - 'luy' => "Luyia", - 'mk_MK' => "Macedonian (Macedonia)", - 'mk' => "Macedonian", - 'jmc_TZ' => "Machame (Tanzania)", - 'jmc' => "Machame", - 'kde_TZ' => "Makonde (Tanzania)", - 'kde' => "Makonde", - 'mg_MG' => "Malagasy (Madagascar)", - 'mg' => "Malagasy", - 'ms_BN' => "Malay (Brunei)", - 'ms_MY' => "Malay (Malaysia)", - 'ms' => "Malay", - 'ml_IN' => "Malayalam (India)", - 'ml' => "Malayalam", - 'mt_MT' => "Maltese (Malta)", - 'mt' => "Maltese", - 'gv_GB' => "Manx (United Kingdom)", - 'gv' => "Manx", - 'mr_IN' => "Marathi (India)", - 'mr' => "Marathi", - 'mas_KE' => "Masai (Kenya)", - 'mas_TZ' => "Masai (Tanzania)", - 'mas' => "Masai", - 'mer_KE' => "Meru (Kenya)", - 'mer' => "Meru", - 'mfe_MU' => "Morisyen (Mauritius)", - 'mfe' => "Morisyen", - 'naq_NA' => "Nama (Namibia)", - 'naq' => "Nama", - 'ne_IN' => "Nepali (India)", - 'ne_NP' => "Nepali (Nepal)", - 'ne' => "Nepali", - 'nd_ZW' => "North Ndebele (Zimbabwe)", - 'nd' => "North Ndebele", - 'nb_NO' => "Norwegian Bokmål (Norway)", - 'nb' => "Norwegian Bokmål", - 'nn_NO' => "Norwegian Nynorsk (Norway)", - 'nn' => "Norwegian Nynorsk", - 'nyn_UG' => "Nyankole (Uganda)", - 'nyn' => "Nyankole", - 'or_IN' => "Oriya (India)", - 'or' => "Oriya", - 'om_ET' => "Oromo (Ethiopia)", - 'm_KE' => "Oromo (Kenya)", - 'om' => "Oromo", - 'ps_AF' => "Pashto (Afghanistan)", - 'ps' => "Pashto", - 'fa_AF' => "Persian (Afghanistan)", - 'fa_IR' => "Persian (Iran)", - 'fa' => "Persian", - 'pl_PL' => "Polish (Poland)", - 'pl' => "Polish", - 'pt_BR' => "Portuguese (Brazil)", - 'pt_GW' => "Portuguese (Guinea-Bissau)", - 'pt_MZ' => "Portuguese (Mozambique)", - 'pt_PT' => "Portuguese (Portugal)", - 'pt' => "Portuguese", - 'pa_Arab' => "Punjabi (Arabic)", - 'pa_Arab_PK' => "Punjabi (Arabic, Pakistan)", - 'pa_Guru' => "Punjabi (Gurmukhi)", - 'pa_Guru_IN' => "Punjabi (Gurmukhi, India)", - 'pa' => "Punjabi", - 'ro_MD' => "Romanian (Moldova)", - 'ro_RO' => "Romanian (Romania)", - 'ro' => "Romanian", - 'rm_CH' => "Romansh (Switzerland)", - 'rm' => "Romansh", - 'rof_TZ' => "Rombo (Tanzania)", - 'rof' => "Rombo", - 'ru_MD' => "Russian (Moldova)", - 'ru_RU' => "Russian (Russia)", - 'ru_UA' => "Russian (Ukraine)", - 'ru' => "Russian", - 'rwk_TZ' => "Rwa (Tanzania)", - 'rwk' => "Rwa", - 'saq_KE' => "Samburu (Kenya)", - 'saq' => "Samburu", - 'sg_CF' => "Sango (Central African Republic)", - 'sg' => "Sango", - 'seh_MZ' => "Sena (Mozambique)", - 'seh' => "Sena", - 'sr_Cyrl' => "Serbian (Cyrillic)", - 'sr_Cyrl_BA' => "Serbian (Cyrillic, Bosnia and Herzegovina)", - 'sr_Cyrl_ME' => "Serbian (Cyrillic, Montenegro)", - 'sr_Cyrl_RS' => "Serbian (Cyrillic, Serbia)", - 'sr_Latn' => "Serbian (Latin)", - 'sr_Latn_BA' => "Serbian (Latin, Bosnia and Herzegovina)", - 'sr_Latn_ME' => "Serbian (Latin, Montenegro)", - 'sr_Latn_RS' => "Serbian (Latin, Serbia)", - 'sr' => "Serbian", - 'sn_ZW' => "Shona (Zimbabwe)", - 'sn' => "Shona", - 'ii_CN' => "Sichuan Yi (China)", - 'ii' => "Sichuan Yi", - 'si_LK' => "Sinhala (Sri Lanka)", - 'si' => "Sinhala", - 'sk_SK' => "Slovak (Slovakia)", - 'sk' => "Slovak", - 'sl_SI' => "Slovenian (Slovenia)", - 'sl' => "Slovenian", - 'xog_UG' => "Soga (Uganda)", - 'xog' => "Soga", - 'so_DJ' => "Somali (Djibouti)", - 'so_ET' => "Somali (Ethiopia)", - 'so_KE' => "Somali (Kenya)", - 'so_SO' => "Somali (Somalia)", - 'so' => "Somali", - 'es_AR' => "Spanish (Argentina)", - 'es_BO' => "Spanish (Bolivia)", - 'es_CL' => "Spanish (Chile)", - 'es_CO' => "Spanish (Colombia)", - 'es_CR' => "Spanish (Costa Rica)", - 'es_DO' => "Spanish (Dominican Republic)", - 'es_EC' => "Spanish (Ecuador)", - 'es_SV' => "Spanish (El Salvador)", - 'es_GQ' => "Spanish (Equatorial Guinea)", - 'es_GT' => "Spanish (Guatemala)", - 'es_HN' => "Spanish (Honduras)", - 'es_419' => "Spanish (Latin America)", - 'es_MX' => "Spanish (Mexico)", - 'es_NI' => "Spanish (Nicaragua)", - 'es_PA' => "Spanish (Panama)", - 'es_PY' => "Spanish (Paraguay)", - 'es_PE' => "Spanish (Peru)", - 'es_PR' => "Spanish (Puerto Rico)", - 'es_ES' => "Spanish (Spain)", - 'es_US' => "Spanish (United States)", - 'es_UY' => "Spanish (Uruguay)", - 'es_VE' => "Spanish (Venezuela)", - 'es' => "Spanish", - 'sw_KE' => "Swahili (Kenya)", - 'sw_TZ' => "Swahili (Tanzania)", - 'sw' => "Swahili", - 'sv_FI' => "Swedish (Finland)", - 'sv_SE' => "Swedish (Sweden)", - 'sv' => "Swedish", - 'gsw_CH' => "Swiss German (Switzerland)", - 'gsw' => "Swiss German", - 'shi_Latn' => "Tachelhit (Latin)", - 'shi_Latn_MA' => "Tachelhit (Latin, Morocco)", - 'shi_Tfng' => "Tachelhit (Tifinagh)", - 'shi_Tfng_MA' => "Tachelhit (Tifinagh, Morocco)", - 'shi' => "Tachelhit", - 'dav_KE' => "Taita (Kenya)", - 'dav' => "Taita", - 'ta_IN' => "Tamil (India)", - 'ta_LK' => "Tamil (Sri Lanka)", - 'ta' => "Tamil", - 'te_IN' => "Telugu (India)", - 'te' => "Telugu", - 'teo_KE' => "Teso (Kenya)", - 'teo_UG' => "Teso (Uganda)", - 'teo' => "Teso", - 'th_TH' => "Thai (Thailand)", - 'th' => "Thai", - 'bo_CN' => "Tibetan (China)", - 'bo_IN' => "Tibetan (India)", - 'bo' => "Tibetan", - 'ti_ER' => "Tigrinya (Eritrea)", - 'ti_ET' => "Tigrinya (Ethiopia)", - 'ti' => "Tigrinya", - 'to_TO' => "Tonga (Tonga)", - 'to' => "Tonga", - 'tr_TR' => "Turkish (Turkey)", - 'tr' => "Turkish", - 'uk_UA' => "Ukrainian (Ukraine)", - 'uk' => "Ukrainian", - 'ur_IN' => "Urdu (India)", - 'ur_PK' => "Urdu (Pakistan)", - 'ur' => "Urdu", - 'uz_Arab' => "Uzbek (Arabic)", - 'uz_Arab_AF' => "Uzbek (Arabic, Afghanistan)", - 'uz_Cyrl' => "Uzbek (Cyrillic)", - 'uz_Cyrl_UZ' => "Uzbek (Cyrillic, Uzbekistan)", - 'uz_Latn' => "Uzbek (Latin)", - 'uz_Latn_UZ' => "Uzbek (Latin, Uzbekistan)", - 'uz' => "Uzbek", - 'vi_VN' => "Vietnamese (Vietnam)", - 'vi' => "Vietnamese", - 'vun_TZ' => "Vunjo (Tanzania)", - 'vun' => "Vunjo", - 'cy_GB' => "Welsh (United Kingdom)", - 'cy' => "Welsh", - 'yo_NG' => "Yoruba (Nigeria)", - 'yo' => "Yoruba", - 'zu_ZA' => "Zulu (South Africa)", - 'zu' => "Zulu", + 'af_NA' => 'Afrikaans (Namibia)', + 'af_ZA' => 'Afrikaans (South Africa)', + 'af' => 'Afrikaans', + 'ak_GH' => 'Akan (Ghana)', + 'ak' => 'Akan', + 'sq_AL' => 'Albanian (Albania)', + 'sq' => 'Albanian', + 'am_ET' => 'Amharic (Ethiopia)', + 'am' => 'Amharic', + 'ar_DZ' => 'Arabic (Algeria)', + 'ar_BH' => 'Arabic (Bahrain)', + 'ar_EG' => 'Arabic (Egypt)', + 'ar_IQ' => 'Arabic (Iraq)', + 'ar_JO' => 'Arabic (Jordan)', + 'ar_KW' => 'Arabic (Kuwait)', + 'ar_LB' => 'Arabic (Lebanon)', + 'ar_LY' => 'Arabic (Libya)', + 'ar_MA' => 'Arabic (Morocco)', + 'ar_OM' => 'Arabic (Oman)', + 'ar_QA' => 'Arabic (Qatar)', + 'ar_SA' => 'Arabic (Saudi Arabia)', + 'ar_SD' => 'Arabic (Sudan)', + 'ar_SY' => 'Arabic (Syria)', + 'ar_TN' => 'Arabic (Tunisia)', + 'ar_AE' => 'Arabic (United Arab Emirates)', + 'ar_YE' => 'Arabic (Yemen)', + 'ar' => 'Arabic', + 'hy_AM' => 'Armenian (Armenia)', + 'hy' => 'Armenian', + 'as_IN' => 'Assamese (India)', + 'as' => 'Assamese', + 'asa_TZ' => 'Asu (Tanzania)', + 'asa' => 'Asu', + 'az_Cyrl' => 'Azerbaijani (Cyrillic)', + 'az_Cyrl_AZ' => 'Azerbaijani (Cyrillic, Azerbaijan)', + 'az_Latn' => 'Azerbaijani (Latin)', + 'az_Latn_AZ' => 'Azerbaijani (Latin, Azerbaijan)', + 'az' => 'Azerbaijani', + 'bm_ML' => 'Bambara (Mali)', + 'bm' => 'Bambara', + 'eu_ES' => 'Basque (Spain)', + 'eu' => 'Basque', + 'be_BY' => 'Belarusian (Belarus)', + 'be' => 'Belarusian', + 'bem_ZM' => 'Bemba (Zambia)', + 'bem' => 'Bemba', + 'bez_TZ' => 'Bena (Tanzania)', + 'bez' => 'Bena', + 'bn_BD' => 'Bengali (Bangladesh)', + 'bn_IN' => 'Bengali (India)', + 'bn' => 'Bengali', + 'bs_BA' => 'Bosnian (Bosnia and Herzegovina)', + 'bs' => 'Bosnian', + 'bg_BG' => 'Bulgarian (Bulgaria)', + 'bg' => 'Bulgarian', + 'my_MM' => 'Burmese (Myanmar [Burma])', + 'my' => 'Burmese', + 'ca_ES' => 'Catalan (Spain)', + 'ca' => 'Catalan', + 'tzm_Latn' => 'Central Morocco Tamazight (Latin)', + 'tzm_Latn_MA' => 'Central Morocco Tamazight (Latin, Morocco)', + 'tzm' => 'Central Morocco Tamazight', + 'chr_US' => 'Cherokee (United States)', + 'chr' => 'Cherokee', + 'cgg_UG' => 'Chiga (Uganda)', + 'cgg' => 'Chiga', + 'zh_Hans' => 'Chinese (Simplified Han)', + 'zh_Hans_CN' => 'Chinese (Simplified Han, China)', + 'zh_Hans_HK' => 'Chinese (Simplified Han, Hong Kong SAR China)', + 'zh_Hans_MO' => 'Chinese (Simplified Han, Macau SAR China)', + 'zh_Hans_SG' => 'Chinese (Simplified Han, Singapore)', + 'zh_Hant' => 'Chinese (Traditional Han)', + 'zh_Hant_HK' => 'Chinese (Traditional Han, Hong Kong SAR China)', + 'zh_Hant_MO' => 'Chinese (Traditional Han, Macau SAR China)', + 'zh_Hant_TW' => 'Chinese (Traditional Han, Taiwan)', + 'zh' => 'Chinese', + 'kw_GB' => 'Cornish (United Kingdom)', + 'kw' => 'Cornish', + 'hr_HR' => 'Croatian (Croatia)', + 'hr' => 'Croatian', + 'cs_CZ' => 'Czech (Czech Republic)', + 'cs' => 'Czech', + 'da_DK' => 'Danish (Denmark)', + 'da' => 'Danish', + 'nl_BE' => 'Dutch (Belgium)', + 'nl_NL' => 'Dutch (Netherlands)', + 'nl' => 'Dutch', + 'ebu_KE' => 'Embu (Kenya)', + 'ebu' => 'Embu', + 'en_AS' => 'English (American Samoa)', + 'en_AU' => 'English (Australia)', + 'en_BE' => 'English (Belgium)', + 'en_BZ' => 'English (Belize)', + 'en_BW' => 'English (Botswana)', + 'en_CA' => 'English (Canada)', + 'en_GU' => 'English (Guam)', + 'en_HK' => 'English (Hong Kong SAR China)', + 'en_IN' => 'English (India)', + 'en_IE' => 'English (Ireland)', + 'en_JM' => 'English (Jamaica)', + 'en_MT' => 'English (Malta)', + 'en_MH' => 'English (Marshall Islands)', + 'en_MU' => 'English (Mauritius)', + 'en_NA' => 'English (Namibia)', + 'en_NZ' => 'English (New Zealand)', + 'en_MP' => 'English (Northern Mariana Islands)', + 'en_PK' => 'English (Pakistan)', + 'en_PH' => 'English (Philippines)', + 'en_SG' => 'English (Singapore)', + 'en_ZA' => 'English (South Africa)', + 'en_TT' => 'English (Trinidad and Tobago)', + 'en_UM' => 'English (U.S. Minor Outlying Islands)', + 'en_VI' => 'English (U.S. Virgin Islands)', + 'en_GB' => 'English (United Kingdom)', + 'en_US' => 'English (United States)', + 'en_ZW' => 'English (Zimbabwe)', + 'en' => 'English', + 'eo' => 'Esperanto', + 'et_EE' => 'Estonian (Estonia)', + 'et' => 'Estonian', + 'ee_GH' => 'Ewe (Ghana)', + 'ee_TG' => 'Ewe (Togo)', + 'ee' => 'Ewe', + 'fo_FO' => 'Faroese (Faroe Islands)', + 'fo' => 'Faroese', + 'fil_PH' => 'Filipino (Philippines)', + 'fil' => 'Filipino', + 'fi_FI' => 'Finnish (Finland)', + 'fi' => 'Finnish', + 'fr_BE' => 'French (Belgium)', + 'fr_BJ' => 'French (Benin)', + 'fr_BF' => 'French (Burkina Faso)', + 'fr_BI' => 'French (Burundi)', + 'fr_CM' => 'French (Cameroon)', + 'fr_CA' => 'French (Canada)', + 'fr_CF' => 'French (Central African Republic)', + 'fr_TD' => 'French (Chad)', + 'fr_KM' => 'French (Comoros)', + 'fr_CG' => 'French (Congo - Brazzaville)', + 'fr_CD' => 'French (Congo - Kinshasa)', + 'fr_CI' => 'French (Côte d’Ivoire)', + 'fr_DJ' => 'French (Djibouti)', + 'fr_GQ' => 'French (Equatorial Guinea)', + 'fr_FR' => 'French (France)', + 'fr_GA' => 'French (Gabon)', + 'fr_GP' => 'French (Guadeloupe)', + 'fr_GN' => 'French (Guinea)', + 'fr_LU' => 'French (Luxembourg)', + 'fr_MG' => 'French (Madagascar)', + 'fr_ML' => 'French (Mali)', + 'fr_MQ' => 'French (Martinique)', + 'fr_MC' => 'French (Monaco)', + 'fr_NE' => 'French (Niger)', + 'fr_RW' => 'French (Rwanda)', + 'fr_RE' => 'French (Réunion)', + 'fr_BL' => 'French (Saint Barthélemy)', + 'fr_MF' => 'French (Saint Martin)', + 'fr_SN' => 'French (Senegal)', + 'fr_CH' => 'French (Switzerland)', + 'fr_TG' => 'French (Togo)', + 'fr' => 'French', + 'ff_SN' => 'Fulah (Senegal)', + 'ff' => 'Fulah', + 'gl_ES' => 'Galician (Spain)', + 'gl' => 'Galician', + 'lg_UG' => 'Ganda (Uganda)', + 'lg' => 'Ganda', + 'ka_GE' => 'Georgian (Georgia)', + 'ka' => 'Georgian', + 'de_AT' => 'German (Austria)', + 'de_BE' => 'German (Belgium)', + 'de_DE' => 'German (Germany)', + 'de_LI' => 'German (Liechtenstein)', + 'de_LU' => 'German (Luxembourg)', + 'de_CH' => 'German (Switzerland)', + 'de' => 'German', + 'el_CY' => 'Greek (Cyprus)', + 'el_GR' => 'Greek (Greece)', + 'el' => 'Greek', + 'gu_IN' => 'Gujarati (India)', + 'gu' => 'Gujarati', + 'guz_KE' => 'Gusii (Kenya)', + 'guz' => 'Gusii', + 'ha_Latn' => 'Hausa (Latin)', + 'ha_Latn_GH' => 'Hausa (Latin, Ghana)', + 'ha_Latn_NE' => 'Hausa (Latin, Niger)', + 'ha_Latn_NG' => 'Hausa (Latin, Nigeria)', + 'ha' => 'Hausa', + 'haw_US' => 'Hawaiian (United States)', + 'haw' => 'Hawaiian', + 'he_IL' => 'Hebrew (Israel)', + 'he' => 'Hebrew', + 'hi_IN' => 'Hindi (India)', + 'hi' => 'Hindi', + 'hu_HU' => 'Hungarian (Hungary)', + 'hu' => 'Hungarian', + 'is_IS' => 'Icelandic (Iceland)', + 'is' => 'Icelandic', + 'ig_NG' => 'Igbo (Nigeria)', + 'ig' => 'Igbo', + 'id_ID' => 'Indonesian (Indonesia)', + 'id' => 'Indonesian', + 'ga_IE' => 'Irish (Ireland)', + 'ga' => 'Irish', + 'it_IT' => 'Italian (Italy)', + 'it_CH' => 'Italian (Switzerland)', + 'it' => 'Italian', + 'ja_JP' => 'Japanese (Japan)', + 'ja' => 'Japanese', + 'kea_CV' => 'Kabuverdianu (Cape Verde)', + 'kea' => 'Kabuverdianu', + 'kab_DZ' => 'Kabyle (Algeria)', + 'kab' => 'Kabyle', + 'kl_GL' => 'Kalaallisut (Greenland)', + 'kl' => 'Kalaallisut', + 'kln_KE' => 'Kalenjin (Kenya)', + 'kln' => 'Kalenjin', + 'kam_KE' => 'Kamba (Kenya)', + 'kam' => 'Kamba', + 'kn_IN' => 'Kannada (India)', + 'kn' => 'Kannada', + 'kk_Cyrl' => 'Kazakh (Cyrillic)', + 'kk_Cyrl_KZ' => 'Kazakh (Cyrillic, Kazakhstan)', + 'kk' => 'Kazakh', + 'km_KH' => 'Khmer (Cambodia)', + 'km' => 'Khmer', + 'ki_KE' => 'Kikuyu (Kenya)', + 'ki' => 'Kikuyu', + 'rw_RW' => 'Kinyarwanda (Rwanda)', + 'rw' => 'Kinyarwanda', + 'kok_IN' => 'Konkani (India)', + 'kok' => 'Konkani', + 'ko_KR' => 'Korean (South Korea)', + 'ko' => 'Korean', + 'khq_ML' => 'Koyra Chiini (Mali)', + 'khq' => 'Koyra Chiini', + 'ses_ML' => 'Koyraboro Senni (Mali)', + 'ses' => 'Koyraboro Senni', + 'lag_TZ' => 'Langi (Tanzania)', + 'lag' => 'Langi', + 'lv_LV' => 'Latvian (Latvia)', + 'lv' => 'Latvian', + 'lt_LT' => 'Lithuanian (Lithuania)', + 'lt' => 'Lithuanian', + 'luo_KE' => 'Luo (Kenya)', + 'luo' => 'Luo', + 'luy_KE' => 'Luyia (Kenya)', + 'luy' => 'Luyia', + 'mk_MK' => 'Macedonian (Macedonia)', + 'mk' => 'Macedonian', + 'jmc_TZ' => 'Machame (Tanzania)', + 'jmc' => 'Machame', + 'kde_TZ' => 'Makonde (Tanzania)', + 'kde' => 'Makonde', + 'mg_MG' => 'Malagasy (Madagascar)', + 'mg' => 'Malagasy', + 'ms_BN' => 'Malay (Brunei)', + 'ms_MY' => 'Malay (Malaysia)', + 'ms' => 'Malay', + 'ml_IN' => 'Malayalam (India)', + 'ml' => 'Malayalam', + 'mt_MT' => 'Maltese (Malta)', + 'mt' => 'Maltese', + 'gv_GB' => 'Manx (United Kingdom)', + 'gv' => 'Manx', + 'mr_IN' => 'Marathi (India)', + 'mr' => 'Marathi', + 'mas_KE' => 'Masai (Kenya)', + 'mas_TZ' => 'Masai (Tanzania)', + 'mas' => 'Masai', + 'mer_KE' => 'Meru (Kenya)', + 'mer' => 'Meru', + 'mfe_MU' => 'Morisyen (Mauritius)', + 'mfe' => 'Morisyen', + 'naq_NA' => 'Nama (Namibia)', + 'naq' => 'Nama', + 'ne_IN' => 'Nepali (India)', + 'ne_NP' => 'Nepali (Nepal)', + 'ne' => 'Nepali', + 'nd_ZW' => 'North Ndebele (Zimbabwe)', + 'nd' => 'North Ndebele', + 'nb_NO' => 'Norwegian Bokmål (Norway)', + 'nb' => 'Norwegian Bokmål', + 'nn_NO' => 'Norwegian Nynorsk (Norway)', + 'nn' => 'Norwegian Nynorsk', + 'nyn_UG' => 'Nyankole (Uganda)', + 'nyn' => 'Nyankole', + 'or_IN' => 'Oriya (India)', + 'or' => 'Oriya', + 'om_ET' => 'Oromo (Ethiopia)', + 'm_KE' => 'Oromo (Kenya)', + 'om' => 'Oromo', + 'ps_AF' => 'Pashto (Afghanistan)', + 'ps' => 'Pashto', + 'fa_AF' => 'Persian (Afghanistan)', + 'fa_IR' => 'Persian (Iran)', + 'fa' => 'Persian', + 'pl_PL' => 'Polish (Poland)', + 'pl' => 'Polish', + 'pt_BR' => 'Portuguese (Brazil)', + 'pt_GW' => 'Portuguese (Guinea-Bissau)', + 'pt_MZ' => 'Portuguese (Mozambique)', + 'pt_PT' => 'Portuguese (Portugal)', + 'pt' => 'Portuguese', + 'pa_Arab' => 'Punjabi (Arabic)', + 'pa_Arab_PK' => 'Punjabi (Arabic, Pakistan)', + 'pa_Guru' => 'Punjabi (Gurmukhi)', + 'pa_Guru_IN' => 'Punjabi (Gurmukhi, India)', + 'pa' => 'Punjabi', + 'ro_MD' => 'Romanian (Moldova)', + 'ro_RO' => 'Romanian (Romania)', + 'ro' => 'Romanian', + 'rm_CH' => 'Romansh (Switzerland)', + 'rm' => 'Romansh', + 'rof_TZ' => 'Rombo (Tanzania)', + 'rof' => 'Rombo', + 'ru_MD' => 'Russian (Moldova)', + 'ru_RU' => 'Russian (Russia)', + 'ru_UA' => 'Russian (Ukraine)', + 'ru' => 'Russian', + 'rwk_TZ' => 'Rwa (Tanzania)', + 'rwk' => 'Rwa', + 'saq_KE' => 'Samburu (Kenya)', + 'saq' => 'Samburu', + 'sg_CF' => 'Sango (Central African Republic)', + 'sg' => 'Sango', + 'seh_MZ' => 'Sena (Mozambique)', + 'seh' => 'Sena', + 'sr_Cyrl' => 'Serbian (Cyrillic)', + 'sr_Cyrl_BA' => 'Serbian (Cyrillic, Bosnia and Herzegovina)', + 'sr_Cyrl_ME' => 'Serbian (Cyrillic, Montenegro)', + 'sr_Cyrl_RS' => 'Serbian (Cyrillic, Serbia)', + 'sr_Latn' => 'Serbian (Latin)', + 'sr_Latn_BA' => 'Serbian (Latin, Bosnia and Herzegovina)', + 'sr_Latn_ME' => 'Serbian (Latin, Montenegro)', + 'sr_Latn_RS' => 'Serbian (Latin, Serbia)', + 'sr' => 'Serbian', + 'sn_ZW' => 'Shona (Zimbabwe)', + 'sn' => 'Shona', + 'ii_CN' => 'Sichuan Yi (China)', + 'ii' => 'Sichuan Yi', + 'si_LK' => 'Sinhala (Sri Lanka)', + 'si' => 'Sinhala', + 'sk_SK' => 'Slovak (Slovakia)', + 'sk' => 'Slovak', + 'sl_SI' => 'Slovenian (Slovenia)', + 'sl' => 'Slovenian', + 'xog_UG' => 'Soga (Uganda)', + 'xog' => 'Soga', + 'so_DJ' => 'Somali (Djibouti)', + 'so_ET' => 'Somali (Ethiopia)', + 'so_KE' => 'Somali (Kenya)', + 'so_SO' => 'Somali (Somalia)', + 'so' => 'Somali', + 'es_AR' => 'Spanish (Argentina)', + 'es_BO' => 'Spanish (Bolivia)', + 'es_CL' => 'Spanish (Chile)', + 'es_CO' => 'Spanish (Colombia)', + 'es_CR' => 'Spanish (Costa Rica)', + 'es_DO' => 'Spanish (Dominican Republic)', + 'es_EC' => 'Spanish (Ecuador)', + 'es_SV' => 'Spanish (El Salvador)', + 'es_GQ' => 'Spanish (Equatorial Guinea)', + 'es_GT' => 'Spanish (Guatemala)', + 'es_HN' => 'Spanish (Honduras)', + 'es_419' => 'Spanish (Latin America)', + 'es_MX' => 'Spanish (Mexico)', + 'es_NI' => 'Spanish (Nicaragua)', + 'es_PA' => 'Spanish (Panama)', + 'es_PY' => 'Spanish (Paraguay)', + 'es_PE' => 'Spanish (Peru)', + 'es_PR' => 'Spanish (Puerto Rico)', + 'es_ES' => 'Spanish (Spain)', + 'es_US' => 'Spanish (United States)', + 'es_UY' => 'Spanish (Uruguay)', + 'es_VE' => 'Spanish (Venezuela)', + 'es' => 'Spanish', + 'sw_KE' => 'Swahili (Kenya)', + 'sw_TZ' => 'Swahili (Tanzania)', + 'sw' => 'Swahili', + 'sv_FI' => 'Swedish (Finland)', + 'sv_SE' => 'Swedish (Sweden)', + 'sv' => 'Swedish', + 'gsw_CH' => 'Swiss German (Switzerland)', + 'gsw' => 'Swiss German', + 'shi_Latn' => 'Tachelhit (Latin)', + 'shi_Latn_MA' => 'Tachelhit (Latin, Morocco)', + 'shi_Tfng' => 'Tachelhit (Tifinagh)', + 'shi_Tfng_MA' => 'Tachelhit (Tifinagh, Morocco)', + 'shi' => 'Tachelhit', + 'dav_KE' => 'Taita (Kenya)', + 'dav' => 'Taita', + 'ta_IN' => 'Tamil (India)', + 'ta_LK' => 'Tamil (Sri Lanka)', + 'ta' => 'Tamil', + 'te_IN' => 'Telugu (India)', + 'te' => 'Telugu', + 'teo_KE' => 'Teso (Kenya)', + 'teo_UG' => 'Teso (Uganda)', + 'teo' => 'Teso', + 'th_TH' => 'Thai (Thailand)', + 'th' => 'Thai', + 'bo_CN' => 'Tibetan (China)', + 'bo_IN' => 'Tibetan (India)', + 'bo' => 'Tibetan', + 'ti_ER' => 'Tigrinya (Eritrea)', + 'ti_ET' => 'Tigrinya (Ethiopia)', + 'ti' => 'Tigrinya', + 'to_TO' => 'Tonga (Tonga)', + 'to' => 'Tonga', + 'tr_TR' => 'Turkish (Turkey)', + 'tr' => 'Turkish', + 'uk_UA' => 'Ukrainian (Ukraine)', + 'uk' => 'Ukrainian', + 'ur_IN' => 'Urdu (India)', + 'ur_PK' => 'Urdu (Pakistan)', + 'ur' => 'Urdu', + 'uz_Arab' => 'Uzbek (Arabic)', + 'uz_Arab_AF' => 'Uzbek (Arabic, Afghanistan)', + 'uz_Cyrl' => 'Uzbek (Cyrillic)', + 'uz_Cyrl_UZ' => 'Uzbek (Cyrillic, Uzbekistan)', + 'uz_Latn' => 'Uzbek (Latin)', + 'uz_Latn_UZ' => 'Uzbek (Latin, Uzbekistan)', + 'uz' => 'Uzbek', + 'vi_VN' => 'Vietnamese (Vietnam)', + 'vi' => 'Vietnamese', + 'vun_TZ' => 'Vunjo (Tanzania)', + 'vun' => 'Vunjo', + 'cy_GB' => 'Welsh (United Kingdom)', + 'cy' => 'Welsh', + 'yo_NG' => 'Yoruba (Nigeria)', + 'yo' => 'Yoruba', + 'zu_ZA' => 'Zulu (South Africa)', + 'zu' => 'Zulu', ]; #[SymfonySerializer\Ignore] #[Serializer\Exclude] public static array $rtlLanguages = [ - 'ar_DZ' => "Arabic (Algeria)", - 'ar_BH' => "Arabic (Bahrain)", - 'ar_EG' => "Arabic (Egypt)", - 'ar_IQ' => "Arabic (Iraq)", - 'ar_JO' => "Arabic (Jordan)", - 'ar_KW' => "Arabic (Kuwait)", - 'ar_LB' => "Arabic (Lebanon)", - 'ar_LY' => "Arabic (Libya)", - 'ar_MA' => "Arabic (Morocco)", - 'ar_OM' => "Arabic (Oman)", - 'ar_QA' => "Arabic (Qatar)", - 'ar_SA' => "Arabic (Saudi Arabia)", - 'ar_SD' => "Arabic (Sudan)", - 'ar_SY' => "Arabic (Syria)", - 'ar_TN' => "Arabic (Tunisia)", - 'ar_AE' => "Arabic (United Arab Emirates)", - 'ar_YE' => "Arabic (Yemen)", - 'ar' => "Arabic", - 'he_IL' => "Hebrew (Israel)", - 'he' => "Hebrew", - 'ur_IN' => "Urdu (India)", - 'ur_PK' => "Urdu (Pakistan)", - 'fa_AF' => "Persian (Afghanistan)", - 'fa_IR' => "Persian (Iran)", - 'fa' => "Persian", + 'ar_DZ' => 'Arabic (Algeria)', + 'ar_BH' => 'Arabic (Bahrain)', + 'ar_EG' => 'Arabic (Egypt)', + 'ar_IQ' => 'Arabic (Iraq)', + 'ar_JO' => 'Arabic (Jordan)', + 'ar_KW' => 'Arabic (Kuwait)', + 'ar_LB' => 'Arabic (Lebanon)', + 'ar_LY' => 'Arabic (Libya)', + 'ar_MA' => 'Arabic (Morocco)', + 'ar_OM' => 'Arabic (Oman)', + 'ar_QA' => 'Arabic (Qatar)', + 'ar_SA' => 'Arabic (Saudi Arabia)', + 'ar_SD' => 'Arabic (Sudan)', + 'ar_SY' => 'Arabic (Syria)', + 'ar_TN' => 'Arabic (Tunisia)', + 'ar_AE' => 'Arabic (United Arab Emirates)', + 'ar_YE' => 'Arabic (Yemen)', + 'ar' => 'Arabic', + 'he_IL' => 'Hebrew (Israel)', + 'he' => 'Hebrew', + 'ur_IN' => 'Urdu (India)', + 'ur_PK' => 'Urdu (Pakistan)', + 'fa_AF' => 'Persian (Afghanistan)', + 'fa_IR' => 'Persian (Iran)', + 'fa' => 'Persian', ]; /** * @var Collection @@ -548,13 +548,11 @@ class Translation extends AbstractDateTimed implements TranslationInterface * * fr or en for example * - * @var string * @see https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes - * @Serializer\Groups({"translation", "document", "nodes_sources", "tag", "attribute", "folder", "log_sources"}) - * @Serializer\Type("string") */ #[ORM\Column(type: 'string', length: 10, unique: true, nullable: false)] #[SymfonySerializer\Ignore] + #[Serializer\Exclude] #[Assert\NotBlank] #[Assert\NotNull] #[Assert\Length(max: 10)] @@ -564,13 +562,9 @@ class Translation extends AbstractDateTimed implements TranslationInterface )] private string $locale = ''; - /** - * @var string|null - * @Serializer\Groups({"translation", "document", "nodes_sources", "tag", "attribute", "folder"}) - * @Serializer\Type("string") - */ #[ORM\Column(name: 'override_locale', type: 'string', length: 10, unique: true, nullable: true)] #[SymfonySerializer\Ignore] + #[Serializer\Exclude] #[Assert\Length(max: 10)] #[ApiProperty( description: 'Override standard locale with an other one (for example, `uk` instead of `en`)', @@ -578,13 +572,10 @@ class Translation extends AbstractDateTimed implements TranslationInterface )] private ?string $overrideLocale = null; - /** - * @var string - * @Serializer\Groups({"translation", "translation_base"}) - * @Serializer\Type("string") - */ #[ORM\Column(type: 'string', length: 250, unique: true)] #[SymfonySerializer\Groups(['translation', 'translation_base'])] + #[Serializer\Groups(['translation', 'translation_base'])] + #[Serializer\Type('string')] #[Assert\NotNull] #[Assert\NotBlank] #[Assert\Length(max: 250)] @@ -594,26 +585,20 @@ class Translation extends AbstractDateTimed implements TranslationInterface )] private string $name = ''; - /** - * @var bool - * @Serializer\Groups({"translation", "translation_base"}) - * @Serializer\Type("bool") - */ #[ORM\Column(name: 'default_translation', type: 'boolean', nullable: false, options: ['default' => false])] #[SymfonySerializer\Groups(['translation', 'translation_base'])] + #[Serializer\Groups(['translation', 'translation_base'])] + #[Serializer\Type('bool')] #[ApiProperty( description: 'Is translation default one?', example: 'true', )] private bool $defaultTranslation = false; - /** - * @var bool - * @Serializer\Groups({"translation", "translation_base"}) - * @Serializer\Type("bool") - */ #[ORM\Column(type: 'boolean', nullable: false, options: ['default' => true])] #[SymfonySerializer\Groups(['translation', 'translation_base'])] + #[Serializer\Groups(['translation', 'translation_base'])] + #[Serializer\Type('bool')] #[ApiProperty( description: 'Is translation available publicly?', example: 'true', @@ -657,8 +642,6 @@ public function __construct() /** * Return available locales in an array. - * - * @return array */ #[SymfonySerializer\Ignore] public static function getAvailableLocales(): array @@ -666,120 +649,89 @@ public static function getAvailableLocales(): array return array_keys(static::$availableLocales); } - /** - * @return string - */ #[SymfonySerializer\Ignore] public function getOneLineSummary(): string { - return $this->getId() . " — " . $this->getName() . " (" . $this->getLocale() . ')' . - " — " . ($this->isAvailable() ? 'Enabled' : 'Disabled') . - ($this->isDefaultTranslation() ? ' - Default' : '') . PHP_EOL; + return $this->getId().' — '.$this->getName().' ('.$this->getLocale().')'. + ' — '.($this->isAvailable() ? 'Enabled' : 'Disabled'). + ($this->isDefaultTranslation() ? ' - Default' : '').PHP_EOL; } - /** - * @return string - */ public function __toString(): string { return (string) $this->getId(); } - /** - * @return string - */ public function getName(): string { return $this->name; } /** - * @param string|null $name - * * @return $this */ public function setName(?string $name): Translation { $this->name = $name ?? ''; + return $this; } - /** - * @return string - */ public function getLocale(): string { return $this->locale; } /** - * @param string $locale - * * @return $this */ public function setLocale(string $locale): Translation { $this->locale = $locale; + return $this; } - /** - * @return boolean - */ public function isAvailable(): bool { return $this->available; } /** - * @param boolean $available - * * @return $this */ public function setAvailable(bool $available): Translation { $this->available = $available; + return $this; } - /** - * @return boolean - */ public function isDefaultTranslation(): bool { return $this->defaultTranslation; } /** - * @param boolean $defaultTranslation - * * @return $this */ public function setDefaultTranslation(bool $defaultTranslation): Translation { $this->defaultTranslation = $defaultTranslation; + return $this; } - /** - * @return Collection - */ public function getNodeSources(): Collection { return $this->nodeSources; } - /** - * @return Collection - */ public function getTagTranslations(): Collection { return $this->tagTranslations; } - /** - * @return Collection - */ public function getDocumentTranslations(): Collection { return $this->documentTranslations; @@ -787,8 +739,6 @@ public function getDocumentTranslations(): Collection /** * Gets the value of overrideLocale. - * - * @return string */ public function getOverrideLocale(): ?string { @@ -799,8 +749,6 @@ public function getOverrideLocale(): ?string * Sets the value of overrideLocale. * * @param string|null $overrideLocale the override locale - * - * @return self */ public function setOverrideLocale(?string $overrideLocale): Translation { @@ -811,11 +759,11 @@ public function setOverrideLocale(?string $overrideLocale): Translation /** * Get preferred locale between overrideLocale or locale. - * - * @return string */ #[SymfonySerializer\SerializedName('locale')] #[SymfonySerializer\Groups(['translation_base'])] + #[Serializer\SerializedName('locale')] + #[Serializer\Groups(['translation_base'])] #[ApiProperty( description: 'Translation ISO 639-1 locale. See https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes', example: 'fr', @@ -825,26 +773,17 @@ public function getPreferredLocale(): string return !empty($this->overrideLocale) ? $this->overrideLocale : $this->locale; } - /** - * @return bool - */ public function isRtl(): bool { return in_array($this->getLocale(), static::getRightToLeftLocales()); } - /** - * @return array - */ #[SymfonySerializer\Ignore] public static function getRightToLeftLocales(): array { return array_keys(static::$rtlLanguages); } - /** - * @return Collection - */ #[SymfonySerializer\Ignore] public function getFolderTranslations(): Collection { diff --git a/src/Entity/UrlAlias.php b/src/Entity/UrlAlias.php index 9f713fef..9718184a 100644 --- a/src/Entity/UrlAlias.php +++ b/src/Entity/UrlAlias.php @@ -5,20 +5,20 @@ namespace RZ\Roadiz\CoreBundle\Entity; use Doctrine\ORM\Mapping as ORM; +use JMS\Serializer\Annotation as Serializer; use RZ\Roadiz\Core\AbstractEntities\AbstractEntity; +use RZ\Roadiz\CoreBundle\Form\Constraint as RoadizAssert; use RZ\Roadiz\CoreBundle\Repository\UrlAliasRepository; use RZ\Roadiz\Utils\StringHandler; -use JMS\Serializer\Annotation as Serializer; use Symfony\Component\Serializer\Annotation as SymfonySerializer; use Symfony\Component\Validator\Constraints as Assert; -use RZ\Roadiz\CoreBundle\Form\Constraint as RoadizAssert; /** * UrlAliases are used to translate Nodes URLs. */ #[ ORM\Entity(repositoryClass: UrlAliasRepository::class), - ORM\Table(name: "url_aliases") + ORM\Table(name: 'url_aliases') ] class UrlAlias extends AbstractEntity { @@ -37,22 +37,18 @@ class UrlAlias extends AbstractEntity #[Serializer\Exclude] private NodesSources $nodeSource; - /** - * @return string - */ public function getAlias(): string { return $this->alias; } /** - * @param string $alias - * * @return $this */ public function setAlias(string $alias): UrlAlias { $this->alias = StringHandler::slugify($alias); + return $this; } @@ -64,6 +60,7 @@ public function getNodeSource(): NodesSources public function setNodeSource(NodesSources $nodeSource): UrlAlias { $this->nodeSource = $nodeSource; + return $this; } } diff --git a/src/Entity/User.php b/src/Entity/User.php index a5d39a62..f0fc18fd 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -7,7 +7,6 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; -use JMS\Serializer\Annotation as Serializer; use Rollerworks\Component\PasswordStrength\Validator\Constraints\PasswordStrength; use RZ\Roadiz\Core\AbstractEntities\AbstractHuman; use RZ\Roadiz\CoreBundle\Form\Constraint\ValidFacebookName; @@ -17,26 +16,26 @@ use Symfony\Component\Security\Core\User\EquatableInterface; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\UserInterface; -use Symfony\Component\Serializer\Annotation as SymfonySerializer; +use Symfony\Component\Serializer\Annotation as Serializer; use Symfony\Component\Validator\Constraints as Assert; #[ ORM\Entity(repositoryClass: UserRepository::class), - ORM\Table(name: "users"), - ORM\Index(columns: ["username"], name: "idx_users_username"), - ORM\Index(columns: ["email"], name: "idx_users_email"), - ORM\Index(columns: ["enabled"], name: "idx_users_enabled"), - ORM\Index(columns: ["credentials_expires_at"], name: "idx_users_credentials_expires_at"), - ORM\Index(columns: ["password_requested_at"], name: "idx_users_password_requested_at"), - ORM\Index(columns: ["expires_at"], name: "idx_users_expires_at"), - ORM\Index(columns: ["last_login"], name: "idx_users_last_login"), - ORM\Index(columns: ["locked"], name: "idx_users_locked"), - ORM\Index(columns: ["locale"], name: "idx_users_locale"), - ORM\Index(columns: ["created_at"], name: "idx_user_created_at"), - ORM\Index(columns: ["updated_at"], name: "idx_user_updated_at"), + ORM\Table(name: 'users'), + ORM\Index(columns: ['username'], name: 'idx_users_username'), + ORM\Index(columns: ['email'], name: 'idx_users_email'), + ORM\Index(columns: ['enabled'], name: 'idx_users_enabled'), + ORM\Index(columns: ['credentials_expires_at'], name: 'idx_users_credentials_expires_at'), + ORM\Index(columns: ['password_requested_at'], name: 'idx_users_password_requested_at'), + ORM\Index(columns: ['expires_at'], name: 'idx_users_expires_at'), + ORM\Index(columns: ['last_login'], name: 'idx_users_last_login'), + ORM\Index(columns: ['locked'], name: 'idx_users_locked'), + ORM\Index(columns: ['locale'], name: 'idx_users_locale'), + ORM\Index(columns: ['created_at'], name: 'idx_user_created_at'), + ORM\Index(columns: ['updated_at'], name: 'idx_user_updated_at'), ORM\HasLifecycleCallbacks, - UniqueEntity("email"), - UniqueEntity("username") + UniqueEntity('email'), + UniqueEntity('username') ] class User extends AbstractHuman implements UserInterface, AdvancedUserInterface, EquatableInterface, PasswordAuthenticatedUserInterface { @@ -48,12 +47,8 @@ class User extends AbstractHuman implements UserInterface, AdvancedUserInterface */ public const CONFIRMATION_TTL = 900; - /** - * @Serializer\Groups({"user_personal", "human"}) - * @var string|null - */ #[ORM\Column(type: 'string', length: 200, unique: true, nullable: false)] - #[SymfonySerializer\Groups(['user_personal', 'human'])] + #[Serializer\Groups(['user_personal', 'human'])] #[Assert\NotNull] #[Assert\NotBlank] #[Assert\Length(max: 200)] @@ -61,60 +56,35 @@ class User extends AbstractHuman implements UserInterface, AdvancedUserInterface /** @phpstan-ignore-next-line */ protected ?string $email = null; - /** - * @var bool - * @Serializer\Exclude() - */ - #[SymfonySerializer\Ignore] + #[Serializer\Ignore] protected bool $sendCreationConfirmationEmail = false; #[ORM\Column(name: 'facebook_name', type: 'string', length: 128, unique: false, nullable: true)] - #[SymfonySerializer\Groups(['user_social'])] #[Serializer\Groups(['user_social'])] #[Assert\Length(max: 128)] #[ValidFacebookName] protected ?string $facebookName = null; - /** - * @var string|null - * @Serializer\Groups({"user"}) - */ #[ORM\Column(name: 'picture_url', type: 'text', nullable: true)] - #[SymfonySerializer\Groups(['user'])] + #[Serializer\Groups(['user'])] #[Assert\Length(max: 250)] protected ?string $pictureUrl = null; - /** - * @var boolean - * @Serializer\Groups({"user_security"}) - */ #[ORM\Column(type: 'boolean', nullable: false, options: ['default' => true])] - #[SymfonySerializer\Groups(['user_security'])] + #[Serializer\Groups(['user_security'])] protected bool $enabled = true; - /** - * @Serializer\Groups({"user_security"}) - * @var string|null - */ #[ORM\Column(name: 'confirmation_token', type: 'string', length: 128, unique: true, nullable: true)] - #[SymfonySerializer\Groups(['user_security'])] + #[Serializer\Groups(['user_security'])] #[Assert\Length(max: 128)] protected ?string $confirmationToken = null; - /** - * @Serializer\Groups({"user_security"}) - * @var \DateTime|null - */ #[ORM\Column(name: 'password_requested_at', type: 'datetime', nullable: true)] - #[SymfonySerializer\Groups(['user_security'])] + #[Serializer\Groups(['user_security'])] protected ?\DateTime $passwordRequestedAt = null; - /** - * @Serializer\Groups({"user_personal", "log_user"}) - * @var string - */ #[ORM\Column(type: 'string', length: 200, unique: true)] - #[SymfonySerializer\Groups(['user_personal', 'log_user'])] + #[Serializer\Groups(['user_personal', 'log_user'])] #[Assert\NotNull] #[Assert\NotBlank] #[Assert\Length(max: 200)] @@ -124,29 +94,21 @@ class User extends AbstractHuman implements UserInterface, AdvancedUserInterface * Encrypted password. */ #[ORM\Column(type: 'string', length: 128, nullable: false)] - #[SymfonySerializer\Ignore] - #[Serializer\Exclude] + #[Serializer\Ignore] #[Assert\Length(max: 128)] private string $password = ''; /** * Plain password. Used for model validation. - * **Must not be persisted.** - * - * @var string|null - * @Serializer\Groups({"user:write"}) - * @PasswordStrength(minLength=8, minStrength=3) + * **Must not be persisted.**. */ - #[SymfonySerializer\Groups(['user:write'])] + #[PasswordStrength(minStrength: 3, minLength: 8)] + #[Serializer\Groups(['user:write'])] #[Assert\NotBlank(groups: ['no_empty_password'])] private ?string $plainPassword = null; - /** - * @var \DateTime|null - * @Serializer\Groups({"user_security"}) - */ #[ORM\Column(name: 'last_login', type: 'datetime', nullable: true)] - #[SymfonySerializer\Groups(['user_security'])] + #[Serializer\Groups(['user_security'])] private ?\DateTime $lastLogin = null; /** @@ -156,70 +118,47 @@ class User extends AbstractHuman implements UserInterface, AdvancedUserInterface #[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id', onDelete: 'CASCADE')] #[ORM\InverseJoinColumn(name: 'role_id', referencedColumnName: 'id', onDelete: 'CASCADE')] #[ORM\ManyToMany(targetEntity: Role::class)] - #[SymfonySerializer\Ignore] - #[Serializer\Exclude] + #[Serializer\Ignore] private Collection $roleEntities; /** * Names of current User roles - * to be compatible with symfony security scheme + * to be compatible with symfony security scheme. * * @var array|null */ - #[SymfonySerializer\Ignore] - #[Serializer\Exclude] + #[Serializer\Ignore] private ?array $roles = null; /** * @var Collection - * @Serializer\Groups({"user_group"}) */ #[ORM\JoinTable(name: 'users_groups')] #[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id')] #[ORM\InverseJoinColumn(name: 'group_id', referencedColumnName: 'id')] #[ORM\ManyToMany(targetEntity: Group::class, inversedBy: 'users')] - #[SymfonySerializer\Groups(['user_group'])] + #[Serializer\Groups(['user_group'])] private Collection $groups; - /** - * @var boolean - * @Serializer\Groups({"user_security"}) - */ #[ORM\Column(type: 'boolean', nullable: false, options: ['default' => false])] - #[SymfonySerializer\Groups(['user_security'])] + #[Serializer\Groups(['user_security'])] private bool $locked = false; - /** - * @Serializer\Groups({"user_security"}) - * @var \DateTime|null - */ #[ORM\Column(name: 'credentials_expires_at', type: 'datetime', nullable: true)] - #[SymfonySerializer\Groups(['user_security'])] + #[Serializer\Groups(['user_security'])] private ?\DateTime $credentialsExpiresAt = null; - /** - * @Serializer\Groups({"user_security"}) - * @var \DateTime|null - */ #[ORM\Column(name: 'expires_at', type: 'datetime', nullable: true)] - #[SymfonySerializer\Groups(['user_security'])] + #[Serializer\Groups(['user_security'])] private ?\DateTime $expiresAt = null; - /** - * @Serializer\Groups({"user_chroot"}) - * @var Node|null - */ #[ORM\ManyToOne(targetEntity: Node::class)] #[ORM\JoinColumn(name: 'chroot_id', referencedColumnName: 'id', onDelete: 'SET NULL')] - #[SymfonySerializer\Groups(['user_chroot'])] + #[Serializer\Groups(['user_chroot'])] private ?Node $chroot = null; - /** - * @var null|string - * @Serializer\Groups({"user"}) - */ #[ORM\Column(name: 'locale', type: 'string', length: 7, nullable: true)] - #[SymfonySerializer\Groups(['user'])] + #[Serializer\Groups(['user'])] #[Assert\Length(max: 7)] private ?string $locale = null; @@ -234,21 +173,17 @@ public function __construct() /** * Set if we need Roadiz to send a default email * when User will be persisted. - * - * @param bool $sendCreationConfirmationEmail - * @return User */ public function sendCreationConfirmationEmail(bool $sendCreationConfirmationEmail): User { $this->sendCreationConfirmationEmail = $sendCreationConfirmationEmail; + return $this; } /** * Tells if we need Roadiz to send a default email * when User will be persisted. Default: false. - * - * @return bool */ public function willSendCreationConfirmationEmail(): bool { @@ -258,29 +193,21 @@ public function willSendCreationConfirmationEmail(): bool /** * Get available username data, first name and last name * or username as a last try. - * - * @return string - * @Serializer\Exclude() */ - #[SymfonySerializer\Ignore] + #[Serializer\Ignore] public function getIdentifier(): string { - if ($this->getFirstName() != "" && $this->getLastName() != "") { - return $this->getFirstName() . " " . $this->getLastName(); - } elseif ($this->getFirstName() != "") { + if ('' != $this->getFirstName() && '' != $this->getLastName()) { + return $this->getFirstName().' '.$this->getLastName(); + } elseif ('' != $this->getFirstName()) { return $this->getFirstName(); } else { return $this->getUsername(); } } - /** - * @return string - * @Serializer\Groups({"user_identifier", "user_personal"}) - * @Serializer\VirtualProperty() - */ - #[SymfonySerializer\SerializedName('identifier')] - #[SymfonySerializer\Groups(['user_identifier', 'user_personal'])] + #[Serializer\SerializedName('identifier')] + #[Serializer\Groups(['user_identifier', 'user_personal'])] public function getUserIdentifier(): string { return $this->username; @@ -295,20 +222,17 @@ public function getUsername(): string } /** - * @param string $username - * * @return $this */ public function setUsername(string $username): User { $this->username = $username; + return $this; } /** - * Get facebook profile name to grab public infos such as picture - * - * @return string|null + * Get facebook profile name to grab public infos such as picture. */ public function getFacebookName(): ?string { @@ -316,36 +240,30 @@ public function getFacebookName(): ?string } /** - * @param string|null $facebookName * @return $this */ public function setFacebookName(?string $facebookName): User { $this->facebookName = $facebookName; + return $this; } - /** - * @return string|null - */ public function getPictureUrl(): ?string { return $this->pictureUrl; } /** - * @param string|null $pictureUrl * @return $this */ public function setPictureUrl(?string $pictureUrl): User { $this->pictureUrl = $pictureUrl; + return $this; } - /** - * @return string|null - */ public function getSalt(): ?string { return null; @@ -360,12 +278,12 @@ public function getPassword(): string } /** - * @param string $password * @return $this */ public function setPassword(string $password): User { $this->password = $password; + return $this; } @@ -377,19 +295,16 @@ public function getPlainPassword(): ?string return $this->plainPassword; } - /** - * @param string|null $plainPassword - * @return User - */ public function setPlainPassword(?string $plainPassword): User { $this->plainPassword = $plainPassword; - if (null !== $plainPassword && $plainPassword != '') { + if (null !== $plainPassword && '' != $plainPassword) { /* * We MUST change password to trigger preUpdate lifeCycle event. */ - $this->password = '--password-changed--' . uniqid(); + $this->password = '--password-changed--'.uniqid(); } + return $this; } @@ -401,20 +316,15 @@ public function getLastLogin(): ?\DateTime return $this->lastLogin; } - /** - * @param \DateTime|null $lastLogin - * @return User - */ public function setLastLogin(?\DateTime $lastLogin): User { $this->lastLogin = $lastLogin; + return $this; } /** * Get random string sent to the user email address in order to verify it. - * - * @return string|null */ public function getConfirmationToken(): ?string { @@ -424,7 +334,6 @@ public function getConfirmationToken(): ?string /** * Set random string sent to the user email address in order to verify it. * - * @param string|null $confirmationToken * @return $this */ public function setConfirmationToken(?string $confirmationToken): User @@ -437,20 +346,16 @@ public function setConfirmationToken(?string $confirmationToken): User /** * Check if password reset request has expired. * - * @param int $ttl Password request time to live. - * - * @return boolean + * @param int $ttl password request time to live */ public function isPasswordRequestNonExpired(int $ttl): bool { - return $this->getPasswordRequestedAt() instanceof \DateTime && - $this->getPasswordRequestedAt()->getTimestamp() + $ttl > time(); + return $this->getPasswordRequestedAt() instanceof \DateTime + && $this->getPasswordRequestedAt()->getTimestamp() + $ttl > time(); } /** * Gets the timestamp that the user requested a password reset. - * - * @return null|\DateTime */ public function getPasswordRequestedAt(): ?\DateTime { @@ -460,18 +365,18 @@ public function getPasswordRequestedAt(): ?\DateTime /** * Sets the timestamp that the user requested a password reset. * - * @param \DateTime|null $date * @return $this */ - public function setPasswordRequestedAt(\DateTime $date = null): User + public function setPasswordRequestedAt(?\DateTime $date = null): User { $this->passwordRequestedAt = $date; + return $this; } /** - * @param Role $role * @return $this + * * @deprecated Use addRoleEntity */ public function addRole(Role $role): User @@ -482,8 +387,6 @@ public function addRole(Role $role): User /** * Add a role object to current user. * - * @param Role $role - * * @return $this */ public function addRoleEntity(Role $role): User @@ -496,28 +399,23 @@ public function addRoleEntity(Role $role): User } /** - * Get roles entities - * - * @return Collection|null + * Get roles entities. */ public function getRolesEntities(): ?Collection { return $this->roleEntities; } - /** - * @param ArrayCollection $roles - * @return User - */ public function setRolesEntities(ArrayCollection $roles): User { $this->roleEntities = $roles; + return $this; } /** - * @param Role $role * @return $this + * * @deprecated Use removeRoleEntity */ public function removeRole(Role $role): User @@ -528,8 +426,6 @@ public function removeRole(Role $role): User /** * Remove role from current user. * - * @param Role $role - * * @return $this */ public function removeRoleEntity(Role $role): User @@ -537,13 +433,12 @@ public function removeRoleEntity(Role $role): User if ($this->getRolesEntities()->contains($role)) { $this->getRolesEntities()->removeElement($role); } + return $this; } /** * Removes sensitive data from the user. - * - * @return User */ public function eraseCredentials(): User { @@ -553,8 +448,6 @@ public function eraseCredentials(): User /** * Insert user into group. * - * @param Group $group - * * @return $this */ public function addGroup(Group $group): User @@ -566,18 +459,13 @@ public function addGroup(Group $group): User return $this; } - /** - * @return Collection - */ public function getGroups(): ?Collection { return $this->groups; } /** - * Remove user from group - * - * @param Group $group + * Remove user from group. * * @return $this */ @@ -594,10 +482,8 @@ public function removeGroup(Group $group): User * Get current user groups name. * * @return array Array of strings - * @Serializer\Groups({"user"}) - * @Serializer\VirtualProperty() */ - #[SymfonySerializer\Groups(['user'])] + #[Serializer\Groups(['user'])] public function getGroupNames(): array { $names = []; @@ -616,16 +502,14 @@ public function getGroupNames(): array * Internally, if this method returns false, the authentication system * will throw an AccountExpiredException and prevent login. * - * @return bool true if the user's account is non expired, false otherwise + * @return bool true if the user's account is non expired, false otherwise * * @see AccountExpiredException - * @Serializer\Groups({"user_security"}) - * @Serializer\VirtualProperty() */ - #[SymfonySerializer\Groups(['user_security'])] + #[Serializer\Groups(['user_security'])] public function isAccountNonExpired(): bool { - return $this->expiresAt === null || $this->expiresAt->getTimestamp() > time(); + return null === $this->expiresAt || $this->expiresAt->getTimestamp() > time(); } /** @@ -637,10 +521,8 @@ public function isAccountNonExpired(): bool * @return bool true if the user is not locked, false otherwise * * @see LockedException - * @Serializer\Groups({"user_security"}) - * @Serializer\VirtualProperty() */ - #[SymfonySerializer\Groups(['user_security'])] + #[Serializer\Groups(['user_security'])] public function isAccountNonLocked(): bool { return !$this->locked; @@ -649,43 +531,28 @@ public function isAccountNonLocked(): bool public function setLocked(bool $locked): self { $this->locked = $locked; + return $this; } - /** - * @return bool - */ public function isLocked(): bool { return $this->locked; } - /** - * @param User $user - * - * @return boolean - */ public function equals(User $user): bool { - return ( - $this->username == $user->getUsername() || - $this->email == $user->getEmail() - ); + return + $this->username == $user->getUsername() + || $this->email == $user->getEmail() + ; } - /** - * @return \DateTime|null - */ public function getCredentialsExpiresAt(): ?\DateTime { return $this->credentialsExpiresAt; } - /** - * @param \DateTime|null $date - * - * @return User - */ public function setCredentialsExpiresAt(?\DateTime $date = null): User { $this->credentialsExpiresAt = $date; @@ -694,7 +561,6 @@ public function setCredentialsExpiresAt(?\DateTime $date = null): User } /** - * @return Node|null * @internal Do use directly, use NodeChrootResolver class to support external users (SSO, oauth2, …) */ public function getChroot(): ?Node @@ -702,11 +568,7 @@ public function getChroot(): ?Node return $this->chroot; } - /** - * @param Node|null $chroot - * @return User - */ - public function setChroot(Node $chroot = null): User + public function setChroot(?Node $chroot = null): User { $this->chroot = $chroot; @@ -716,17 +578,16 @@ public function setChroot(Node $chroot = null): User /** * Get prototype abstract Gravatar url. * - * @Serializer\Exclude() * @param string $type Default: "identicon" * @param string $size Default: "200" - * @return string */ - #[SymfonySerializer\Ignore] - public function getGravatarUrl(string $type = "identicon", string $size = "200"): string + #[Serializer\Ignore] + public function getGravatarUrl(string $type = 'identicon', string $size = '200'): string { if (null !== $this->getEmail()) { - return "https://www.gravatar.com/avatar/" . md5(\mb_strtolower(trim($this->getEmail()))) . "?d=" . $type . "&s=" . $size; + return 'https://www.gravatar.com/avatar/'.md5(\mb_strtolower(trim($this->getEmail()))).'?d='.$type.'&s='.$size; } + return ''; } @@ -753,11 +614,6 @@ public function isEnabled(): bool return $this->enabled; } - /** - * @param boolean $enabled - * - * @return User - */ public function setEnabled(bool $enabled): User { $this->enabled = $enabled; @@ -773,31 +629,25 @@ public function setEnabled(bool $enabled): User * Internally, if this method returns false, the authentication system * will throw a CredentialsExpiredException and prevent login. * - * @return bool true if the user's credentials are non expired, false otherwise + * @return bool true if the user's credentials are non expired, false otherwise * * @see CredentialsExpiredException */ - #[SymfonySerializer\Ignore] + #[Serializer\Ignore] public function isCredentialsNonExpired(): bool { - return $this->credentialsExpiresAt === null || $this->credentialsExpiresAt->getTimestamp() > time(); + return null === $this->credentialsExpiresAt || $this->credentialsExpiresAt->getTimestamp() > time(); } - /** - * @return \DateTime|null - */ public function getExpiresAt(): ?\DateTime { return $this->expiresAt; } - /** - * @param \DateTime|null $expiresAt - * @return User - */ public function setExpiresAt(?\DateTime $expiresAt): User { $this->expiresAt = $expiresAt; + return $this; } @@ -806,8 +656,8 @@ public function setExpiresAt(?\DateTime $expiresAt): User * * @return array */ - #[SymfonySerializer\SerializedName('roles')] - #[SymfonySerializer\Groups(['user_role'])] + #[Serializer\SerializedName('roles')] + #[Serializer\Groups(['user_role'])] public function getRoles(): array { if (null === $this->roles) { @@ -836,21 +686,15 @@ public function getRoles(): array return $this->roles; } - /** - * @return null|string - */ public function getLocale(): ?string { return $this->locale; } - /** - * @param null|string $locale - * @return User - */ public function setLocale(?string $locale): User { $this->locale = $locale; + return $this; } @@ -891,30 +735,17 @@ public function __unserialize(array $data): void ] = $data; } - /** - * @Serializer\Groups({"user_security"}) - */ - #[SymfonySerializer\Groups(['user_security'])] + #[Serializer\Groups(['user_security'])] public function isSuperAdmin(): bool { return $this->hasRole(Role::ROLE_SUPERADMIN); } - /** - * @param string $name - * - * @return bool - */ public function hasGroup(string $name): bool { return in_array((string) $name, $this->getGroupNames()); } - /** - * @param string $role - * - * @return bool - */ public function hasRole(string $role): bool { return in_array(\mb_strtoupper((string) $role), $this->getRoles(), true); @@ -922,12 +753,8 @@ public function hasRole(string $role): bool /** * Every field tested in this methods must be serialized in token. - * - * @param UserInterface $user - * - * @return bool */ - #[SymfonySerializer\Ignore] + #[Serializer\Ignore] public function isEqualTo(UserInterface $user): bool { if (!$user instanceof User) { diff --git a/src/Entity/UserLogEntry.php b/src/Entity/UserLogEntry.php index 9714f502..84dc6b61 100644 --- a/src/Entity/UserLogEntry.php +++ b/src/Entity/UserLogEntry.php @@ -9,15 +9,15 @@ use RZ\Roadiz\CoreBundle\Repository\UserLogEntryRepository; /** - * Add User to Gedmo\Loggable\Entity\LogEntry + * Add User to Gedmo\Loggable\Entity\LogEntry. */ #[ ORM\Entity(repositoryClass: UserLogEntryRepository::class), - ORM\Table(name: "user_log_entries", options: ["row_format" => "DYNAMIC"]), - ORM\Index(columns: ["object_class"], name: "log_class_lookup_idx"), - ORM\Index(columns: ["logged_at"], name: "log_date_lookup_idx"), - ORM\Index(columns: ["username"], name: "log_user_lookup_idx"), - ORM\Index(columns: ["object_id", "object_class", "version"], name: "log_version_lookup_idx") + ORM\Table(name: 'user_log_entries', options: ['row_format' => 'DYNAMIC']), + ORM\Index(columns: ['object_class'], name: 'log_class_lookup_idx'), + ORM\Index(columns: ['logged_at'], name: 'log_date_lookup_idx'), + ORM\Index(columns: ['username'], name: 'log_user_lookup_idx'), + ORM\Index(columns: ['object_id', 'object_class', 'version'], name: 'log_version_lookup_idx') ] class UserLogEntry extends AbstractLogEntry { diff --git a/src/Entity/Webhook.php b/src/Entity/Webhook.php index 840cff92..bb02f6ed 100644 --- a/src/Entity/Webhook.php +++ b/src/Entity/Webhook.php @@ -14,62 +14,50 @@ #[ ORM\Entity(repositoryClass: WebhookRepository::class), - ORM\Table(name: "webhooks"), - ORM\Index(columns: ["message_type"], name: "webhook_message_type"), - ORM\Index(columns: ["created_at"], name: "webhook_created_at"), - ORM\Index(columns: ["updated_at"], name: "webhook_updated_at"), - ORM\Index(columns: ["automatic"], name: "webhook_automatic"), - ORM\Index(columns: ["root_node"], name: "webhook_root_node"), - ORM\Index(columns: ["last_triggered_at"], name: "webhook_last_triggered_at"), + ORM\Table(name: 'webhooks'), + ORM\Index(columns: ['message_type'], name: 'webhook_message_type'), + ORM\Index(columns: ['created_at'], name: 'webhook_created_at'), + ORM\Index(columns: ['updated_at'], name: 'webhook_updated_at'), + ORM\Index(columns: ['automatic'], name: 'webhook_automatic'), + ORM\Index(columns: ['root_node'], name: 'webhook_root_node'), + ORM\Index(columns: ['last_triggered_at'], name: 'webhook_last_triggered_at'), ORM\HasLifecycleCallbacks ] class Webhook extends AbstractDateTimed implements WebhookInterface { #[ ORM\Id, - ORM\Column(type:"string", length:36), - Serializer\Groups(["id"]), - SymfonySerializer\Groups(["id"]), - Serializer\Type("string") + ORM\Column(type: 'string', length: 36), + Serializer\Groups(['id']), + SymfonySerializer\Groups(['id']), + Serializer\Type('string') ] /** @phpstan-ignore-next-line */ protected int|string|null $id = null; - /** - * @var string|null - */ #[ORM\Column(type: 'text', nullable: true)] #[Assert\NotBlank] #[Assert\Length(min: 1, max: 250)] #[Serializer\Type('string')] protected ?string $description = null; - /** - * @var string|null - */ #[ORM\Column(name: 'message_type', type: 'string', length: 255, nullable: true)] #[Serializer\Type('string')] #[Assert\Length(max: 255)] protected ?string $messageType = null; - /** - * @var string|null - */ #[ORM\Column(type: 'text', nullable: true)] #[Assert\NotBlank] #[Assert\Url] #[Serializer\Type('string')] protected ?string $uri = null; - /** - * @var array|null - */ #[ORM\Column(type: 'json', nullable: true)] #[Serializer\Type('array')] protected ?array $payload = null; /** - * @var int Wait between webhook call and webhook triggering request. + * @var int wait between webhook call and webhook triggering request */ #[ORM\Column(name: 'throttleseconds', type: 'integer', nullable: false)] #[Assert\NotNull] @@ -77,23 +65,14 @@ class Webhook extends AbstractDateTimed implements WebhookInterface #[Serializer\Type('int')] protected int $throttleSeconds = 60; - /** - * @var \DateTime|null - */ #[ORM\Column(name: 'last_triggered_at', type: 'datetime', nullable: true)] #[Serializer\Type('\DateTime')] protected ?\DateTime $lastTriggeredAt = null; - /** - * @var bool - */ #[ORM\Column(name: 'automatic', type: 'boolean', nullable: false, options: ['default' => false])] #[Serializer\Type('boolean')] protected bool $automatic = false; - /** - * @var Node|null - */ #[ORM\ManyToOne(targetEntity: Node::class)] #[ORM\JoinColumn(name: 'root_node', onDelete: 'SET NULL')] #[SymfonySerializer\Ignore] @@ -104,97 +83,68 @@ public function __construct(?string $uuid = null) $this->id = $uuid ?? \Ramsey\Uuid\Uuid::uuid4()->toString(); } - /** - * @return string|null - */ public function getDescription(): ?string { return $this->description; } - /** - * @param string|null $description - * @return Webhook - */ public function setDescription(?string $description): Webhook { $this->description = $description; + return $this; } - /** - * @return string|null - */ public function getMessageType(): ?string { return $this->messageType; } - /** - * @param string|null $messageType - * @return Webhook - */ public function setMessageType(?string $messageType): Webhook { $this->messageType = $messageType; + return $this; } - /** - * @return string|null - */ public function getUri(): ?string { return $this->uri; } - /** - * @param string|null $uri - * @return Webhook - */ public function setUri(?string $uri): Webhook { $this->uri = $uri; + return $this; } - /** - * @return array|null - */ public function getPayload(): ?array { return $this->payload; } - /** - * @param array|null $payload - * @return Webhook - */ public function setPayload(?array $payload): Webhook { $this->payload = $payload; + return $this; } - /** - * @return int - */ public function getThrottleSeconds(): int { return $this->throttleSeconds; } /** - * @return \DateInterval * @throws \Exception */ public function getThrottleInterval(): \DateInterval { - return new \DateInterval('PT' . $this->getThrottleSeconds() . 'S'); + return new \DateInterval('PT'.$this->getThrottleSeconds().'S'); } /** - * @return \DateTime|null * @throws \Exception */ public function doNotTriggerBefore(): ?\DateTime @@ -203,70 +153,50 @@ public function doNotTriggerBefore(): ?\DateTime return null; } $doNotTriggerBefore = clone $this->getLastTriggeredAt(); + return $doNotTriggerBefore->add($this->getThrottleInterval()); } - /** - * @param int $throttleSeconds - * @return Webhook - */ public function setThrottleSeconds(int $throttleSeconds): Webhook { $this->throttleSeconds = $throttleSeconds; + return $this; } - /** - * @return \DateTime|null - */ public function getLastTriggeredAt(): ?\DateTime { return $this->lastTriggeredAt; } - /** - * @param \DateTime|null $lastTriggeredAt - * @return Webhook - */ public function setLastTriggeredAt(?\DateTime $lastTriggeredAt): Webhook { $this->lastTriggeredAt = $lastTriggeredAt; + return $this; } - /** - * @return bool - */ public function isAutomatic(): bool { return $this->automatic; } - /** - * @param bool $automatic - * @return Webhook - */ public function setAutomatic(bool $automatic): Webhook { $this->automatic = $automatic; + return $this; } - /** - * @return Node|null - */ public function getRootNode(): ?Node { return $this->rootNode; } - /** - * @param Node|null $rootNode - * @return Webhook - */ public function setRootNode(?Node $rootNode): Webhook { $this->rootNode = $rootNode; + return $this; } diff --git a/src/EntityApi/AbstractApi.php b/src/EntityApi/AbstractApi.php index 23d662b9..1e4037db 100644 --- a/src/EntityApi/AbstractApi.php +++ b/src/EntityApi/AbstractApi.php @@ -4,49 +4,34 @@ namespace RZ\Roadiz\CoreBundle\EntityApi; +use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Tools\Pagination\Paginator; use Doctrine\Persistence\ManagerRegistry; +use RZ\Roadiz\Core\AbstractEntities\PersistableInterface; +/** + * @deprecated Use EntityRepository directly + */ abstract class AbstractApi { - protected ManagerRegistry $managerRegistry; - - /** - * @param ManagerRegistry $managerRegistry - */ - public function __construct(ManagerRegistry $managerRegistry) + public function __construct(protected ManagerRegistry $managerRegistry) { - $this->managerRegistry = $managerRegistry; } - /** - * Return entity path for current API. - * - * @return \Doctrine\ORM\EntityRepository - */ - abstract public function getRepository(); + abstract public function getRepository(): EntityRepository; /** * Return an array of entities matching criteria array. - * - * @param array $criteria - * @return array|Paginator */ - abstract public function getBy(array $criteria); + abstract public function getBy(array $criteria): array|Paginator; /** * Return one entity matching criteria array. - * - * @param array $criteria - * @return mixed */ - abstract public function getOneBy(array $criteria); + abstract public function getOneBy(array $criteria): ?PersistableInterface; /** * Count entities matching criteria array. - * - * @param array $criteria - * @return int */ - abstract public function countBy(array $criteria); + abstract public function countBy(array $criteria): int; } diff --git a/src/EntityApi/NodeApi.php b/src/EntityApi/NodeApi.php index 2024bf32..108e7673 100644 --- a/src/EntityApi/NodeApi.php +++ b/src/EntityApi/NodeApi.php @@ -8,12 +8,12 @@ use RZ\Roadiz\CoreBundle\Entity\Node; use RZ\Roadiz\CoreBundle\Repository\NodeRepository; +/** + * @deprecated Use NodeRepository directly + */ class NodeApi extends AbstractApi { - /** - * @return NodeRepository - */ - public function getRepository() + public function getRepository(): NodeRepository { // phpstan cannot resolve repository type. /** @var NodeRepository $repository */ @@ -21,22 +21,19 @@ public function getRepository() ->getRepository(Node::class) ->setDisplayingNotPublishedNodes(false) ->setDisplayingAllNodesStatuses(false); + return $repository; } /** - * @param array $criteria - * @param array|null $order - * @param int|null $limit - * @param int|null $offset - * @return array|Paginator + * @return array|Paginator */ public function getBy( array $criteria, - array $order = null, + ?array $order = null, ?int $limit = null, - ?int $offset = null - ) { + ?int $offset = null, + ): array|Paginator { if (!in_array('translation.available', $criteria, true)) { $criteria['translation.available'] = true; } @@ -50,10 +47,8 @@ public function getBy( null ); } - /** - * {@inheritdoc} - */ - public function countBy(array $criteria) + + public function countBy(array $criteria): int { if (!in_array('translation.available', $criteria, true)) { $criteria['translation.available'] = true; @@ -65,10 +60,8 @@ public function countBy(array $criteria) null ); } - /** - * {@inheritdoc} - */ - public function getOneBy(array $criteria, array $order = null) + + public function getOneBy(array $criteria, ?array $order = null): ?Node { if (!in_array('translation.available', $criteria, true)) { $criteria['translation.available'] = true; diff --git a/src/EntityApi/NodeSourceApi.php b/src/EntityApi/NodeSourceApi.php index d3821a8b..ba4eb6f6 100644 --- a/src/EntityApi/NodeSourceApi.php +++ b/src/EntityApi/NodeSourceApi.php @@ -10,27 +10,29 @@ use RZ\Roadiz\CoreBundle\Entity\NodeType; use RZ\Roadiz\CoreBundle\Repository\NodesSourcesRepository; +/** + * @deprecated Use NodesSourcesRepository directly + */ class NodeSourceApi extends AbstractApi { /** - * @var class-string + * @var class-string */ protected string $nodeSourceClassName = NodesSources::class; /** - * @param array|null $criteria * @return class-string */ - protected function getNodeSourceClassName(array $criteria = null): string + protected function getNodeSourceClassName(?array $criteria = null): string { if (isset($criteria['node.nodeType']) && $criteria['node.nodeType'] instanceof NodeType) { $this->nodeSourceClassName = $criteria['node.nodeType']->getSourceEntityFullQualifiedClassName(); unset($criteria['node.nodeType']); } elseif ( - isset($criteria['node.nodeType']) && - is_array($criteria['node.nodeType']) && - count($criteria['node.nodeType']) === 1 && - $criteria['node.nodeType'][0] instanceof NodeType + isset($criteria['node.nodeType']) + && is_array($criteria['node.nodeType']) + && 1 === count($criteria['node.nodeType']) + && $criteria['node.nodeType'][0] instanceof NodeType ) { $this->nodeSourceClassName = $criteria['node.nodeType'][0]->getSourceEntityFullQualifiedClassName(); unset($criteria['node.nodeType']); @@ -41,9 +43,6 @@ protected function getNodeSourceClassName(array $criteria = null): string return $this->nodeSourceClassName; } - /** - * @return NodesSourcesRepository - */ public function getRepository(): NodesSourcesRepository { // @phpstan-ignore-next-line @@ -51,18 +50,14 @@ public function getRepository(): NodesSourcesRepository } /** - * @param array $criteria - * @param array|null $order - * @param int|null $limit - * @param int|null $offset - * @return array|Paginator + * @return array|Paginator */ public function getBy( array $criteria, - array $order = null, + ?array $order = null, ?int $limit = null, - ?int $offset = null - ) { + ?int $offset = null, + ): array|Paginator { $this->getNodeSourceClassName($criteria); return $this->getRepository() @@ -75,14 +70,13 @@ public function getBy( } /** - * @param array $criteria - * @return int * @throws \Doctrine\ORM\NoResultException - * @throws \Doctrine\ORM\NonUniqueResultException + * @throws NonUniqueResultException */ - public function countBy(array $criteria) + public function countBy(array $criteria): int { $this->getNodeSourceClassName($criteria); + return $this->getRepository() ->countBy( $criteria @@ -90,14 +84,12 @@ public function countBy(array $criteria) } /** - * @param array $criteria - * @param array|null $order - * @return null|NodesSources * @throws NonUniqueResultException */ - public function getOneBy(array $criteria, array $order = null) + public function getOneBy(array $criteria, ?array $order = null): ?NodesSources { $this->getNodeSourceClassName($criteria); + return $this->getRepository() ->findOneBy( $criteria, @@ -108,21 +100,14 @@ public function getOneBy(array $criteria, array $order = null) /** * Search Nodes-Sources using LIKE condition on title, * meta-title, meta-keywords and meta-description. - * - * @param string $textQuery - * @param int $limit - * @param array $nodeTypes - * @param bool $onlyVisible - * @param array $additionalCriteria - * @return array */ public function searchBy( string $textQuery, int $limit = 0, array $nodeTypes = [], bool $onlyVisible = false, - array $additionalCriteria = [] - ) { + array $additionalCriteria = [], + ): array { return $this->getRepository() ->findByTextQuery( $textQuery, diff --git a/src/EntityApi/NodeTypeApi.php b/src/EntityApi/NodeTypeApi.php index c3aecd2a..43ebde2b 100644 --- a/src/EntityApi/NodeTypeApi.php +++ b/src/EntityApi/NodeTypeApi.php @@ -4,36 +4,31 @@ namespace RZ\Roadiz\CoreBundle\EntityApi; +use Doctrine\ORM\Tools\Pagination\Paginator; use RZ\Roadiz\CoreBundle\Entity\NodeType; use RZ\Roadiz\CoreBundle\Repository\NodeTypeRepository; +/** + * @deprecated Use NodeTypeRepository directly + */ class NodeTypeApi extends AbstractApi { - /** - * @return NodeTypeRepository - */ - public function getRepository() + public function getRepository(): NodeTypeRepository { return $this->managerRegistry->getRepository(NodeType::class); } - /** - * {@inheritdoc} - */ - public function getBy(array $criteria, array $order = null) + + public function getBy(array $criteria, ?array $order = null): array|Paginator { return $this->getRepository()->findBy($criteria, $order); } - /** - * {@inheritdoc} - */ - public function getOneBy(array $criteria, array $order = null) + + public function getOneBy(array $criteria, ?array $order = null): ?NodeType { return $this->getRepository()->findOneBy($criteria, $order); } - /** - * {@inheritdoc} - */ - public function countBy(array $criteria) + + public function countBy(array $criteria): int { return $this->getRepository()->countBy($criteria); } diff --git a/src/EntityApi/TagApi.php b/src/EntityApi/TagApi.php index 3b363371..c894b897 100644 --- a/src/EntityApi/TagApi.php +++ b/src/EntityApi/TagApi.php @@ -8,12 +8,12 @@ use RZ\Roadiz\CoreBundle\Entity\Tag; use RZ\Roadiz\CoreBundle\Repository\TagRepository; +/** + * @deprecated Use TagRepository directly + */ class TagApi extends AbstractApi { - /** - * @return TagRepository - */ - public function getRepository() + public function getRepository(): TagRepository { return $this->managerRegistry->getRepository(Tag::class); } @@ -23,19 +23,14 @@ public function getRepository() * * When no order is defined, tags are ordered by position. * - * @param array $criteria - * @param array|null $order - * @param int|null $limit - * @param int|null $offset - * - * @return array|Paginator + * @return array|Paginator */ public function getBy( array $criteria, - array $order = null, + ?array $order = null, ?int $limit = null, - ?int $offset = null - ) { + ?int $offset = null, + ): array|Paginator { if (null === $order) { $order = [ 'position' => 'ASC', @@ -51,10 +46,8 @@ public function getBy( null ); } - /** - * {@inheritdoc} - */ - public function countBy(array $criteria) + + public function countBy(array $criteria): int { return $this->getRepository() ->countBy( @@ -62,10 +55,8 @@ public function countBy(array $criteria) null ); } - /** - * {@inheritdoc} - */ - public function getOneBy(array $criteria, array $order = null) + + public function getOneBy(array $criteria, ?array $order = null): ?Tag { return $this->getRepository() ->findOneBy( diff --git a/src/EntityHandler/CustomFormFieldHandler.php b/src/EntityHandler/CustomFormFieldHandler.php index dfa24595..38fc7b1b 100644 --- a/src/EntityHandler/CustomFormFieldHandler.php +++ b/src/EntityHandler/CustomFormFieldHandler.php @@ -15,31 +15,26 @@ final class CustomFormFieldHandler extends AbstractHandler { private ?CustomFormField $customFormField = null; - /** - * @param ObjectManager $objectManager - * @param CustomFormHandler $customFormHandler - */ public function __construct( ObjectManager $objectManager, - private readonly CustomFormHandler $customFormHandler + private readonly CustomFormHandler $customFormHandler, ) { parent::__construct($objectManager); } /** - * @param CustomFormField $customFormField * @return $this */ public function setCustomFormField(CustomFormField $customFormField): self { $this->customFormField = $customFormField; + return $this; } /** * Clean position for current customForm siblings. * - * @param bool $setPositions * @return float Return the next position after the **last** customFormField */ public function cleanPositions(bool $setPositions = true): float @@ -49,6 +44,7 @@ public function cleanPositions(bool $setPositions = true): float } $this->customFormHandler->setCustomForm($this->customFormField->getCustomForm()); + return $this->customFormHandler->cleanFieldsPositions($setPositions); } } diff --git a/src/EntityHandler/CustomFormHandler.php b/src/EntityHandler/CustomFormHandler.php index 721e121a..a04f0fd4 100644 --- a/src/EntityHandler/CustomFormHandler.php +++ b/src/EntityHandler/CustomFormHandler.php @@ -18,13 +18,13 @@ final class CustomFormHandler extends AbstractHandler public function setCustomForm(CustomForm $customForm): self { $this->customForm = $customForm; + return $this; } /** * Reset current node-type fields positions. * - * @param bool $setPositions * @return float Return the next position after the **last** field */ public function cleanFieldsPositions(bool $setPositions = true): float @@ -41,7 +41,7 @@ public function cleanFieldsPositions(bool $setPositions = true): float if ($setPositions) { $field->setPosition($i); } - $i++; + ++$i; } if ($setPositions) { diff --git a/src/EntityHandler/DocumentHandler.php b/src/EntityHandler/DocumentHandler.php index 44e9d885..75381fe9 100644 --- a/src/EntityHandler/DocumentHandler.php +++ b/src/EntityHandler/DocumentHandler.php @@ -34,8 +34,6 @@ public function __construct(ObjectManager $objectManager, private readonly Files * Get a Response object to force download document. * This method works for both private and public documents. * - * @param bool $asAttachment - * @return StreamedResponse * @throws FilesystemException */ public function getDownloadResponse(bool $asAttachment = true): StreamedResponse @@ -45,12 +43,13 @@ public function getDownloadResponse(bool $asAttachment = true): StreamedResponse if ($this->documentStorage->fileExists($documentPath)) { $headers = [ - "Content-Type" => $this->documentStorage->mimeType($documentPath), - "Content-Length" => $this->documentStorage->fileSize($documentPath), + 'Content-Type' => $this->documentStorage->mimeType($documentPath), + 'Content-Length' => $this->documentStorage->fileSize($documentPath), ]; if ($asAttachment) { - $headers["Content-disposition"] = "attachment; filename=\"" . basename($this->document->getFilename()) . "\""; + $headers['Content-disposition'] = 'attachment; filename="'.basename($this->document->getFilename()).'"'; } + return new StreamedResponse(function () use ($documentPath) { \fpassthru($this->documentStorage->readStream($documentPath)); }, Response::HTTP_OK, $headers); @@ -63,11 +62,8 @@ public function getDownloadResponse(bool $asAttachment = true): StreamedResponse /** * Return documents folders with the same translation as * current document. - * - * @param Translation|null $translation - * @return array */ - public function getFolders(Translation $translation = null): array + public function getFolders(?Translation $translation = null): array { if (!$this->document instanceof Document) { return []; @@ -92,12 +88,12 @@ public function getDocument(): ?DocumentInterface } /** - * @param DocumentInterface $document * @return $this */ public function setDocument(DocumentInterface $document): self { $this->document = $document; + return $this; } } diff --git a/src/EntityHandler/FolderHandler.php b/src/EntityHandler/FolderHandler.php index 5cb16fdb..5233f87d 100644 --- a/src/EntityHandler/FolderHandler.php +++ b/src/EntityHandler/FolderHandler.php @@ -20,16 +20,17 @@ public function getFolder(): Folder if (null === $this->folder) { throw new \BadMethodCallException('Folder is null'); } + return $this->folder; } /** - * @param Folder $folder * @return $this */ public function setFolder(Folder $folder): self { $this->folder = $folder; + return $this; } @@ -65,22 +66,23 @@ public function removeWithChildrenAndAssociations(): self * Final flush */ $this->objectManager->flush(); + return $this; } /** * Clean position for current folder siblings. * - * @param bool $setPositions * @return float Return the next position after the **last** folder */ public function cleanPositions(bool $setPositions = true): float { - if ($this->getFolder()->getParent() !== null) { + if (null !== $this->getFolder()->getParent()) { $parentHandler = new FolderHandler($this->objectManager); /** @var Folder|null $parent */ $parent = $this->getFolder()->getParent(); $parentHandler->setFolder($parent); + return $parentHandler->cleanChildrenPositions($setPositions); } else { return $this->cleanRootFoldersPositions($setPositions); @@ -92,7 +94,6 @@ public function cleanPositions(bool $setPositions = true): float * * Warning, this method does not flush. * - * @param bool $setPositions * @return float Return the next position after the **last** folder */ public function cleanChildrenPositions(bool $setPositions = true): float @@ -102,7 +103,7 @@ public function cleanChildrenPositions(bool $setPositions = true): float */ $sort = Criteria::create(); $sort->orderBy([ - 'position' => Criteria::ASC + 'position' => Criteria::ASC, ]); $children = $this->getFolder()->getChildren()->matching($sort); @@ -112,7 +113,7 @@ public function cleanChildrenPositions(bool $setPositions = true): float if ($setPositions) { $child->setPosition($i); } - $i++; + ++$i; } return $i; @@ -123,7 +124,6 @@ public function cleanChildrenPositions(bool $setPositions = true): float * * Warning, this method does not flush. * - * @param bool $setPositions * @return float Return the next position after the **last** folder */ public function cleanRootFoldersPositions(bool $setPositions = true): float @@ -138,7 +138,7 @@ public function cleanRootFoldersPositions(bool $setPositions = true): float if ($setPositions) { $child->setPosition($i); } - $i++; + ++$i; } return $i; diff --git a/src/EntityHandler/GroupHandler.php b/src/EntityHandler/GroupHandler.php index 9fb78ea9..751157bd 100644 --- a/src/EntityHandler/GroupHandler.php +++ b/src/EntityHandler/GroupHandler.php @@ -4,9 +4,9 @@ namespace RZ\Roadiz\CoreBundle\EntityHandler; +use RZ\Roadiz\Core\Handlers\AbstractHandler; use RZ\Roadiz\CoreBundle\Entity\Group; use RZ\Roadiz\CoreBundle\Entity\Role; -use RZ\Roadiz\Core\Handlers\AbstractHandler; /** * Handle operations with Group entities. @@ -20,27 +20,26 @@ public function getGroup(): Group if (null === $this->group) { throw new \BadMethodCallException('Group is null'); } + return $this->group; } /** - * @param Group $group * @return $this */ public function setGroup(Group $group): self { $this->group = $group; + return $this; } /** * This method does not flush ORM. You'll need to manually call it. - * - * @param Group $newGroup */ public function diff(Group $newGroup): void { - if ("" != $newGroup->getName()) { + if ('' != $newGroup->getName()) { $this->getGroup()->setName($newGroup->getName()); } diff --git a/src/EntityHandler/HandlerFactory.php b/src/EntityHandler/HandlerFactory.php index 860b941e..df97de0d 100644 --- a/src/EntityHandler/HandlerFactory.php +++ b/src/EntityHandler/HandlerFactory.php @@ -20,45 +20,43 @@ use RZ\Roadiz\CoreBundle\Entity\Tag; use RZ\Roadiz\CoreBundle\Entity\Translation; -final class HandlerFactory implements HandlerFactoryInterface +final readonly class HandlerFactory implements HandlerFactoryInterface { - public function __construct(private readonly ContainerInterface $container) + public function __construct(private ContainerInterface $container) { } /** - * @param AbstractEntity $entity - * @return AbstractHandler * @throws \Psr\Container\ContainerExceptionInterface * @throws \Psr\Container\NotFoundExceptionInterface */ public function getHandler(AbstractEntity $entity): AbstractHandler { switch (true) { - case ($entity instanceof Node): + case $entity instanceof Node: return $this->container->get(NodeHandler::class)->setNode($entity); - case ($entity instanceof NodesSources): + case $entity instanceof NodesSources: return $this->container->get(NodesSourcesHandler::class)->setNodeSource($entity); - case ($entity instanceof NodeType): + case $entity instanceof NodeType: return $this->container->get(NodeTypeHandler::class)->setNodeType($entity); - case ($entity instanceof NodeTypeField): + case $entity instanceof NodeTypeField: return $this->container->get(NodeTypeFieldHandler::class)->setNodeTypeField($entity); - case ($entity instanceof Document): + case $entity instanceof Document: return $this->container->get(DocumentHandler::class)->setDocument($entity); - case ($entity instanceof CustomForm): + case $entity instanceof CustomForm: return $this->container->get(CustomFormHandler::class)->setCustomForm($entity); - case ($entity instanceof CustomFormField): + case $entity instanceof CustomFormField: return $this->container->get(CustomFormFieldHandler::class)->setCustomFormField($entity); - case ($entity instanceof Folder): + case $entity instanceof Folder: return $this->container->get(FolderHandler::class)->setFolder($entity); - case ($entity instanceof Group): + case $entity instanceof Group: return $this->container->get(GroupHandler::class)->setGroup($entity); - case ($entity instanceof Tag): + case $entity instanceof Tag: return $this->container->get(TagHandler::class)->setTag($entity); - case ($entity instanceof Translation): + case $entity instanceof Translation: return $this->container->get(TranslationHandler::class)->setTranslation($entity); } - throw new \InvalidArgumentException('HandlerFactory does not support ' . get_class($entity)); + throw new \InvalidArgumentException('HandlerFactory does not support '.get_class($entity)); } } diff --git a/src/EntityHandler/NodeHandler.php b/src/EntityHandler/NodeHandler.php index fced6244..7a3deb1b 100644 --- a/src/EntityHandler/NodeHandler.php +++ b/src/EntityHandler/NodeHandler.php @@ -15,7 +15,6 @@ use RZ\Roadiz\CoreBundle\Entity\NodesSources; use RZ\Roadiz\CoreBundle\Entity\NodesToNodes; use RZ\Roadiz\CoreBundle\Entity\NodeTypeField; -use RZ\Roadiz\CoreBundle\Entity\Translation; use RZ\Roadiz\CoreBundle\Node\NodeDuplicator; use RZ\Roadiz\CoreBundle\Node\NodeNamePolicyInterface; use RZ\Roadiz\CoreBundle\Repository\NodeRepository; @@ -35,7 +34,7 @@ final public function __construct( ObjectManager $objectManager, private readonly Registry $registry, private readonly NodeChrootResolver $chrootResolver, - private readonly NodeNamePolicyInterface $nodeNamePolicy + private readonly NodeNamePolicyInterface $nodeNamePolicy, ) { parent::__construct($objectManager); } @@ -50,24 +49,22 @@ protected function createSelf(): self ); } - /** - * @return Node - */ public function getNode(): Node { if (null === $this->node) { throw new \BadMethodCallException('Node is null'); } + return $this->node; } /** - * @param Node $node * @return $this */ public function setNode(Node $node): self { $this->node = $node; + return $this; } @@ -75,7 +72,7 @@ public function setNode(Node $node): self * Remove every node to custom-forms associations for a given field. * * @param NodeTypeField $field - * @param bool $flush + * * @return $this */ public function cleanCustomFormsFromField(NodeTypeFieldInterface $field, bool $flush = true): self @@ -98,17 +95,15 @@ public function cleanCustomFormsFromField(NodeTypeFieldInterface $field, bool $f /** * Add a node to current custom-forms for a given node-type field. * - * @param CustomForm $customForm * @param NodeTypeField $field - * @param bool $flush - * @param null|float $position + * * @return $this */ public function addCustomFormForField( CustomForm $customForm, NodeTypeFieldInterface $field, bool $flush = true, - ?float $position = null + ?float $position = null, ): self { $ncf = new NodesCustomForms($this->getNode(), $customForm, $field); @@ -134,7 +129,6 @@ public function addCustomFormForField( * Get custom forms linked to current node for a given field name. * * @param string $fieldName Name of the node-type field - * @return array */ public function getCustomFormsFromFieldName(string $fieldName): array { @@ -150,7 +144,7 @@ public function getCustomFormsFromFieldName(string $fieldName): array * Remove every node to node associations for a given field. * * @param NodeTypeField $field - * @param bool $flush + * * @return $this */ public function cleanNodesFromField(NodeTypeFieldInterface $field, bool $flush = true): self @@ -167,10 +161,8 @@ public function cleanNodesFromField(NodeTypeFieldInterface $field, bool $flush = /** * Add a node to current node for a given node-type field. * - * @param Node $node * @param NodeTypeField $field - * @param bool $flush - * @param null|float $position + * * @return $this */ public function addNodeForField(Node $node, NodeTypeFieldInterface $field, bool $flush = true, ?float $position = null): self @@ -196,59 +188,6 @@ public function addNodeForField(Node $node, NodeTypeFieldInterface $field, bool return $this; } - /** - * Get nodes linked to current node for a given field name. - * - * @param string $fieldName Name of the node-type field - * @return Node[] - */ - public function getNodesFromFieldName(string $fieldName): array - { - $field = $this->getNode()->getNodeType()->getFieldByName($fieldName); - if (null !== $field) { - return $this->getRepository() - ->findByNodeAndField( - $this->getNode(), - $field - ); - } - return []; - } - - /** - * Get nodes reversed-linked to current node for a given field name. - * - * @param string $fieldName Name of the node-type field - * @return Node[] - */ - public function getReverseNodesFromFieldName(string $fieldName): array - { - $field = $this->getNode()->getNodeType()->getFieldByName($fieldName); - if (null !== $field) { - return $this->getRepository() - ->findByReverseNodeAndField( - $this->getNode(), - $field - ); - } - return []; - } - - /** - * Get node source by translation. - * - * @param Translation $translation - * - * @return null|NodesSources - * @deprecated Use Node::getNodeSourcesByTranslation() instead. - */ - public function getNodeSourceByTranslation($translation): ?NodesSources - { - return $this->objectManager - ->getRepository(NodesSources::class) - ->findOneBy(["node" => $this->getNode(), "translation" => $translation]); - } - /** * Remove only current node children. * @@ -265,6 +204,7 @@ private function removeChildren(): self return $this; } + /** * Remove only current node associations. * @@ -279,6 +219,7 @@ public function removeAssociations(): self return $this; } + /** * Remove current node with its children recursively and * its associations. @@ -296,9 +237,6 @@ public function removeWithChildrenAndAssociations(): self return $this; } - /** - * @return WorkflowInterface - */ private function getWorkflow(): WorkflowInterface { return $this->registry->get($this->getNode()); @@ -372,6 +310,7 @@ public function publishWithChildren(): self $handler->setNode($node); $handler->publishWithChildren(); } + return $this; } @@ -401,10 +340,6 @@ public function archiveWithChildren(): self /** * Return if part of Node offspring. - * - * @param Node $relative - * - * @return bool */ public function isRelatedToNode(Node $relative): bool { @@ -418,13 +353,13 @@ public function isRelatedToNode(Node $relative): bool return true; } } + return false; } /** - * Return every node’s parents + * Return every node’s parents. * - * @param TokenStorageInterface|null $tokenStorage * @return array */ public function getParents(?TokenStorageInterface $tokenStorage = null): array @@ -433,13 +368,13 @@ public function getParents(?TokenStorageInterface $tokenStorage = null): array $parent = $this->getNode()->getParent(); $chroot = null; - if ($tokenStorage !== null) { + if (null !== $tokenStorage) { $user = $tokenStorage->getToken()->getUser(); /** @var Node|null $chroot */ $chroot = $this->chrootResolver->getChroot($user); } - while ($parent !== null && $parent !== $chroot) { + while (null !== $parent && $parent !== $chroot) { $parentsArray[] = $parent; $parent = $parent->getParent(); } @@ -452,16 +387,16 @@ public function getParents(?TokenStorageInterface $tokenStorage = null): array * * Warning, this method does not flush. * - * @param bool $setPositions * @return float Return the next position after the **last** node */ public function cleanPositions(bool $setPositions = true): float { - if ($this->getNode()->getParent() !== null) { + if (null !== $this->getNode()->getParent()) { $parentHandler = $this->createSelf(); /** @var Node|null $parent */ $parent = $this->getNode()->getParent(); $parentHandler->setNode($parent); + return $parentHandler->cleanChildrenPositions($setPositions); } else { return $this->cleanRootNodesPositions($setPositions); @@ -473,7 +408,6 @@ public function cleanPositions(bool $setPositions = true): float * * Warning, this method does not flush. * - * @param bool $setPositions * @return float Return the next position after the **last** node */ public function cleanChildrenPositions(bool $setPositions = true): float @@ -483,7 +417,7 @@ public function cleanChildrenPositions(bool $setPositions = true): float */ $sort = Criteria::create(); $sort->orderBy([ - 'position' => Criteria::ASC + 'position' => Criteria::ASC, ]); $children = $this->getNode()->getChildren()->matching($sort); @@ -493,7 +427,7 @@ public function cleanChildrenPositions(bool $setPositions = true): float if ($setPositions) { $child->setPosition($i); } - $i++; + ++$i; } return $i; @@ -504,7 +438,6 @@ public function cleanChildrenPositions(bool $setPositions = true): float * * Warning, this method does not flush. * - * @param bool $setPositions * @return float Return the next position after the **last** node */ public function cleanRootNodesPositions(bool $setPositions = true): float @@ -519,49 +452,16 @@ public function cleanRootNodesPositions(bool $setPositions = true): float if ($setPositions) { $child->setPosition($i); } - $i++; + ++$i; } return $i; } - /** - * Return all node offspring id. - * - * @return array - * @deprecated Use NodeOffspringResolverInterface::getAllOffspringIds($chroot). - */ - public function getAllOffspringId(): array - { - return $this->getRepository()->findAllOffspringIdByNode($this->getNode()); - } - - /** - * Set current node as the Home node. - * - * @return $this - */ - public function makeHome(): self - { - $defaults = $this->getRepository() - ->setDisplayingNotPublishedNodes(true) - ->findBy(['home' => true]); - - /** @var Node $default */ - foreach ($defaults as $default) { - $default->setHome(false); - } - $this->getNode()->setHome(true); - $this->objectManager->flush(); - - return $this; - } - /** * Duplicate current node with all its children. * - * @return Node - * @deprecated Use NodeDuplicator::duplicate() instead. + * @deprecated use NodeDuplicator::duplicate() instead */ public function duplicate(): Node { @@ -570,22 +470,20 @@ public function duplicate(): Node $this->objectManager, $this->nodeNamePolicy ); + return $duplicator->duplicate(); } /** * Get previous node from hierarchy. * - * @param array|null $criteria - * @param array|null $order - * - * @return Node|null * @throws NonUniqueResultException - * @deprecated Use NodeRepository::findPreviousNode() instead. + * + * @deprecated use NodeRepository::findPreviousNode() instead */ public function getPrevious( ?array $criteria = null, - ?array $order = null + ?array $order = null, ): ?Node { if ($this->getNode()->getPosition() <= 1) { return null; @@ -619,16 +517,13 @@ public function getPrevious( /** * Get next node from hierarchy. * - * @param array|null $criteria - * @param array|null $order - * - * @return Node|null * @throws NonUniqueResultException - * @deprecated Use NodeRepository::findNextNode() instead. + * + * @deprecated use NodeRepository::findNextNode() instead */ public function getNext( ?array $criteria = null, - ?array $order = null + ?array $order = null, ): ?Node { if (null === $criteria) { $criteria = []; @@ -656,9 +551,6 @@ public function getNext( ); } - /** - * @return NodeRepository - */ protected function getRepository(): NodeRepository { return $this->objectManager->getRepository(Node::class); diff --git a/src/EntityHandler/NodeTypeFieldHandler.php b/src/EntityHandler/NodeTypeFieldHandler.php index 2a17f9d5..d660c2ec 100644 --- a/src/EntityHandler/NodeTypeFieldHandler.php +++ b/src/EntityHandler/NodeTypeFieldHandler.php @@ -5,9 +5,9 @@ namespace RZ\Roadiz\CoreBundle\EntityHandler; use Doctrine\Persistence\ObjectManager; +use RZ\Roadiz\Core\Handlers\AbstractHandler; use RZ\Roadiz\CoreBundle\Entity\NodeType; use RZ\Roadiz\CoreBundle\Entity\NodeTypeField; -use RZ\Roadiz\Core\Handlers\AbstractHandler; /** * Handle operations with node-type fields entities. @@ -21,16 +21,17 @@ public function getNodeTypeField(): NodeTypeField if (null === $this->nodeTypeField) { throw new \BadMethodCallException('NodeTypeField is null'); } + return $this->nodeTypeField; } /** - * @param NodeTypeField $nodeTypeField * @return $this */ public function setNodeTypeField(NodeTypeField $nodeTypeField): self { $this->nodeTypeField = $nodeTypeField; + return $this; } @@ -42,8 +43,8 @@ public function __construct(ObjectManager $objectManager, private readonly Handl /** * Clean position for current node siblings. * - * @param bool $setPositions * @return float Return the next position after the **last** node + * * @throws \Psr\Container\ContainerExceptionInterface * @throws \Psr\Container\NotFoundExceptionInterface */ @@ -52,6 +53,7 @@ public function cleanPositions(bool $setPositions = false): float if ($this->nodeTypeField->getNodeType() instanceof NodeType) { /** @var NodeTypeHandler $nodeTypeHandler */ $nodeTypeHandler = $this->handlerFactory->getHandler($this->nodeTypeField->getNodeType()); + return $nodeTypeHandler->cleanPositions(); } diff --git a/src/EntityHandler/NodeTypeHandler.php b/src/EntityHandler/NodeTypeHandler.php index e391a276..5e423b64 100644 --- a/src/EntityHandler/NodeTypeHandler.php +++ b/src/EntityHandler/NodeTypeHandler.php @@ -28,24 +28,22 @@ final class NodeTypeHandler extends AbstractHandler { private ?NodeType $nodeType = null; - /** - * @return NodeType - */ public function getNodeType(): NodeType { if (null === $this->nodeType) { throw new \BadMethodCallException('NodeType is null'); } + return $this->nodeType; } /** - * @param NodeType $nodeType * @return $this */ public function setNodeType(NodeType $nodeType): self { $this->nodeType = $nodeType; + return $this; } @@ -59,7 +57,7 @@ public function __construct( private readonly string $generatedEntitiesDir, private readonly string $serializedNodeTypesDir, private readonly string $importFilesConfigPath, - private readonly string $kernelProjectDir + private readonly string $kernelProjectDir, ) { parent::__construct($objectManager); } @@ -71,7 +69,7 @@ public function getGeneratedEntitiesFolder(): string public function getGeneratedRepositoriesFolder(): string { - return $this->getGeneratedEntitiesFolder() . DIRECTORY_SEPARATOR . 'Repository'; + return $this->getGeneratedEntitiesFolder().DIRECTORY_SEPARATOR.'Repository'; } /** @@ -96,6 +94,7 @@ public function removeSourceEntityClass(): bool 'file' => $file, 'repositoryFile' => $repositoryFile, ]); + return true; } @@ -111,20 +110,21 @@ public function exportNodeTypeJsonFile(): ?string 'json', SerializationContext::create()->setGroups(['node_type', 'position']) ); - $file = $this->serializedNodeTypesDir . DIRECTORY_SEPARATOR . $this->nodeType->getName() . '.json'; + $file = $this->serializedNodeTypesDir.DIRECTORY_SEPARATOR.$this->nodeType->getName().'.json'; @file_put_contents($file, $content); $this->addNodeTypeToImportFilesConfiguration($fileSystem, $file); return $file; } + return null; } protected function removeNodeTypeJsonFile(): void { $fileSystem = new Filesystem(); - $file = $this->serializedNodeTypesDir . DIRECTORY_SEPARATOR . $this->nodeType->getName() . '.json'; + $file = $this->serializedNodeTypesDir.DIRECTORY_SEPARATOR.$this->nodeType->getName().'.json'; if ($fileSystem->exists($file)) { @unlink($file); $this->removeNodeTypeFromImportFilesConfiguration($fileSystem, $file); @@ -140,7 +140,7 @@ protected function addNodeTypeToImportFilesConfiguration(Filesystem $fileSystem, $config = Yaml::parseFile($this->importFilesConfigPath); if (!isset($config['importFiles'])) { $config['importFiles'] = [ - 'nodetypes' => [] + 'nodetypes' => [], ]; } if (!isset($config['importFiles']['nodetypes'])) { @@ -148,7 +148,7 @@ protected function addNodeTypeToImportFilesConfiguration(Filesystem $fileSystem, } $relativePath = str_replace( - $this->kernelProjectDir . DIRECTORY_SEPARATOR, + $this->kernelProjectDir.DIRECTORY_SEPARATOR, '', $file ); @@ -181,7 +181,7 @@ protected function removeNodeTypeFromImportFilesConfiguration(Filesystem $fileSy } $relativePath = str_replace( - $this->kernelProjectDir . DIRECTORY_SEPARATOR, + $this->kernelProjectDir.DIRECTORY_SEPARATOR, '', $file ); @@ -201,8 +201,6 @@ protected function removeNodeTypeFromImportFilesConfiguration(Filesystem $fileSy /** * Generate Doctrine entity class for current node-type. - * - * @return bool */ public function generateSourceEntityClass(): bool { @@ -226,10 +224,10 @@ public function generateSourceEntityClass(): bool $repositoryContent = $repositoryGenerator->getClassContent(); if (false === @file_put_contents($file, $content)) { - throw new IOException("Impossible to write entity class file (" . $file . ").", 1); + throw new IOException('Impossible to write entity class file ('.$file.').', 1); } if (false === @file_put_contents($repositoryFile, $repositoryContent)) { - throw new IOException("Impossible to write entity class file (" . $repositoryFile . ").", 1); + throw new IOException('Impossible to write entity class file ('.$repositoryFile.').', 1); } /* * Force Zend OPcache to reset file @@ -252,19 +250,22 @@ public function generateSourceEntityClass(): bool return true; } + return false; } public function getSourceClassPath(): string { $folder = $this->getGeneratedEntitiesFolder(); - return $folder . DIRECTORY_SEPARATOR . $this->nodeType->getSourceEntityClassName() . '.php'; + + return $folder.DIRECTORY_SEPARATOR.$this->nodeType->getSourceEntityClassName().'.php'; } public function getRepositoryClassPath(): string { $folder = $this->getGeneratedRepositoriesFolder(); - return $folder . DIRECTORY_SEPARATOR . $this->nodeType->getSourceEntityClassName() . 'Repository.php'; + + return $folder.DIRECTORY_SEPARATOR.$this->nodeType->getSourceEntityClassName().'Repository.php'; } /** @@ -316,6 +317,7 @@ public function deleteSchema(): NodeTypeHandler * before removing it from node-types table. * * @return $this + * * @throws \Psr\Container\ContainerExceptionInterface * @throws \Psr\Container\NotFoundExceptionInterface */ @@ -355,7 +357,6 @@ public function deleteWithAssociations(): NodeTypeHandler /** * Reset current node-type fields positions. * - * @param bool $setPositions * @return float Return the next position after the **last** field */ public function cleanPositions(bool $setPositions = false): float @@ -367,7 +368,7 @@ public function cleanPositions(bool $setPositions = false): float /** @var NodeTypeField $field */ foreach ($fields as $field) { $field->setPosition($i); - $i++; + ++$i; } return $i; diff --git a/src/EntityHandler/NodesSourcesHandler.php b/src/EntityHandler/NodesSourcesHandler.php index 55b2eb90..23467a2f 100644 --- a/src/EntityHandler/NodesSourcesHandler.php +++ b/src/EntityHandler/NodesSourcesHandler.php @@ -10,7 +10,6 @@ use RZ\Roadiz\Core\Handlers\AbstractHandler; use RZ\Roadiz\CoreBundle\Bag\Settings; use RZ\Roadiz\CoreBundle\Entity\Document; -use RZ\Roadiz\CoreBundle\Entity\Node; use RZ\Roadiz\CoreBundle\Entity\NodesSources; use RZ\Roadiz\CoreBundle\Entity\NodesSourcesDocuments; use RZ\Roadiz\CoreBundle\Entity\NodeTypeField; @@ -40,24 +39,22 @@ protected function getRepository(): EntityRepository return $this->objectManager->getRepository(NodesSources::class); } - /** - * @return NodesSources - */ public function getNodeSource(): NodesSources { if (null === $this->nodeSource) { throw new \BadMethodCallException('NodesSources is null'); } + return $this->nodeSource; } /** - * @param NodesSources $nodeSource * @return $this */ public function setNodeSource(NodesSources $nodeSource): self { $this->nodeSource = $nodeSource; + return $this; } @@ -65,7 +62,7 @@ public function setNodeSource(NodesSources $nodeSource): self * Remove every node-source documents associations for a given field. * * @param NodeTypeField $field - * @param bool $flush + * * @return $this */ public function cleanDocumentsFromField(NodeTypeFieldInterface $field, bool $flush = true): self @@ -82,17 +79,15 @@ public function cleanDocumentsFromField(NodeTypeFieldInterface $field, bool $flu /** * Add a document to current node-source for a given node-type field. * - * @param Document $document * @param NodeTypeField $field - * @param bool $flush - * @param null|float $position + * * @return $this */ public function addDocumentForField( Document $document, NodeTypeFieldInterface $field, bool $flush = true, - ?float $position = null + ?float $position = null, ): self { $nsDoc = new NodesSourcesDocuments($this->nodeSource, $document, $field); @@ -120,7 +115,9 @@ public function addDocumentForField( * Get documents linked to current node-source for a given field name. * * @param string $fieldName Name of the node-type field + * * @return array + * * @deprecated Use directly NodesSources::getDocumentsByFieldsWithName */ public function getDocumentsFromFieldName(string $fieldName): array @@ -137,8 +134,8 @@ public function getDocumentsFromFieldName(string $fieldName): array * Get a string describing uniquely the current nodeSource. * * Can be the urlAlias or the nodeName + * * @deprecated Use directly NodesSources::getIdentifier - * @return string */ public function getIdentifier(): string { @@ -154,7 +151,6 @@ public function getIdentifier(): string * Get parent node-source to get the current translation. * * @deprecated Use directly NodesSources::getParent - * @return NodesSources|null */ public function getParent(): ?NodesSources { @@ -164,12 +160,12 @@ public function getParent(): ?NodesSources /** * Get every nodeSources parents from direct parent to farest ancestor. * - * @param array|null $criteria * @return array + * * @deprecated Use NodesSourcesRepository::findParents */ public function getParents( - array $criteria = null + ?array $criteria = null, ): array { if (null === $this->parentsNodeSources) { $this->parentsNodeSources = []; @@ -208,14 +204,15 @@ public function getParents( * Get children nodes sources to lock with current translation. * * @param array|null $criteria Additional criteria - * @param array|null $order Non default ordering + * @param array|null $order Non default ordering * * @return array + * * @deprecated Use TreeWalker or NodesSourcesRepository::findChildren */ public function getChildren( - array $criteria = null, - array $order = null + ?array $criteria = null, + ?array $order = null, ): array { $defaultCrit = [ 'node.parent' => $this->nodeSource->getNode(), @@ -243,19 +240,15 @@ public function getChildren( /** * Get first node-source among current node-source children. * - * @param array|null $criteria - * @param array|null $order - * - * @return NodesSources|null * @deprecated Use NodesSourcesRepository::findFirstChild */ public function getFirstChild( - array $criteria = null, - array $order = null + ?array $criteria = null, + ?array $order = null, ): ?NodesSources { $defaultCrit = [ 'node.parent' => $this->nodeSource->getNode(), - 'translation' => $this->nodeSource->getTranslation() + 'translation' => $this->nodeSource->getTranslation(), ]; if (null !== $order) { @@ -275,18 +268,15 @@ public function getFirstChild( $defaultOrder ); } + /** * Get last node-source among current node-source children. * - * @param array|null $criteria - * @param array|null $order - * - * @return NodesSources|null * @deprecated Use NodesSourcesRepository::findLastChild */ public function getLastChild( - array $criteria = null, - array $order = null + ?array $criteria = null, + ?array $order = null, ): ?NodesSources { $defaultCrit = [ 'node.parent' => $this->nodeSource->getNode(), @@ -314,22 +304,20 @@ public function getLastChild( /** * Get first node-source in the same parent as current node-source. * - * @param array|null $criteria - * @param array|null $order - * - * @return NodesSources|null * @deprecated Use NodesSourcesRepository::findFirstSibling */ public function getFirstSibling( - array $criteria = null, - array $order = null + ?array $criteria = null, + ?array $order = null, ): ?NodesSources { if (null !== $this->nodeSource->getParent()) { $parentHandler = new NodesSourcesHandler($this->objectManager, $this->settingsBag); $parentHandler->setNodeSource($this->nodeSource->getParent()); + return $parentHandler->getFirstChild($criteria, $order); } else { $criteria['node.parent'] = null; + return $this->getFirstChild($criteria, $order); } } @@ -337,22 +325,20 @@ public function getFirstSibling( /** * Get last node-source in the same parent as current node-source. * - * @param array|null $criteria - * @param array|null $order - * - * @return NodesSources|null * @deprecated Use NodesSourcesRepository::findLastSibling */ public function getLastSibling( - array $criteria = null, - array $order = null + ?array $criteria = null, + ?array $order = null, ): ?NodesSources { if (null !== $this->nodeSource->getParent()) { $parentHandler = new NodesSourcesHandler($this->objectManager, $this->settingsBag); $parentHandler->setNodeSource($this->nodeSource->getParent()); + return $parentHandler->getLastChild($criteria, $order); } else { $criteria['node.parent'] = null; + return $this->getLastChild($criteria, $order); } } @@ -360,15 +346,11 @@ public function getLastSibling( /** * Get previous node-source from hierarchy. * - * @param array|null $criteria - * @param array|null $order - * - * @return NodesSources|null * @deprecated Use NodesSourcesRepository::findPrevious */ public function getPrevious( - array $criteria = null, - array $order = null + ?array $criteria = null, + ?array $order = null, ): ?NodesSources { if ($this->nodeSource->getNode()->getPosition() <= 1) { return null; @@ -407,15 +389,11 @@ public function getPrevious( /** * Get next node-source from hierarchy. * - * @param array|null $criteria - * @param array|null $order - * - * @return NodesSources|null * @deprecated Use NodesSourcesRepository::findNext */ public function getNext( - array $criteria = null, - array $order = null + ?array $criteria = null, + ?array $order = null, ): ?NodesSources { $defaultCrit = [ /* @@ -451,16 +429,17 @@ public function getNext( * Get node tags with current source translation. * * @return iterable + * * @deprecated Use TagRepository::findByNodesSources */ public function getTags(): iterable { - /** + /* * @phpstan-ignore-next-line */ return $this->objectManager->getRepository(Tag::class)->findBy([ - "nodes" => $this->nodeSource->getNode(), - "translation" => $this->nodeSource->getTranslation(), + 'nodes' => $this->nodeSource->getNode(), + 'translation' => $this->nodeSource->getTranslation(), ], [ 'position' => 'ASC', ]); @@ -480,56 +459,12 @@ public function getTags(): iterable public function getSEO(): array { return [ - 'title' => ($this->nodeSource->getMetaTitle() != "") ? + 'title' => ('' != $this->nodeSource->getMetaTitle()) ? $this->nodeSource->getMetaTitle() : - $this->nodeSource->getTitle() . ' – ' . $this->settingsBag->get('site_name'), - 'description' => ($this->nodeSource->getMetaDescription() != "") ? + $this->nodeSource->getTitle().' – '.$this->settingsBag->get('site_name'), + 'description' => ('' != $this->nodeSource->getMetaDescription()) ? $this->nodeSource->getMetaDescription() : - $this->nodeSource->getTitle() . ', ' . $this->settingsBag->get('seo_description'), + $this->nodeSource->getTitle().', '.$this->settingsBag->get('seo_description'), ]; } - - /** - * Get nodes linked to current node for a given fieldname. - * - * @param string $fieldName Name of the node-type field - * - * @return array Collection of nodes - */ - public function getNodesFromFieldName(string $fieldName): array - { - $field = $this->nodeSource->getNode()->getNodeType()->getFieldByName($fieldName); - if (null !== $field) { - return $this->objectManager - ->getRepository(Node::class) - ->findByNodeAndFieldAndTranslation( - $this->nodeSource->getNode(), - $field, - $this->nodeSource->getTranslation() - ); - } - return []; - } - - /** - * Get nodes which own a reference to current node for a given fieldname. - * - * @param string $fieldName Name of the node-type field - * - * @return array Collection of nodes - */ - public function getReverseNodesFromFieldName(string $fieldName): array - { - $field = $this->nodeSource->getNode()->getNodeType()->getFieldByName($fieldName); - if (null !== $field) { - return $this->objectManager - ->getRepository(Node::class) - ->findByReverseNodeAndFieldAndTranslation( - $this->nodeSource->getNode(), - $field, - $this->nodeSource->getTranslation() - ); - } - return []; - } } diff --git a/src/EntityHandler/TagHandler.php b/src/EntityHandler/TagHandler.php index 355d583a..180a1a5e 100644 --- a/src/EntityHandler/TagHandler.php +++ b/src/EntityHandler/TagHandler.php @@ -16,12 +16,12 @@ final class TagHandler extends AbstractHandler private ?Tag $tag = null; /** - * @param Tag $tag * @return $this */ public function setTag(Tag $tag): self { $this->tag = $tag; + return $this; } @@ -41,6 +41,7 @@ private function removeChildren(): self return $this; } + /** * Remove only current tag associations. * @@ -54,6 +55,7 @@ public function removeAssociations(): self return $this; } + /** * Remove current tag with its children recursively and * its associations. @@ -78,16 +80,16 @@ public function removeWithChildrenAndAssociations(): self /** * Clean position for current tag siblings. * - * @param bool $setPositions * @return float Return the next position after the **last** tag */ public function cleanPositions(bool $setPositions = true): float { - if ($this->tag->getParent() !== null) { + if (null !== $this->tag->getParent()) { $tagHandler = new TagHandler($this->objectManager); /** @var Tag|null $parent */ $parent = $this->tag->getParent(); $tagHandler->setTag($parent); + return $tagHandler->cleanChildrenPositions($setPositions); } else { return $this->cleanRootTagsPositions($setPositions); @@ -99,7 +101,6 @@ public function cleanPositions(bool $setPositions = true): float * * Warning, this method does not flush. * - * @param bool $setPositions * @return float Return the next position after the **last** tag */ public function cleanChildrenPositions(bool $setPositions = true): float @@ -109,7 +110,7 @@ public function cleanChildrenPositions(bool $setPositions = true): float */ $sort = Criteria::create(); $sort->orderBy([ - 'position' => Criteria::ASC + 'position' => Criteria::ASC, ]); $children = $this->tag->getChildren()->matching($sort); @@ -119,7 +120,7 @@ public function cleanChildrenPositions(bool $setPositions = true): float if ($setPositions) { $child->setPosition($i); } - $i++; + ++$i; } return $i; @@ -130,7 +131,6 @@ public function cleanChildrenPositions(bool $setPositions = true): float * * Warning, this method does not flush. * - * @param bool $setPositions * @return float Return the next position after the **last** tag */ public function cleanRootTagsPositions(bool $setPositions = true): float @@ -145,7 +145,7 @@ public function cleanRootTagsPositions(bool $setPositions = true): float if ($setPositions) { $child->setPosition($i); } - $i++; + ++$i; } return $i; diff --git a/src/EntityHandler/TranslationHandler.php b/src/EntityHandler/TranslationHandler.php index 6f3f30ea..e55c70b3 100644 --- a/src/EntityHandler/TranslationHandler.php +++ b/src/EntityHandler/TranslationHandler.php @@ -19,13 +19,12 @@ final class TranslationHandler extends AbstractHandler private ?TranslationInterface $translation = null; /** - * @param TranslationInterface $translation - * * @return $this */ public function setTranslation(TranslationInterface $translation): self { $this->translation = $translation; + return $this; } diff --git a/src/Enum/NodeStatus.php b/src/Enum/NodeStatus.php new file mode 100644 index 00000000..5593658b --- /dev/null +++ b/src/Enum/NodeStatus.php @@ -0,0 +1,88 @@ + 'draft', + NodeStatus::PENDING => 'pending', + NodeStatus::PUBLISHED => 'published', + NodeStatus::ARCHIVED => 'archived', + NodeStatus::DELETED => 'deleted', + }; + } + + public static function fromLabel(string $label): self + { + return match (strtolower($label)) { + 'pending' => NodeStatus::PENDING, + 'published' => NodeStatus::PUBLISHED, + 'archived' => NodeStatus::ARCHIVED, + 'deleted' => NodeStatus::DELETED, + default => NodeStatus::DRAFT, + }; + } + + public static function fromName(string $name): self + { + return match (strtoupper($name)) { + 'PENDING' => NodeStatus::PENDING, + 'PUBLISHED' => NodeStatus::PUBLISHED, + 'ARCHIVED' => NodeStatus::ARCHIVED, + 'DELETED' => NodeStatus::DELETED, + default => NodeStatus::DRAFT, + }; + } + + public static function allLabelsAndValues(): array + { + return array_combine( + array_map(fn (NodeStatus $status) => $status->getLabel(), self::cases()), + array_map(fn (NodeStatus $status) => $status->value, self::cases()) + ); + } + + public function isPublished(): bool + { + return NodeStatus::PUBLISHED === $this; + } + + public function isPending(): bool + { + return NodeStatus::PENDING === $this; + } + + public function isDraft(): bool + { + return NodeStatus::DRAFT === $this; + } + + public function isDeleted(): bool + { + return NodeStatus::DELETED === $this; + } + + public function isArchived(): bool + { + return NodeStatus::ARCHIVED === $this; + } + + public function trans(TranslatorInterface $translator, ?string $locale = null): string + { + return $translator->trans($this->getLabel(), locale: $locale); + } +} diff --git a/src/Event/Document/DocumentTranslationIndexingEvent.php b/src/Event/Document/DocumentTranslationIndexingEvent.php index 1130fb58..692ce82e 100644 --- a/src/Event/Document/DocumentTranslationIndexingEvent.php +++ b/src/Event/Document/DocumentTranslationIndexingEvent.php @@ -14,49 +14,34 @@ public function __construct( private readonly DocumentTranslation $documentTranslation, private array $associations, private readonly AbstractSolarium $solariumDocument, - private readonly bool $subResource = false + private readonly bool $subResource = false, ) { } - /** - * @return DocumentTranslation - */ public function getDocumentTranslation(): DocumentTranslation { return $this->documentTranslation; } - /** - * @return array - */ public function getAssociations(): array { return $this->associations; } - /** - * @return AbstractSolarium - */ public function getSolariumDocument(): AbstractSolarium { return $this->solariumDocument; } - /** - * @return bool - */ public function isSubResource(): bool { return $this->subResource; } - /** - * @param array $associations - * @return DocumentTranslationIndexingEvent - */ public function setAssociations(array $associations): DocumentTranslationIndexingEvent { $this->associations = $associations; + return $this; } } diff --git a/src/Event/Document/DocumentTranslationUpdatedEvent.php b/src/Event/Document/DocumentTranslationUpdatedEvent.php index bf889883..80aa9284 100644 --- a/src/Event/Document/DocumentTranslationUpdatedEvent.php +++ b/src/Event/Document/DocumentTranslationUpdatedEvent.php @@ -12,14 +12,11 @@ final class DocumentTranslationUpdatedEvent extends FilterDocumentEvent { public function __construct( DocumentInterface $document, - private readonly ?DocumentTranslation $documentTranslation = null + private readonly ?DocumentTranslation $documentTranslation = null, ) { parent::__construct($document); } - /** - * @return DocumentTranslation|null - */ public function getDocumentTranslation(): ?DocumentTranslation { return $this->documentTranslation; diff --git a/src/Event/FilterCacheEvent.php b/src/Event/FilterCacheEvent.php index 934e18b5..5a6ef779 100644 --- a/src/Event/FilterCacheEvent.php +++ b/src/Event/FilterCacheEvent.php @@ -8,9 +8,6 @@ use Doctrine\Common\Collections\Collection; use Symfony\Contracts\EventDispatcher\Event; -/** - * @package RZ\Roadiz\CoreBundle\Event - */ abstract class FilterCacheEvent extends Event { private Collection $messageCollection; @@ -22,45 +19,29 @@ public function __construct() $this->errorCollection = new ArrayCollection(); } - /** - * @param string $message - * @param string|null $classname - * @param string|null $description - */ public function addMessage(string $message, ?string $classname = null, ?string $description = null): void { $this->messageCollection->add([ - "clearer" => $classname, - "description" => $description, - "message" => $message, + 'clearer' => $classname, + 'description' => $description, + 'message' => $message, ]); } - /** - * @param string $message - * @param string|null $classname - * @param string|null $description - */ public function addError(string $message, ?string $classname = null, ?string $description = null): void { $this->errorCollection->add([ - "clearer" => $classname, - "description" => $description, - "message" => $message, + 'clearer' => $classname, + 'description' => $description, + 'message' => $message, ]); } - /** - * @return array - */ public function getErrors(): array { return $this->errorCollection->toArray(); } - /** - * @return array - */ public function getMessages(): array { return $this->messageCollection->toArray(); diff --git a/src/Event/FilterFolderEvent.php b/src/Event/FilterFolderEvent.php index eb426b11..db042169 100644 --- a/src/Event/FilterFolderEvent.php +++ b/src/Event/FilterFolderEvent.php @@ -7,16 +7,10 @@ use RZ\Roadiz\CoreBundle\Entity\Folder; use Symfony\Contracts\EventDispatcher\Event; -/** - * @package RZ\Roadiz\CoreBundle\Event - */ abstract class FilterFolderEvent extends Event { - protected Folder $folder; - - public function __construct(Folder $folder) + public function __construct(protected readonly Folder $folder) { - $this->folder = $folder; } public function getFolder(): Folder diff --git a/src/Event/FilterNodeEvent.php b/src/Event/FilterNodeEvent.php index c04c2639..c13ceaca 100644 --- a/src/Event/FilterNodeEvent.php +++ b/src/Event/FilterNodeEvent.php @@ -7,16 +7,10 @@ use RZ\Roadiz\CoreBundle\Entity\Node; use Symfony\Contracts\EventDispatcher\Event; -/** - * @package RZ\Roadiz\CoreBundle\Event - */ abstract class FilterNodeEvent extends Event { - protected Node $node; - - public function __construct(Node $node) + public function __construct(protected readonly Node $node) { - $this->node = $node; } public function getNode(): Node diff --git a/src/Event/FilterNodePathEvent.php b/src/Event/FilterNodePathEvent.php index ed4cc2f9..4e2b3e39 100644 --- a/src/Event/FilterNodePathEvent.php +++ b/src/Event/FilterNodePathEvent.php @@ -6,37 +6,21 @@ use RZ\Roadiz\CoreBundle\Entity\Node; -/** - * @package RZ\Roadiz\CoreBundle\Event - */ abstract class FilterNodePathEvent extends FilterNodeEvent { - protected array $paths; - protected ?\DateTime $updatedAt; - - /** - * @param Node $node - * @param array $paths - * @param \DateTime|null $updatedAt - */ - public function __construct(Node $node, array $paths = [], \DateTime $updatedAt = null) - { + public function __construct( + Node $node, + protected readonly array $paths = [], + protected readonly ?\DateTime $updatedAt = null, + ) { parent::__construct($node); - $this->paths = $paths; - $this->updatedAt = $updatedAt; } - /** - * @return array - */ public function getPaths(): array { return $this->paths; } - /** - * @return \DateTime|null - */ public function getUpdatedAt(): ?\DateTime { return $this->updatedAt; diff --git a/src/Event/FilterNodesSourcesEvent.php b/src/Event/FilterNodesSourcesEvent.php index be277645..b816134e 100644 --- a/src/Event/FilterNodesSourcesEvent.php +++ b/src/Event/FilterNodesSourcesEvent.php @@ -7,16 +7,10 @@ use RZ\Roadiz\CoreBundle\Entity\NodesSources; use Symfony\Contracts\EventDispatcher\Event; -/** - * @package RZ\Roadiz\CoreBundle\Event - */ abstract class FilterNodesSourcesEvent extends Event { - protected NodesSources $nodeSource; - - public function __construct(NodesSources $nodeSource) + public function __construct(protected readonly NodesSources $nodeSource) { - $this->nodeSource = $nodeSource; } public function getNodeSource(): NodesSources diff --git a/src/Event/FilterSettingEvent.php b/src/Event/FilterSettingEvent.php index edbd0d1c..d0b2be0a 100644 --- a/src/Event/FilterSettingEvent.php +++ b/src/Event/FilterSettingEvent.php @@ -9,11 +9,8 @@ abstract class FilterSettingEvent extends Event { - protected Setting $setting; - - public function __construct(Setting $setting) + public function __construct(protected readonly Setting $setting) { - $this->setting = $setting; } public function getSetting(): Setting diff --git a/src/Event/FilterTagEvent.php b/src/Event/FilterTagEvent.php index 9bb701d0..7a3ab303 100644 --- a/src/Event/FilterTagEvent.php +++ b/src/Event/FilterTagEvent.php @@ -7,19 +7,10 @@ use RZ\Roadiz\CoreBundle\Entity\Tag; use Symfony\Contracts\EventDispatcher\Event; -/** - * @package RZ\Roadiz\CoreBundle\Event - */ abstract class FilterTagEvent extends Event { - protected Tag $tag; - - /** - * @param Tag $tag - */ - public function __construct(Tag $tag) + public function __construct(protected readonly Tag $tag) { - $this->tag = $tag; } public function getTag(): Tag diff --git a/src/Event/FilterTranslationEvent.php b/src/Event/FilterTranslationEvent.php index 2e66b738..a8c1a391 100644 --- a/src/Event/FilterTranslationEvent.php +++ b/src/Event/FilterTranslationEvent.php @@ -7,16 +7,10 @@ use RZ\Roadiz\CoreBundle\Entity\Translation; use Symfony\Contracts\EventDispatcher\Event; -/** - * @package RZ\Roadiz\CoreBundle\Event - */ abstract class FilterTranslationEvent extends Event { - protected Translation $translation; - - public function __construct(Translation $translation) + public function __construct(protected readonly Translation $translation) { - $this->translation = $translation; } public function getTranslation(): Translation diff --git a/src/Event/FilterUrlAliasEvent.php b/src/Event/FilterUrlAliasEvent.php index 922c8c70..7d01d476 100644 --- a/src/Event/FilterUrlAliasEvent.php +++ b/src/Event/FilterUrlAliasEvent.php @@ -7,16 +7,10 @@ use RZ\Roadiz\CoreBundle\Entity\UrlAlias; use Symfony\Contracts\EventDispatcher\Event; -/** - * @package RZ\Roadiz\CoreBundle\Event - */ abstract class FilterUrlAliasEvent extends Event { - protected UrlAlias $urlAlias; - - public function __construct(UrlAlias $urlAlias) + public function __construct(protected readonly UrlAlias $urlAlias) { - $this->urlAlias = $urlAlias; } public function getUrlAlias(): UrlAlias diff --git a/src/Event/FilterUserEvent.php b/src/Event/FilterUserEvent.php index 449e75a6..d1e3adea 100644 --- a/src/Event/FilterUserEvent.php +++ b/src/Event/FilterUserEvent.php @@ -7,16 +7,10 @@ use RZ\Roadiz\CoreBundle\Entity\User; use Symfony\Contracts\EventDispatcher\Event; -/** - * @package RZ\Roadiz\CoreBundle\Event - */ abstract class FilterUserEvent extends Event { - private User $user; - - public function __construct(User $user) + public function __construct(protected readonly User $user) { - $this->user = $user; } public function getUser(): User diff --git a/src/Event/NodesSources/NodesSourcesIndexingEvent.php b/src/Event/NodesSources/NodesSourcesIndexingEvent.php index 9e8381e0..10a2e931 100644 --- a/src/Event/NodesSources/NodesSourcesIndexingEvent.php +++ b/src/Event/NodesSources/NodesSourcesIndexingEvent.php @@ -14,7 +14,7 @@ public function __construct( private readonly NodesSources $nodeSource, private array $associations, private readonly AbstractSolarium $solariumDocument, - private readonly bool $subResource = false + private readonly bool $subResource = false, ) { } @@ -25,8 +25,6 @@ public function getNodeSource(): NodesSources /** * Get Solr document data to index. - * - * @return array */ public function getAssociations(): array { @@ -35,13 +33,11 @@ public function getAssociations(): array /** * Set Solr document data to index. - * - * @param array $associations - * @return NodesSourcesIndexingEvent */ public function setAssociations(array $associations): NodesSourcesIndexingEvent { $this->associations = $associations; + return $this; } diff --git a/src/Event/NodesSources/NodesSourcesPathGeneratingEvent.php b/src/Event/NodesSources/NodesSourcesPathGeneratingEvent.php index 2efc28d3..c3c613be 100644 --- a/src/Event/NodesSources/NodesSourcesPathGeneratingEvent.php +++ b/src/Event/NodesSources/NodesSourcesPathGeneratingEvent.php @@ -13,50 +13,31 @@ final class NodesSourcesPathGeneratingEvent extends Event { private ?string $path; /** - * @var bool Tells Node Router to prepend request context information to path or not. + * @var bool tells Node Router to prepend request context information to path or not */ private bool $isComplete = false; protected bool $containsScheme = false; - /** - * @param Theme|null $theme - * @param NodesSources|null $nodeSource - * @param RequestContext|null $requestContext - * @param array $parameters - * @param bool $forceLocale - * @param bool $forceLocaleWithUrlAlias - */ public function __construct( private readonly ?Theme $theme, private ?NodesSources $nodeSource, private readonly ?RequestContext $requestContext, private array $parameters = [], private readonly bool $forceLocale = false, - private bool $forceLocaleWithUrlAlias = false + private bool $forceLocaleWithUrlAlias = false, ) { } - /** - * @return Theme|null - */ public function getTheme(): ?Theme { return $this->theme; } - /** - * @return NodesSources|null - */ public function getNodeSource(): ?NodesSources { return $this->nodeSource; } - /** - * @param NodesSources|null $nodeSource - * - * @return NodesSourcesPathGeneratingEvent - */ public function setNodeSource(?NodesSources $nodeSource): NodesSourcesPathGeneratingEvent { $this->nodeSource = $nodeSource; @@ -64,35 +45,21 @@ public function setNodeSource(?NodesSources $nodeSource): NodesSourcesPathGenera return $this; } - /** - * @return RequestContext|null - */ public function getRequestContext(): ?RequestContext { return $this->requestContext; } - /** - * @return bool - */ public function isForceLocale(): bool { return $this->forceLocale; } - /** - * @return string|null - */ public function getPath(): ?string { return $this->path; } - /** - * @param string|null $path - * - * @return NodesSourcesPathGeneratingEvent - */ public function setPath(?string $path): NodesSourcesPathGeneratingEvent { $this->path = $path; @@ -100,19 +67,11 @@ public function setPath(?string $path): NodesSourcesPathGeneratingEvent return $this; } - /** - * @return array|null - */ public function getParameters(): ?array { return $this->parameters; } - /** - * @param array|null $parameters - * - * @return NodesSourcesPathGeneratingEvent - */ public function setParameters(?array $parameters): NodesSourcesPathGeneratingEvent { $this->parameters = $parameters; @@ -120,19 +79,11 @@ public function setParameters(?array $parameters): NodesSourcesPathGeneratingEve return $this; } - /** - * @return bool - */ public function isComplete(): bool { return $this->isComplete; } - /** - * @param bool $isComplete - * - * @return NodesSourcesPathGeneratingEvent - */ public function setComplete(bool $isComplete): NodesSourcesPathGeneratingEvent { $this->isComplete = $isComplete; @@ -140,19 +91,11 @@ public function setComplete(bool $isComplete): NodesSourcesPathGeneratingEvent return $this; } - /** - * @return bool - */ public function containsScheme(): bool { return $this->containsScheme; } - /** - * @param bool $containsScheme - * - * @return NodesSourcesPathGeneratingEvent - */ public function setContainsScheme(bool $containsScheme): NodesSourcesPathGeneratingEvent { $this->containsScheme = $containsScheme; @@ -160,19 +103,11 @@ public function setContainsScheme(bool $containsScheme): NodesSourcesPathGenerat return $this; } - /** - * @return bool - */ public function isForceLocaleWithUrlAlias(): bool { return $this->forceLocaleWithUrlAlias; } - /** - * @param bool $forceLocaleWithUrlAlias - * - * @return NodesSourcesPathGeneratingEvent - */ public function setForceLocaleWithUrlAlias(bool $forceLocaleWithUrlAlias): NodesSourcesPathGeneratingEvent { $this->forceLocaleWithUrlAlias = $forceLocaleWithUrlAlias; diff --git a/src/Event/Realm/AbstractRealmNodeEvent.php b/src/Event/Realm/AbstractRealmNodeEvent.php index ab6554c1..433663fe 100644 --- a/src/Event/Realm/AbstractRealmNodeEvent.php +++ b/src/Event/Realm/AbstractRealmNodeEvent.php @@ -4,8 +4,6 @@ namespace RZ\Roadiz\CoreBundle\Event\Realm; -use RZ\Roadiz\CoreBundle\Entity\Node; -use RZ\Roadiz\CoreBundle\Entity\Realm; use RZ\Roadiz\CoreBundle\Entity\RealmNode; use Symfony\Contracts\EventDispatcher\Event; @@ -18,9 +16,6 @@ public function __construct(RealmNode $realmNode) $this->realmNode = $realmNode; } - /** - * @return RealmNode - */ public function getRealmNode(): RealmNode { return $this->realmNode; diff --git a/src/Event/Redirection/RedirectionEvent.php b/src/Event/Redirection/RedirectionEvent.php index 3d379471..60c0a07f 100644 --- a/src/Event/Redirection/RedirectionEvent.php +++ b/src/Event/Redirection/RedirectionEvent.php @@ -11,29 +11,20 @@ abstract class RedirectionEvent extends Event { protected ?Redirection $redirection; - /** - * @param Redirection|null $redirection - */ public function __construct(?Redirection $redirection) { $this->redirection = $redirection; } - /** - * @return Redirection|null - */ public function getRedirection(): ?Redirection { return $this->redirection; } - /** - * @param Redirection|null $redirection - * @return RedirectionEvent - */ public function setRedirection(?Redirection $redirection): RedirectionEvent { $this->redirection = $redirection; + return $this; } } diff --git a/src/Event/Role/RoleEvent.php b/src/Event/Role/RoleEvent.php index 7f292e06..73d1b4d9 100644 --- a/src/Event/Role/RoleEvent.php +++ b/src/Event/Role/RoleEvent.php @@ -14,29 +14,20 @@ abstract class RoleEvent extends Event */ protected $role; - /** - * @param Role|null $role - */ public function __construct(?Role $role) { $this->role = $role; } - /** - * @return Role|null - */ public function getRole(): ?Role { return $this->role; } - /** - * @param Role|null $role - * @return RoleEvent - */ public function setRole(?Role $role): RoleEvent { $this->role = $role; + return $this; } } diff --git a/src/Event/User/UserJoinedGroupEvent.php b/src/Event/User/UserJoinedGroupEvent.php index 77c1ef3b..2e778f53 100644 --- a/src/Event/User/UserJoinedGroupEvent.php +++ b/src/Event/User/UserJoinedGroupEvent.php @@ -15,9 +15,6 @@ public function __construct(User $user, private readonly Group $group) parent::__construct($user); } - /** - * @return Group - */ public function getGroup(): Group { return $this->group; diff --git a/src/Event/User/UserLeavedGroupEvent.php b/src/Event/User/UserLeavedGroupEvent.php index e776a374..105ce030 100644 --- a/src/Event/User/UserLeavedGroupEvent.php +++ b/src/Event/User/UserLeavedGroupEvent.php @@ -15,9 +15,6 @@ public function __construct(User $user, private readonly Group $group) parent::__construct($user); } - /** - * @return Group - */ public function getGroup(): Group { return $this->group; diff --git a/src/EventSubscriber/AssetsCacheEventSubscriber.php b/src/EventSubscriber/AssetsCacheEventSubscriber.php index 664344d0..6faec771 100644 --- a/src/EventSubscriber/AssetsCacheEventSubscriber.php +++ b/src/EventSubscriber/AssetsCacheEventSubscriber.php @@ -9,18 +9,18 @@ use RZ\Roadiz\Documents\Events\CachePurgeAssetsRequestEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -final class AssetsCacheEventSubscriber implements EventSubscriberInterface +final readonly class AssetsCacheEventSubscriber implements EventSubscriberInterface { public function __construct( - private readonly AssetsFileClearer $assetsClearer, - private readonly LoggerInterface $logger + private AssetsFileClearer $assetsClearer, + private LoggerInterface $logger, ) { } public static function getSubscribedEvents(): array { return [ - CachePurgeAssetsRequestEvent::class => ['onPurgeAssetsRequest', 0] + CachePurgeAssetsRequestEvent::class => ['onPurgeAssetsRequest', 0], ]; } diff --git a/src/EventSubscriber/AutomaticWebhookSubscriber.php b/src/EventSubscriber/AutomaticWebhookSubscriber.php index fb29b2fc..970ad388 100644 --- a/src/EventSubscriber/AutomaticWebhookSubscriber.php +++ b/src/EventSubscriber/AutomaticWebhookSubscriber.php @@ -23,12 +23,12 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Workflow\Event\Event; -final class AutomaticWebhookSubscriber implements EventSubscriberInterface +final readonly class AutomaticWebhookSubscriber implements EventSubscriberInterface { public function __construct( - private readonly WebhookDispatcher $webhookDispatcher, - private readonly ManagerRegistry $managerRegistry, - private readonly HandlerFactoryInterface $handlerFactory + private WebhookDispatcher $webhookDispatcher, + private ManagerRegistry $managerRegistry, + private HandlerFactoryInterface $handlerFactory, ) { } @@ -48,19 +48,15 @@ public static function getSubscribedEvents(): array ]; } - /** - * @param mixed $event - * @return bool - */ protected function isEventRelatedToNode(mixed $event): bool { - return $event instanceof Event || - $event instanceof NodeVisibilityChangedEvent || - $event instanceof NodesSourcesPreUpdatedEvent || - $event instanceof NodesSourcesDeletedEvent || - $event instanceof NodeUpdatedEvent || - $event instanceof NodeDeletedEvent || - $event instanceof NodeTaggedEvent; + return $event instanceof Event + || $event instanceof NodeVisibilityChangedEvent + || $event instanceof NodesSourcesPreUpdatedEvent + || $event instanceof NodesSourcesDeletedEvent + || $event instanceof NodeUpdatedEvent + || $event instanceof NodeDeletedEvent + || $event instanceof NodeTaggedEvent; } /** @@ -70,7 +66,7 @@ public function onAutomaticWebhook(mixed $event): void { /** @var Webhook[] $webhooks */ $webhooks = $this->managerRegistry->getRepository(Webhook::class)->findBy([ - 'automatic' => true + 'automatic' => true, ]); foreach ($webhooks as $webhook) { if (!$this->isEventRelatedToNode($event) || $this->isEventSubjectInRootNode($event, $webhook->getRootNode())) { diff --git a/src/EventSubscriber/CachedNodeOffspringEventSubscriber.php b/src/EventSubscriber/CachedNodeOffspringEventSubscriber.php index b06e2058..35fba6ec 100644 --- a/src/EventSubscriber/CachedNodeOffspringEventSubscriber.php +++ b/src/EventSubscriber/CachedNodeOffspringEventSubscriber.php @@ -11,9 +11,9 @@ use RZ\Roadiz\CoreBundle\Node\CachedNodeOffspringResolverInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -class CachedNodeOffspringEventSubscriber implements EventSubscriberInterface +final readonly class CachedNodeOffspringEventSubscriber implements EventSubscriberInterface { - public function __construct(private readonly CachedNodeOffspringResolverInterface $cachedNodeOffspringResolver) + public function __construct(private CachedNodeOffspringResolverInterface $cachedNodeOffspringResolver) { } diff --git a/src/EventSubscriber/CloudflareCacheEventSubscriber.php b/src/EventSubscriber/CloudflareCacheEventSubscriber.php index 48fd5f2e..4e2a9f76 100644 --- a/src/EventSubscriber/CloudflareCacheEventSubscriber.php +++ b/src/EventSubscriber/CloudflareCacheEventSubscriber.php @@ -4,36 +4,32 @@ namespace RZ\Roadiz\CoreBundle\EventSubscriber; -use GuzzleHttp\Exception\ClientException; -use GuzzleHttp\Exception\ConnectException; -use GuzzleHttp\Exception\RequestException; -use GuzzleHttp\Psr7\Request; -use Psr\Http\Message\RequestInterface; use Psr\Log\LoggerInterface; use RZ\Roadiz\CoreBundle\Cache\CloudflareProxyCache; use RZ\Roadiz\CoreBundle\Cache\ReverseProxyCacheLocator; use RZ\Roadiz\CoreBundle\Event\Cache\CachePurgeRequestEvent; use RZ\Roadiz\CoreBundle\Event\NodesSources\NodesSourcesUpdatedEvent; -use RZ\Roadiz\CoreBundle\Message\GuzzleRequestMessage; +use RZ\Roadiz\CoreBundle\Message\HttpRequestMessage; +use RZ\Roadiz\CoreBundle\Message\HttpRequestMessageInterface; use Symfony\Cmf\Component\Routing\RouteObjectInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Messenger\Envelope; -use Symfony\Component\Messenger\Exception\ExceptionInterface; +use Symfony\Component\Messenger\Exception\ExceptionInterface as MessengerExceptionInterface; use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; +use Symfony\Contracts\HttpClient\Exception\ExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface; -final class CloudflareCacheEventSubscriber implements EventSubscriberInterface +final readonly class CloudflareCacheEventSubscriber implements EventSubscriberInterface { public function __construct( - private readonly MessageBusInterface $bus, - private readonly ReverseProxyCacheLocator $reverseProxyCacheLocator, - private readonly UrlGeneratorInterface $urlGenerator, - private readonly LoggerInterface $logger + private MessageBusInterface $bus, + private ReverseProxyCacheLocator $reverseProxyCacheLocator, + private UrlGeneratorInterface $urlGenerator, + private LoggerInterface $logger, ) { } - /** - * @inheritDoc - */ + public static function getSubscribedEvents(): array { return [ @@ -60,22 +56,14 @@ public function onBanRequest(CachePurgeRequestEvent $event): void self::class, 'Cloudflare proxy cache' ); - } catch (RequestException $e) { - if (null !== $e->getResponse()) { - $data = \json_decode($e->getResponse()->getBody()->getContents(), true); - $event->addError( - $data['errors'][0]['message'] ?? $e->getMessage(), - self::class, - 'Cloudflare proxy cache' - ); - } else { - $event->addError( - $e->getMessage(), - self::class, - 'Cloudflare proxy cache' - ); - } - } catch (ConnectException $e) { + } catch (HttpExceptionInterface $e) { + $data = \json_decode($e->getResponse()->getContent(false), true); + $event->addError( + $data['errors'][0]['message'] ?? $e->getMessage(), + self::class, + 'Cloudflare proxy cache' + ); + } catch (ExceptionInterface $e) { $event->addError( $e->getMessage(), self::class, @@ -107,7 +95,7 @@ public function onPurgeRequest(NodesSourcesUpdatedEvent $event): void UrlGeneratorInterface::ABSOLUTE_URL )]); $this->sendRequest($purgeRequest); - } catch (ClientException $e) { + } catch (ExceptionInterface $e) { // do nothing } } @@ -118,20 +106,19 @@ private function getCloudflareCacheProxy(): CloudflareProxyCache if (null === $proxy) { throw new \RuntimeException('Cloudflare cache proxy is not configured'); } + return $proxy; } /** - * @param array $body - * @return Request * @throws \JsonException */ - protected function createRequest(array $body): Request + protected function createRequest(array $body): HttpRequestMessageInterface { $headers = [ 'Content-type' => 'application/json', ]; - $headers['Authorization'] = 'Bearer ' . trim($this->getCloudflareCacheProxy()->getBearer()); + $headers['Authorization'] = 'Bearer '.trim($this->getCloudflareCacheProxy()->getBearer()); $headers['X-Auth-Email'] = $this->getCloudflareCacheProxy()->getEmail(); $headers['X-Auth-Key'] = $this->getCloudflareCacheProxy()->getKey(); @@ -141,19 +128,22 @@ protected function createRequest(array $body): Request $this->getCloudflareCacheProxy()->getZone() ); $body = \json_encode($body, JSON_THROW_ON_ERROR); - return new Request( + + return new HttpRequestMessage( 'POST', $uri, - $headers, - $body + [ + 'timeout' => $this->getCloudflareCacheProxy()->getTimeout(), + 'headers' => $headers, + 'body' => $body, + ], ); } /** - * @return Request * @throws \JsonException */ - protected function createBanRequest(): Request + protected function createBanRequest(): HttpRequestMessageInterface { return $this->createRequest([ 'purge_everything' => true, @@ -162,28 +152,21 @@ protected function createBanRequest(): Request /** * @param string[] $uris - * @return Request + * * @throws \JsonException */ - protected function createPurgeRequest(array $uris = []): Request + protected function createPurgeRequest(array $uris = []): HttpRequestMessageInterface { return $this->createRequest([ - 'files' => $uris + 'files' => $uris, ]); } - /** - * @param RequestInterface $request - * @return void - */ - protected function sendRequest(RequestInterface $request): void + protected function sendRequest(HttpRequestMessageInterface $requestMessage): void { try { - $this->bus->dispatch(new Envelope(new GuzzleRequestMessage($request, [ - 'debug' => false, - 'timeout' => $this->getCloudflareCacheProxy()->getTimeout() - ]))); - } catch (ExceptionInterface $exception) { + $this->bus->dispatch(new Envelope($requestMessage)); + } catch (MessengerExceptionInterface $exception) { $this->logger->error($exception->getMessage()); } } diff --git a/src/EventSubscriber/DocumentTimestampSubscriber.php b/src/EventSubscriber/DocumentTimestampSubscriber.php index 54dac92d..67c90790 100644 --- a/src/EventSubscriber/DocumentTimestampSubscriber.php +++ b/src/EventSubscriber/DocumentTimestampSubscriber.php @@ -8,15 +8,12 @@ use RZ\Roadiz\CoreBundle\Event\Document\DocumentTranslationUpdatedEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -class DocumentTimestampSubscriber implements EventSubscriberInterface +final readonly class DocumentTimestampSubscriber implements EventSubscriberInterface { - /** - * @inheritDoc - */ public static function getSubscribedEvents(): array { return [ - DocumentTranslationUpdatedEvent::class => 'onDocumentTranslationUpdatedEvent' + DocumentTranslationUpdatedEvent::class => 'onDocumentTranslationUpdatedEvent', ]; } diff --git a/src/EventSubscriber/JwtAuthenticationSuccessEventSubscriber.php b/src/EventSubscriber/JwtAuthenticationSuccessEventSubscriber.php new file mode 100644 index 00000000..b39f1a69 --- /dev/null +++ b/src/EventSubscriber/JwtAuthenticationSuccessEventSubscriber.php @@ -0,0 +1,38 @@ + 'onAuthenticationSuccess', + AuthenticationSuccessEvent::class => 'onAuthenticationSuccess', + ]; + } + + public function onAuthenticationSuccess(AuthenticationSuccessEvent $event): void + { + $user = $event->getUser(); + + if (!($user instanceof User)) { + return; + } + + $user->setLastLogin(new \DateTime()); + $this->managerRegistry->getManager()->flush(); + } +} diff --git a/src/EventSubscriber/LocaleSubscriber.php b/src/EventSubscriber/LocaleSubscriber.php index 8583550f..f5013173 100644 --- a/src/EventSubscriber/LocaleSubscriber.php +++ b/src/EventSubscriber/LocaleSubscriber.php @@ -14,18 +14,15 @@ use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\Routing\RequestContextAwareInterface; -final class LocaleSubscriber implements EventSubscriberInterface +final readonly class LocaleSubscriber implements EventSubscriberInterface { public function __construct( - private readonly PreviewResolverInterface $previewResolver, - private readonly ManagerRegistry $managerRegistry, - private readonly RequestContextAwareInterface $router + private PreviewResolverInterface $previewResolver, + private ManagerRegistry $managerRegistry, + private RequestContextAwareInterface $router, ) { } - /** - * @return array - */ public static function getSubscribedEvents(): array { return [ @@ -46,7 +43,7 @@ private function getDefaultTranslation(): ?TranslationInterface private function supportsLocale(?string $locale): bool { - if (null === $locale || $locale === '') { + if (null === $locale || '' === $locale) { return false; } @@ -55,6 +52,7 @@ private function supportsLocale(?string $locale): bool } else { $locales = $this->getRepository()->getAvailableLocales(); } + return \in_array( $locale, $locales, @@ -67,6 +65,7 @@ private function getTranslationByLocale(string $locale): ?TranslationInterface if ($this->previewResolver->isPreview()) { return $this->getRepository()->findOneByLocaleOrOverrideLocale($locale); } + return $this->getRepository()->findOneAvailableByLocaleOrOverrideLocale($locale); } @@ -80,6 +79,7 @@ public function onKernelRequest(RequestEvent $event): void */ if ($this->supportsLocale($locale)) { $this->setTranslation($request, $this->getTranslationByLocale($locale)); + return; } @@ -93,19 +93,21 @@ public function onKernelRequest(RequestEvent $event): void 'interventionRequestProcess', ]; if ( - !\in_array($request->attributes->getString('_route'), $statelessRoutes, true) && - !$request->attributes->getBoolean('_stateless') && - $request->hasPreviousSession() + !\in_array($request->attributes->getString('_route'), $statelessRoutes, true) + && !$request->attributes->getBoolean('_stateless') + && $request->hasPreviousSession() ) { $sessionLocale = $request->getSession()->get('_locale', null); if ($this->supportsLocale($sessionLocale)) { $this->setTranslation($request, $this->getTranslationByLocale($sessionLocale)); + return; } } if (null !== $translation = $this->getDefaultTranslation()) { $this->setTranslation($request, $translation); + return; } } diff --git a/src/EventSubscriber/LoggableSubscriber.php b/src/EventSubscriber/LoggableSubscriber.php index 8bec9f86..11abf4b6 100644 --- a/src/EventSubscriber/LoggableSubscriber.php +++ b/src/EventSubscriber/LoggableSubscriber.php @@ -11,11 +11,11 @@ use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\KernelEvents; -final class LoggableSubscriber implements EventSubscriberInterface +final readonly class LoggableSubscriber implements EventSubscriberInterface { public function __construct( - private readonly LoggableListener $loggableListener, - private readonly Security $security, + private LoggableListener $loggableListener, + private Security $security, ) { } @@ -36,8 +36,8 @@ public function onKernelRequest(RequestEvent $event): void public static function getSubscribedEvents(): array { - return array( + return [ KernelEvents::REQUEST => 'onKernelRequest', - ); + ]; } } diff --git a/src/EventSubscriber/NodeDuplicationSubscriber.php b/src/EventSubscriber/NodeDuplicationSubscriber.php index 6990f179..a14e61ae 100644 --- a/src/EventSubscriber/NodeDuplicationSubscriber.php +++ b/src/EventSubscriber/NodeDuplicationSubscriber.php @@ -6,15 +6,15 @@ use Doctrine\Persistence\ManagerRegistry; use RZ\Roadiz\Core\Handlers\HandlerFactoryInterface; -use RZ\Roadiz\CoreBundle\Event\Node\NodeDuplicatedEvent; use RZ\Roadiz\CoreBundle\EntityHandler\NodeHandler; +use RZ\Roadiz\CoreBundle\Event\Node\NodeDuplicatedEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -final class NodeDuplicationSubscriber implements EventSubscriberInterface +final readonly class NodeDuplicationSubscriber implements EventSubscriberInterface { public function __construct( - private readonly ManagerRegistry $managerRegistry, - private readonly HandlerFactoryInterface $handlerFactory + private ManagerRegistry $managerRegistry, + private HandlerFactoryInterface $handlerFactory, ) { } diff --git a/src/EventSubscriber/NodeNameSubscriber.php b/src/EventSubscriber/NodeNameSubscriber.php index 6f9288a9..e01304cf 100644 --- a/src/EventSubscriber/NodeNameSubscriber.php +++ b/src/EventSubscriber/NodeNameSubscriber.php @@ -17,18 +17,15 @@ /** * Updates node name against default node-source title is applicable. */ -final class NodeNameSubscriber implements EventSubscriberInterface +final readonly class NodeNameSubscriber implements EventSubscriberInterface { public function __construct( - private readonly LoggerInterface $logger, - private readonly NodeNamePolicyInterface $nodeNamePolicy, - private readonly NodeMover $nodeMover + private LoggerInterface $logger, + private NodeNamePolicyInterface $nodeNamePolicy, + private NodeMover $nodeMover, ) { } - /** - * @inheritDoc - */ public static function getSubscribedEvents(): array { return [ @@ -39,7 +36,7 @@ public static function getSubscribedEvents(): array public function onBeforeUpdate( NodesSourcesPreUpdatedEvent $event, string $eventName, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ): void { $nodeSource = $event->getNodeSource(); $title = $nodeSource->getTitle(); @@ -49,9 +46,9 @@ public function onBeforeUpdate( * default translation */ if ( - "" != $title && - true === $nodeSource->getNode()->isDynamicNodeName() && - $nodeSource->getTranslation()->isDefaultTranslation() + '' != $title + && true === $nodeSource->getNode()->isDynamicNodeName() + && $nodeSource->getTranslation()->isDefaultTranslation() ) { $testingNodeName = $this->nodeNamePolicy->getCanonicalNodeName($nodeSource); @@ -60,9 +57,9 @@ public function onBeforeUpdate( * if it is ALREADY suffixed with a unique ID. */ if ( - $testingNodeName != $nodeSource->getNode()->getNodeName() && - $this->nodeNamePolicy->isNodeNameValid($testingNodeName) && - !$this->nodeNamePolicy->isNodeNameWithUniqId( + $testingNodeName != $nodeSource->getNode()->getNodeName() + && $this->nodeNamePolicy->isNodeNameValid($testingNodeName) + && !$this->nodeNamePolicy->isNodeNameWithUniqId( $testingNodeName, $nodeSource->getNode()->getNodeName() ) diff --git a/src/EventSubscriber/NodeRedirectionSubscriber.php b/src/EventSubscriber/NodeRedirectionSubscriber.php index 2b3e00e8..01d16706 100644 --- a/src/EventSubscriber/NodeRedirectionSubscriber.php +++ b/src/EventSubscriber/NodeRedirectionSubscriber.php @@ -14,12 +14,12 @@ /** * Subscribe to Node, NodesSources and UrlAlias event to clear ns url cache. */ -class NodeRedirectionSubscriber implements EventSubscriberInterface +final readonly class NodeRedirectionSubscriber implements EventSubscriberInterface { public function __construct( - protected readonly NodeMover $nodeMover, - protected readonly string $kernelEnvironment, - protected readonly PreviewResolverInterface $previewResolver + private NodeMover $nodeMover, + private string $kernelEnvironment, + private PreviewResolverInterface $previewResolver, ) { } @@ -31,24 +31,20 @@ public static function getSubscribedEvents(): array } /** - * Empty nodeSources Url cache - * - * @param NodePathChangedEvent $event - * @param string $eventName - * @param EventDispatcherInterface $dispatcher + * Empty nodeSources Url cache. */ public function redirectOldPaths( NodePathChangedEvent $event, string $eventName, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ): void { if ( - $this->kernelEnvironment === 'prod' && - !$this->previewResolver->isPreview() && - null !== $event->getNode() && - $event->getNode()->isPublished() && - $event->getNode()->getNodeType()->isReachable() && - count($event->getPaths()) > 0 + 'prod' === $this->kernelEnvironment + && !$this->previewResolver->isPreview() + && null !== $event->getNode() + && $event->getNode()->isPublished() + && $event->getNode()->getNodeType()->isReachable() + && count($event->getPaths()) > 0 ) { $this->nodeMover->redirectAll($event->getNode(), $event->getPaths()); $dispatcher->dispatch(new CachePurgeRequestEvent()); diff --git a/src/EventSubscriber/NodeSourcePathSubscriber.php b/src/EventSubscriber/NodeSourcePathSubscriber.php index 0165266b..92033716 100644 --- a/src/EventSubscriber/NodeSourcePathSubscriber.php +++ b/src/EventSubscriber/NodeSourcePathSubscriber.php @@ -9,16 +9,13 @@ use RZ\Roadiz\CoreBundle\Routing\NodesSourcesUrlGenerator; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -final class NodeSourcePathSubscriber implements EventSubscriberInterface +final readonly class NodeSourcePathSubscriber implements EventSubscriberInterface { public function __construct( - private readonly NodesSourcesPathAggregator $pathAggregator + private NodesSourcesPathAggregator $pathAggregator, ) { } - /** - * @inheritDoc - */ public static function getSubscribedEvents(): array { return [ @@ -26,9 +23,6 @@ public static function getSubscribedEvents(): array ]; } - /** - * @param NodesSourcesPathGeneratingEvent $event - */ public function onNodesSourcesPath(NodesSourcesPathGeneratingEvent $event): void { $urlGenerator = new NodesSourcesUrlGenerator( diff --git a/src/EventSubscriber/NodesSourcesAddHeadersSubscriber.php b/src/EventSubscriber/NodesSourcesAddHeadersSubscriber.php index 63808c9f..d93eef3d 100644 --- a/src/EventSubscriber/NodesSourcesAddHeadersSubscriber.php +++ b/src/EventSubscriber/NodesSourcesAddHeadersSubscriber.php @@ -4,7 +4,7 @@ namespace RZ\Roadiz\CoreBundle\EventSubscriber; -use ApiPlatform\Util\RequestAttributesExtractor; +use ApiPlatform\State\Util\RequestAttributesExtractor; use RZ\Roadiz\CoreBundle\Api\Model\WebResponseInterface; use RZ\Roadiz\CoreBundle\Entity\NodesSources; use RZ\Roadiz\CoreBundle\Preview\PreviewResolverInterface; @@ -13,18 +13,18 @@ use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; -final class NodesSourcesAddHeadersSubscriber implements EventSubscriberInterface +final readonly class NodesSourcesAddHeadersSubscriber implements EventSubscriberInterface { public function __construct( - private readonly PreviewResolverInterface $previewResolver, - private readonly Security $security + private PreviewResolverInterface $previewResolver, + private Security $security, ) { } public static function getSubscribedEvents(): array { return [ - KernelEvents::RESPONSE => ['onKernelResponse', 0] + KernelEvents::RESPONSE => ['onKernelResponse', 0], ]; } diff --git a/src/EventSubscriber/NodesSourcesLinkHeaderEventSubscriber.php b/src/EventSubscriber/NodesSourcesLinkHeaderEventSubscriber.php index 3c0b5c91..e4846f61 100644 --- a/src/EventSubscriber/NodesSourcesLinkHeaderEventSubscriber.php +++ b/src/EventSubscriber/NodesSourcesLinkHeaderEventSubscriber.php @@ -15,21 +15,18 @@ use Symfony\Component\WebLink\GenericLinkProvider; use Symfony\Component\WebLink\Link; -final class NodesSourcesLinkHeaderEventSubscriber implements EventSubscriberInterface +final readonly class NodesSourcesLinkHeaderEventSubscriber implements EventSubscriberInterface { public function __construct( - private readonly ManagerRegistry $managerRegistry, - private readonly UrlGeneratorInterface $urlGenerator + private ManagerRegistry $managerRegistry, + private UrlGeneratorInterface $urlGenerator, ) { } - /** - * @inheritDoc - */ public static function getSubscribedEvents(): array { return [ - ViewEvent::class => ['onKernelView', 15] + ViewEvent::class => ['onKernelView', 15], ]; } @@ -61,7 +58,7 @@ public function onKernelView(ViewEvent $event): void (new Link( 'alternate', $this->urlGenerator->generate(RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, [ - RouteObjectInterface::ROUTE_OBJECT => $singleSource + RouteObjectInterface::ROUTE_OBJECT => $singleSource, ]) )) ->withAttribute('hreflang', $singleSource->getTranslation()->getLocale()) diff --git a/src/EventSubscriber/NodesSourcesUniversalSubscriber.php b/src/EventSubscriber/NodesSourcesUniversalSubscriber.php index b16cb180..aa27e90d 100644 --- a/src/EventSubscriber/NodesSourcesUniversalSubscriber.php +++ b/src/EventSubscriber/NodesSourcesUniversalSubscriber.php @@ -11,24 +11,12 @@ use RZ\Roadiz\CoreBundle\Node\UniversalDataDuplicator; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -class NodesSourcesUniversalSubscriber implements EventSubscriberInterface +final readonly class NodesSourcesUniversalSubscriber implements EventSubscriberInterface { - private ManagerRegistry $managerRegistry; - private UniversalDataDuplicator $universalDataDuplicator; - - /** - * @param ManagerRegistry $managerRegistry - * @param UniversalDataDuplicator $universalDataDuplicator - */ - public function __construct(ManagerRegistry $managerRegistry, UniversalDataDuplicator $universalDataDuplicator) + public function __construct(private ManagerRegistry $managerRegistry, private UniversalDataDuplicator $universalDataDuplicator) { - $this->universalDataDuplicator = $universalDataDuplicator; - $this->managerRegistry = $managerRegistry; } - /** - * @return array - */ public static function getSubscribedEvents(): array { return [ @@ -37,8 +25,6 @@ public static function getSubscribedEvents(): array } /** - * @param NodesSourcesUpdatedEvent $event - * * @throws ORMException * @throws OptimisticLockException */ diff --git a/src/EventSubscriber/NodesSourcesUrlsCacheEventSubscriber.php b/src/EventSubscriber/NodesSourcesUrlsCacheEventSubscriber.php index d6d9ccae..621702aa 100644 --- a/src/EventSubscriber/NodesSourcesUrlsCacheEventSubscriber.php +++ b/src/EventSubscriber/NodesSourcesUrlsCacheEventSubscriber.php @@ -18,15 +18,12 @@ use RZ\Roadiz\CoreBundle\Event\UrlAlias\UrlAliasUpdatedEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -final class NodesSourcesUrlsCacheEventSubscriber implements EventSubscriberInterface +final readonly class NodesSourcesUrlsCacheEventSubscriber implements EventSubscriberInterface { - public function __construct(private readonly NodesSourcesUrlsCacheClearer $cacheClearer) + public function __construct(private NodesSourcesUrlsCacheClearer $cacheClearer) { } - /** - * @inheritDoc - */ public static function getSubscribedEvents(): array { return [ diff --git a/src/EventSubscriber/OPCacheEventSubscriber.php b/src/EventSubscriber/OPCacheEventSubscriber.php index fb080645..465fd2e6 100644 --- a/src/EventSubscriber/OPCacheEventSubscriber.php +++ b/src/EventSubscriber/OPCacheEventSubscriber.php @@ -10,9 +10,6 @@ final class OPCacheEventSubscriber implements EventSubscriberInterface { - /** - * @inheritDoc - */ public static function getSubscribedEvents(): array { return [ @@ -20,9 +17,6 @@ public static function getSubscribedEvents(): array ]; } - /** - * @param CachePurgeRequestEvent $event - */ public function onPurgeRequest(CachePurgeRequestEvent $event): void { try { diff --git a/src/EventSubscriber/RealmNodeInheritanceSubscriber.php b/src/EventSubscriber/RealmNodeInheritanceSubscriber.php index d41b9d7e..127a3a92 100644 --- a/src/EventSubscriber/RealmNodeInheritanceSubscriber.php +++ b/src/EventSubscriber/RealmNodeInheritanceSubscriber.php @@ -17,15 +17,12 @@ use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\MessageBusInterface; -final class RealmNodeInheritanceSubscriber implements EventSubscriberInterface +final readonly class RealmNodeInheritanceSubscriber implements EventSubscriberInterface { - public function __construct(private readonly MessageBusInterface $bus) + public function __construct(private MessageBusInterface $bus) { } - /** - * @inheritDoc - */ public static function getSubscribedEvents(): array { return [ diff --git a/src/EventSubscriber/RedirectionCacheSubscriber.php b/src/EventSubscriber/RedirectionCacheSubscriber.php index 49dece5c..3495b2fe 100644 --- a/src/EventSubscriber/RedirectionCacheSubscriber.php +++ b/src/EventSubscriber/RedirectionCacheSubscriber.php @@ -12,18 +12,12 @@ use RZ\Roadiz\CoreBundle\Routing\RedirectionPathResolver; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -class RedirectionCacheSubscriber implements EventSubscriberInterface +final readonly class RedirectionCacheSubscriber implements EventSubscriberInterface { - private CacheItemPoolInterface $cacheAdapter; - - public function __construct(CacheItemPoolInterface $cacheAdapter) + public function __construct(private CacheItemPoolInterface $cacheAdapter) { - $this->cacheAdapter = $cacheAdapter; } - /** - * @inheritDoc - */ public static function getSubscribedEvents(): array { return [ diff --git a/src/EventSubscriber/ReverseProxyCacheEventSubscriber.php b/src/EventSubscriber/ReverseProxyCacheEventSubscriber.php index 4285e7f4..2fb5327c 100644 --- a/src/EventSubscriber/ReverseProxyCacheEventSubscriber.php +++ b/src/EventSubscriber/ReverseProxyCacheEventSubscriber.php @@ -4,14 +4,14 @@ namespace RZ\Roadiz\CoreBundle\EventSubscriber; -use GuzzleHttp\Psr7\Request; use Psr\Log\LoggerInterface; use RZ\Roadiz\CoreBundle\Cache\ReverseProxyCacheLocator; use RZ\Roadiz\CoreBundle\Entity\Node; use RZ\Roadiz\CoreBundle\Entity\NodesSources; use RZ\Roadiz\CoreBundle\Event\Cache\CachePurgeRequestEvent; use RZ\Roadiz\CoreBundle\Event\NodesSources\NodesSourcesUpdatedEvent; -use RZ\Roadiz\CoreBundle\Message\GuzzleRequestMessage; +use RZ\Roadiz\CoreBundle\Message\HttpRequestMessage; +use RZ\Roadiz\CoreBundle\Message\HttpRequestMessageInterface; use RZ\Roadiz\CoreBundle\Message\PurgeReverseProxyCacheMessage; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Messenger\Envelope; @@ -19,17 +19,15 @@ use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Workflow\Event\Event; -final class ReverseProxyCacheEventSubscriber implements EventSubscriberInterface +final readonly class ReverseProxyCacheEventSubscriber implements EventSubscriberInterface { public function __construct( - private readonly ReverseProxyCacheLocator $reverseProxyCacheLocator, - private readonly MessageBusInterface $bus, - private readonly LoggerInterface $logger + private ReverseProxyCacheLocator $reverseProxyCacheLocator, + private MessageBusInterface $bus, + private LoggerInterface $logger, ) { } - /** - * @inheritDoc - */ + public static function getSubscribedEvents(): array { return [ @@ -39,17 +37,11 @@ public static function getSubscribedEvents(): array ]; } - /** - * @return bool - */ protected function supportConfig(): bool { return count($this->reverseProxyCacheLocator->getFrontends()) > 0; } - /** - * @param Event $event - */ public function onNodeWorkflowCompleted(Event $event): void { $node = $event->getSubject(); @@ -63,9 +55,6 @@ public function onNodeWorkflowCompleted(Event $event): void } } - /** - * @param CachePurgeRequestEvent $event - */ public function onBanRequest(CachePurgeRequestEvent $event): void { if (!$this->supportConfig()) { @@ -77,14 +66,11 @@ public function onBanRequest(CachePurgeRequestEvent $event): void $event->addMessage( 'Reverse proxy cache cleared.', self::class, - 'Reverse proxy cache [' . $name . ']' + 'Reverse proxy cache ['.$name.']' ); } } - /** - * @param NodesSourcesUpdatedEvent $event - */ public function onPurgeRequest(NodesSourcesUpdatedEvent $event): void { if (!$this->supportConfig()) { @@ -95,7 +81,7 @@ public function onPurgeRequest(NodesSourcesUpdatedEvent $event): void } /** - * @return Request[] + * @return HttpRequestMessageInterface[] */ protected function createBanRequests(): array { @@ -104,24 +90,25 @@ protected function createBanRequests(): array // Add protocol if host does not start with it if (!\str_starts_with($frontend->getHost(), 'http')) { // Use HTTP to be able to call Varnish from a Docker network - $uri = 'http://' . $frontend->getHost(); + $uri = 'http://'.$frontend->getHost(); } else { $uri = $frontend->getHost(); } - $requests[$frontend->getName()] = new Request( + $requests[$frontend->getName()] = new HttpRequestMessage( 'BAN', $uri, [ - 'Host' => $frontend->getDomainName() + 'timeout' => 3, + 'headers' => [ + 'Host' => $frontend->getDomainName(), + ], ] ); } + return $requests; } - /** - * @param NodesSources $nodeSource - */ protected function purgeNodesSources(NodesSources $nodeSource): void { try { @@ -131,17 +118,10 @@ protected function purgeNodesSources(NodesSources $nodeSource): void } } - /** - * @param Request $request - * @return void - */ - protected function sendRequest(Request $request): void + protected function sendRequest(HttpRequestMessageInterface $requestMessage): void { try { - $this->bus->dispatch(new Envelope(new GuzzleRequestMessage($request, [ - 'debug' => false, - 'timeout' => 3 - ]))); + $this->bus->dispatch(new Envelope($requestMessage)); } catch (ExceptionInterface $exception) { $this->logger->error($exception->getMessage()); } diff --git a/src/EventSubscriber/RoleSubscriber.php b/src/EventSubscriber/RoleSubscriber.php index b3547449..0b82a0aa 100644 --- a/src/EventSubscriber/RoleSubscriber.php +++ b/src/EventSubscriber/RoleSubscriber.php @@ -15,24 +15,12 @@ use RZ\Roadiz\CoreBundle\Event\Role\RoleEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -class RoleSubscriber implements EventSubscriberInterface +final readonly class RoleSubscriber implements EventSubscriberInterface { - protected ?LazyParameterBag $roles; - private ManagerRegistry $managerRegistry; - - /** - * @param ManagerRegistry $managerRegistry - * @param LazyParameterBag|null $roles - */ - public function __construct(ManagerRegistry $managerRegistry, ?LazyParameterBag $roles) + public function __construct(private ManagerRegistry $managerRegistry, private ?LazyParameterBag $roles) { - $this->roles = $roles; - $this->managerRegistry = $managerRegistry; } - /** - * @inheritDoc - */ public static function getSubscribedEvents(): array { return [ @@ -47,8 +35,8 @@ public function onRoleChanged(RoleEvent $event): void $manager = $this->managerRegistry->getManagerForClass(Role::class); // Clear result cache if ( - $manager instanceof EntityManagerInterface && - $manager->getConfiguration()->getResultCacheImpl() instanceof CacheProvider + $manager instanceof EntityManagerInterface + && $manager->getConfiguration()->getResultCacheImpl() instanceof CacheProvider ) { $manager->getConfiguration()->getResultCacheImpl()->deleteAll(); } diff --git a/src/EventSubscriber/SignatureSubscriber.php b/src/EventSubscriber/SignatureSubscriber.php index 68bcb97c..2860eb28 100644 --- a/src/EventSubscriber/SignatureSubscriber.php +++ b/src/EventSubscriber/SignatureSubscriber.php @@ -8,14 +8,15 @@ use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; -final class SignatureSubscriber implements EventSubscriberInterface +final readonly class SignatureSubscriber implements EventSubscriberInterface { public function __construct( - private readonly string $cmsVersion, - private readonly bool $hideRoadizVersion, - private readonly bool $debug = false + private string $cmsVersion, + private bool $hideRoadizVersion, + private bool $debug = false, ) { } + /** * Filters the Response. * diff --git a/src/EventSubscriber/TagTimestampSubscriber.php b/src/EventSubscriber/TagTimestampSubscriber.php index 86b30b43..71f0c496 100644 --- a/src/EventSubscriber/TagTimestampSubscriber.php +++ b/src/EventSubscriber/TagTimestampSubscriber.php @@ -4,19 +4,15 @@ namespace RZ\Roadiz\CoreBundle\EventSubscriber; -use RZ\Roadiz\Core\AbstractEntities\AbstractDateTimed; use RZ\Roadiz\CoreBundle\Event\Tag\TagUpdatedEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -class TagTimestampSubscriber implements EventSubscriberInterface +final readonly class TagTimestampSubscriber implements EventSubscriberInterface { - /** - * @inheritDoc - */ public static function getSubscribedEvents(): array { return [ - TagUpdatedEvent::class => 'onTagUpdatedEvent' + TagUpdatedEvent::class => 'onTagUpdatedEvent', ]; } diff --git a/src/EventSubscriber/TranslationSubscriber.php b/src/EventSubscriber/TranslationSubscriber.php index d9b85f68..8b10fc2f 100644 --- a/src/EventSubscriber/TranslationSubscriber.php +++ b/src/EventSubscriber/TranslationSubscriber.php @@ -18,9 +18,9 @@ /** * Subscribe to Translation event to clear result cache. */ -final class TranslationSubscriber implements EventSubscriberInterface +final readonly class TranslationSubscriber implements EventSubscriberInterface { - public function __construct(private readonly ManagerRegistry $managerRegistry) + public function __construct(private ManagerRegistry $managerRegistry) { } @@ -34,15 +34,15 @@ public static function getSubscribedEvents(): array } /** - * Empty nodeSources Url cache + * Empty nodeSources Url cache. */ public function purgeCache(Event $event, string $eventName, EventDispatcherInterface $dispatcher): void { $manager = $this->managerRegistry->getManager(); // Clear result cache if ( - $manager instanceof EntityManagerInterface && - $manager->getConfiguration()->getResultCacheImpl() instanceof CacheProvider + $manager instanceof EntityManagerInterface + && $manager->getConfiguration()->getResultCacheImpl() instanceof CacheProvider ) { $manager->getConfiguration()->getResultCacheImpl()->deleteAll(); } diff --git a/src/EventSubscriber/UserLocaleSubscriber.php b/src/EventSubscriber/UserLocaleSubscriber.php index 5b865a5c..33775d51 100644 --- a/src/EventSubscriber/UserLocaleSubscriber.php +++ b/src/EventSubscriber/UserLocaleSubscriber.php @@ -13,17 +13,14 @@ use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; use Symfony\Component\Security\Http\SecurityEvents; -final class UserLocaleSubscriber implements EventSubscriberInterface +final readonly class UserLocaleSubscriber implements EventSubscriberInterface { public function __construct( - private readonly RequestStack $requestStack, - private readonly TokenStorageInterface $tokenStorage + private RequestStack $requestStack, + private TokenStorageInterface $tokenStorage, ) { } - /** - * @return array - */ public static function getSubscribedEvents(): array { // must be registered after the default Locale listener @@ -33,9 +30,6 @@ public static function getSubscribedEvents(): array ]; } - /** - * @param InteractiveLoginEvent $event - */ public function onInteractiveLogin(InteractiveLoginEvent $event): void { if ($this->requestStack->getMainRequest()?->attributes->getBoolean('_stateless')) { @@ -45,16 +39,13 @@ public function onInteractiveLogin(InteractiveLoginEvent $event): void $user = $event->getAuthenticationToken()->getUser(); if ( - $user instanceof User && - null !== $user->getLocale() + $user instanceof User + && null !== $user->getLocale() ) { $this->requestStack->getSession()->set('_locale', $user->getLocale()); } } - /** - * @param FilterUserEvent $event - */ public function onUserUpdated(FilterUserEvent $event): void { if ($this->requestStack->getMainRequest()?->attributes->getBoolean('_stateless')) { @@ -63,9 +54,9 @@ public function onUserUpdated(FilterUserEvent $event): void $user = $event->getUser(); if ( - null !== $this->tokenStorage->getToken() && - $this->tokenStorage->getToken()->getUser() instanceof User && - $this->tokenStorage->getToken()->getUserIdentifier() === $user->getUserIdentifier() + null !== $this->tokenStorage->getToken() + && $this->tokenStorage->getToken()->getUser() instanceof User + && $this->tokenStorage->getToken()->getUserIdentifier() === $user->getUserIdentifier() ) { if (null === $user->getLocale()) { $this->requestStack->getSession()->remove('_locale'); diff --git a/src/Exception/BadFormRequestException.php b/src/Exception/BadFormRequestException.php index c0ba063e..8afeaa0b 100644 --- a/src/Exception/BadFormRequestException.php +++ b/src/Exception/BadFormRequestException.php @@ -12,12 +12,6 @@ class BadFormRequestException extends \Exception protected string $statusText; protected ?string $fieldErrored; - /** - * @param string|null $message - * @param int $code - * @param string $statusText - * @param string|null $fieldErrored - */ public function __construct(?string $message = null, int $code = 403, string $statusText = 'danger', ?string $fieldErrored = null) { parent::__construct($message, $code); diff --git a/src/Exception/ForceResponseException.php b/src/Exception/ForceResponseException.php index 9265bc7c..cf3a9a88 100644 --- a/src/Exception/ForceResponseException.php +++ b/src/Exception/ForceResponseException.php @@ -21,8 +21,6 @@ public function __construct(Response $response) /** * Gets the value of response. - * - * @return Response */ public function getResponse(): Response { diff --git a/src/Exception/MaintenanceModeException.php b/src/Exception/MaintenanceModeException.php index 434bbeb3..371fd747 100644 --- a/src/Exception/MaintenanceModeException.php +++ b/src/Exception/MaintenanceModeException.php @@ -22,9 +22,8 @@ public function getController(): ?AbstractController protected $message = 'Website is currently under maintenance. We will be back shortly.'; /** - * @param AbstractController|null $controller * @param string $message - * @param int $code + * @param int $code */ public function __construct(?AbstractController $controller = null, $message = null, $code = 0) { diff --git a/src/Exception/NoConfigurationFoundException.php b/src/Exception/NoConfigurationFoundException.php index 47753fc5..33afc988 100644 --- a/src/Exception/NoConfigurationFoundException.php +++ b/src/Exception/NoConfigurationFoundException.php @@ -14,5 +14,5 @@ class NoConfigurationFoundException extends InvalidConfigurationException /** * @var string */ - protected $message = "No configuration file was found. Make sure that conf/config.json exists."; + protected $message = 'No configuration file was found. Make sure that conf/config.json exists.'; } diff --git a/src/Exception/NoYamlConfigurationFoundException.php b/src/Exception/NoYamlConfigurationFoundException.php index fad6e7a6..ebc57330 100644 --- a/src/Exception/NoYamlConfigurationFoundException.php +++ b/src/Exception/NoYamlConfigurationFoundException.php @@ -12,5 +12,5 @@ class NoYamlConfigurationFoundException extends NoConfigurationFoundException /** * @var string */ - protected $message = "No configuration file was found. Make sure that conf/config.yml exists."; + protected $message = 'No configuration file was found. Make sure that conf/config.yml exists.'; } diff --git a/src/Explorer/AbstractDoctrineExplorerProvider.php b/src/Explorer/AbstractDoctrineExplorerProvider.php index ce57dc48..d70ee0c4 100644 --- a/src/Explorer/AbstractDoctrineExplorerProvider.php +++ b/src/Explorer/AbstractDoctrineExplorerProvider.php @@ -14,18 +14,12 @@ abstract class AbstractDoctrineExplorerProvider extends AbstractExplorerProvider { - protected ManagerRegistry $managerRegistry; - protected RequestStack $requestStack; - protected UrlGeneratorInterface $urlGenerator; - public function __construct( - ManagerRegistry $managerRegistry, - RequestStack $requestStack, - UrlGeneratorInterface $urlGenerator + protected ExplorerItemFactoryInterface $explorerItemFactory, + protected ManagerRegistry $managerRegistry, + protected RequestStack $requestStack, + protected UrlGeneratorInterface $urlGenerator, ) { - $this->managerRegistry = $managerRegistry; - $this->requestStack = $requestStack; - $this->urlGenerator = $urlGenerator; } /** @@ -33,20 +27,12 @@ public function __construct( */ abstract protected function getProvidedClassname(): string; - /** - * @return array - */ abstract protected function getDefaultCriteria(): array; - /** - * @return array - */ abstract protected function getDefaultOrdering(): array; /** - * @param array $options - * - * @return EntityListManagerInterface + * @throws \ReflectionException */ protected function doFetchItems(array $options = []): EntityListManagerInterface { @@ -54,6 +40,7 @@ protected function doFetchItems(array $options = []): EntityListManagerInterface $this->configureOptions($resolver); $this->options = $resolver->resolve($options); + /** @var EntityListManager $listManager */ $listManager = new EntityListManager( $this->requestStack->getCurrentRequest(), $this->managerRegistry->getManager(), @@ -68,9 +55,7 @@ protected function doFetchItems(array $options = []): EntityListManagerInterface return $listManager; } - /** - * @inheritDoc - */ + public function getItems($options = []): array { $listManager = $this->doFetchItems($options); @@ -83,9 +68,6 @@ public function getItems($options = []): array return $items; } - /** - * @inheritDoc - */ public function getFilters($options = []): array { $listManager = $this->doFetchItems($options); @@ -93,14 +75,11 @@ public function getFilters($options = []): array return $listManager->getAssignation(); } - /** - * @inheritDoc - */ public function getItemsById(array $ids = []): array { if (is_array($ids) && count($ids) > 0) { $entities = $this->managerRegistry->getRepository($this->getProvidedClassname())->findBy([ - 'id' => $ids + 'id' => $ids, ]); /* @@ -120,4 +99,9 @@ public function getItemsById(array $ids = []): array return []; } + + public function toExplorerItem(mixed $item): ExplorerItemInterface + { + return $this->explorerItemFactory->createForEntity($item); + } } diff --git a/src/Explorer/AbstractExplorerItem.php b/src/Explorer/AbstractExplorerItem.php index dbfd3efd..2dc54089 100644 --- a/src/Explorer/AbstractExplorerItem.php +++ b/src/Explorer/AbstractExplorerItem.php @@ -4,6 +4,8 @@ namespace RZ\Roadiz\CoreBundle\Explorer; +use RZ\Roadiz\Documents\Models\DocumentInterface; + abstract class AbstractExplorerItem implements ExplorerItemInterface { protected function getEditItemPath(): ?string @@ -11,14 +13,21 @@ protected function getEditItemPath(): ?string return null; } - protected function getThumbnail(): ?array + protected function getThumbnail(): DocumentInterface|array|null + { + return null; + } + + protected function isPublished(): bool + { + return true; + } + + protected function getColor(): ?string { return null; } - /** - * @inheritDoc - */ public function toArray(): array { return [ @@ -26,7 +35,9 @@ public function toArray(): array 'classname' => $this->getAlternativeDisplayable() ?? '', 'displayable' => $this->getDisplayable(), 'editItem' => $this->getEditItemPath(), - 'thumbnail' => $this->getThumbnail() + 'thumbnail' => $this->getThumbnail(), + 'published' => $this->isPublished(), + 'color' => $this->getColor(), ]; } } diff --git a/src/Explorer/AbstractExplorerProvider.php b/src/Explorer/AbstractExplorerProvider.php index 14dc0936..3b3ad7ec 100644 --- a/src/Explorer/AbstractExplorerProvider.php +++ b/src/Explorer/AbstractExplorerProvider.php @@ -10,23 +10,28 @@ abstract class AbstractExplorerProvider implements ExplorerProviderInterface { protected array $options; + + /** + * @deprecated + */ protected ContainerInterface $container; + /** + * @deprecated + */ public function setContainer(ContainerInterface $container): self { $this->container = $container; + return $this; } - /** - * @param OptionsResolver $resolver - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ - 'page' => 1, - 'search' => null, - 'itemPerPage' => 30 + 'page' => 1, + 'search' => null, + 'itemPerPage' => 30, ]); } } diff --git a/src/Explorer/ExplorerItemFactoryInterface.php b/src/Explorer/ExplorerItemFactoryInterface.php new file mode 100644 index 00000000..ad8b4c14 --- /dev/null +++ b/src/Explorer/ExplorerItemFactoryInterface.php @@ -0,0 +1,10 @@ + $ids + * * @return ExplorerItemInterface[] */ public function getItemsById(array $ids = []): array; /** * Check if object can be handled be current ExplorerProvider. - * - * @param mixed $item - * @return bool */ public function supports(mixed $item): bool; } diff --git a/src/Filesystem/RoadizFileDirectories.php b/src/Filesystem/RoadizFileDirectories.php index 8a475cb9..829ae6e6 100644 --- a/src/Filesystem/RoadizFileDirectories.php +++ b/src/Filesystem/RoadizFileDirectories.php @@ -6,15 +6,15 @@ use RZ\Roadiz\Documents\Models\FileAwareInterface; -final class RoadizFileDirectories implements FileAwareInterface +final readonly class RoadizFileDirectories implements FileAwareInterface { - public function __construct(private readonly string $projectDir) + public function __construct(private string $projectDir) { } public function getPublicFilesPath(): string { - return $this->projectDir . '/public' . $this->getPublicFilesBasePath(); + return $this->projectDir.'/public'.$this->getPublicFilesBasePath(); } public function getPublicFilesBasePath(): string @@ -24,7 +24,7 @@ public function getPublicFilesBasePath(): string public function getPrivateFilesPath(): string { - return $this->projectDir . '/var' . $this->getPrivateFilesBasePath(); + return $this->projectDir.'/var'.$this->getPrivateFilesBasePath(); } public function getPrivateFilesBasePath(): string @@ -34,7 +34,7 @@ public function getPrivateFilesBasePath(): string public function getFontsFilesPath(): string { - return $this->projectDir . '/var' . $this->getFontsFilesBasePath(); + return $this->projectDir.'/var'.$this->getFontsFilesBasePath(); } public function getFontsFilesBasePath(): string @@ -44,7 +44,7 @@ public function getFontsFilesBasePath(): string public function getPublicCachePath(): string { - return $this->projectDir . '/public' . $this->getPublicCacheBasePath(); + return $this->projectDir.'/public'.$this->getPublicCacheBasePath(); } public function getPublicCacheBasePath(): string diff --git a/src/Form/AttributeChoiceType.php b/src/Form/AttributeChoiceType.php index 1a385c3e..3b3fa9b0 100644 --- a/src/Form/AttributeChoiceType.php +++ b/src/Form/AttributeChoiceType.php @@ -20,9 +20,6 @@ public function __construct(private readonly ManagerRegistry $managerRegistry) { } - /** - * @inheritDoc - */ public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->addModelTransformer(new CallbackTransformer( @@ -30,6 +27,7 @@ function ($dataToForm) { if ($dataToForm instanceof Attribute) { return $dataToForm->getId(); } + return null; }, function ($formToData) { @@ -38,9 +36,6 @@ function ($formToData) { )); } - /** - * @inheritDoc - */ public function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); @@ -57,8 +52,8 @@ public function configureOptions(OptionsResolver $resolver): void foreach ($attributes as $attribute) { $label = $attribute->getLabelOrCode($options['translation']); if ( - null !== $attribute->getGroup() && - null !== $groupName = $attribute->getGroup()->getName() + null !== $attribute->getGroup() + && null !== $groupName = $attribute->getGroup()->getName() ) { if (!isset($choices[$groupName]) || !is_array($choices[$groupName])) { $choices[$groupName] = []; @@ -68,13 +63,11 @@ public function configureOptions(OptionsResolver $resolver): void $choices[$label] = $attribute->getId(); } } + return $choices; }); } - /** - * @inheritDoc - */ public function getParent(): ?string { return ChoiceType::class; diff --git a/src/Form/AttributeDocumentType.php b/src/Form/AttributeDocumentType.php index f361f14c..e827ed77 100644 --- a/src/Form/AttributeDocumentType.php +++ b/src/Form/AttributeDocumentType.php @@ -5,10 +5,10 @@ namespace RZ\Roadiz\CoreBundle\Form; use Doctrine\ORM\EntityManagerInterface; -use RZ\Roadiz\CoreBundle\Form\DataTransformer\AttributeDocumentsTransformer; -use RZ\Roadiz\CoreBundle\Model\AttributeInterface; use RZ\Roadiz\CoreBundle\Entity\Attribute; use RZ\Roadiz\CoreBundle\Entity\AttributeDocuments; +use RZ\Roadiz\CoreBundle\Form\DataTransformer\AttributeDocumentsTransformer; +use RZ\Roadiz\CoreBundle\Model\AttributeInterface; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\CollectionType; use Symfony\Component\Form\FormBuilderInterface; @@ -20,18 +20,11 @@ class AttributeDocumentType extends AbstractType { protected EntityManagerInterface $entityManager; - /** - * @param EntityManagerInterface $entityManager - */ public function __construct(EntityManagerInterface $entityManager) { $this->entityManager = $entityManager; } - /** - * @param FormBuilderInterface $builder - * @param array $options - */ public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->addEventListener( @@ -44,9 +37,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void )); } - /** - * @param OptionsResolver $resolver - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ @@ -60,17 +50,11 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('attribute', [AttributeInterface::class]); } - /** - * {@inheritdoc} - */ public function getBlockPrefix(): string { return 'documents'; } - /** - * @inheritDoc - */ public function getParent(): ?string { return CollectionType::class; @@ -78,8 +62,6 @@ public function getParent(): ?string /** * Delete existing document association. - * - * @param FormEvent $event */ public function onPostSubmit(FormEvent $event): void { diff --git a/src/Form/AttributeGroupTranslationType.php b/src/Form/AttributeGroupTranslationType.php index d5de4b4b..9cf7ab68 100644 --- a/src/Form/AttributeGroupTranslationType.php +++ b/src/Form/AttributeGroupTranslationType.php @@ -17,48 +17,36 @@ class AttributeGroupTranslationType extends AbstractType { protected ManagerRegistry $managerRegistry; - /** - * @param ManagerRegistry $managerRegistry - */ public function __construct(ManagerRegistry $managerRegistry) { $this->managerRegistry = $managerRegistry; } - /** - * @inheritDoc - */ public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->add('name', TextType::class, [ - 'empty_data' => '', - 'label' => false, - 'required' => false, - ]) + 'empty_data' => '', + 'label' => false, + 'required' => false, + ]) ->add('translation', TranslationsType::class, [ 'label' => false, 'required' => true, 'constraints' => [ - new NotNull() - ] + new NotNull(), + ], ]) ; $builder->get('translation')->addModelTransformer(new TranslationTransformer($this->managerRegistry)); } - /** - * @inheritDoc - */ public function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); $resolver->setDefault('data_class', AttributeGroupTranslation::class); } - /** - * @inheritDoc - */ public function getBlockPrefix(): string { return 'attribute_group_translation'; diff --git a/src/Form/AttributeGroupType.php b/src/Form/AttributeGroupType.php index 3e2c1b58..aa38df8b 100644 --- a/src/Form/AttributeGroupType.php +++ b/src/Form/AttributeGroupType.php @@ -16,9 +16,9 @@ class AttributeGroupType extends AbstractType public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->add('canonicalName', TextType::class, [ - 'label' => 'attribute_group.form.canonicalName', - 'empty_data' => '', - ]) + 'label' => 'attribute_group.form.canonicalName', + 'empty_data' => '', + ]) ->add('attributeGroupTranslations', CollectionType::class, [ 'label' => 'attribute_group.form.attributeGroupTranslations', 'allow_add' => true, @@ -29,12 +29,12 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'entry_options' => [ 'label' => false, 'attr' => [ - 'class' => 'uk-form uk-form-horizontal' - ] + 'class' => 'uk-form uk-form-horizontal', + ], ], 'attr' => [ - 'class' => 'rz-collection-form-type' - ] + 'class' => 'rz-collection-form-type', + ], ]) ; } diff --git a/src/Form/AttributeGroupsType.php b/src/Form/AttributeGroupsType.php index 39d0c4f6..2ac851c2 100644 --- a/src/Form/AttributeGroupsType.php +++ b/src/Form/AttributeGroupsType.php @@ -5,8 +5,8 @@ namespace RZ\Roadiz\CoreBundle\Form; use Doctrine\ORM\EntityManagerInterface; -use RZ\Roadiz\CoreBundle\Form\DataTransformer\AttributeGroupTransformer; use RZ\Roadiz\CoreBundle\Entity\AttributeGroup; +use RZ\Roadiz\CoreBundle\Form\DataTransformer\AttributeGroupTransformer; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; @@ -29,15 +29,12 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $builder->addModelTransformer(new AttributeGroupTransformer($this->entityManager)); } - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setNormalizer('choices', function (Options $options, $choices) { $criteria = []; $ordering = [ - 'canonicalName' => 'ASC' + 'canonicalName' => 'ASC', ]; $attributeGroups = $this->entityManager ->getRepository(AttributeGroup::class) @@ -51,16 +48,12 @@ public function configureOptions(OptionsResolver $resolver): void return $choices; }); } - /** - * {@inheritdoc} - */ + public function getParent(): ?string { return ChoiceType::class; } - /** - * {@inheritdoc} - */ + public function getBlockPrefix(): string { return 'attribute_groups'; diff --git a/src/Form/AttributeImportType.php b/src/Form/AttributeImportType.php index 7f006640..97e9cb6e 100644 --- a/src/Form/AttributeImportType.php +++ b/src/Form/AttributeImportType.php @@ -11,9 +11,6 @@ class AttributeImportType extends AbstractType { - /** - * @inheritDoc - */ public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->add('file', FileType::class, [ @@ -21,9 +18,9 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'help' => 'attributes.import_form.file.help', 'constraints' => [ new File([ - 'mimeTypes' => ['application/json', 'text/json', 'text/plain'] - ]) - ] + 'mimeTypes' => ['application/json', 'text/json', 'text/plain'], + ]), + ], ]); } } diff --git a/src/Form/AttributeTranslationType.php b/src/Form/AttributeTranslationType.php index 2074be9a..c0838414 100644 --- a/src/Form/AttributeTranslationType.php +++ b/src/Form/AttributeTranslationType.php @@ -19,30 +19,24 @@ class AttributeTranslationType extends AbstractType { protected ManagerRegistry $managerRegistry; - /** - * @param ManagerRegistry $managerRegistry - */ public function __construct(ManagerRegistry $managerRegistry) { $this->managerRegistry = $managerRegistry; } - /** - * @inheritDoc - */ public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->add('label', TextType::class, [ - 'empty_data' => '', - 'label' => false, - 'required' => false, - ]) + 'empty_data' => '', + 'label' => false, + 'required' => false, + ]) ->add('translation', TranslationsType::class, [ 'label' => false, 'required' => true, 'constraints' => [ - new NotNull() - ] + new NotNull(), + ], ]) ->add('options', CollectionType::class, [ 'label' => 'attributes.form.options', @@ -53,7 +47,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'required' => false, ], 'attr' => [ - 'class' => 'rz-collection-form-type' + 'class' => 'rz-collection-form-type', ], ]) ; @@ -61,9 +55,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $builder->get('translation')->addModelTransformer(new TranslationTransformer($this->managerRegistry)); } - /** - * @inheritDoc - */ public function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); @@ -72,14 +63,11 @@ public function configureOptions(OptionsResolver $resolver): void // Keep this constraint as class annotation is not validated new UniqueEntity([ 'fields' => ['attribute', 'translation'], - 'errorPath' => 'translation' - ]) + 'errorPath' => 'translation', + ]), ]); } - /** - * @inheritDoc - */ public function getBlockPrefix(): string { return 'attribute_translation'; diff --git a/src/Form/AttributeType.php b/src/Form/AttributeType.php index cd461657..46053a9f 100644 --- a/src/Form/AttributeType.php +++ b/src/Form/AttributeType.php @@ -17,21 +17,18 @@ class AttributeType extends AbstractType { - /** - * @inheritDoc - */ public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->add('code', TextType::class, [ - 'label' => 'attributes.form.code', - 'required' => true, - 'help' => 'attributes.form_help.code', - ]) + 'label' => 'attributes.form.code', + 'required' => true, + 'help' => 'attributes.form_help.code', + ]) ->add('group', AttributeGroupsType::class, [ 'label' => 'attributes.form.group', 'required' => false, 'help' => 'attributes.form_help.group', - 'placeholder' => 'attributes.form.group.placeholder' + 'placeholder' => 'attributes.form.group.placeholder', ]) ->add('color', ColorType::class, [ 'label' => 'attributes.form.color', @@ -58,13 +55,13 @@ public function buildForm(FormBuilderInterface $builder, array $options): void ->add('searchable', CheckboxType::class, [ 'label' => 'attributes.form.searchable', 'required' => false, - 'help' => 'attributes.form_help.searchable' + 'help' => 'attributes.form_help.searchable', ]) ->add('weight', NumberType::class, [ 'label' => 'attributes.weight', 'required' => false, 'scale' => 1, - 'help' => 'attributes.form_help.weight' + 'help' => 'attributes.form_help.weight', ]) ->add('defaultRealm', RealmChoiceType::class, [ 'label' => 'attributes.defaultRealm', @@ -82,34 +79,28 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'entry_options' => [ 'label' => false, 'attr' => [ - 'class' => 'uk-form uk-form-horizontal' - ] + 'class' => 'uk-form uk-form-horizontal', + ], ], 'attr' => [ - 'class' => 'rz-collection-form-type' - ] + 'class' => 'rz-collection-form-type', + ], ]) ->add('attributeDocuments', AttributeDocumentType::class, [ 'label' => 'attributes.form.documents', 'help' => 'attributes.form_help.documents', 'required' => false, - 'attribute' => $builder->getForm()->getData() + 'attribute' => $builder->getForm()->getData(), ]) ; } - /** - * @inheritDoc - */ public function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); $resolver->setDefault('data_class', Attribute::class); } - /** - * @inheritDoc - */ public function getBlockPrefix(): string { return 'attribute'; diff --git a/src/Form/AttributeValueTranslationType.php b/src/Form/AttributeValueTranslationType.php index 0e3b2e8b..a5beaa3d 100644 --- a/src/Form/AttributeValueTranslationType.php +++ b/src/Form/AttributeValueTranslationType.php @@ -13,7 +13,6 @@ use Symfony\Component\Form\Extension\Core\Type\DateTimeType; use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\Extension\Core\Type\EmailType; -use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\Extension\Core\Type\IntegerType; use Symfony\Component\Form\Extension\Core\Type\NumberType; use Symfony\Component\Form\Extension\Core\Type\TextType; @@ -24,9 +23,6 @@ class AttributeValueTranslationType extends AbstractType { - /** - * @inheritDoc - */ public function buildForm(FormBuilderInterface $builder, array $options): void { $attributeValueTranslation = $builder->getData(); @@ -38,9 +34,9 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'label' => false, 'constraints' => [ new Length([ - 'max' => 254 - ]) - ] + 'max' => 254, + ]), + ], ]; switch ($attributeValueTranslation->getAttributeValue()->getType()) { case AttributeInterface::INTEGER_T: @@ -54,14 +50,14 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'placeholder' => [ 'year' => 'year', 'month' => 'month', - 'day' => 'day' + 'day' => 'day', ], 'widget' => 'single_text', 'format' => 'yyyy-MM-dd', 'attr' => [ 'class' => 'rz-datetime-field', ], - 'constraints' => [] + 'constraints' => [], ])); break; case AttributeInterface::COLOUR_T: @@ -81,7 +77,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'attr' => [ 'class' => 'rz-datetime-field', ], - 'constraints' => [] + 'constraints' => [], ])); break; case AttributeInterface::BOOLEAN_T: @@ -90,14 +86,14 @@ public function buildForm(FormBuilderInterface $builder, array $options): void case AttributeInterface::ENUM_T: $builder->add('value', ChoiceType::class, array_merge($defaultOptions, [ 'required' => true, - 'choices' => $this->getOptions($attributeValueTranslation) + 'choices' => $this->getOptions($attributeValueTranslation), ])); break; case AttributeInterface::EMAIL_T: $builder->add('value', EmailType::class, array_merge($defaultOptions, [ 'constraints' => [ - new Email() - ] + new Email(), + ], ])); break; default: @@ -110,21 +106,11 @@ public function buildForm(FormBuilderInterface $builder, array $options): void ]); } - /** - * @param AttributeValueTranslationInterface $attributeValueTranslation - * - * @return AttributeInterface|null - */ protected function getAttribute(AttributeValueTranslationInterface $attributeValueTranslation): ?AttributeInterface { return $attributeValueTranslation->getAttributeValue()->getAttribute(); } - /** - * @param AttributeValueTranslationInterface $attributeValueTranslation - * - * @return array - */ protected function getOptions(AttributeValueTranslationInterface $attributeValueTranslation): array { $options = $this->getAttribute($attributeValueTranslation)->getOptions( @@ -147,10 +133,6 @@ public function configureOptions(OptionsResolver $resolver): void ]); } - - /** - * @inheritDoc - */ public function getBlockPrefix(): string { return 'attribute_value_translation'; diff --git a/src/Form/AttributeValueType.php b/src/Form/AttributeValueType.php index 452523da..d7bdcf3e 100644 --- a/src/Form/AttributeValueType.php +++ b/src/Form/AttributeValueType.php @@ -4,7 +4,6 @@ namespace RZ\Roadiz\CoreBundle\Form; -use Doctrine\ORM\EntityManagerInterface; use RZ\Roadiz\CoreBundle\Entity\Translation; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; @@ -12,9 +11,6 @@ class AttributeValueType extends AbstractType { - /** - * @inheritDoc - */ public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->add('attribute', AttributeChoiceType::class, [ @@ -23,9 +19,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void ]); } - /** - * @inheritDoc - */ public function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); @@ -34,9 +27,6 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('translation', [Translation::class]); } - /** - * @inheritDoc - */ public function getBlockPrefix(): string { return 'attribute_value'; diff --git a/src/Form/ColorType.php b/src/Form/ColorType.php index 695e9c54..567866c7 100644 --- a/src/Form/ColorType.php +++ b/src/Form/ColorType.php @@ -13,9 +13,6 @@ class ColorType extends AbstractType { - /** - * @inheritDoc - */ public function buildView(FormView $view, FormInterface $form, array $options): void { parent::buildView($view, $form, $options); diff --git a/src/Form/CompareDateType.php b/src/Form/CompareDateType.php index b8bb779f..f28a1fee 100644 --- a/src/Form/CompareDateType.php +++ b/src/Form/CompareDateType.php @@ -21,8 +21,8 @@ public function buildForm(FormBuilderInterface $builder, array $options): void '>' => '>', '<=' => '<=', '>=' => '>=', - '=' => '=' - ] + '=' => '=', + ], ]) ->add('compareDate', DateType::class, [ 'label' => false, @@ -35,9 +35,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void ]); } - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ diff --git a/src/Form/CompareDatetimeType.php b/src/Form/CompareDatetimeType.php index ea3f86d1..c3f69eab 100644 --- a/src/Form/CompareDatetimeType.php +++ b/src/Form/CompareDatetimeType.php @@ -23,8 +23,8 @@ public function buildForm(FormBuilderInterface $builder, array $options): void '>' => '>', '<=' => '<=', '>=' => '>=', - '=' => '=' - ] + '=' => '=', + ], ]) ->add('compareDatetime', DateTimeType::class, [ 'label' => false, @@ -41,9 +41,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void ]); } - /** - * @inheritDoc - */ public function buildView(FormView $view, FormInterface $form, array $options): void { parent::buildView($view, $form, $options); @@ -51,9 +48,6 @@ public function buildView(FormView $view, FormInterface $form, array $options): $view->vars['attr']['class'] = 'rz-compare-datetype'; } - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ diff --git a/src/Form/Constraint/HexadecimalColorValidator.php b/src/Form/Constraint/HexadecimalColorValidator.php index 4b637d11..f0c62054 100644 --- a/src/Form/Constraint/HexadecimalColorValidator.php +++ b/src/Form/Constraint/HexadecimalColorValidator.php @@ -12,7 +12,7 @@ class HexadecimalColorValidator extends ConstraintValidator public function validate(mixed $value, Constraint $constraint): void { if ($constraint instanceof HexadecimalColor) { - if (null !== $value && preg_match('#\#[0-9a-f]{6}#', \mb_strtolower($value)) === 0) { + if (null !== $value && 0 === preg_match('#\#[0-9a-f]{6}#', \mb_strtolower($value))) { $this->context->addViolation($constraint->message); } } diff --git a/src/Form/Constraint/NodeTypeField.php b/src/Form/Constraint/NodeTypeField.php index 34cc19c6..215ba5f9 100644 --- a/src/Form/Constraint/NodeTypeField.php +++ b/src/Form/Constraint/NodeTypeField.php @@ -15,9 +15,6 @@ class NodeTypeField extends Constraint { public string $message = 'default_values_do_not_match_field_type'; - /** - * {@inheritdoc} - */ public function getTargets(): string { return self::CLASS_CONSTRAINT; diff --git a/src/Form/Constraint/NodeTypeFieldValidator.php b/src/Form/Constraint/NodeTypeFieldValidator.php index 696252df..4ab74c3f 100644 --- a/src/Form/Constraint/NodeTypeFieldValidator.php +++ b/src/Form/Constraint/NodeTypeFieldValidator.php @@ -29,6 +29,7 @@ public function validate(mixed $value, Constraint $constraint): void { if (!$value instanceof NodeTypeFieldEntity) { $this->context->buildViolation('Value is not a valid NodeTypeField.')->addViolation(); + return; } @@ -63,10 +64,6 @@ public function validate(mixed $value, Constraint $constraint): void } } - /** - * @param NodeTypeFieldEntity $value - * @param Constraint $constraint - */ protected function validateJoinTypes(NodeTypeFieldEntity $value, Constraint $constraint): void { try { @@ -88,6 +85,7 @@ protected function validateJoinTypes(NodeTypeFieldEntity $value, Constraint $con ->setParameter('%classname%', $configuration['classname']) ->atPath('classname') ->addViolation(); + return; } @@ -135,9 +133,6 @@ protected function validateJoinTypes(NodeTypeFieldEntity $value, Constraint $con } /** - * @param NodeTypeFieldEntity $value - * @param Constraint $constraint - * * @throws \ReflectionException */ protected function validateProviderTypes(NodeTypeFieldEntity $value, Constraint $constraint): void @@ -164,6 +159,7 @@ protected function validateProviderTypes(NodeTypeFieldEntity $value, Constraint ->setParameter('%classname%', $configuration['classname']) ->atPath('defaultValues') ->addViolation(); + return; } @@ -183,10 +179,6 @@ protected function validateProviderTypes(NodeTypeFieldEntity $value, Constraint } } - /** - * @param NodeTypeFieldEntity $value - * @param Constraint $constraint - */ protected function validateCollectionTypes(NodeTypeFieldEntity $value, Constraint $constraint): void { try { @@ -208,6 +200,7 @@ protected function validateCollectionTypes(NodeTypeFieldEntity $value, Constrain ->setParameter('%classname%', $configuration['entry_type']) ->atPath('defaultValues') ->addViolation(); + return; } @@ -226,9 +219,6 @@ protected function validateCollectionTypes(NodeTypeFieldEntity $value, Constrain } } - /** - * @param NodeTypeFieldEntity $value - */ protected function validateMarkdownOptions(NodeTypeFieldEntity $value): void { try { diff --git a/src/Form/Constraint/NonSqlReservedWord.php b/src/Form/Constraint/NonSqlReservedWord.php index 5190f76c..deb5ff7e 100644 --- a/src/Form/Constraint/NonSqlReservedWord.php +++ b/src/Form/Constraint/NonSqlReservedWord.php @@ -17,6 +17,7 @@ class NonSqlReservedWord extends Constraint * List of forbidden field names. These are SQL reserved words. * * @see https://dev.mysql.com/doc/refman/8.0/en/keywords.html + * * @var array */ public static array $forbiddenNames = [ diff --git a/src/Form/Constraint/NonSqlReservedWordValidator.php b/src/Form/Constraint/NonSqlReservedWordValidator.php index da6f1a7d..939a391e 100644 --- a/src/Form/Constraint/NonSqlReservedWordValidator.php +++ b/src/Form/Constraint/NonSqlReservedWordValidator.php @@ -16,9 +16,9 @@ public function validate(mixed $value, Constraint $constraint): void $fieldName = StringHandler::variablize($value); $lowerName = \mb_strtolower($value); if ( - in_array($value, NonSqlReservedWord::$forbiddenNames) || - in_array($lowerName, NonSqlReservedWord::$forbiddenNames) || - in_array($fieldName, NonSqlReservedWord::$forbiddenNames) + in_array($value, NonSqlReservedWord::$forbiddenNames) + || in_array($lowerName, NonSqlReservedWord::$forbiddenNames) + || in_array($fieldName, NonSqlReservedWord::$forbiddenNames) ) { if ($constraint instanceof NonSqlReservedWord) { $this->context->addViolation($constraint->message); diff --git a/src/Form/Constraint/RecaptchaServiceInterface.php b/src/Form/Constraint/RecaptchaServiceInterface.php index 362a60c7..48121a18 100644 --- a/src/Form/Constraint/RecaptchaServiceInterface.php +++ b/src/Form/Constraint/RecaptchaServiceInterface.php @@ -10,12 +10,10 @@ interface RecaptchaServiceInterface * Makes a request to recaptcha service and checks if recaptcha field is valid. * Returns Google error-codes if recaptcha fails. * - * @param string $responseValue - * @param string $verifyUrl * @return true|mixed */ public function check( string $responseValue, - string $verifyUrl = 'https://www.google.com/recaptcha/api/siteverify' + string $verifyUrl = 'https://www.google.com/recaptcha/api/siteverify', ): mixed; } diff --git a/src/Form/Constraint/RecaptchaValidator.php b/src/Form/Constraint/RecaptchaValidator.php index b662918e..8b55ec86 100644 --- a/src/Form/Constraint/RecaptchaValidator.php +++ b/src/Form/Constraint/RecaptchaValidator.php @@ -4,29 +4,28 @@ namespace RZ\Roadiz\CoreBundle\Form\Constraint; -use GuzzleHttp\Client; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; /** * @see https://github.com/thrace-project/form-bundle/blob/master/Validator/Constraint/RecaptchaValidator.php */ class RecaptchaValidator extends ConstraintValidator implements RecaptchaServiceInterface { - protected RequestStack $requestStack; - protected ?string $recaptchaPrivateKey; - - public function __construct(RequestStack $requestStack, ?string $recaptchaPrivateKey) - { - $this->requestStack = $requestStack; - $this->recaptchaPrivateKey = $recaptchaPrivateKey; + public function __construct( + protected HttpClientInterface $client, + protected RequestStack $requestStack, + protected ?string $recaptchaPrivateKey, + ) { } /** - * @param mixed $data - * @param Constraint $constraint - * @throws \GuzzleHttp\Exception\GuzzleException * @see \Symfony\Component\Validator\ConstraintValidator::validate() */ public function validate(mixed $data, Constraint $constraint): void @@ -70,36 +69,34 @@ public function validate(mixed $data, Constraint $constraint): void * Makes a request to recaptcha service and checks if recaptcha field is valid. * Returns Google error-codes if recaptcha fails. * - * @param string $responseValue - * @param string $verifyUrl * @return true|mixed - * @throws \GuzzleHttp\Exception\GuzzleException + * + * @throws ClientExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ServerExceptionInterface + * @throws TransportExceptionInterface */ public function check( string $responseValue, - string $verifyUrl = 'https://www.google.com/recaptcha/api/siteverify' + string $verifyUrl = 'https://www.google.com/recaptcha/api/siteverify', ): mixed { if (empty($this->recaptchaPrivateKey)) { return true; } - $data = [ - 'secret' => $this->recaptchaPrivateKey, - 'response' => $responseValue, - ]; - - $client = new Client(); - $response = $client->post($verifyUrl, [ - 'form_params' => $data, - 'connect_timeout' => 10, + $response = $this->client->request('POST', $verifyUrl, [ + 'query' => [ + 'secret' => $this->recaptchaPrivateKey, + 'response' => $responseValue, + ], 'timeout' => 10, 'headers' => [ - 'Accept' => 'application/json', - ] + 'Accept' => 'application/json', + ], ]); - $jsonResponse = json_decode($response->getBody()->getContents(), true); + $jsonResponse = json_decode($response->getContent(false), true); - return (isset($jsonResponse['success']) && $jsonResponse['success'] === true) ? + return (isset($jsonResponse['success']) && true === $jsonResponse['success']) ? (true) : ($jsonResponse['error-codes']); } diff --git a/src/Form/Constraint/SimpleLatinStringValidator.php b/src/Form/Constraint/SimpleLatinStringValidator.php index af4918a2..93e0f094 100644 --- a/src/Form/Constraint/SimpleLatinStringValidator.php +++ b/src/Form/Constraint/SimpleLatinStringValidator.php @@ -12,7 +12,7 @@ class SimpleLatinStringValidator extends ConstraintValidator public function validate(mixed $value, Constraint $constraint): void { if ($constraint instanceof SimpleLatinString) { - if (null !== $value && preg_match('#[^a-z_\s\-]#', \mb_strtolower($value)) === 1) { + if (null !== $value && 1 === preg_match('#[^a-z_\s\-]#', \mb_strtolower($value))) { $this->context->addViolation($constraint->message); } } diff --git a/src/Form/Constraint/UniqueFilename.php b/src/Form/Constraint/UniqueFilename.php index 3293d75c..b14bd089 100644 --- a/src/Form/Constraint/UniqueFilename.php +++ b/src/Form/Constraint/UniqueFilename.php @@ -7,9 +7,6 @@ use RZ\Roadiz\Documents\Models\DocumentInterface; use Symfony\Component\Validator\Constraint; -/** - * @package RZ\Roadiz\CoreBundle\Form\Constraint - */ class UniqueFilename extends Constraint { public ?DocumentInterface $document = null; diff --git a/src/Form/Constraint/UniqueFilenameValidator.php b/src/Form/Constraint/UniqueFilenameValidator.php index c677d7e2..a55d2f44 100644 --- a/src/Form/Constraint/UniqueFilenameValidator.php +++ b/src/Form/Constraint/UniqueFilenameValidator.php @@ -19,8 +19,6 @@ public function __construct(FilesystemOperator $documentsStorage) } /** - * @param mixed $value - * @param Constraint $constraint * @throws FilesystemException */ public function validate(mixed $value, Constraint $constraint): void @@ -32,15 +30,15 @@ public function validate(mixed $value, Constraint $constraint): void * do nothing. */ if ( - null !== $document && - $value == $document->getFilename() + null !== $document + && $value == $document->getFilename() ) { return; } $folder = $document->getMountFolderPath(); - if ($this->documentsStorage->fileExists($folder . '/' . $value)) { + if ($this->documentsStorage->fileExists($folder.'/'.$value)) { $this->context->addViolation($constraint->message); } } diff --git a/src/Form/Constraint/UniqueNodeNameValidator.php b/src/Form/Constraint/UniqueNodeNameValidator.php index 00bb3d48..4e66cb46 100644 --- a/src/Form/Constraint/UniqueNodeNameValidator.php +++ b/src/Form/Constraint/UniqueNodeNameValidator.php @@ -18,17 +18,14 @@ class UniqueNodeNameValidator extends ConstraintValidator { protected ManagerRegistry $managerRegistry; - /** - * @param ManagerRegistry $managerRegistry - */ public function __construct(ManagerRegistry $managerRegistry) { $this->managerRegistry = $managerRegistry; } /** - * @param mixed $value * @param UniqueNodeName $constraint + * * @throws NoResultException * @throws NonUniqueResultException */ @@ -51,27 +48,20 @@ public function validate(mixed $value, Constraint $constraint): void } } - /** - * @param string $name - * - * @return bool - */ protected function urlAliasExists(string $name): bool { return (bool) $this->managerRegistry->getRepository(UrlAlias::class)->exists($name); } /** - * @param string $name - * - * @return bool - * @throws \Doctrine\ORM\NonUniqueResultException|\Doctrine\ORM\NoResultException + * @throws NonUniqueResultException|NoResultException */ protected function nodeNameExists(string $name): bool { /** @var NodeRepository $nodeRepo */ $nodeRepo = $this->managerRegistry->getRepository(Node::class); $nodeRepo->setDisplayingNotPublishedNodes(true); + return $nodeRepo->exists($name); } } diff --git a/src/Form/Constraint/UniqueTagNameValidator.php b/src/Form/Constraint/UniqueTagNameValidator.php index c7d396b6..b023daf0 100644 --- a/src/Form/Constraint/UniqueTagNameValidator.php +++ b/src/Form/Constraint/UniqueTagNameValidator.php @@ -14,16 +14,13 @@ class UniqueTagNameValidator extends ConstraintValidator { protected ManagerRegistry $managerRegistry; - /** - * @param ManagerRegistry $managerRegistry - */ public function __construct(ManagerRegistry $managerRegistry) { $this->managerRegistry = $managerRegistry; } /** - * @param string $value + * @param string $value * @param UniqueTagName $constraint */ public function validate(mixed $value, Constraint $constraint): void @@ -40,7 +37,6 @@ public function validate(mixed $value, Constraint $constraint): void } /** - * @param string|null $value * @param UniqueTagName $constraint */ protected function testSingleValue(?string $value, Constraint $constraint): void @@ -62,22 +58,13 @@ protected function testSingleValue(?string $value, Constraint $constraint): void } } - /** - * @param string $name - * - * @return bool - */ protected function tagNameExists(string $name): bool { $entity = $this->managerRegistry->getRepository(Tag::class)->findOneByTagName($name); - return (null !== $entity); + return null !== $entity; } - /** - * @param string|null $value - * @return bool - */ protected function isMulti(?string $value): bool { return (bool) \mb_strpos($value ?? '', ','); diff --git a/src/Form/Constraint/ValidAccountConfirmationToken.php b/src/Form/Constraint/ValidAccountConfirmationToken.php index 74a7c642..7f3010e1 100644 --- a/src/Form/Constraint/ValidAccountConfirmationToken.php +++ b/src/Form/Constraint/ValidAccountConfirmationToken.php @@ -9,9 +9,7 @@ class ValidAccountConfirmationToken extends Constraint { /** - * Confirmation token time to live, in seconds - * - * @var integer + * Confirmation token time to live, in seconds. */ public int $ttl = 60; diff --git a/src/Form/Constraint/ValidAccountConfirmationTokenValidator.php b/src/Form/Constraint/ValidAccountConfirmationTokenValidator.php index 6907e90b..7ba50844 100644 --- a/src/Form/Constraint/ValidAccountConfirmationTokenValidator.php +++ b/src/Form/Constraint/ValidAccountConfirmationTokenValidator.php @@ -13,18 +13,13 @@ class ValidAccountConfirmationTokenValidator extends ConstraintValidator { protected ManagerRegistry $managerRegistry; - /** - * @param ManagerRegistry $managerRegistry - */ public function __construct(ManagerRegistry $managerRegistry) { $this->managerRegistry = $managerRegistry; } /** - * @param mixed $value * @param ValidAccountConfirmationToken $constraint - * @return void */ public function validate(mixed $value, Constraint $constraint): void { diff --git a/src/Form/Constraint/ValidAccountEmailValidator.php b/src/Form/Constraint/ValidAccountEmailValidator.php index 97240c4c..05d341f6 100644 --- a/src/Form/Constraint/ValidAccountEmailValidator.php +++ b/src/Form/Constraint/ValidAccountEmailValidator.php @@ -13,18 +13,13 @@ class ValidAccountEmailValidator extends ConstraintValidator { protected ManagerRegistry $managerRegistry; - /** - * @param ManagerRegistry $managerRegistry - */ public function __construct(ManagerRegistry $managerRegistry) { $this->managerRegistry = $managerRegistry; } /** - * @param mixed $value * @param ValidAccountEmail $constraint - * @return void */ public function validate(mixed $value, Constraint $constraint): void { diff --git a/src/Form/Constraint/ValidFacebookNameValidator.php b/src/Form/Constraint/ValidFacebookNameValidator.php index e9b1be15..13d8675a 100644 --- a/src/Form/Constraint/ValidFacebookNameValidator.php +++ b/src/Form/Constraint/ValidFacebookNameValidator.php @@ -10,24 +10,24 @@ class ValidFacebookNameValidator extends ConstraintValidator { + public function __construct(private readonly FacebookPictureFinder $facebookPictureFinder) + { + } + /** - * @param mixed $value * @param ValidFacebookName $constraint - * @return void - * @throws \GuzzleHttp\Exception\GuzzleException */ public function validate(mixed $value, Constraint $constraint): void { - if ($value != "") { - if (0 === preg_match("#^[0-9]*$#", $value)) { + if ('' != $value) { + if (0 === preg_match('#^[0-9]*$#', $value)) { $this->context->addViolation($constraint->message); } else { /* * Test if the username really exists. */ - $facebook = new FacebookPictureFinder($value); try { - $facebook->getPictureUrl(); + $this->facebookPictureFinder->getPictureUrl($value); } catch (\Exception $e) { $this->context->addViolation($constraint->message); } diff --git a/src/Form/Constraint/ValidJsonValidator.php b/src/Form/Constraint/ValidJsonValidator.php index afa16613..b754d331 100644 --- a/src/Form/Constraint/ValidJsonValidator.php +++ b/src/Form/Constraint/ValidJsonValidator.php @@ -4,27 +4,22 @@ namespace RZ\Roadiz\CoreBundle\Form\Constraint; -use JsonException; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; -use Symfony\Component\Yaml\Exception\ParseException; -use Symfony\Component\Yaml\Yaml; class ValidJsonValidator extends ConstraintValidator { /** - * @param mixed $value * @param ValidJson $constraint - * @return void */ public function validate(mixed $value, Constraint $constraint): void { if (!empty($value)) { try { \json_decode($value, true, 512, JSON_THROW_ON_ERROR); - } catch (JsonException $e) { + } catch (\JsonException $e) { $this->context->addViolation($constraint->message, [ - '{{ error }}' => $e->getMessage() + '{{ error }}' => $e->getMessage(), ]); } } diff --git a/src/Form/Constraint/ValidYamlValidator.php b/src/Form/Constraint/ValidYamlValidator.php index e9e96c97..bbc2c31c 100644 --- a/src/Form/Constraint/ValidYamlValidator.php +++ b/src/Form/Constraint/ValidYamlValidator.php @@ -12,13 +12,11 @@ class ValidYamlValidator extends ConstraintValidator { /** - * @param mixed $value * @param ValidYaml $constraint - * @return void */ public function validate(mixed $value, Constraint $constraint): void { - if ($value != "") { + if ('' != $value) { try { if (is_array($value)) { // value already has been parsed into array @@ -27,7 +25,7 @@ public function validate(mixed $value, Constraint $constraint): void Yaml::parse($value); } catch (ParseException $e) { $this->context->addViolation($constraint->message, [ - '{{ error }}' => $e->getMessage() + '{{ error }}' => $e->getMessage(), ]); } } diff --git a/src/Form/CreatePasswordType.php b/src/Form/CreatePasswordType.php index edb2630e..58e25014 100644 --- a/src/Form/CreatePasswordType.php +++ b/src/Form/CreatePasswordType.php @@ -12,9 +12,6 @@ class CreatePasswordType extends RepeatedType { - /** - * @inheritDoc - */ public function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); @@ -24,8 +21,8 @@ public function configureOptions(OptionsResolver $resolver): void 'invalid_message' => 'password.must.match', 'options' => [ 'constraints' => [ - new NotInPasswordCommonList() - ] + new NotInPasswordCommonList(), + ], ], 'first_options' => [ 'label' => 'choose.a.new.password', @@ -40,9 +37,6 @@ public function configureOptions(OptionsResolver $resolver): void ]); } - /** - * {@inheritdoc} - */ public function getBlockPrefix(): string { return 'repeated'; diff --git a/src/Form/CssType.php b/src/Form/CssType.php index f1b124ea..9abfa5be 100644 --- a/src/Form/CssType.php +++ b/src/Form/CssType.php @@ -15,24 +15,16 @@ */ class CssType extends AbstractType { - /** - * {@inheritdoc} - */ public function getParent(): ?string { return TextareaType::class; } - /** - * {@inheritdoc} - */ + public function getBlockPrefix(): string { return 'css'; } - /** - * @inheritDoc - */ public function buildView(FormView $view, FormInterface $form, array $options): void { parent::buildView($view, $form, $options); diff --git a/src/Form/CustomFormsType.php b/src/Form/CustomFormsType.php index 059f5e28..844e9f49 100644 --- a/src/Form/CustomFormsType.php +++ b/src/Form/CustomFormsType.php @@ -4,10 +4,10 @@ namespace RZ\Roadiz\CoreBundle\Form; -use RZ\Roadiz\CoreBundle\Form\Constraint\Recaptcha; use RZ\Roadiz\Core\AbstractEntities\AbstractField; use RZ\Roadiz\CoreBundle\Entity\CustomForm; use RZ\Roadiz\CoreBundle\Entity\CustomFormField; +use RZ\Roadiz\CoreBundle\Form\Constraint\Recaptcha; use RZ\Roadiz\Utils\StringHandler; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; @@ -29,9 +29,6 @@ use Symfony\Component\Validator\Constraints\File; use Symfony\Component\Validator\Constraints\NotBlank; -/** - * @package RZ\Roadiz\CoreBundle\Form - */ class CustomFormsType extends AbstractType { protected ?string $recaptchaPrivateKey; @@ -43,10 +40,6 @@ public function __construct(?string $recaptchaPrivateKey, ?string $recaptchaPubl $this->recaptchaPublicKey = $recaptchaPublicKey; } - /** - * @param FormBuilderInterface $builder - * @param array $options - */ public function buildForm(FormBuilderInterface $builder, array $options): void { $fieldsArray = $this->getFieldsByGroups($options); @@ -62,7 +55,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'inherit_data' => true, 'attr' => [ 'data-group-wrapper' => $groupCanonical, - ] + ], ]); /** @var CustomFormField $subfield */ foreach ($field as $subfield) { @@ -76,8 +69,8 @@ public function buildForm(FormBuilderInterface $builder, array $options): void * Add Google Recaptcha if setting optional options. */ if ( - !empty($this->recaptchaPublicKey) && - !empty($this->recaptchaPrivateKey) + !empty($this->recaptchaPublicKey) + && !empty($this->recaptchaPrivateKey) ) { $builder->add($options['recaptcha_name'], RecaptchaType::class, [ 'label' => false, @@ -87,17 +80,13 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'constraints' => [ new Recaptcha([ 'privateKey' => $this->recaptchaPrivateKey, - 'fieldName' => $options['recaptcha_name'] + 'fieldName' => $options['recaptcha_name'], ]), ], ]); } } - /** - * @param array $options - * @return array - */ protected function getFieldsByGroups(array $options): array { $fieldsArray = []; @@ -106,7 +95,7 @@ protected function getFieldsByGroups(array $options): array /** @var CustomFormField $field */ foreach ($fields as $field) { $groupName = $field->getGroupName(); - if (\is_string($groupName) && $groupName !== '') { + if (\is_string($groupName) && '' !== $groupName) { if (!isset($fieldsArray[$groupName]) || !\is_array($fieldsArray[$groupName])) { $fieldsArray[$groupName] = []; } @@ -120,9 +109,6 @@ protected function getFieldsByGroups(array $options): array } /** - * @param FormBuilderInterface $builder - * @param CustomFormField $field - * @param array $formOptions * @return $this */ protected function addSingleField(FormBuilderInterface $builder, CustomFormField $field, array $formOptions): self @@ -132,11 +118,11 @@ protected function addSingleField(FormBuilderInterface $builder, CustomFormField $this->getTypeForField($field), $this->getOptionsForField($field, $formOptions) ); + return $this; } /** - * @param CustomFormField $field * @return class-string */ protected function getTypeForField(CustomFormField $field): string @@ -159,14 +145,12 @@ protected function getTypeForField(CustomFormField $field): string } /** - * @param CustomFormField $field - * @param array $formOptions * @return array */ protected function getOptionsForField(CustomFormField $field, array $formOptions): array { $option = [ - "label" => $field->getLabel(), + 'label' => $field->getLabel(), 'help' => $field->getDescription(), 'attr' => [ 'data-group' => $field->getGroupName(), @@ -177,7 +161,7 @@ protected function getOptionsForField(CustomFormField $field, array $formOptions $option['attr']['placeholder'] = $field->getPlaceholder(); } - if ($field->getAutocomplete() !== null) { + if (null !== $field->getAutocomplete()) { $option['attr']['autocomplete'] = $field->getAutocomplete(); } @@ -185,8 +169,8 @@ protected function getOptionsForField(CustomFormField $field, array $formOptions $option['required'] = true; $option['constraints'] = [ new NotBlank([ - 'message' => 'you.need.to.fill.this.required.field' - ]) + 'message' => 'you.need.to.fill.this.required.field', + ]), ]; } else { $option['required'] = false; @@ -194,24 +178,24 @@ protected function getOptionsForField(CustomFormField $field, array $formOptions switch ($field->getType()) { case AbstractField::DATETIME_T: - $option["widget"] = 'single_text'; - $option["format"] = DateTimeType::HTML5_FORMAT; + $option['widget'] = 'single_text'; + $option['format'] = DateTimeType::HTML5_FORMAT; break; case AbstractField::DATE_T: - $option["widget"] = 'single_text'; - $option["format"] = DateType::HTML5_FORMAT; + $option['widget'] = 'single_text'; + $option['format'] = DateType::HTML5_FORMAT; break; case AbstractField::ENUM_T: if (!empty($field->getPlaceholder())) { $option['placeholder'] = $field->getPlaceholder(); } - $option["choices"] = $this->getChoices($field); - $option["expanded"] = $field->isExpanded(); + $option['choices'] = $this->getChoices($field); + $option['expanded'] = $field->isExpanded(); if ($formOptions['forceExpanded']) { - $option["expanded"] = true; + $option['expanded'] = true; } - if ($field->isRequired() === false) { + if (false === $field->isRequired()) { $option['placeholder'] = 'none'; } break; @@ -219,14 +203,14 @@ protected function getOptionsForField(CustomFormField $field, array $formOptions if (!empty($field->getPlaceholder())) { $option['placeholder'] = $field->getPlaceholder(); } - $option["choices"] = $this->getChoices($field); - $option["multiple"] = true; - $option["expanded"] = $field->isExpanded(); + $option['choices'] = $this->getChoices($field); + $option['multiple'] = true; + $option['expanded'] = $field->isExpanded(); if ($formOptions['forceExpanded']) { - $option["expanded"] = true; + $option['expanded'] = true; } - if ($field->isRequired() === false) { + if (false === $field->isRequired()) { $option['placeholder'] = 'none'; } break; @@ -252,13 +236,13 @@ protected function getOptionsForField(CustomFormField $field, array $formOptions 'constraints' => [ new File([ 'maxSize' => $formOptions['fileUploadMaxSize'], - 'mimeTypes' => $mimeTypes - ]) - ] + 'mimeTypes' => $mimeTypes, + ]), + ], ]); break; case AbstractField::COUNTRY_T: - $option["expanded"] = $field->isExpanded(); + $option['expanded'] = $field->isExpanded(); if (!empty($field->getPlaceholder())) { $option['placeholder'] = $field->getPlaceholder(); } @@ -277,23 +261,18 @@ protected function getOptionsForField(CustomFormField $field, array $formOptions default: break; } + return $option; } - /** - * @param CustomFormField $field - * @return array - */ protected function getChoices(CustomFormField $field): array { $choices = explode(',', $field->getDefaultValues() ?? ''); $choices = array_map('trim', $choices); + return array_combine(array_values($choices), array_values($choices)); } - /** - * @param OptionsResolver $resolver - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ @@ -312,9 +291,6 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('recaptcha_name', ['string']); } - /** - * @return string - */ public function getBlockPrefix(): string { return 'custom_form_public'; diff --git a/src/Form/DataListTextType.php b/src/Form/DataListTextType.php index 4cf6b095..13c74561 100644 --- a/src/Form/DataListTextType.php +++ b/src/Form/DataListTextType.php @@ -30,7 +30,6 @@ public function buildView(FormView $view, FormInterface $form, array $options): $view->vars['list'] = $options['list']; } - public function getBlockPrefix(): string { return 'data_list_text'; diff --git a/src/Form/DataTransformer/AttributeDocumentsTransformer.php b/src/Form/DataTransformer/AttributeDocumentsTransformer.php index da372aef..d98dbe2e 100644 --- a/src/Form/DataTransformer/AttributeDocumentsTransformer.php +++ b/src/Form/DataTransformer/AttributeDocumentsTransformer.php @@ -6,9 +6,9 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Persistence\ObjectManager; -use RZ\Roadiz\CoreBundle\Entity\Document; use RZ\Roadiz\CoreBundle\Entity\Attribute; use RZ\Roadiz\CoreBundle\Entity\AttributeDocuments; +use RZ\Roadiz\CoreBundle\Entity\Document; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; @@ -23,6 +23,7 @@ public function __construct(private readonly ObjectManager $manager, private rea * to Document entities for displaying in document VueJS component. * * @param AttributeDocuments[]|null $value + * * @return Document[] */ public function transform(mixed $value): array @@ -40,7 +41,6 @@ public function transform(mixed $value): array /** * @param array $value - * @return ArrayCollection */ public function reverseTransform(mixed $value): ArrayCollection { @@ -56,10 +56,7 @@ public function reverseTransform(mixed $value): ArrayCollection ->find($documentId) ; if (null === $document) { - throw new TransformationFailedException(sprintf( - 'A document with id "%s" does not exist!', - $documentId - )); + throw new TransformationFailedException(sprintf('A document with id "%s" does not exist!', $documentId)); } $ttd = new AttributeDocuments($this->attribute, $document); @@ -67,7 +64,7 @@ public function reverseTransform(mixed $value): ArrayCollection $this->manager->persist($ttd); $documents->add($ttd); - $position++; + ++$position; } return $documents; diff --git a/src/Form/DataTransformer/AttributeGroupTransformer.php b/src/Form/DataTransformer/AttributeGroupTransformer.php index 8fb7c550..7180052a 100644 --- a/src/Form/DataTransformer/AttributeGroupTransformer.php +++ b/src/Form/DataTransformer/AttributeGroupTransformer.php @@ -10,16 +10,12 @@ use Symfony\Component\Form\Exception\TransformationFailedException; /** - * Class AttributeGroupTransformer - * @package RZ\Roadiz\CoreBundle\Form\DataTransformer + * Class AttributeGroupTransformer. */ class AttributeGroupTransformer implements DataTransformerInterface { private ObjectManager $manager; - /** - * @param ObjectManager $manager - */ public function __construct(ObjectManager $manager) { $this->manager = $manager; @@ -27,20 +23,16 @@ public function __construct(ObjectManager $manager) /** * @param AttributeGroup|null $value - * @return int|string */ public function transform(mixed $value): int|string { if (!$value instanceof AttributeGroup) { return ''; } + return $value->getId(); } - /** - * @param mixed $value - * @return null|AttributeGroup - */ public function reverseTransform(mixed $value): ?AttributeGroup { if (!$value) { @@ -56,10 +48,7 @@ public function reverseTransform(mixed $value): ?AttributeGroup // causes a validation error // this message is not shown to the user // see the invalid_message option - throw new TransformationFailedException(sprintf( - 'A attribute-group with id "%s" does not exist!', - $value - )); + throw new TransformationFailedException(sprintf('A attribute-group with id "%s" does not exist!', $value)); } return $attributeGroup; diff --git a/src/Form/DataTransformer/DocumentCollectionTransformer.php b/src/Form/DataTransformer/DocumentCollectionTransformer.php index 28fe6359..ffb7103f 100644 --- a/src/Form/DataTransformer/DocumentCollectionTransformer.php +++ b/src/Form/DataTransformer/DocumentCollectionTransformer.php @@ -7,15 +7,8 @@ use Doctrine\Persistence\ObjectManager; use RZ\Roadiz\CoreBundle\Entity\Document; -/** - * @package RZ\Roadiz\CoreBundle\Form\DataTransformer - */ class DocumentCollectionTransformer extends EntityCollectionTransformer { - /** - * @param ObjectManager $manager - * @param bool $asCollection - */ public function __construct(ObjectManager $manager, bool $asCollection = false) { parent::__construct($manager, Document::class, $asCollection); diff --git a/src/Form/DataTransformer/EntityCollectionTransformer.php b/src/Form/DataTransformer/EntityCollectionTransformer.php index bee48792..6d5abccc 100644 --- a/src/Form/DataTransformer/EntityCollectionTransformer.php +++ b/src/Form/DataTransformer/EntityCollectionTransformer.php @@ -10,9 +10,6 @@ use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; -/** - * @package RZ\Roadiz\CoreBundle\Form\DataTransformer - */ class EntityCollectionTransformer implements DataTransformerInterface { protected bool $asCollection; @@ -23,9 +20,7 @@ class EntityCollectionTransformer implements DataTransformerInterface private string $classname; /** - * @param ObjectManager $manager * @param class-string $classname - * @param bool $asCollection */ public function __construct(ObjectManager $manager, string $classname, bool $asCollection = false) { @@ -36,7 +31,6 @@ public function __construct(ObjectManager $manager, string $classname, bool $asC /** * @param iterable|mixed|null $value - * @return string|array */ public function transform(mixed $value): string|array { @@ -51,11 +45,13 @@ public function transform(mixed $value): string|array if ($this->asCollection) { return $ids; } + return implode(',', $ids); } /** * @param string|array|null $value + * * @return array|ArrayCollection */ public function reverseTransform(mixed $value): array|ArrayCollection @@ -64,6 +60,7 @@ public function reverseTransform(mixed $value): array|ArrayCollection if ($this->asCollection) { return new ArrayCollection(); } + return []; } @@ -82,11 +79,7 @@ public function reverseTransform(mixed $value): array|ArrayCollection ->find($entityId) ; if (null === $entity) { - throw new TransformationFailedException(sprintf( - 'A %s with id "%s" does not exist!', - $this->classname, - $entityId - )); + throw new TransformationFailedException(sprintf('A %s with id "%s" does not exist!', $this->classname, $entityId)); } $entities[] = $entity; @@ -94,6 +87,7 @@ public function reverseTransform(mixed $value): array|ArrayCollection if ($this->asCollection) { return new ArrayCollection($entities); } + return $entities; } } diff --git a/src/Form/DataTransformer/ExplorerProviderItemTransformer.php b/src/Form/DataTransformer/ExplorerProviderItemTransformer.php index f94a7863..bc88ff0e 100644 --- a/src/Form/DataTransformer/ExplorerProviderItemTransformer.php +++ b/src/Form/DataTransformer/ExplorerProviderItemTransformer.php @@ -16,24 +16,16 @@ class ExplorerProviderItemTransformer implements DataTransformerInterface protected bool $multiple; protected bool $useCollection; - /** - * @param ExplorerProviderInterface $explorerProvider - * @param bool $multiple - * @param bool $useCollection - */ public function __construct( ExplorerProviderInterface $explorerProvider, bool $multiple = true, - bool $useCollection = false + bool $useCollection = false, ) { $this->explorerProvider = $explorerProvider; $this->multiple = $multiple; $this->useCollection = $useCollection; } - /** - * @inheritDoc - */ public function transform(mixed $value): array|string { if (!empty($value) && $this->explorerProvider->supports($value)) { @@ -41,6 +33,7 @@ public function transform(mixed $value): array|string if (!$item instanceof ExplorerItemInterface) { throw new TransformationFailedException('Cannot transform model to ExplorerItem.'); } + return [$item]; } elseif (!empty($value) && is_iterable($value)) { $idArray = []; @@ -58,12 +51,10 @@ public function transform(mixed $value): array|string return array_filter($idArray); } + return ''; } - /** - * @inheritDoc - */ public function reverseTransform(mixed $value): mixed { if (empty($value)) { @@ -89,8 +80,10 @@ public function reverseTransform(mixed $value): mixed if ($this->useCollection) { return new ArrayCollection(array_filter($originals)); } + return array_filter($originals); } + return array_filter($originals)[0] ?? null; } } diff --git a/src/Form/DataTransformer/FolderCollectionTransformer.php b/src/Form/DataTransformer/FolderCollectionTransformer.php index a234bcac..98e11644 100644 --- a/src/Form/DataTransformer/FolderCollectionTransformer.php +++ b/src/Form/DataTransformer/FolderCollectionTransformer.php @@ -7,15 +7,8 @@ use Doctrine\Persistence\ObjectManager; use RZ\Roadiz\CoreBundle\Entity\Folder; -/** - * @package RZ\Roadiz\CoreBundle\Form\DataTransformer - */ class FolderCollectionTransformer extends EntityCollectionTransformer { - /** - * @param ObjectManager $manager - * @param bool $asCollection - */ public function __construct(ObjectManager $manager, bool $asCollection = false) { parent::__construct($manager, Folder::class, $asCollection); diff --git a/src/Form/DataTransformer/JoinDataTransformer.php b/src/Form/DataTransformer/JoinDataTransformer.php index 5259300a..18ea79c9 100644 --- a/src/Form/DataTransformer/JoinDataTransformer.php +++ b/src/Form/DataTransformer/JoinDataTransformer.php @@ -11,9 +11,6 @@ class JoinDataTransformer implements DataTransformerInterface { - /** - * @var NodeTypeField - */ private NodeTypeField $nodeTypeField; private ManagerRegistry $managerRegistry; /** @@ -22,14 +19,12 @@ class JoinDataTransformer implements DataTransformerInterface private string $entityClassname; /** - * @param NodeTypeField $nodeTypeField - * @param ManagerRegistry $managerRegistry * @param class-string $entityClassname */ public function __construct( NodeTypeField $nodeTypeField, ManagerRegistry $managerRegistry, - string $entityClassname + string $entityClassname, ) { $this->nodeTypeField = $nodeTypeField; $this->entityClassname = $entityClassname; @@ -37,8 +32,7 @@ public function __construct( } /** - * @param mixed $value - * @return array JoinDataTransformer must always return an array for view data. + * @return array joinDataTransformer must always return an array for view data */ public function transform(mixed $value): array { @@ -46,8 +40,8 @@ public function transform(mixed $value): array * If model is already an PersistableInterface */ if ( - !empty($value) && - $value instanceof PersistableInterface + !empty($value) + && $value instanceof PersistableInterface ) { return [$value->getId()]; } elseif (!empty($value) && is_iterable($value)) { @@ -60,15 +54,16 @@ public function transform(mixed $value): array $idArray[] = $entity->getId(); } } + return $idArray; } elseif (!empty($value)) { return [$value]; } + return []; } /** - * @param mixed $value * @return array|object|null */ public function reverseTransform(mixed $value): mixed @@ -85,6 +80,7 @@ public function reverseTransform(mixed $value): mixed return array_search($a->getId(), $value) - array_search($b->getId(), $value); }); + return $unorderedEntities; } if ($this->nodeTypeField->isManyToOne()) { @@ -92,6 +88,7 @@ public function reverseTransform(mixed $value): mixed 'id' => $value, ]); } + return null; } } diff --git a/src/Form/DataTransformer/NodeTypeTransformer.php b/src/Form/DataTransformer/NodeTypeTransformer.php index afe915d9..730255ad 100644 --- a/src/Form/DataTransformer/NodeTypeTransformer.php +++ b/src/Form/DataTransformer/NodeTypeTransformer.php @@ -20,20 +20,16 @@ public function __construct(ObjectManager $manager) /** * @param NodeType|null $value - * @return int|string */ public function transform(mixed $value): int|string { if (!$value instanceof NodeType) { return ''; } + return $value->getId(); } - /** - * @param mixed $value - * @return null|NodeType - */ public function reverseTransform(mixed $value): ?NodeType { if (!$value) { @@ -49,10 +45,7 @@ public function reverseTransform(mixed $value): ?NodeType // causes a validation error // this message is not shown to the user // see the invalid_message option - throw new TransformationFailedException(sprintf( - 'A node-type with id "%s" does not exist!', - $value - )); + throw new TransformationFailedException(sprintf('A node-type with id "%s" does not exist!', $value)); } return $nodeType; diff --git a/src/Form/DataTransformer/PersistableTransformer.php b/src/Form/DataTransformer/PersistableTransformer.php index 28a272c3..f859df1a 100644 --- a/src/Form/DataTransformer/PersistableTransformer.php +++ b/src/Form/DataTransformer/PersistableTransformer.php @@ -20,7 +20,6 @@ class PersistableTransformer implements DataTransformerInterface private EntityManagerInterface $entityManager; /** - * @param EntityManagerInterface $entityManager * @param class-string $doctrineEntity */ public function __construct(EntityManagerInterface $entityManager, string $doctrineEntity) @@ -39,6 +38,7 @@ public function transform(mixed $value): mixed if ($value instanceof PersistableInterface) { return $value->getId(); } + return null; } @@ -47,8 +47,9 @@ public function reverseTransform(mixed $value): ?array if (null === $value) { return null; } + return $this->entityManager->getRepository($this->doctrineEntity)->findBy([ - 'id' => $value + 'id' => $value, ]); } } diff --git a/src/Form/DataTransformer/ProviderDataTransformer.php b/src/Form/DataTransformer/ProviderDataTransformer.php index 205f4102..0da320a2 100644 --- a/src/Form/DataTransformer/ProviderDataTransformer.php +++ b/src/Form/DataTransformer/ProviderDataTransformer.php @@ -13,20 +13,12 @@ class ProviderDataTransformer implements DataTransformerInterface protected NodeTypeField $nodeTypeField; protected ExplorerProviderInterface $provider; - /** - * @param NodeTypeField $nodeTypeField - * @param ExplorerProviderInterface $provider - */ public function __construct(NodeTypeField $nodeTypeField, ExplorerProviderInterface $provider) { $this->nodeTypeField = $nodeTypeField; $this->provider = $provider; } - /** - * @param mixed $value - * @return array|null - */ public function transform(mixed $value): ?array { if (null === $value) { @@ -39,23 +31,19 @@ public function transform(mixed $value): ?array $value = array_filter($value); - if (count($value) === 0) { + if (0 === count($value)) { return null; } return $this->provider->getItemsById($value); } - /** - * @param mixed $value - * @return mixed - */ public function reverseTransform(mixed $value): mixed { if ( - is_array($value) && - $this->nodeTypeField->isSingleProvider() && - isset($value[0]) + is_array($value) + && $this->nodeTypeField->isSingleProvider() + && isset($value[0]) ) { return $value[0]; } diff --git a/src/Form/DataTransformer/ReversePersistableTransformer.php b/src/Form/DataTransformer/ReversePersistableTransformer.php index 11f6c497..8cb1111a 100644 --- a/src/Form/DataTransformer/ReversePersistableTransformer.php +++ b/src/Form/DataTransformer/ReversePersistableTransformer.php @@ -17,13 +17,9 @@ class ReversePersistableTransformer implements DataTransformerInterface * @var class-string */ protected string $doctrineEntity; - /** - * @var EntityManagerInterface - */ private EntityManagerInterface $entityManager; /** - * @param EntityManagerInterface $entityManager * @param class-string $doctrineEntity */ public function __construct(EntityManagerInterface $entityManager, string $doctrineEntity) @@ -37,8 +33,9 @@ public function transform(mixed $value): ?array if (null === $value) { return null; } + return $this->entityManager->getRepository($this->doctrineEntity)->findBy([ - 'id' => $value + 'id' => $value, ]); } @@ -52,6 +49,7 @@ public function reverseTransform(mixed $value): mixed if ($value instanceof PersistableInterface) { return $value->getId(); } + return null; } } diff --git a/src/Form/DataTransformer/TagTranslationDocumentsTransformer.php b/src/Form/DataTransformer/TagTranslationDocumentsTransformer.php index ad9b53f9..9277340b 100644 --- a/src/Form/DataTransformer/TagTranslationDocumentsTransformer.php +++ b/src/Form/DataTransformer/TagTranslationDocumentsTransformer.php @@ -13,18 +13,13 @@ use Symfony\Component\Form\Exception\TransformationFailedException; /** - * Class TagTranslationDocumentsTransformer - * @package RZ\Roadiz\CoreBundle\Form\DataTransformer + * Class TagTranslationDocumentsTransformer. */ class TagTranslationDocumentsTransformer implements DataTransformerInterface { private ObjectManager $manager; private TagTranslation $tagTranslation; - /** - * @param ObjectManager $manager - * @param TagTranslation $tagTranslation - */ public function __construct(ObjectManager $manager, TagTranslation $tagTranslation) { $this->manager = $manager; @@ -36,6 +31,7 @@ public function __construct(ObjectManager $manager, TagTranslation $tagTranslati * to Document entities for displaying in document VueJS component. * * @param TagTranslationDocuments[]|null $value + * * @return Document[] */ public function transform(mixed $value): array @@ -53,7 +49,6 @@ public function transform(mixed $value): array /** * @param array $value - * @return ArrayCollection */ public function reverseTransform(mixed $value): ArrayCollection { @@ -69,10 +64,7 @@ public function reverseTransform(mixed $value): ArrayCollection ->find($documentId) ; if (null === $document) { - throw new TransformationFailedException(sprintf( - 'A document with id "%s" does not exist!', - $documentId - )); + throw new TransformationFailedException(sprintf('A document with id "%s" does not exist!', $documentId)); } $ttd = new TagTranslationDocuments($this->tagTranslation, $document); @@ -80,7 +72,7 @@ public function reverseTransform(mixed $value): ArrayCollection $this->manager->persist($ttd); $documents->add($ttd); - $position++; + ++$position; } return $documents; diff --git a/src/Form/DataTransformer/TranslationTransformer.php b/src/Form/DataTransformer/TranslationTransformer.php index a28baf6b..4291fb24 100644 --- a/src/Form/DataTransformer/TranslationTransformer.php +++ b/src/Form/DataTransformer/TranslationTransformer.php @@ -21,20 +21,16 @@ public function __construct(ManagerRegistry $managerRegistry) /** * @param Translation|null $value - * @return int|string */ public function transform(mixed $value): int|string { if (!($value instanceof PersistableInterface)) { return ''; } + return $value->getId(); } - /** - * @param mixed $value - * @return null|Translation - */ public function reverseTransform(mixed $value): ?Translation { if (!$value) { @@ -51,10 +47,7 @@ public function reverseTransform(mixed $value): ?Translation // causes a validation error // this message is not shown to the user // see the invalid_message option - throw new TransformationFailedException(sprintf( - 'A translation with id "%s" does not exist!', - $value - )); + throw new TransformationFailedException(sprintf('A translation with id "%s" does not exist!', $value)); } return $translation; diff --git a/src/Form/DocumentCollectionType.php b/src/Form/DocumentCollectionType.php index be057e78..0d28ccd1 100644 --- a/src/Form/DocumentCollectionType.php +++ b/src/Form/DocumentCollectionType.php @@ -5,8 +5,8 @@ namespace RZ\Roadiz\CoreBundle\Form; use Doctrine\Persistence\ManagerRegistry; -use RZ\Roadiz\CoreBundle\Form\DataTransformer\DocumentCollectionTransformer; use RZ\Roadiz\CoreBundle\Entity\Document; +use RZ\Roadiz\CoreBundle\Form\DataTransformer\DocumentCollectionTransformer; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; @@ -16,17 +16,11 @@ class DocumentCollectionType extends AbstractType { protected ManagerRegistry $managerRegistry; - /** - * @param ManagerRegistry $managerRegistry - */ public function __construct(ManagerRegistry $managerRegistry) { $this->managerRegistry = $managerRegistry; } - /** - * {@inheritdoc} - */ public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->addModelTransformer(new DocumentCollectionTransformer( @@ -35,9 +29,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void )); } - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ @@ -49,17 +40,11 @@ public function configureOptions(OptionsResolver $resolver): void ]); } - /** - * {@inheritdoc} - */ public function getParent(): ?string { return TextType::class; } - /** - * {@inheritdoc} - */ public function getBlockPrefix(): string { return 'documents'; diff --git a/src/Form/EnumerationType.php b/src/Form/EnumerationType.php index d97578a1..783d1d58 100644 --- a/src/Form/EnumerationType.php +++ b/src/Form/EnumerationType.php @@ -15,9 +15,6 @@ */ class EnumerationType extends AbstractType { - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ @@ -36,6 +33,7 @@ public function configureOptions(OptionsResolver $resolver): void $value = trim($value); $choices[$value] = $value; } + return $choices; }); @@ -43,6 +41,7 @@ public function configureOptions(OptionsResolver $resolver): void if ('' !== $options['nodeTypeField']->getPlaceholder()) { $placeholder = $options['nodeTypeField']->getPlaceholder(); } + return $placeholder; }); @@ -50,16 +49,12 @@ public function configureOptions(OptionsResolver $resolver): void return $options['nodeTypeField']->isExpanded(); }); } - /** - * {@inheritdoc} - */ + public function getParent(): ?string { return ChoiceType::class; } - /** - * {@inheritdoc} - */ + public function getBlockPrefix(): string { return 'enumeration'; diff --git a/src/Form/Error/FormErrorSerializer.php b/src/Form/Error/FormErrorSerializer.php index 4837bdc5..4e4add2f 100644 --- a/src/Form/Error/FormErrorSerializer.php +++ b/src/Form/Error/FormErrorSerializer.php @@ -34,9 +34,9 @@ public function getErrorsAsArray(FormInterface $form): array } if (is_object($cause)) { if ($cause instanceof \Exception) { - $errors[$errorFieldName . '_cause_message'] = $cause->getMessage(); + $errors[$errorFieldName.'_cause_message'] = $cause->getMessage(); } - $errors[$errorFieldName . '_cause'] = get_class($cause); + $errors[$errorFieldName.'_cause'] = get_class($cause); } } } @@ -48,6 +48,7 @@ public function getErrorsAsArray(FormInterface $form): array $errors[$key] = $err; } } + return $errors; } } diff --git a/src/Form/ExplorerProviderItemType.php b/src/Form/ExplorerProviderItemType.php index 335438af..d8fb8708 100644 --- a/src/Form/ExplorerProviderItemType.php +++ b/src/Form/ExplorerProviderItemType.php @@ -4,8 +4,8 @@ namespace RZ\Roadiz\CoreBundle\Form; -use RZ\Roadiz\CoreBundle\Form\DataTransformer\ExplorerProviderItemTransformer; use RZ\Roadiz\CoreBundle\Explorer\ExplorerProviderInterface; +use RZ\Roadiz\CoreBundle\Form\DataTransformer\ExplorerProviderItemTransformer; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\FormBuilderInterface; @@ -13,15 +13,8 @@ use Symfony\Component\Form\FormView; use Symfony\Component\OptionsResolver\OptionsResolver; -/** - * @package RZ\Roadiz\CoreBundle\Form - */ class ExplorerProviderItemType extends AbstractType { - /** - * @param FormBuilderInterface $builder - * @param array $options - */ public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->addModelTransformer(new ExplorerProviderItemTransformer( @@ -33,10 +26,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void /** * Pass data to form twig template. - * - * @param FormView $view - * @param FormInterface $form - * @param array $options */ public function buildView(FormView $view, FormInterface $form, array $options): void { @@ -48,24 +37,18 @@ public function buildView(FormView $view, FormInterface $form, array $options): if ($options['min_length'] > 0) { $view->vars['attr']['data-min-length'] = $options['min_length']; } - if ($options['asMultiple'] === false) { + if (false === $options['asMultiple']) { $view->vars['attr']['data-max-length'] = 1; } $view->vars['provider_class'] = get_class($options['explorerProvider']); } - /** - * {@inheritdoc} - */ public function getBlockPrefix(): string { return 'explorer_provider'; } - /** - * @inheritDoc - */ public function configureOptions(OptionsResolver $resolver): void { parent::configureOptions($resolver); @@ -85,9 +68,6 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('useCollection', ['bool']); } - /** - * {@inheritdoc} - */ public function getParent(): ?string { return HiddenType::class; diff --git a/src/Form/ExtendedBooleanType.php b/src/Form/ExtendedBooleanType.php index 8bacddc1..bcf6fc81 100644 --- a/src/Form/ExtendedBooleanType.php +++ b/src/Form/ExtendedBooleanType.php @@ -13,9 +13,6 @@ */ class ExtendedBooleanType extends AbstractType { - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ @@ -28,16 +25,12 @@ public function configureOptions(OptionsResolver $resolver): void 'expanded' => true, ]); } - /** - * {@inheritdoc} - */ + public function getParent(): ?string { return ChoiceType::class; } - /** - * {@inheritdoc} - */ + public function getBlockPrefix(): string { return 'extendedboolean'; diff --git a/src/Form/GroupsType.php b/src/Form/GroupsType.php index 06cbaa8d..2374cb10 100644 --- a/src/Form/GroupsType.php +++ b/src/Form/GroupsType.php @@ -23,21 +23,14 @@ class GroupsType extends AbstractType protected AuthorizationCheckerInterface $authorizationChecker; protected ManagerRegistry $managerRegistry; - /** - * @param ManagerRegistry $managerRegistry - * @param AuthorizationCheckerInterface $authorizationChecker - */ public function __construct( ManagerRegistry $managerRegistry, - AuthorizationCheckerInterface $authorizationChecker + AuthorizationCheckerInterface $authorizationChecker, ) { $this->authorizationChecker = $authorizationChecker; $this->managerRegistry = $managerRegistry; } - /** - * @inheritDoc - */ public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->addModelTransformer(new CallbackTransformer(function ($modelToForm) { @@ -45,25 +38,24 @@ public function buildForm(FormBuilderInterface $builder, array $options): void if ($modelToForm instanceof Collection) { $modelToForm = $modelToForm->toArray(); } + return array_map(function (Group $group) { return $group->getId(); }, $modelToForm); } + return null; }, function ($formToModels) { - if (null === $formToModels || (is_array($formToModels) && count($formToModels) === 0)) { + if (null === $formToModels || (is_array($formToModels) && 0 === count($formToModels))) { return []; } + return $this->managerRegistry->getRepository(Group::class)->findBy([ - 'id' => $formToModels + 'id' => $formToModels, ]); })); } - - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([]); @@ -80,19 +72,16 @@ public function configureOptions(OptionsResolver $resolver): void $choices[$group->getName()] = $group->getId(); } } + return $choices; }); } - /** - * {@inheritdoc} - */ + public function getParent(): ?string { return ChoiceType::class; } - /** - * {@inheritdoc} - */ + public function getBlockPrefix(): string { return 'groups'; diff --git a/src/Form/HoneypotType.php b/src/Form/HoneypotType.php index 215128f8..4ddc0b3f 100644 --- a/src/Form/HoneypotType.php +++ b/src/Form/HoneypotType.php @@ -16,17 +16,11 @@ class HoneypotType extends AbstractType { - /** - * @inheritDoc - */ public function getParent(): ?string { return TextType::class; } - /** - * @inheritDoc - */ public function buildView(FormView $view, FormInterface $form, array $options): void { parent::buildView($view, $form, $options); @@ -34,26 +28,20 @@ public function buildView(FormView $view, FormInterface $form, array $options): $view->vars['attr'] = [ 'autocomplete' => 'nope', 'tabindex' => -1, - 'style' => 'position: fixed; left: -100vw; top: -100vh;' + 'style' => 'position: fixed; left: -100vw; top: -100vh;', ]; } - /** - * @inheritDoc - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'label' => false, 'required' => false, - 'mapped' => false, - 'data' => '', + 'mapped' => false, + 'data' => '', ]); } - /** - * @inheritDoc - */ public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) { diff --git a/src/Form/JsonType.php b/src/Form/JsonType.php index 6350208f..3d0cb1d4 100644 --- a/src/Form/JsonType.php +++ b/src/Form/JsonType.php @@ -16,24 +16,16 @@ */ class JsonType extends AbstractType { - /** - * {@inheritdoc} - */ public function getParent(): ?string { return TextareaType::class; } - /** - * {@inheritdoc} - */ + public function getBlockPrefix(): string { return 'json'; } - /** - * @inheritDoc - */ public function buildView(FormView $view, FormInterface $form, array $options): void { parent::buildView($view, $form, $options); @@ -46,8 +38,8 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setDefaults([ 'required' => false, 'constraints' => [ - new ValidJson() - ] + new ValidJson(), + ], ]); } } diff --git a/src/Form/LoginRequestForm.php b/src/Form/LoginRequestForm.php index 7d7ccf99..4b91cb0c 100644 --- a/src/Form/LoginRequestForm.php +++ b/src/Form/LoginRequestForm.php @@ -26,9 +26,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void ]); } - /** - * {@inheritdoc} - */ public function getBlockPrefix(): string { return 'login_request'; diff --git a/src/Form/LoginResetForm.php b/src/Form/LoginResetForm.php index d9bfc73e..830b31ce 100644 --- a/src/Form/LoginResetForm.php +++ b/src/Form/LoginResetForm.php @@ -12,9 +12,6 @@ class LoginResetForm extends AbstractType { - /** - * {@inheritdoc} - */ public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->add('token', HiddenType::class, [ @@ -34,17 +31,11 @@ public function buildForm(FormBuilderInterface $builder, array $options): void ]); } - /** - * {@inheritdoc} - */ public function getBlockPrefix(): string { return 'login_reset'; } - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired([ diff --git a/src/Form/MarkdownType.php b/src/Form/MarkdownType.php index f2d90190..c93dcf1a 100644 --- a/src/Form/MarkdownType.php +++ b/src/Form/MarkdownType.php @@ -15,24 +15,16 @@ */ class MarkdownType extends AbstractType { - /** - * {@inheritdoc} - */ public function getParent(): ?string { return TextareaType::class; } - /** - * {@inheritdoc} - */ + public function getBlockPrefix(): string { return 'markdown'; } - /** - * @inheritDoc - */ public function buildView(FormView $view, FormInterface $form, array $options): void { parent::buildView($view, $form, $options); diff --git a/src/Form/MultipleEnumerationType.php b/src/Form/MultipleEnumerationType.php index aefdecf2..54dc6920 100644 --- a/src/Form/MultipleEnumerationType.php +++ b/src/Form/MultipleEnumerationType.php @@ -15,9 +15,6 @@ */ class MultipleEnumerationType extends AbstractType { - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ @@ -32,6 +29,7 @@ public function configureOptions(OptionsResolver $resolver): void if ('' !== $options['nodeTypeField']->getPlaceholder()) { $placeholder = $options['nodeTypeField']->getPlaceholder(); } + return $placeholder; }); @@ -42,6 +40,7 @@ public function configureOptions(OptionsResolver $resolver): void $value = trim($value); $choices[$value] = $value; } + return $choices; }); @@ -49,16 +48,12 @@ public function configureOptions(OptionsResolver $resolver): void return $options['nodeTypeField']->isExpanded(); }); } - /** - * {@inheritdoc} - */ + public function getParent(): ?string { return ChoiceType::class; } - /** - * {@inheritdoc} - */ + public function getBlockPrefix(): string { return 'enumeration'; diff --git a/src/Form/NodeStatesType.php b/src/Form/NodeStatesType.php index 50c2cbac..3d76a523 100644 --- a/src/Form/NodeStatesType.php +++ b/src/Form/NodeStatesType.php @@ -4,9 +4,9 @@ namespace RZ\Roadiz\CoreBundle\Form; -use RZ\Roadiz\CoreBundle\Entity\Node; +use RZ\Roadiz\CoreBundle\Enum\NodeStatus; use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\EnumType; use Symfony\Component\OptionsResolver\OptionsResolver; /** @@ -14,33 +14,19 @@ */ class NodeStatesType extends AbstractType { - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { - $choices = []; - $choices[Node::getStatusLabel(Node::DRAFT)] = Node::DRAFT; - $choices[Node::getStatusLabel(Node::PENDING)] = Node::PENDING; - $choices[Node::getStatusLabel(Node::PUBLISHED)] = Node::PUBLISHED; - $choices[Node::getStatusLabel(Node::ARCHIVED)] = Node::ARCHIVED; - $choices[Node::getStatusLabel(Node::DELETED)] = Node::DELETED; - $resolver->setDefaults([ - 'choices' => $choices, + 'class' => NodeStatus::class, 'placeholder' => 'ignore', ]); } - /** - * {@inheritdoc} - */ + public function getParent(): ?string { - return ChoiceType::class; + return EnumType::class; } - /** - * {@inheritdoc} - */ + public function getBlockPrefix(): string { return 'node_statuses'; diff --git a/src/Form/NodeTypesType.php b/src/Form/NodeTypesType.php index 6c340b31..4c98d70d 100644 --- a/src/Form/NodeTypesType.php +++ b/src/Form/NodeTypesType.php @@ -18,17 +18,11 @@ class NodeTypesType extends AbstractType { protected ManagerRegistry $managerRegistry; - /** - * @param ManagerRegistry $managerRegistry - */ public function __construct(ManagerRegistry $managerRegistry) { $this->managerRegistry = $managerRegistry; } - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ @@ -37,7 +31,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('showInvisible', ['boolean']); $resolver->setNormalizer('choices', function (Options $options, $choices) { $criteria = []; - if ($options['showInvisible'] === false) { + if (false === $options['showInvisible']) { $criteria['visible'] = true; } $nodeTypes = $this->managerRegistry->getRepository(NodeType::class)->findBy($criteria); @@ -51,16 +45,12 @@ public function configureOptions(OptionsResolver $resolver): void return $choices; }); } - /** - * {@inheritdoc} - */ + public function getParent(): ?string { return ChoiceType::class; } - /** - * {@inheritdoc} - */ + public function getBlockPrefix(): string { return 'node_types'; diff --git a/src/Form/NodesType.php b/src/Form/NodesType.php index e3d450d5..bfbe9e0e 100644 --- a/src/Form/NodesType.php +++ b/src/Form/NodesType.php @@ -23,9 +23,6 @@ class NodesType extends AbstractType { protected ManagerRegistry $managerRegistry; - /** - * @param ManagerRegistry $managerRegistry - */ public function __construct(ManagerRegistry $managerRegistry) { $this->managerRegistry = $managerRegistry; @@ -40,20 +37,22 @@ public function buildForm(FormBuilderInterface $builder, array $options): void if (!is_array($mixedEntities)) { return [$mixedEntities]; } + return $mixedEntities; }, function ($mixedIds) use ($options) { /** @var NodeRepository $repository */ $repository = $this->managerRegistry ->getRepository(Node::class) ->setDisplayingAllNodesStatuses(true); - if (\is_array($mixedIds) && count($mixedIds) === 0) { + if (\is_array($mixedIds) && 0 === count($mixedIds)) { return []; } elseif (\is_array($mixedIds)) { - if ($options['multiple'] === false) { + if (false === $options['multiple']) { return $repository->findOneBy(['id' => $mixedIds]); } + return $repository->findBy(['id' => $mixedIds]); - } elseif ($options['multiple'] === true) { + } elseif (true === $options['multiple']) { return []; } else { return $repository->findOneById($mixedIds); @@ -61,11 +60,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void })); } - /** - * {@inheritdoc} - * - * @param OptionsResolver $resolver - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ @@ -76,13 +70,6 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('multiple', ['boolean']); } - /** - * {@inheritdoc} - * - * @param FormView $view - * @param FormInterface $form - * @param array $options - */ public function finishView(FormView $view, FormInterface $form, array $options): void { parent::finishView($view, $form, $options); @@ -94,17 +81,12 @@ public function finishView(FormView $view, FormInterface $form, array $options): $view->vars['data'] = $options['nodes']; } } - /** - * {@inheritdoc} - */ + public function getParent(): ?string { return HiddenType::class; } - /** - * @inheritDoc - */ public function getBlockPrefix(): string { return 'nodes'; diff --git a/src/Form/RealmChoiceType.php b/src/Form/RealmChoiceType.php index a92877b4..337f5e57 100644 --- a/src/Form/RealmChoiceType.php +++ b/src/Form/RealmChoiceType.php @@ -16,9 +16,6 @@ public function __construct(private readonly ManagerRegistry $managerRegistry) { } - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ @@ -36,17 +33,11 @@ public function configureOptions(OptionsResolver $resolver): void }); } - /** - * {@inheritdoc} - */ public function getParent(): ?string { return ChoiceType::class; } - /** - * {@inheritdoc} - */ public function getBlockPrefix(): string { return 'realms'; diff --git a/src/Form/RealmNodeType.php b/src/Form/RealmNodeType.php index 44fcf645..9fcf76b1 100644 --- a/src/Form/RealmNodeType.php +++ b/src/Form/RealmNodeType.php @@ -25,10 +25,10 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'help' => 'realm_node.inheritanceType.help', 'required' => true, 'choices' => [ - 'realm_node.' . RealmInterface::INHERITANCE_ROOT => RealmInterface::INHERITANCE_ROOT, - 'realm_node.' . RealmInterface::INHERITANCE_AUTO => RealmInterface::INHERITANCE_AUTO, - 'realm_node.' . RealmInterface::INHERITANCE_NONE => RealmInterface::INHERITANCE_NONE, - ] + 'realm_node.'.RealmInterface::INHERITANCE_ROOT => RealmInterface::INHERITANCE_ROOT, + 'realm_node.'.RealmInterface::INHERITANCE_AUTO => RealmInterface::INHERITANCE_AUTO, + 'realm_node.'.RealmInterface::INHERITANCE_NONE => RealmInterface::INHERITANCE_NONE, + ], ]); } diff --git a/src/Form/RealmType.php b/src/Form/RealmType.php index def44935..f76007c8 100644 --- a/src/Form/RealmType.php +++ b/src/Form/RealmType.php @@ -27,19 +27,19 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'help' => 'realm.type.help', 'required' => true, 'choices' => [ - 'realm.' . RealmInterface::TYPE_PLAIN_PASSWORD => RealmInterface::TYPE_PLAIN_PASSWORD, - 'realm.' . RealmInterface::TYPE_ROLE => RealmInterface::TYPE_ROLE, - 'realm.' . RealmInterface::TYPE_USER => RealmInterface::TYPE_USER, - ] + 'realm.'.RealmInterface::TYPE_PLAIN_PASSWORD => RealmInterface::TYPE_PLAIN_PASSWORD, + 'realm.'.RealmInterface::TYPE_ROLE => RealmInterface::TYPE_ROLE, + 'realm.'.RealmInterface::TYPE_USER => RealmInterface::TYPE_USER, + ], ])->add('behaviour', ChoiceType::class, [ 'label' => 'realm.behaviour', 'help' => 'realm.behaviour.help', 'required' => true, 'choices' => [ - 'realm.behaviour_' . RealmInterface::BEHAVIOUR_NONE => RealmInterface::BEHAVIOUR_NONE, - 'realm.behaviour_' . RealmInterface::BEHAVIOUR_DENY => RealmInterface::BEHAVIOUR_DENY, - 'realm.behaviour_' . RealmInterface::BEHAVIOUR_HIDE_BLOCKS => RealmInterface::BEHAVIOUR_HIDE_BLOCKS, - ] + 'realm.behaviour_'.RealmInterface::BEHAVIOUR_NONE => RealmInterface::BEHAVIOUR_NONE, + 'realm.behaviour_'.RealmInterface::BEHAVIOUR_DENY => RealmInterface::BEHAVIOUR_DENY, + 'realm.behaviour_'.RealmInterface::BEHAVIOUR_HIDE_BLOCKS => RealmInterface::BEHAVIOUR_HIDE_BLOCKS, + ], ])->add('plainPassword', TextType::class, [ 'label' => 'realm.plainPassword', 'help' => 'realm.plainPassword.help', @@ -68,7 +68,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setDefault('data_class', Realm::class); $resolver->setDefault('constraints', [ new UniqueEntity(['name']), - new UniqueEntity(['serializationGroup']) + new UniqueEntity(['serializationGroup']), ]); } } diff --git a/src/Form/RecaptchaType.php b/src/Form/RecaptchaType.php index a44912b7..cb0706e7 100644 --- a/src/Form/RecaptchaType.php +++ b/src/Form/RecaptchaType.php @@ -11,19 +11,18 @@ use Symfony\Component\OptionsResolver\OptionsResolver; /** - * This class creates recaptcha element + * This class creates recaptcha element. * * @author Nikolay Georgiev + * * @since 1.0 */ class RecaptchaType extends AbstractType { /** - * (non-PHPdoc) + * (non-PHPdoc). + * * @see \Symfony\Component\Form\AbstractType::buildView() - * @param FormView $view - * @param FormInterface $form - * @param array $options */ public function buildView(FormView $view, FormInterface $form, array $options): void { @@ -32,13 +31,12 @@ public function buildView(FormView $view, FormInterface $form, array $options): /** * @see \Symfony\Component\Form\AbstractType::configureOptions() - * @param OptionsResolver $resolver */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'configs' => [ - 'publicKey' => '' + 'publicKey' => '', ], ]); } diff --git a/src/Form/RoleEntityType.php b/src/Form/RoleEntityType.php index 0ac24b40..d49c28e3 100644 --- a/src/Form/RoleEntityType.php +++ b/src/Form/RoleEntityType.php @@ -6,23 +6,20 @@ use Doctrine\Persistence\ManagerRegistry; use RZ\Roadiz\CoreBundle\Entity\Role; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Bundle\SecurityBundle\Security; final class RoleEntityType extends AbstractType { public function __construct( private readonly ManagerRegistry $managerRegistry, - private readonly Security $security + private readonly Security $security, ) { } - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ @@ -44,21 +41,16 @@ public function configureOptions(OptionsResolver $resolver): void $choices[] = $role; } } + return $choices; }); } - /** - * {@inheritdoc} - */ public function getParent(): ?string { return ChoiceType::class; } - /** - * {@inheritdoc} - */ public function getBlockPrefix(): string { return 'role_entity'; diff --git a/src/Form/RolesType.php b/src/Form/RolesType.php index be9cfecf..f022aba2 100644 --- a/src/Form/RolesType.php +++ b/src/Form/RolesType.php @@ -22,21 +22,14 @@ class RolesType extends AbstractType protected ManagerRegistry $managerRegistry; protected AuthorizationCheckerInterface $authorizationChecker; - /** - * @param ManagerRegistry $managerRegistry - * @param AuthorizationCheckerInterface $authorizationChecker - */ public function __construct( ManagerRegistry $managerRegistry, - AuthorizationCheckerInterface $authorizationChecker + AuthorizationCheckerInterface $authorizationChecker, ) { $this->authorizationChecker = $authorizationChecker; $this->managerRegistry = $managerRegistry; } - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ @@ -56,25 +49,22 @@ public function configureOptions(OptionsResolver $resolver): void /** @var Role $role */ foreach ($roles as $role) { if ( - $this->authorizationChecker->isGranted($role->getRole()) && - !$options['roles']->contains($role) + $this->authorizationChecker->isGranted($role->getRole()) + && !$options['roles']->contains($role) ) { $choices[$role->getRole()] = $role->getId(); } } + return $choices; }); } - /** - * {@inheritdoc} - */ + public function getParent(): ?string { return ChoiceType::class; } - /** - * {@inheritdoc} - */ + public function getBlockPrefix(): string { return 'roles'; diff --git a/src/Form/SeparatorType.php b/src/Form/SeparatorType.php index f3c05734..4b2dd1e5 100644 --- a/src/Form/SeparatorType.php +++ b/src/Form/SeparatorType.php @@ -12,18 +12,13 @@ */ class SeparatorType extends AbstractType { - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ - 'required' => false + 'required' => false, ]); } - /** - * {@inheritdoc} - */ + public function getBlockPrefix(): string { return 'separator'; diff --git a/src/Form/SettingDocumentType.php b/src/Form/SettingDocumentType.php index ce4ddd9f..14ccf073 100644 --- a/src/Form/SettingDocumentType.php +++ b/src/Form/SettingDocumentType.php @@ -21,24 +21,16 @@ class SettingDocumentType extends AbstractType protected AbstractDocumentFactory $documentFactory; protected FilesystemOperator $documentsStorage; - /** - * @param ManagerRegistry $managerRegistry - * @param AbstractDocumentFactory $documentFactory - * @param FilesystemOperator $documentsStorage - */ public function __construct( ManagerRegistry $managerRegistry, AbstractDocumentFactory $documentFactory, - FilesystemOperator $documentsStorage + FilesystemOperator $documentsStorage, ) { $this->documentFactory = $documentFactory; $this->managerRegistry = $managerRegistry; $this->documentsStorage = $documentsStorage; } - /** - * {@inheritdoc} - */ public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->addModelTransformer(new CallbackTransformer( @@ -52,6 +44,7 @@ function ($value) { return new File($this->documentsStorage->publicUrl($document->getMountPath()), false); } } + return null; }, function ($file) { @@ -67,14 +60,12 @@ function ($file) { return $document->getId(); } } + return null; } )); } - /** - * {@inheritdoc} - */ public function getParent(): ?string { return FileType::class; diff --git a/src/Form/SettingGroupType.php b/src/Form/SettingGroupType.php index da3b5412..dac0481c 100644 --- a/src/Form/SettingGroupType.php +++ b/src/Form/SettingGroupType.php @@ -20,40 +20,34 @@ class SettingGroupType extends AbstractType { protected ManagerRegistry $managerRegistry; - /** - * @param ManagerRegistry $managerRegistry - */ public function __construct(ManagerRegistry $managerRegistry) { $this->managerRegistry = $managerRegistry; } - /** - * @inheritDoc - */ public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->addModelTransformer(new CallbackTransformer( - function (SettingGroup $settingGroup = null) { + function (?SettingGroup $settingGroup = null) { if (null !== $settingGroup) { // transform the array to a string return $settingGroup->getId(); } + return null; }, function ($id) { if (null !== $id) { $manager = $this->managerRegistry->getManagerForClass(SettingGroup::class); + return $manager->find(SettingGroup::class, $id); } + return null; } )); } - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ @@ -70,19 +64,16 @@ public function configureOptions(OptionsResolver $resolver): void foreach ($groups as $group) { $choices[$group->getName()] = $group->getId(); } + return $choices; }); } - /** - * {@inheritdoc} - */ + public function getParent(): ?string { return ChoiceType::class; } - /** - * {@inheritdoc} - */ + public function getBlockPrefix(): string { return 'setting_groups'; diff --git a/src/Form/SettingType.php b/src/Form/SettingType.php index 56392a67..d9254856 100644 --- a/src/Form/SettingType.php +++ b/src/Form/SettingType.php @@ -21,20 +21,14 @@ class SettingType extends AbstractType { protected SettingTypeResolver $settingTypeResolver; - /** - * @param SettingTypeResolver $settingTypeResolver - */ public function __construct(SettingTypeResolver $settingTypeResolver) { $this->settingTypeResolver = $settingTypeResolver; } - /** - * {@inheritdoc} - */ public function buildForm(FormBuilderInterface $builder, array $options): void { - if ($options['shortEdit'] === false) { + if (false === $options['shortEdit']) { $builder ->add('name', TextType::class, [ 'empty_data' => '', @@ -73,7 +67,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $form = $event->getForm(); if ($setting instanceof Setting) { - if ($setting->getType() === AbstractField::DOCUMENTS_T) { + if (AbstractField::DOCUMENTS_T === $setting->getType()) { $form->add( 'value', SettingDocumentType::class, @@ -98,9 +92,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void }); } - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefault('data_class', Setting::class); @@ -119,12 +110,13 @@ protected function getFormOptionsForSetting(Setting $setting, bool $shortEdit = $values = array_map(function ($item) { return trim($item); }, $values); + return [ 'label' => $label, 'placeholder' => 'choose.value', 'required' => false, 'choices' => array_combine($values, $values), - 'multiple' => $setting->getType() === AbstractField::MULTIPLE_T + 'multiple' => AbstractField::MULTIPLE_T === $setting->getType(), ]; case AbstractField::EMAIL_T: return [ @@ -132,7 +124,7 @@ protected function getFormOptionsForSetting(Setting $setting, bool $shortEdit = 'required' => false, 'constraints' => [ new Email(), - ] + ], ]; case AbstractField::DATETIME_T: return [ diff --git a/src/Form/SettingTypeResolver.php b/src/Form/SettingTypeResolver.php index 4043b72e..b4c44bf9 100644 --- a/src/Form/SettingTypeResolver.php +++ b/src/Form/SettingTypeResolver.php @@ -41,7 +41,6 @@ class SettingTypeResolver ]; /** - * @param Setting $setting * @return class-string */ public function getSettingType(Setting $setting): string diff --git a/src/Form/TagTranslationDocumentType.php b/src/Form/TagTranslationDocumentType.php index bc82c33f..d5a32888 100644 --- a/src/Form/TagTranslationDocumentType.php +++ b/src/Form/TagTranslationDocumentType.php @@ -5,9 +5,9 @@ namespace RZ\Roadiz\CoreBundle\Form; use Doctrine\Persistence\ManagerRegistry; -use RZ\Roadiz\CoreBundle\Form\DataTransformer\TagTranslationDocumentsTransformer; use RZ\Roadiz\CoreBundle\Entity\TagTranslation; use RZ\Roadiz\CoreBundle\Entity\TagTranslationDocuments; +use RZ\Roadiz\CoreBundle\Form\DataTransformer\TagTranslationDocumentsTransformer; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\CollectionType; use Symfony\Component\Form\FormBuilderInterface; @@ -15,25 +15,15 @@ use Symfony\Component\Form\FormEvents; use Symfony\Component\OptionsResolver\OptionsResolver; -/** - * @package RZ\Roadiz\CoreBundle\Form\NodeSource - */ class TagTranslationDocumentType extends AbstractType { protected ManagerRegistry $managerRegistry; - /** - * @param ManagerRegistry $managerRegistry - */ public function __construct(ManagerRegistry $managerRegistry) { $this->managerRegistry = $managerRegistry; } - /** - * @param FormBuilderInterface $builder - * @param array $options - */ public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->addEventListener( @@ -46,9 +36,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void )); } - /** - * @param OptionsResolver $resolver - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ @@ -62,17 +49,11 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('tagTranslation', [TagTranslation::class]); } - /** - * {@inheritdoc} - */ public function getBlockPrefix(): string { return 'documents'; } - /** - * @inheritDoc - */ public function getParent(): ?string { return CollectionType::class; @@ -80,8 +61,6 @@ public function getParent(): ?string /** * Delete existing document association. - * - * @param FormEvent $event */ public function onPostSubmit(FormEvent $event): void { diff --git a/src/Form/TagsType.php b/src/Form/TagsType.php index 2af4cb3c..e2a7b6a5 100644 --- a/src/Form/TagsType.php +++ b/src/Form/TagsType.php @@ -16,9 +16,6 @@ */ class TagsType extends AbstractType { - /** - * @inheritDoc - */ public function buildView(FormView $view, FormInterface $form, array $options): void { parent::buildView($view, $form, $options); @@ -28,8 +25,6 @@ public function buildView(FormView $view, FormInterface $form, array $options): /** * Set every tags s default choices values. - * - * @param OptionsResolver $resolver */ public function configureOptions(OptionsResolver $resolver): void { @@ -39,16 +34,9 @@ public function configureOptions(OptionsResolver $resolver): void 'entry_type' => HiddenType::class, 'label' => 'list.tags.to_link', 'help' => 'use.new_or_existing.tags_with_hierarchy', - ]); + ]); } - /** - * {@inheritdoc} - * - * @param FormView $view - * @param FormInterface $form - * @param array $options - */ public function finishView(FormView $view, FormInterface $form, array $options): void { parent::finishView($view, $form, $options); @@ -59,17 +47,11 @@ public function finishView(FormView $view, FormInterface $form, array $options): $view->vars['data'] = $form->getData(); } - /** - * {@inheritdoc} - */ public function getParent(): ?string { return CollectionType::class; } - /** - * {@inheritdoc} - */ public function getBlockPrefix(): string { return 'tags'; diff --git a/src/Form/ThemesType.php b/src/Form/ThemesType.php index e47a6590..5256b841 100644 --- a/src/Form/ThemesType.php +++ b/src/Form/ThemesType.php @@ -14,9 +14,6 @@ */ class ThemesType extends AbstractType { - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ @@ -32,21 +29,16 @@ public function configureOptions(OptionsResolver $resolver): void $callable = [$class, 'getThemeName']; $value[call_user_func($callable)] = $class; } + return $value; }); } - /** - * {@inheritdoc} - */ public function getParent(): ?string { return ChoiceType::class; } - /** - * {@inheritdoc} - */ public function getBlockPrefix(): string { return 'classname'; diff --git a/src/Form/TranslationsType.php b/src/Form/TranslationsType.php index 5d444401..fa35b363 100644 --- a/src/Form/TranslationsType.php +++ b/src/Form/TranslationsType.php @@ -18,17 +18,11 @@ class TranslationsType extends AbstractType { protected ManagerRegistry $managerRegistry; - /** - * @param ManagerRegistry $managerRegistry - */ public function __construct(ManagerRegistry $managerRegistry) { $this->managerRegistry = $managerRegistry; } - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([]); @@ -48,16 +42,11 @@ public function configureOptions(OptionsResolver $resolver): void }); } - /** - * {@inheritdoc} - */ public function getParent(): ?string { return ChoiceType::class; } - /** - * {@inheritdoc} - */ + public function getBlockPrefix(): string { return 'translations'; diff --git a/src/Form/UrlAliasType.php b/src/Form/UrlAliasType.php index 70d9113a..e44f558a 100644 --- a/src/Form/UrlAliasType.php +++ b/src/Form/UrlAliasType.php @@ -16,17 +16,11 @@ class UrlAliasType extends AbstractType { private ManagerRegistry $managerRegistry; - /** - * @param ManagerRegistry $managerRegistry - */ public function __construct(ManagerRegistry $managerRegistry) { $this->managerRegistry = $managerRegistry; } - /** - * @inheritDoc - */ public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->add('alias', TextType::class, [ @@ -46,9 +40,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void } } - /** - * @inheritDoc - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefault('data_class', UrlAlias::class); diff --git a/src/Form/UserCollectionType.php b/src/Form/UserCollectionType.php index e372ff50..b2df226f 100644 --- a/src/Form/UserCollectionType.php +++ b/src/Form/UserCollectionType.php @@ -23,9 +23,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $builder->addModelTransformer(new CollectionToArrayTransformer()); } - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ @@ -43,17 +40,11 @@ public function configureOptions(OptionsResolver $resolver): void }); } - /** - * {@inheritdoc} - */ public function getParent(): ?string { return ChoiceType::class; } - /** - * {@inheritdoc} - */ public function getBlockPrefix(): string { return 'user_collection'; diff --git a/src/Form/UsersType.php b/src/Form/UsersType.php index dcbcdcdb..fe325550 100644 --- a/src/Form/UsersType.php +++ b/src/Form/UsersType.php @@ -20,17 +20,11 @@ class UsersType extends AbstractType { private ManagerRegistry $managerRegistry; - /** - * @param ManagerRegistry $managerRegistry - */ public function __construct(ManagerRegistry $managerRegistry) { $this->managerRegistry = $managerRegistry; } - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ @@ -50,19 +44,16 @@ public function configureOptions(OptionsResolver $resolver): void $choices[$user->getUserName()] = $user->getId(); } } + return $choices; }); } - /** - * {@inheritdoc} - */ + public function getParent(): ?string { return ChoiceType::class; } - /** - * {@inheritdoc} - */ + public function getBlockPrefix(): string { return 'users'; diff --git a/src/Form/WebhookType.php b/src/Form/WebhookType.php index 44eaf33e..6bea0879 100644 --- a/src/Form/WebhookType.php +++ b/src/Form/WebhookType.php @@ -20,9 +20,6 @@ class WebhookType extends AbstractType { private array $webhookMessageTypes; - /** - * @param array $webhookMessageTypes - */ public function __construct(array $webhookMessageTypes) { $this->webhookMessageTypes = $webhookMessageTypes; @@ -33,7 +30,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $builder->add('messageType', ChoiceType::class, [ 'required' => true, 'label' => 'webhooks.messageType', - 'choices' => $this->webhookMessageTypes + 'choices' => $this->webhookMessageTypes, ])->add('description', TextType::class, [ 'required' => true, 'label' => 'webhooks.description', @@ -54,7 +51,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'required' => false, 'label' => 'webhooks.rootNode', 'help' => 'webhooks.rootNode.help', - 'multiple' => false + 'multiple' => false, ]); $builder->get('payload')->addModelTransformer(new CallbackTransformer(function (?array $model) { diff --git a/src/Form/WebhooksChoiceType.php b/src/Form/WebhooksChoiceType.php index 822dea13..41cab8a2 100644 --- a/src/Form/WebhooksChoiceType.php +++ b/src/Form/WebhooksChoiceType.php @@ -17,15 +17,10 @@ class WebhooksChoiceType extends ChoiceType { private ManagerRegistry $managerRegistry; - /** - * @param ManagerRegistry $managerRegistry - * @param ChoiceListFactoryInterface|null $choiceListFactory - * @param TranslatorInterface|null $translator - */ public function __construct( ManagerRegistry $managerRegistry, - ChoiceListFactoryInterface $choiceListFactory = null, - ?TranslatorInterface $translator = null + ?ChoiceListFactoryInterface $choiceListFactory = null, + ?TranslatorInterface $translator = null, ) { parent::__construct($choiceListFactory, $translator); $this->managerRegistry = $managerRegistry; @@ -38,11 +33,13 @@ public function buildForm(FormBuilderInterface $builder, array $options): void if (null === $webhook) { return null; } + return $webhook->getId(); }, function (?string $id) { if (null === $id) { return null; } + return $this->managerRegistry->getRepository(Webhook::class)->find($id); })); } diff --git a/src/Form/YamlType.php b/src/Form/YamlType.php index 668ddbed..c4983245 100644 --- a/src/Form/YamlType.php +++ b/src/Form/YamlType.php @@ -16,25 +16,16 @@ */ class YamlType extends AbstractType { - /** - * {@inheritdoc} - */ public function getParent(): ?string { return TextareaType::class; } - /** - * {@inheritdoc} - */ public function getBlockPrefix(): string { return 'yaml'; } - /** - * @inheritDoc - */ public function buildView(FormView $view, FormInterface $form, array $options): void { parent::buildView($view, $form, $options); @@ -47,8 +38,8 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setDefaults([ 'required' => false, 'constraints' => [ - new ValidYaml() - ] + new ValidYaml(), + ], ]); } } diff --git a/src/Importer/AttributeImporter.php b/src/Importer/AttributeImporter.php index a3c96fcb..321cf976 100644 --- a/src/Importer/AttributeImporter.php +++ b/src/Importer/AttributeImporter.php @@ -15,22 +15,16 @@ public function __construct(private readonly SerializerInterface $serializer) { } - /** - * @inheritDoc - */ public function supports(string $entityClass): bool { - return $entityClass === Attribute::class || $entityClass === 'array<' . Attribute::class . '>'; + return Attribute::class === $entityClass || $entityClass === 'array<'.Attribute::class.'>'; } - /** - * @inheritDoc - */ public function import(string $serializedData): bool { $this->serializer->deserialize( $serializedData, - 'array<' . Attribute::class . '>', + 'array<'.Attribute::class.'>', 'json', DeserializationContext::create() ->setAttribute(TypedObjectConstructorInterface::PERSIST_NEW_OBJECTS, true) diff --git a/src/Importer/ChainImporter.php b/src/Importer/ChainImporter.php index e975f723..fea7689e 100644 --- a/src/Importer/ChainImporter.php +++ b/src/Importer/ChainImporter.php @@ -4,32 +4,22 @@ namespace RZ\Roadiz\CoreBundle\Importer; -class ChainImporter implements EntityImporterInterface +final class ChainImporter implements EntityImporterInterface { - private array $importers = []; - /** * @param array $importers */ - public function __construct(array $importers = []) + public function __construct(private array $importers = []) { - $this->importers = $importers; } - /** - * @param EntityImporterInterface $entityImporter - * - * @return ChainImporter - */ public function addImporter(EntityImporterInterface $entityImporter): self { $this->importers[] = $entityImporter; + return $this; } - /** - * @inheritDoc - */ public function supports(string $entityClass): bool { foreach ($this->importers as $importer) { @@ -41,18 +31,11 @@ public function supports(string $entityClass): bool return false; } - /** - * @inheritDoc - */ public function import(string $serializedData): bool { throw new \RuntimeException('You cannot call import method on ChainImporter, but importWithType method'); } - - /** - * @inheritDoc - */ public function importWithType(string $serializedData, string $entityClass): bool { foreach ($this->importers as $importer) { @@ -60,6 +43,7 @@ public function importWithType(string $serializedData, string $entityClass): boo return $importer->import($serializedData); } } + return false; } } diff --git a/src/Importer/EntityImporterInterface.php b/src/Importer/EntityImporterInterface.php index cf176773..0cf7108a 100644 --- a/src/Importer/EntityImporterInterface.php +++ b/src/Importer/EntityImporterInterface.php @@ -6,17 +6,7 @@ interface EntityImporterInterface { - /** - * @param string $entityClass - * - * @return bool - */ public function supports(string $entityClass): bool; - /** - * @param string $serializedData - * - * @return bool - */ public function import(string $serializedData): bool; } diff --git a/src/Importer/GroupsImporter.php b/src/Importer/GroupsImporter.php index a25934dc..48f12d3d 100644 --- a/src/Importer/GroupsImporter.php +++ b/src/Importer/GroupsImporter.php @@ -9,39 +9,28 @@ use RZ\Roadiz\CoreBundle\Entity\Group; use RZ\Roadiz\CoreBundle\Serializer\ObjectConstructor\TypedObjectConstructorInterface; -class GroupsImporter implements EntityImporterInterface +final readonly class GroupsImporter implements EntityImporterInterface { - protected SerializerInterface $serializer; - - /** - * @param SerializerInterface $serializer - */ - public function __construct(SerializerInterface $serializer) + public function __construct(private SerializerInterface $serializer) { - $this->serializer = $serializer; } - /** - * @inheritDoc - */ public function supports(string $entityClass): bool { - return $entityClass === Group::class; + return Group::class === $entityClass; } - /** - * @inheritDoc - */ public function import(string $serializedData): bool { $this->serializer->deserialize( $serializedData, - 'array<' . Group::class . '>', + 'array<'.Group::class.'>', 'json', DeserializationContext::create() ->setAttribute(TypedObjectConstructorInterface::PERSIST_NEW_OBJECTS, true) ->setAttribute(TypedObjectConstructorInterface::FLUSH_NEW_OBJECTS, true) ); + return true; } } diff --git a/src/Importer/NodeTypesImporter.php b/src/Importer/NodeTypesImporter.php index 0a8c4077..eaf8f751 100644 --- a/src/Importer/NodeTypesImporter.php +++ b/src/Importer/NodeTypesImporter.php @@ -9,21 +9,18 @@ use RZ\Roadiz\CoreBundle\Entity\NodeType; use RZ\Roadiz\CoreBundle\Serializer\ObjectConstructor\TypedObjectConstructorInterface; -class NodeTypesImporter implements EntityImporterInterface +final readonly class NodeTypesImporter implements EntityImporterInterface { public function __construct( - protected SerializerInterface $serializer + private SerializerInterface $serializer, ) { } public function supports(string $entityClass): bool { - return $entityClass === NodeType::class; + return NodeType::class === $entityClass; } - /** - * @inheritDoc - */ public function import(string $serializedData): bool { $this->serializer->deserialize( diff --git a/src/Importer/RolesImporter.php b/src/Importer/RolesImporter.php index ecdd5389..d9ccec00 100644 --- a/src/Importer/RolesImporter.php +++ b/src/Importer/RolesImporter.php @@ -9,34 +9,22 @@ use RZ\Roadiz\CoreBundle\Entity\Role; use RZ\Roadiz\CoreBundle\Serializer\ObjectConstructor\TypedObjectConstructorInterface; -class RolesImporter implements EntityImporterInterface +final readonly class RolesImporter implements EntityImporterInterface { - protected SerializerInterface $serializer; - - /** - * @param SerializerInterface $serializer - */ - public function __construct(SerializerInterface $serializer) + public function __construct(private SerializerInterface $serializer) { - $this->serializer = $serializer; } - /** - * @inheritDoc - */ public function supports(string $entityClass): bool { - return $entityClass === Role::class; + return Role::class === $entityClass; } - /** - * @inheritDoc - */ public function import(string $serializedData): bool { $this->serializer->deserialize( $serializedData, - 'array<' . Role::class . '>', + 'array<'.Role::class.'>', 'json', DeserializationContext::create() ->setAttribute(TypedObjectConstructorInterface::PERSIST_NEW_OBJECTS, true) diff --git a/src/Importer/SettingsImporter.php b/src/Importer/SettingsImporter.php index 41ed59c0..dc5050bb 100644 --- a/src/Importer/SettingsImporter.php +++ b/src/Importer/SettingsImporter.php @@ -12,37 +12,22 @@ use RZ\Roadiz\CoreBundle\Entity\Setting; use RZ\Roadiz\CoreBundle\Serializer\ObjectConstructor\TypedObjectConstructorInterface; -class SettingsImporter implements EntityImporterInterface +final readonly class SettingsImporter implements EntityImporterInterface { - private ManagerRegistry $managerRegistry; - private SerializerInterface $serializer; - - /** - * @param ManagerRegistry $managerRegistry - * @param SerializerInterface $serializer - */ - public function __construct(ManagerRegistry $managerRegistry, SerializerInterface $serializer) + public function __construct(private ManagerRegistry $managerRegistry, private SerializerInterface $serializer) { - $this->managerRegistry = $managerRegistry; - $this->serializer = $serializer; } - /** - * @inheritDoc - */ public function supports(string $entityClass): bool { - return $entityClass === Setting::class; + return Setting::class === $entityClass; } - /** - * @inheritDoc - */ public function import(string $serializedData): bool { $settings = $this->serializer->deserialize( $serializedData, - 'array<' . Setting::class . '>', + 'array<'.Setting::class.'>', 'json', DeserializationContext::create() ->setAttribute(TypedObjectConstructorInterface::PERSIST_NEW_OBJECTS, true) diff --git a/src/Importer/TagsImporter.php b/src/Importer/TagsImporter.php index 7f902f76..1c97c1a3 100644 --- a/src/Importer/TagsImporter.php +++ b/src/Importer/TagsImporter.php @@ -10,29 +10,17 @@ use RZ\Roadiz\CoreBundle\Serializer\ObjectConstructor\TagObjectConstructor; use RZ\Roadiz\CoreBundle\Serializer\ObjectConstructor\TypedObjectConstructorInterface; -class TagsImporter implements EntityImporterInterface +final readonly class TagsImporter implements EntityImporterInterface { - protected SerializerInterface $serializer; - - /** - * @param SerializerInterface $serializer - */ - public function __construct(SerializerInterface $serializer) + public function __construct(private SerializerInterface $serializer) { - $this->serializer = $serializer; } - /** - * @inheritDoc - */ public function supports(string $entityClass): bool { - return $entityClass === Tag::class; + return Tag::class === $entityClass; } - /** - * @inheritDoc - */ public function import(string $serializedData): bool { $this->serializer->deserialize( diff --git a/src/ListManager/AbstractEntityListManager.php b/src/ListManager/AbstractEntityListManager.php index 2282d0b3..78588ae6 100644 --- a/src/ListManager/AbstractEntityListManager.php +++ b/src/ListManager/AbstractEntityListManager.php @@ -8,7 +8,6 @@ abstract class AbstractEntityListManager implements EntityListManagerInterface { - protected ?Request $request = null; protected bool $pagination = true; protected ?array $queryArray = null; protected ?int $currentPage = null; @@ -19,12 +18,8 @@ abstract class AbstractEntityListManager implements EntityListManagerInterface protected bool $allowRequestSorting = true; protected bool $allowRequestSearching = true; - /** - * @param Request|null $request - */ - public function __construct(?Request $request) + public function __construct(protected readonly ?Request $request = null) { - $this->request = $request; $this->displayNotPublishedNodes = false; $this->displayAllNodesStatuses = false; if (null !== $request) { @@ -35,39 +30,32 @@ public function __construct(?Request $request) $this->itemPerPage = static::ITEM_PER_PAGE; } - public function setAllowRequestSorting(bool $allowRequestSorting) + public function setAllowRequestSorting(bool $allowRequestSorting): self { $this->allowRequestSorting = $allowRequestSorting; + return $this; } - public function setAllowRequestSearching(bool $allowRequestSearching) + public function setAllowRequestSearching(bool $allowRequestSearching): self { $this->allowRequestSearching = $allowRequestSearching; + return $this; } - /** - * @return bool - */ public function isDisplayingNotPublishedNodes(): bool { return $this->displayNotPublishedNodes; } - /** - * @param bool $displayNotPublishedNodes - * @return EntityListManagerInterface - */ - public function setDisplayingNotPublishedNodes(bool $displayNotPublishedNodes) + public function setDisplayingNotPublishedNodes(bool $displayNotPublishedNodes): self { $this->displayNotPublishedNodes = $displayNotPublishedNodes; + return $this; } - /** - * @return bool - */ public function isDisplayingAllNodesStatuses(): bool { return $this->displayAllNodesStatuses; @@ -76,47 +64,34 @@ public function isDisplayingAllNodesStatuses(): bool /** * Switch repository to disable any security on Node status. To use ONLY in order to * view deleted and archived nodes. - * - * @param bool $displayAllNodesStatuses - * @return EntityListManagerInterface */ - public function setDisplayingAllNodesStatuses(bool $displayAllNodesStatuses) + public function setDisplayingAllNodesStatuses(bool $displayAllNodesStatuses): self { $this->displayAllNodesStatuses = $displayAllNodesStatuses; + return $this; } - /** - * @inheritDoc - */ - public function setPage(int $page) + public function setPage(int $page): self { $this->currentPage = $page > 0 ? $page : 1; return $this; } - /** - * @return int - */ protected function getPage(): int { return $this->currentPage; } - /** - * @return EntityListManagerInterface - */ - public function enablePagination() + public function enablePagination(): self { $this->pagination = true; + return $this; } - /** - * @inheritDoc - */ - public function disablePagination() + public function disablePagination(): self { $this->setPage(1); $this->pagination = false; @@ -124,9 +99,6 @@ public function disablePagination() return $this; } - /** - * @inheritDoc - */ public function getAssignation(): array { $assign = [ @@ -179,9 +151,6 @@ protected function getQueryString(): array return $this->queryArray ?? []; } - /** - * @return int - */ protected function getItemPerPage(): int { return $this->itemPerPage; @@ -189,21 +158,14 @@ protected function getItemPerPage(): int /** * Configure a custom item count per page. - * - * @param int $itemPerPage - * - * @return EntityListManagerInterface */ - public function setItemPerPage(int $itemPerPage) + public function setItemPerPage(int $itemPerPage): self { $this->itemPerPage = $itemPerPage > 0 ? $itemPerPage : 1; return $this; } - /** - * @return int - */ public function getPageCount(): int { return (int) ceil($this->getItemCount() / $this->getItemPerPage()); @@ -216,6 +178,7 @@ protected function handleRequestQuery(bool $disabled): void * Disable pagination and paginator */ $this->disablePagination(); + return; } @@ -228,11 +191,11 @@ protected function handleRequestQuery(bool $disabled): void $page = $this->request->query->get('page'); if ( - $this->allowRequestSorting && - \is_string($field) && - $field !== "" && - \is_string($ordering) && - \in_array(strtolower($ordering), ['asc', 'desc']) + $this->allowRequestSorting + && \is_string($field) + && '' !== $field + && \is_string($ordering) + && \in_array(strtolower($ordering), ['asc', 'desc']) ) { $this->handleOrderingParam($field, $ordering); $this->queryArray['field'] = $field; @@ -240,24 +203,24 @@ protected function handleRequestQuery(bool $disabled): void } if ( - $this->allowRequestSearching && - \is_string($search) && - $search !== "" + $this->allowRequestSearching + && \is_string($search) + && '' !== $search ) { $this->handleSearchParam($search); $this->queryArray['search'] = $search; } if ( - \is_numeric($itemPerPage) && - ((int) $itemPerPage) > 0 + \is_numeric($itemPerPage) + && ((int) $itemPerPage) > 0 ) { $this->setItemPerPage((int) $itemPerPage); } if ( - \is_numeric($page) && - ((int) $page) > 1 + \is_numeric($page) + && ((int) $page) > 1 ) { $this->setPage((int) $page); } else { @@ -278,7 +241,7 @@ protected function handleOrderingParam(string $field, string $ordering): void protected function validateOrderingFieldName(string $field): void { // check if field is a valid name without any SQL injection - if (\preg_match('/^[a-zA-Z0-9_.]+$/', $field) !== 1) { + if (1 !== \preg_match('/^[a-zA-Z0-9_.]+$/', $field)) { throw new \InvalidArgumentException('Field name is not valid.'); } } diff --git a/src/ListManager/EntityListManager.php b/src/ListManager/EntityListManager.php index f46adaa8..3f8254bc 100644 --- a/src/ListManager/EntityListManager.php +++ b/src/ListManager/EntityListManager.php @@ -4,68 +4,54 @@ namespace RZ\Roadiz\CoreBundle\ListManager; -use Doctrine\ORM\Tools\Pagination\Paginator as DoctrinePaginator; use Doctrine\Persistence\ObjectManager; use RZ\Roadiz\Core\AbstractEntities\PersistableInterface; use RZ\Roadiz\Core\AbstractEntities\TranslationInterface; use RZ\Roadiz\CoreBundle\Entity\Node; use RZ\Roadiz\CoreBundle\Entity\NodesSources; -use RZ\Roadiz\CoreBundle\Entity\NodeType; use RZ\Roadiz\CoreBundle\Repository\NodeRepository; use RZ\Roadiz\CoreBundle\Repository\StatusAwareRepository; +use Symfony\Component\DependencyInjection\Attribute\Exclude; use Symfony\Component\HttpFoundation\Request; /** * Perform basic filtering and search over entity listings. + * + * @template T of PersistableInterface */ +#[Exclude] class EntityListManager extends AbstractEntityListManager { /** - * @var class-string + * @var Paginator|null */ - protected string $entityName; - protected ObjectManager $entityManager; protected ?Paginator $paginator = null; - protected ?array $orderingArray = null; - protected ?array $filteringArray = null; protected ?array $assignation = null; protected ?TranslationInterface $translation = null; /** - * @param Request|null $request - * @param ObjectManager $entityManager - * @param class-string $entityName - * @param array $preFilters - * @param array $preOrdering + * @param class-string $entityName */ public function __construct( ?Request $request, - ObjectManager $entityManager, - string $entityName, - array $preFilters = [], - array $preOrdering = [] + protected readonly ObjectManager $entityManager, + protected readonly string $entityName, + protected array $filteringArray = [], + protected array $orderingArray = [], ) { parent::__construct($request); - $this->entityName = $entityName; - $this->entityManager = $entityManager; - $this->orderingArray = $preOrdering; - $this->filteringArray = $preFilters; $this->assignation = []; } - /** - * @return TranslationInterface|null - */ public function getTranslation(): ?TranslationInterface { return $this->translation; } /** - * @param TranslationInterface|null $translation * @return $this */ - public function setTranslation(TranslationInterface $translation = null) + public function setTranslation(?TranslationInterface $translation = null): self { $this->translation = $translation; @@ -76,58 +62,59 @@ public function setTranslation(TranslationInterface $translation = null) * Handle request to find filter to apply to entity listing. * * @param bool $disabled Disable pagination and filtering over GET params - * @return void + * + * @throws \ReflectionException */ - public function handle(bool $disabled = false) + public function handle(bool $disabled = false): void { // transform the key chroot in parent if (array_key_exists('chroot', $this->filteringArray)) { - if ($this->filteringArray["chroot"] instanceof Node) { + if ($this->filteringArray['chroot'] instanceof Node) { /** @var NodeRepository $nodeRepo */ $nodeRepo = $this->entityManager ->getRepository(Node::class) ->setDisplayingNotPublishedNodes($this->isDisplayingNotPublishedNodes()) ->setDisplayingAllNodesStatuses($this->isDisplayingAllNodesStatuses()); - $ids = $nodeRepo->findAllOffspringIdByNode($this->filteringArray["chroot"]); // get all offspringId + $ids = $nodeRepo->findAllOffspringIdByNode($this->filteringArray['chroot']); // get all offspringId if (array_key_exists('parent', $this->filteringArray)) { // test if parent key exist - if (is_array($this->filteringArray["parent"])) { + if (is_array($this->filteringArray['parent'])) { // test if multiple parent id if ( - count(array_intersect($this->filteringArray["parent"], $ids)) - != count($this->filteringArray["parent"]) + count(array_intersect($this->filteringArray['parent'], $ids)) + != count($this->filteringArray['parent']) ) { // test if all parent are in the chroot - $this->filteringArray["parent"] = -1; // -1 for make the search return [] + $this->filteringArray['parent'] = -1; // -1 for make the search return [] } } else { - if ($this->filteringArray["parent"] instanceof Node) { + if ($this->filteringArray['parent'] instanceof Node) { // make transform all id in int - $parent = $this->filteringArray["parent"]->getId(); + $parent = $this->filteringArray['parent']->getId(); } else { - $parent = (int) $this->filteringArray["parent"]; + $parent = (int) $this->filteringArray['parent']; } if (!in_array($parent, $ids, true)) { - $this->filteringArray["parent"] = -1; + $this->filteringArray['parent'] = -1; } } } else { - $this->filteringArray["parent"] = $ids; + $this->filteringArray['parent'] = $ids; } } - unset($this->filteringArray["chroot"]); // remove placeholder + unset($this->filteringArray['chroot']); // remove placeholder } $this->handleRequestQuery($disabled); $this->createPaginator(); if ( - $this->allowRequestSearching && - false === $disabled && - null !== $this->request + $this->allowRequestSearching + && false === $disabled + && null !== $this->request ) { $search = $this->request->query->get('search'); - if (\is_string($search) && $search !== "") { + if (\is_string($search) && '' !== $search) { $this->paginator->setSearchPattern($search); } } @@ -137,19 +124,19 @@ protected function handleOrderingParam(string $field, string $ordering): void { $this->validateOrderingFieldName($field); $this->orderingArray = [ - $field => $ordering + $field => $ordering, ]; } - + /** + * @throws \ReflectionException + */ protected function createPaginator(): void { - if ( - $this->entityName === Node::class || - $this->entityName === 'RZ\Roadiz\CoreBundle\Entity\Node' || - $this->entityName === '\RZ\Roadiz\CoreBundle\Entity\Node' || - $this->entityName === "Node" - ) { + $reflectionClass = new \ReflectionClass($this->entityName); + + if (Node::class === $this->entityName) { + // @phpstan-ignore-next-line $this->paginator = new NodePaginator( $this->entityManager, $this->entityName, @@ -158,14 +145,13 @@ protected function createPaginator(): void ); $this->paginator->setTranslation($this->translation); } elseif ( - $this->entityName == NodesSources::class || - $this->entityName == 'RZ\Roadiz\CoreBundle\Entity\NodesSources' || - $this->entityName == '\RZ\Roadiz\CoreBundle\Entity\NodesSources' || - $this->entityName == "NodesSources" || - str_contains($this->entityName, NodeType::getGeneratedEntitiesNamespace()) + NodesSources::class === $this->entityName + || $reflectionClass->isSubclassOf(NodesSources::class) ) { + // @phpstan-ignore-next-line $this->paginator = new NodesSourcesPaginator( $this->entityManager, + // @phpstan-ignore-next-line $this->entityName, $this->itemPerPage, $this->filteringArray @@ -183,14 +169,11 @@ protected function createPaginator(): void $this->paginator->setDisplayingAllNodesStatuses($this->isDisplayingAllNodesStatuses()); } - /** - * @return int - */ public function getItemCount(): int { if ( - $this->pagination === true && - null !== $this->paginator + true === $this->pagination + && null !== $this->paginator ) { return $this->paginator->getTotalCount(); } @@ -198,14 +181,11 @@ public function getItemCount(): int return 0; } - /** - * @return int - */ public function getPageCount(): int { if ( - $this->pagination === true && - null !== $this->paginator + true === $this->pagination + && null !== $this->paginator ) { return $this->paginator->getPageCount(); } @@ -216,12 +196,13 @@ public function getPageCount(): int /** * Return filtered entities. * - * @return array|DoctrinePaginator + * @return array */ - public function getEntities(): array|DoctrinePaginator + public function getEntities(): array { - if ($this->pagination === true && null !== $this->paginator) { + if (true === $this->pagination && null !== $this->paginator) { $this->paginator->setItemsPerPage($this->getItemPerPage()); + return $this->paginator->findByAtPage($this->orderingArray, $this->currentPage); } else { $repository = $this->entityManager->getRepository($this->entityName); @@ -229,6 +210,7 @@ public function getEntities(): array|DoctrinePaginator $repository->setDisplayingNotPublishedNodes($this->isDisplayingNotPublishedNodes()); $repository->setDisplayingAllNodesStatuses($this->isDisplayingAllNodesStatuses()); } + return $repository->findBy( $this->filteringArray, $this->orderingArray, diff --git a/src/ListManager/EntityListManagerInterface.php b/src/ListManager/EntityListManagerInterface.php index 4b5c3551..43f8bb5d 100644 --- a/src/ListManager/EntityListManagerInterface.php +++ b/src/ListManager/EntityListManagerInterface.php @@ -9,63 +9,40 @@ interface EntityListManagerInterface public const ITEM_PER_PAGE = 20; /** - * @param bool $allowRequestSorting * @return $this */ - public function setAllowRequestSorting(bool $allowRequestSorting); + public function setAllowRequestSorting(bool $allowRequestSorting): self; /** - * @param bool $allowRequestSearching * @return $this */ - public function setAllowRequestSearching(bool $allowRequestSearching); + public function setAllowRequestSearching(bool $allowRequestSearching): self; - /** - * @return bool - */ public function isDisplayingNotPublishedNodes(): bool; - /** - * @param bool $displayNotPublishedNodes - * @return EntityListManagerInterface - */ - public function setDisplayingNotPublishedNodes(bool $displayNotPublishedNodes); + public function setDisplayingNotPublishedNodes(bool $displayNotPublishedNodes): self; - /** - * @return bool - */ public function isDisplayingAllNodesStatuses(): bool; /** * Switch repository to disable any security on Node status. To use ONLY in order to * view deleted and archived nodes. - * - * @param bool $displayAllNodesStatuses - * @return EntityListManagerInterface */ - public function setDisplayingAllNodesStatuses(bool $displayAllNodesStatuses); + public function setDisplayingAllNodesStatuses(bool $displayAllNodesStatuses): self; /** * Handle request to find filter to apply to entity listing. * * @param bool $disabled Disable pagination and filtering over GET params - * @return void */ - public function handle(bool $disabled = false); + public function handle(bool $disabled = false): void; /** * Configure a custom current page. - * - * @param int $page - * - * @return EntityListManagerInterface */ - public function setPage(int $page); + public function setPage(int $page): self; - /** - * @return EntityListManagerInterface - */ - public function disablePagination(); + public function disablePagination(): self; /** * Get Twig assignation to render list details. @@ -84,34 +61,20 @@ public function disablePagination(); * * previousPageQuery [string] * * previousQueryArray [array] * * nextQueryArray [array] - * - * @return array */ public function getAssignation(): array; - /** - * @return int - */ public function getItemCount(): int; - /** - * @return int - */ public function getPageCount(): int; /** * Return filtered entities. - * - * @return array|\Doctrine\ORM\Tools\Pagination\Paginator */ - public function getEntities(); + public function getEntities(): array; /** * Configure a custom item count per page. - * - * @param int $itemPerPage - * - * @return EntityListManagerInterface */ - public function setItemPerPage(int $itemPerPage); + public function setItemPerPage(int $itemPerPage): self; } diff --git a/src/ListManager/NodePaginator.php b/src/ListManager/NodePaginator.php index 3f8813fa..eb451ac6 100644 --- a/src/ListManager/NodePaginator.php +++ b/src/ListManager/NodePaginator.php @@ -5,49 +5,40 @@ namespace RZ\Roadiz\CoreBundle\ListManager; use RZ\Roadiz\Core\AbstractEntities\TranslationInterface; +use RZ\Roadiz\CoreBundle\Entity\Node; use RZ\Roadiz\CoreBundle\Repository\NodeRepository; +use Symfony\Component\DependencyInjection\Attribute\Exclude; /** * A paginator class to filter node entities with limit and search. * * This class add some translation and security filters + * + * @extends Paginator */ +#[Exclude] class NodePaginator extends Paginator { protected ?TranslationInterface $translation = null; - /** - * @return TranslationInterface|null - */ - public function getTranslation() + public function getTranslation(): ?TranslationInterface { return $this->translation; } - /** - * @param TranslationInterface|null $translation - * - * @return $this - */ - public function setTranslation(TranslationInterface $translation = null) + public function setTranslation(?TranslationInterface $translation = null): self { $this->translation = $translation; + return $this; } - /** - * Return entities filtered for current page. - * - * @param array $order - * @param int $page - * - * @return array|\Doctrine\ORM\Tools\Pagination\Paginator - */ - public function findByAtPage(array $order = [], int $page = 1) + public function findByAtPage(array $order = [], int $page = 1): array { if (null !== $this->searchPattern) { return $this->searchByAtPage($order, $page); } else { + /** @var NodeRepository $repository */ $repository = $this->getRepository(); if ($repository instanceof NodeRepository) { return $repository->findBy( @@ -58,6 +49,7 @@ public function findByAtPage(array $order = [], int $page = 1) $this->getTranslation() ); } + return $repository->findBy( $this->criteria, $order, @@ -67,9 +59,6 @@ public function findByAtPage(array $order = [], int $page = 1) } } - /** - * @return int - */ public function getTotalCount(): int { if (null === $this->totalCount) { diff --git a/src/ListManager/NodeTreeDtoListManager.php b/src/ListManager/NodeTreeDtoListManager.php new file mode 100644 index 00000000..55d8a426 --- /dev/null +++ b/src/ListManager/NodeTreeDtoListManager.php @@ -0,0 +1,52 @@ +paginator = new NodeTreeDtoPaginator( + $this->entityManager, + Node::class, + $this->itemPerPage, + $this->filteringArray + ); + $this->paginator->setTranslation($this->translation); + $this->paginator->setDisplayingNotPublishedNodes($this->isDisplayingNotPublishedNodes()); + $this->paginator->setDisplayingAllNodesStatuses($this->isDisplayingAllNodesStatuses()); + } + + /** + * @return array + */ + public function getEntities(): array + { + if (true === $this->pagination && null !== $this->paginator) { + $this->paginator->setItemsPerPage($this->getItemPerPage()); + + // @phpstan-ignore-next-line + return $this->paginator->findByAtPage($this->orderingArray, $this->currentPage); + } else { + $repository = $this->entityManager->getRepository(Node::class); + if ($repository instanceof StatusAwareRepository) { + $repository->setDisplayingNotPublishedNodes($this->isDisplayingNotPublishedNodes()); + $repository->setDisplayingAllNodesStatuses($this->isDisplayingAllNodesStatuses()); + } + + return $repository->findByAsNodeTreeDto( + $this->filteringArray, + $this->orderingArray, + $this->itemPerPage + ); + } + } +} diff --git a/src/ListManager/NodeTreeDtoPaginator.php b/src/ListManager/NodeTreeDtoPaginator.php new file mode 100644 index 00000000..6a61fac6 --- /dev/null +++ b/src/ListManager/NodeTreeDtoPaginator.php @@ -0,0 +1,86 @@ +translation; + } + + public function setTranslation(?TranslationInterface $translation = null): self + { + $this->translation = $translation; + + return $this; + } + + /** + * @return array + */ + public function findByAtPage(array $order = [], int $page = 1): array + { + $repository = $this->getRepository(); + if (null !== $this->searchPattern) { + return $repository->searchByAsNodeTreeDto( + $this->searchPattern, + $this->criteria, + $order, + $this->getItemsPerPage(), + $this->getItemsPerPage() * ($page - 1) + ); + } else { + return $repository->findByAsNodeTreeDto( + $this->criteria, + $order, + $this->getItemsPerPage(), + $this->getItemsPerPage() * ($page - 1), + $this->getTranslation() + ); + } + } + + public function getTotalCount(): int + { + if (null === $this->totalCount) { + if (null !== $this->searchPattern) { + $this->totalCount = $this->getRepository() + ->countSearchBy($this->searchPattern, $this->criteria); + } else { + $this->totalCount = $this->getRepository()->countBy( + $this->criteria, + $this->getTranslation() + ); + } + } + + return $this->totalCount; + } + + // @phpstan-ignore-next-line + protected function getRepository(): NodeRepository + { + $repository = $this->em->getRepository(Node::class); + $repository->setDisplayingNotPublishedNodes($this->isDisplayingNotPublishedNodes()); + $repository->setDisplayingAllNodesStatuses($this->isDisplayingAllNodesStatuses()); + + return $repository; + } +} diff --git a/src/ListManager/NodesSourcesPaginator.php b/src/ListManager/NodesSourcesPaginator.php index c6c746ff..c7150223 100644 --- a/src/ListManager/NodesSourcesPaginator.php +++ b/src/ListManager/NodesSourcesPaginator.php @@ -4,16 +4,20 @@ namespace RZ\Roadiz\CoreBundle\ListManager; +use RZ\Roadiz\CoreBundle\Entity\NodesSources; +use RZ\Roadiz\CoreBundle\Repository\NodesSourcesRepository; +use Symfony\Component\DependencyInjection\Attribute\Exclude; + /** * A paginator class to filter node-sources entities with limit and search. * - * This class add authorizationChecker filters + * This class add authorizationChecker filters. + * + * @extends Paginator */ +#[Exclude] class NodesSourcesPaginator extends Paginator { - /** - * {@inheritdoc} - */ public function getTotalCount(): int { if (null === $this->totalCount) { @@ -27,15 +31,7 @@ public function getTotalCount(): int return $this->totalCount; } - /** - * Return entities filtered for current page. - * - * @param array $order - * @param integer $page - * - * @return array|\Doctrine\ORM\Tools\Pagination\Paginator - */ - public function findByAtPage(array $order = [], int $page = 1) + public function findByAtPage(array $order = [], int $page = 1): array { if (null !== $this->searchPattern) { return $this->searchByAtPage($order, $page); @@ -48,4 +44,14 @@ public function findByAtPage(array $order = [], int $page = 1) ); } } + + protected function getRepository(): NodesSourcesRepository + { + /** @var NodesSourcesRepository $repository */ + $repository = $this->em->getRepository($this->entityName); + $repository->setDisplayingNotPublishedNodes($this->isDisplayingNotPublishedNodes()); + $repository->setDisplayingAllNodesStatuses($this->isDisplayingAllNodesStatuses()); + + return $repository; + } } diff --git a/src/ListManager/Paginator.php b/src/ListManager/Paginator.php index 2c22e542..1e087cea 100644 --- a/src/ListManager/Paginator.php +++ b/src/ListManager/Paginator.php @@ -9,75 +9,57 @@ use Doctrine\ORM\NoResultException; use Doctrine\ORM\QueryBuilder; use Doctrine\Persistence\ObjectManager; +use RZ\Roadiz\Core\AbstractEntities\PersistableInterface; use RZ\Roadiz\CoreBundle\Repository\EntityRepository; use RZ\Roadiz\CoreBundle\Repository\StatusAwareRepository; +use Symfony\Component\DependencyInjection\Attribute\Exclude; /** * A simple paginator class to filter entities with limit and search. + * + * @template T of PersistableInterface */ +#[Exclude] class Paginator { - protected int $itemsPerPage; protected ?int $itemCount = null; - /** - * @var class-string - */ - protected string $entityName; - protected array $criteria; protected ?string $searchPattern = null; - protected ObjectManager $em; protected ?int $totalCount = null; protected bool $displayNotPublishedNodes; protected bool $displayAllNodesStatuses; /** - * @param ObjectManager $em - * @param class-string $entityName - * @param int $itemPerPages - * @param array $criteria + * @param class-string $entityName */ public function __construct( - ObjectManager $em, - string $entityName, - int $itemPerPages = 10, - array $criteria = [] + protected readonly ObjectManager $em, + protected readonly string $entityName, + protected int $itemsPerPage = 10, + protected readonly array $criteria = [], ) { - $this->em = $em; - $this->entityName = $entityName; - $this->itemsPerPage = $itemPerPages; - $this->criteria = $criteria; $this->displayNotPublishedNodes = false; $this->displayAllNodesStatuses = false; if (empty($this->entityName)) { - throw new \RuntimeException("Entity name could not be empty", 1); + throw new \RuntimeException('Entity name could not be empty', 1); } if ($this->itemsPerPage < 1) { - throw new \RuntimeException("Items par page could not be lesser than 1.", 1); + throw new \RuntimeException('Items par page could not be lesser than 1.', 1); } } - /** - * @return bool - */ public function isDisplayingNotPublishedNodes(): bool { return $this->displayNotPublishedNodes; } - /** - * @param bool $displayNonPublishedNodes - * @return Paginator - */ - public function setDisplayingNotPublishedNodes(bool $displayNonPublishedNodes) + public function setDisplayingNotPublishedNodes(bool $displayNonPublishedNodes): Paginator { $this->displayNotPublishedNodes = $displayNonPublishedNodes; + return $this; } - /** - * @return bool - */ public function isDisplayingAllNodesStatuses(): bool { return $this->displayAllNodesStatuses; @@ -87,29 +69,24 @@ public function isDisplayingAllNodesStatuses(): bool * Switch repository to disable any security on Node status. To use ONLY in order to * view deleted and archived nodes. * - * @param bool $displayAllNodesStatuses * @return $this */ - public function setDisplayingAllNodesStatuses(bool $displayAllNodesStatuses) + public function setDisplayingAllNodesStatuses(bool $displayAllNodesStatuses): Paginator { $this->displayAllNodesStatuses = $displayAllNodesStatuses; + return $this; } - /** - * @return string|null - */ public function getSearchPattern(): ?string { return $this->searchPattern; } /** - * @param string|null $searchPattern - * * @return $this */ - public function setSearchPattern(?string $searchPattern) + public function setSearchPattern(?string $searchPattern): Paginator { $this->searchPattern = $searchPattern; @@ -118,8 +95,6 @@ public function setSearchPattern(?string $searchPattern) /** * Return total entities count for given criteria. - * - * @return int */ public function getTotalCount(): int { @@ -140,8 +115,8 @@ public function getTotalCount(): int $qb = $this->getSearchQueryBuilder($alias); $qb->select($qb->expr()->countDistinct($alias)); try { - return (int)$qb->getQuery()->getSingleScalarResult(); - } catch (NoResultException | NonUniqueResultException $e) { + return (int) $qb->getQuery()->getSingleScalarResult(); + } catch (NoResultException|NonUniqueResultException $e) { return 0; } } @@ -154,8 +129,6 @@ public function getTotalCount(): int /** * Return page count according to criteria. - * - * @return int */ public function getPageCount(): int { @@ -165,12 +138,9 @@ public function getPageCount(): int /** * Return entities filtered for current page. * - * @param array $order - * @param int $page - * - * @return array|\Doctrine\ORM\Tools\Pagination\Paginator + * @return array */ - public function findByAtPage(array $order = [], int $page = 1) + public function findByAtPage(array $order = [], int $page = 1): array { if (null !== $this->searchPattern) { return $this->searchByAtPage($order, $page); @@ -188,15 +158,15 @@ public function findByAtPage(array $order = [], int $page = 1) /** * Use a search query to paginate instead of a findBy. * - * @param array $order - * @param int $page + * @return array * - * @return array|\Doctrine\ORM\Tools\Pagination\Paginator + * @throws \Exception */ - public function searchByAtPage(array $order = [], int $page = 1) + public function searchByAtPage(array $order = [], int $page = 1): array { $repository = $this->getRepository(); if ($repository instanceof EntityRepository) { + // @phpstan-ignore-next-line return $repository->searchBy( $this->searchPattern, $this->criteria, @@ -215,15 +185,13 @@ public function searchByAtPage(array $order = [], int $page = 1) ->setFirstResult($this->getItemsPerPage() * ($page - 1)); foreach ($order as $key => $value) { - $qb->addOrderBy($alias . '.' . $key, $value); + $qb->addOrderBy($alias.'.'.$key, $value); } return $qb->getQuery()->getResult(); } /** - * @param int $itemsPerPage - * * @return $this */ public function setItemsPerPage(int $itemsPerPage): self @@ -232,9 +200,7 @@ public function setItemsPerPage(int $itemsPerPage): self return $this; } - /** - * @return int - */ + public function getItemsPerPage(): int { return $this->itemsPerPage; @@ -243,18 +209,19 @@ public function getItemsPerPage(): int protected function getSearchQueryBuilder(string $alias): QueryBuilder { $searchableFields = $this->getSearchableFields(); - if (count($searchableFields) === 0) { + if (0 === count($searchableFields)) { throw new \RuntimeException('Entity has no searchable field.'); } $qb = $this->getRepository()->createQueryBuilder($alias); $orX = []; foreach ($this->getSearchableFields() as $field) { $orX[] = $qb->expr()->like( - 'LOWER(' . $alias . '.' . $field . ')', - $qb->expr()->literal('%' . \mb_strtolower($this->searchPattern) . '%') + 'LOWER('.$alias.'.'.$field.')', + $qb->expr()->literal('%'.\mb_strtolower($this->searchPattern).'%') ); } $qb->andWhere($qb->expr()->orX(...$orX)); + return $qb; } @@ -264,19 +231,21 @@ protected function getSearchableFields(): array if (!($metadata instanceof ClassMetadataInfo)) { throw new \RuntimeException('Entity has no metadata.'); } + return EntityRepository::getSearchableColumnsNames($metadata); } /** - * @return \Doctrine\ORM\EntityRepository|EntityRepository|StatusAwareRepository + * @return EntityRepository */ - protected function getRepository() + protected function getRepository(): \Doctrine\ORM\EntityRepository { $repository = $this->em->getRepository($this->entityName); if ($repository instanceof StatusAwareRepository) { $repository->setDisplayingNotPublishedNodes($this->isDisplayingNotPublishedNodes()); $repository->setDisplayingAllNodesStatuses($this->isDisplayingAllNodesStatuses()); } + return $repository; } } diff --git a/src/ListManager/QueryBuilderListManager.php b/src/ListManager/QueryBuilderListManager.php index 98f94230..f675a6e8 100644 --- a/src/ListManager/QueryBuilderListManager.php +++ b/src/ListManager/QueryBuilderListManager.php @@ -6,50 +6,34 @@ use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\Tools\Pagination\Paginator; +use Symfony\Component\DependencyInjection\Attribute\Exclude; use Symfony\Component\HttpFoundation\Request; +#[Exclude] class QueryBuilderListManager extends AbstractEntityListManager { - protected QueryBuilder $queryBuilder; protected ?Paginator $paginator = null; - protected string $identifier; - protected bool $debug = false; /** - * @var null|callable + * @var callable|null */ - protected $searchingCallable = null; + protected $searchingCallable; - /** - * @param Request|null $request - * @param QueryBuilder $queryBuilder - * @param string $identifier - * @param bool $debug - */ public function __construct( ?Request $request, - QueryBuilder $queryBuilder, - string $identifier = 'obj', - bool $debug = false + protected readonly QueryBuilder $queryBuilder, + protected readonly string $identifier = 'obj', + protected readonly bool $debug = false, ) { parent::__construct($request); - $this->queryBuilder = $queryBuilder; - $this->identifier = $identifier; - $this->debug = $debug; } - /** - * @param callable|null $searchingCallable - * @return QueryBuilderListManager - */ public function setSearchingCallable(?callable $searchingCallable): QueryBuilderListManager { $this->searchingCallable = $searchingCallable; + return $this; } - /** - * @param string $search - */ protected function handleSearchParam(string $search): void { parent::handleSearchParam($search); @@ -59,7 +43,7 @@ protected function handleSearchParam(string $search): void } } - public function handle(bool $disabled = false) + public function handle(bool $disabled = false): void { $this->handleRequestQuery($disabled); } @@ -73,64 +57,49 @@ protected function handleOrderingParam(string $field, string $ordering): void ); } - /** - * @return Paginator - */ protected function getPaginator(): Paginator { if (null === $this->paginator) { $this->paginator = new Paginator($this->queryBuilder); } + return $this->paginator; } - /** - * @inheritDoc - */ public function setPage(int $page): self { parent::setPage($page); $this->queryBuilder->setFirstResult($this->getItemPerPage() * ($page - 1)); + return $this; } - /** - * @inheritDoc - */ public function setItemPerPage(int $itemPerPage): self { parent::setItemPerPage($itemPerPage); $this->queryBuilder->setMaxResults((int) $itemPerPage); + return $this; } - - /** - * @inheritDoc - */ public function getItemCount(): int { return $this->getPaginator()->count(); } - /** - * @inheritDoc - */ - public function getEntities(): Paginator + public function getEntities(): array { - return $this->getPaginator(); + return $this->getPaginator()->getIterator()->getArrayCopy(); } - /** - * @return array - */ public function getAssignation(): array { if ($this->debug) { return array_merge(parent::getAssignation(), [ - 'dql_query' => $this->queryBuilder->getDQL() + 'dql_query' => $this->queryBuilder->getDQL(), ]); } + return parent::getAssignation(); } } diff --git a/src/ListManager/SessionListFilters.php b/src/ListManager/SessionListFilters.php index 4e8dc5f7..d3027bf4 100644 --- a/src/ListManager/SessionListFilters.php +++ b/src/ListManager/SessionListFilters.php @@ -4,21 +4,20 @@ namespace RZ\Roadiz\CoreBundle\ListManager; +use Symfony\Component\DependencyInjection\Attribute\Exclude; use Symfony\Component\HttpFoundation\Request; +#[Exclude] class SessionListFilters { public function __construct( private readonly string $sessionIdentifier, - private readonly int $defaultItemsParPage = 20 + private readonly int $defaultItemsParPage = 20, ) { } /** * Handle item_per_page filter form session or from request query. - * - * @param Request $request - * @param EntityListManagerInterface $listManager */ public function handleItemPerPage(Request $request, EntityListManagerInterface $listManager): void { @@ -26,11 +25,11 @@ public function handleItemPerPage(Request $request, EntityListManagerInterface $ * Check if item_per_page is available from session */ if ( - $request->hasSession() && - $request->getSession()->has($this->sessionIdentifier) && - $request->getSession()->get($this->sessionIdentifier) > 0 && - (!$request->query->has('item_per_page') || - $request->query->get('item_per_page') < 1) + $request->hasSession() + && $request->getSession()->has($this->sessionIdentifier) + && $request->getSession()->get($this->sessionIdentifier) > 0 + && (!$request->query->has('item_per_page') + || $request->query->get('item_per_page') < 1) ) { /* * Item count is in session @@ -38,8 +37,8 @@ public function handleItemPerPage(Request $request, EntityListManagerInterface $ $request->query->set('item_per_page', intval($request->getSession()->get($this->sessionIdentifier))); $listManager->setItemPerPage(intval($request->getSession()->get($this->sessionIdentifier))); } elseif ( - $request->query->has('item_per_page') && - $request->query->get('item_per_page') > 0 + $request->query->has('item_per_page') + && $request->query->get('item_per_page') > 0 ) { /* * Item count is in query, save it in session diff --git a/src/ListManager/TagListManager.php b/src/ListManager/TagListManager.php index 4be28eb7..a0d290e3 100644 --- a/src/ListManager/TagListManager.php +++ b/src/ListManager/TagListManager.php @@ -7,36 +7,33 @@ use Doctrine\Persistence\ObjectManager; use RZ\Roadiz\CoreBundle\Entity\Tag; use RZ\Roadiz\CoreBundle\Entity\TagTranslation; +use Symfony\Component\DependencyInjection\Attribute\Exclude; use Symfony\Component\HttpFoundation\Request; -use Doctrine\ORM\Tools\Pagination\Paginator as DoctrinePaginator; /** * Perform basic filtering and search over entity listings. + * + * @extends EntityListManager */ +#[Exclude] class TagListManager extends EntityListManager { - /** - * @param Request|null $request - * @param ObjectManager $entityManager - * @param array $preFilters - * @param array $preOrdering - */ public function __construct( ?Request $request, ObjectManager $entityManager, array $preFilters = [], - array $preOrdering = [] + array $preOrdering = [], ) { parent::__construct($request, $entityManager, Tag::class, $preFilters, $preOrdering); } /** - * @return array|DoctrinePaginator + * @return array|array */ - public function getEntities(): array|DoctrinePaginator + public function getEntities(): array { try { - if ($this->searchPattern != '') { + if ('' != $this->searchPattern) { return $this->entityManager ->getRepository(TagTranslation::class) ->searchBy($this->searchPattern, $this->filteringArray, $this->orderingArray); diff --git a/src/Logger/DoctrineHandler.php b/src/Logger/DoctrineHandler.php index 99c540fd..7f775fbc 100644 --- a/src/Logger/DoctrineHandler.php +++ b/src/Logger/DoctrineHandler.php @@ -30,7 +30,7 @@ public function __construct( private readonly RequestStack $requestStack, private readonly DocumentUrlGeneratorInterface $documentUrlGenerator, $level = Logger::INFO, - $bubble = true + $bubble = true, ) { parent::__construct($level, $bubble); } @@ -40,11 +40,12 @@ protected function getThumbnailSourcePath(?DocumentInterface $thumbnail): ?strin if (null === $thumbnail || $thumbnail->isPrivate()) { return null; } + return $this->documentUrlGenerator ->setDocument($thumbnail) ->setOptions([ - "fit" => "150x150", - "quality" => 70, + 'fit' => '150x150', + 'quality' => 70, ]) ->getUrl(); } @@ -109,9 +110,6 @@ protected function populateForNodesSources(NodesSources $value, Log $log, array } } - /** - * @param array $record - */ public function write(array $record): void { try { @@ -135,7 +133,7 @@ public function write(array $record): void $this->populateForNode($value, $log, $data); } elseif ($value instanceof NodesSources) { $this->populateForNodesSources($value, $log, $data); - } elseif ($key === 'entity' && $value instanceof PersistableInterface) { + } elseif ('entity' === $key && $value instanceof PersistableInterface) { $log->setEntityClass(get_class($value)); $log->setEntityId($value->getId()); @@ -145,7 +143,7 @@ public function write(array $record): void $data = array_merge( $data, [ - 'entity_title' => $value->{$method}() + 'entity_title' => $value->{$method}(), ] ); break; @@ -157,7 +155,7 @@ public function write(array $record): void $data, [ 'exception_class' => get_class($value), - 'message' => $value->getMessage() + 'message' => $value->getMessage(), ] ); } @@ -170,7 +168,7 @@ public function write(array $record): void ] ); } - if ($key === 'request' && \is_array($value)) { + if ('request' === $key && \is_array($value)) { $data = array_merge( $data, $value @@ -202,7 +200,7 @@ public function write(array $record): void 'user_email' => $user->getEmail(), 'user_public_name' => $user->getPublicName(), 'user_picture_url' => $user->getPictureUrl(), - 'user_id' => $user->getId() + 'user_id' => $user->getId(), ] ); } else { diff --git a/src/Logger/Entity/Log.php b/src/Logger/Entity/Log.php index 8dbdf02f..8da1875c 100644 --- a/src/Logger/Entity/Log.php +++ b/src/Logger/Entity/Log.php @@ -16,19 +16,19 @@ #[ ORM\Entity(repositoryClass: LogRepository::class), - ORM\Table(name: "log"), - ORM\Index(columns: ["datetime"]), - ORM\Index(columns: ["entity_class"]), - ORM\Index(columns: ["entity_class", "entity_id"]), - ORM\Index(columns: ["entity_class", "datetime"], name: "log_entity_class_datetime"), - ORM\Index(columns: ["entity_class", "entity_id", "datetime"], name: "log_entity_class_id_datetime"), - ORM\Index(columns: ["username", "datetime"], name: "log_username_datetime"), - ORM\Index(columns: ["user_id", "datetime"], name: "log_user_datetime"), - ORM\Index(columns: ["level", "datetime"], name: "log_level_datetime"), - ORM\Index(columns: ["channel", "datetime"], name: "log_channel_datetime"), - ORM\Index(columns: ["level"]), - ORM\Index(columns: ["username"]), - ORM\Index(columns: ["channel"]), + ORM\Table(name: 'log'), + ORM\Index(columns: ['datetime']), + ORM\Index(columns: ['entity_class']), + ORM\Index(columns: ['entity_class', 'entity_id']), + ORM\Index(columns: ['entity_class', 'datetime'], name: 'log_entity_class_datetime'), + ORM\Index(columns: ['entity_class', 'entity_id', 'datetime'], name: 'log_entity_class_id_datetime'), + ORM\Index(columns: ['username', 'datetime'], name: 'log_username_datetime'), + ORM\Index(columns: ['user_id', 'datetime'], name: 'log_user_datetime'), + ORM\Index(columns: ['level', 'datetime'], name: 'log_level_datetime'), + ORM\Index(columns: ['channel', 'datetime'], name: 'log_channel_datetime'), + ORM\Index(columns: ['level']), + ORM\Index(columns: ['username']), + ORM\Index(columns: ['channel']), ORM\HasLifecycleCallbacks ] class Log extends AbstractEntity @@ -82,9 +82,6 @@ class Log extends AbstractEntity // @phpstan-ignore-next-line protected ?string $entityClass = null; - /** - * @var string|int|null - */ #[ORM\Column(name: 'entity_id', type: 'string', length: 36, unique: false, nullable: true)] #[SymfonySerializer\Groups(['log'])] #[Serializer\Groups(['log'])] @@ -98,59 +95,41 @@ class Log extends AbstractEntity protected ?array $additionalData = null; /** - * @param int $level - * @param string $message - * * @throws \Exception */ public function __construct(int $level, string $message) { $this->level = $level; $this->message = $message; - $this->datetime = new \DateTime("now"); + $this->datetime = new \DateTime('now'); } - /** - * @return int|string|null - */ public function getUserId(): int|string|null { return $this->userId; } - /** - * @param int|string|null $userId - * @return Log - */ public function setUserId(int|string|null $userId): Log { $this->userId = $userId; + return $this; } - /** - * @param User $user - * - * @return Log - */ public function setUser(User $user): Log { $this->userId = $user->getId(); $this->username = $user->getUsername(); + return $this; } - /** - * @return string|null - */ public function getUsername(): ?string { return $this->username; } /** - * @param string|null $username - * * @return Log */ public function setUsername(?string $username) @@ -160,25 +139,16 @@ public function setUsername(?string $username) return $this; } - /** - * @return string - */ public function getMessage(): string { return $this->message; } - /** - * @return int - */ public function getLevel(): int { return $this->level; } - /** - * @return \DateTime - */ public function getDatetime(): \DateTime { return $this->datetime; @@ -187,7 +157,6 @@ public function getDatetime(): \DateTime /** * BC setter. * - * @param NodesSources|null $nodeSource * @return $this */ public function setNodeSource(?NodesSources $nodeSource): Log @@ -196,40 +165,27 @@ public function setNodeSource(?NodesSources $nodeSource): Log $this->entityClass = NodesSources::class; $this->entityId = $nodeSource->getId(); } + return $this; } - /** - * @return string|null - */ public function getClientIp(): ?string { return $this->clientIp; } - /** - * @param string|null $clientIp - * @return Log - */ public function setClientIp(?string $clientIp): Log { $this->clientIp = $clientIp; + return $this; } - /** - * @return array|null - */ public function getAdditionalData(): ?array { return $this->additionalData; } - /** - * @param array|null $additionalData - * - * @return Log - */ public function setAdditionalData(?array $additionalData): Log { $this->additionalData = $additionalData; @@ -237,19 +193,11 @@ public function setAdditionalData(?array $additionalData): Log return $this; } - /** - * @return string|null - */ public function getChannel(): ?string { return $this->channel; } - /** - * @param string|null $channel - * - * @return Log - */ public function setChannel(?string $channel): Log { $this->channel = $channel; @@ -267,35 +215,29 @@ public function getEntityClass(): ?string /** * @param class-string|null $entityClass - * @return Log */ public function setEntityClass(?string $entityClass): Log { $this->entityClass = $entityClass; + return $this; } - /** - * @return int|string|null - */ public function getEntityId(): int|string|null { return $this->entityId; } - /** - * @param int|string|null $entityId - * @return Log - */ public function setEntityId(int|string|null $entityId): Log { $this->entityId = $entityId; + return $this; } #[ORM\PrePersist] public function prePersist(): void { - $this->datetime = new \DateTime("now"); + $this->datetime = new \DateTime('now'); } } diff --git a/src/Mailer/ContactFormManager.php b/src/Mailer/ContactFormManager.php index 2476885d..6d6b6fcf 100644 --- a/src/Mailer/ContactFormManager.php +++ b/src/Mailer/ContactFormManager.php @@ -38,7 +38,7 @@ use Twig\Environment; /** - * @internal Use ContactFormManagerFactory to create a new instance. + * @internal use ContactFormManagerFactory to create a new instance */ final class ContactFormManager extends EmailManager { @@ -74,7 +74,7 @@ public function __construct( private readonly FormFactoryInterface $formFactory, private readonly FormErrorSerializerInterface $formErrorSerializer, private readonly ?string $recaptchaPrivateKey, - private readonly ?string $recaptchaPublicKey + private readonly ?string $recaptchaPublicKey, ) { parent::__construct($requestStack, $translator, $templating, $mailer, $settingsBag, $documentUrlGenerator); @@ -100,40 +100,33 @@ public function __construct( )); } - /** - * @return string - */ public function getFormName(): string { return $this->formName; } /** - * Use this method BEFORE withDefaultFields() - * - * @param string $formName - * @return ContactFormManager + * Use this method BEFORE withDefaultFields(). */ public function setFormName(string $formName): ContactFormManager { $this->formName = $formName; + return $this; } /** - * Use this method BEFORE withDefaultFields() + * Use this method BEFORE withDefaultFields(). * * @return $this */ public function disableCsrfProtection(): self { $this->options['csrf_protection'] = false; + return $this; } - /** - * @return FormInterface - */ public function getForm(): FormInterface { return $this->form; @@ -144,8 +137,8 @@ public function getForm(): FormInterface * * Use this method BEFORE withDefaultFields() * - * @param bool $emailStrictMode * @see https://symfony.com/doc/4.4/reference/constraints/Email.html#strict + * * @return $this */ public function setEmailStrictMode(bool $emailStrictMode = true): self @@ -154,9 +147,7 @@ public function setEmailStrictMode(bool $emailStrictMode = true): self return $this; } - /** - * @return bool - */ + public function isEmailStrictMode(): bool { return $this->emailStrictMode; @@ -165,7 +156,6 @@ public function isEmailStrictMode(): bool /** * Adds email, name and message fields with their constraints. * - * @param bool $useHoneypot * @return $this */ public function withDefaultFields(bool $useHoneypot = true): self @@ -179,7 +169,7 @@ public function withDefaultFields(bool $useHoneypot = true): self 'message' => 'email.not.valid', 'mode' => $this->isEmailStrictMode() ? Email::VALIDATION_MODE_STRICT : - Email::VALIDATION_MODE_HTML5 + Email::VALIDATION_MODE_HTML5, ]), ], ]) @@ -207,21 +197,20 @@ public function withDefaultFields(bool $useHoneypot = true): self } /** - * Use this method AFTER withDefaultFields() + * Use this method AFTER withDefaultFields(). * - * @param string $honeypotName * @return $this */ public function withHoneypot(string $honeypotName = 'eml'): self { $this->getFormBuilder()->add($honeypotName, HoneypotType::class); + return $this; } /** - * Use this method AFTER withDefaultFields() + * Use this method AFTER withDefaultFields(). * - * @param string $consentDescription * @return $this */ public function withUserConsent(string $consentDescription = 'contact_form.user_consent'): self @@ -235,12 +224,10 @@ public function withUserConsent(string $consentDescription = 'contact_form.user_ ]), ], ]); + return $this; } - /** - * @return FormBuilderInterface - */ public function getFormBuilder(): FormBuilderInterface { if (null === $this->formBuilder) { @@ -248,6 +235,7 @@ public function getFormBuilder(): FormBuilderInterface ->createNamedBuilder($this->getFormName(), FormType::class, null, $this->options) ->setMethod($this->method); } + return $this->formBuilder; } @@ -265,16 +253,14 @@ public function getFormBuilder(): FormBuilderInterface * * If you are using API REST POST form, use 'g-recaptcha-response' name * to enable Validator to get challenge value. - * - * @return ContactFormManager */ public function withGoogleRecaptcha( string $name = 'recaptcha', - string $validatorFieldName = Recaptcha::FORM_NAME + string $validatorFieldName = Recaptcha::FORM_NAME, ): self { if ( - !empty($this->recaptchaPublicKey) && - !empty($this->recaptchaPrivateKey) + !empty($this->recaptchaPublicKey) + && !empty($this->recaptchaPrivateKey) ) { $this->getFormBuilder()->add($name, RecaptchaType::class, [ 'label' => false, @@ -296,8 +282,6 @@ public function withGoogleRecaptcha( /** * Handle custom form validation and send it as an email. * - * @param callable|null $onValid - * @return Response|null * @throws \Exception */ public function handle(?callable $onValid = null): ?Response @@ -308,10 +292,10 @@ public function handle(?callable $onValid = null): ?Response } $this->form = $this->getFormBuilder()->getForm(); $this->form->handleRequest($request); - $returnJson = $request->isXmlHttpRequest() || - $request->getRequestFormat() === 'json' || - (count($request->getAcceptableContentTypes()) === 1 && $request->getAcceptableContentTypes()[0] === 'application/json') || - ($request->attributes->has('_format') && $request->attributes->get('_format') === 'json'); + $returnJson = $request->isXmlHttpRequest() + || 'json' === $request->getRequestFormat() + || (1 === count($request->getAcceptableContentTypes()) && 'application/json' === $request->getAcceptableContentTypes()[0]) + || ($request->attributes->has('_format') && 'json' === $request->attributes->get('_format')); if ($this->form->isSubmitted()) { if ($this->form->isValid()) { @@ -333,7 +317,8 @@ public function handle(?callable $onValid = null): ?Response ->add('confirm', $this->translator->trans($this->successMessage)); } - $this->redirectUrl = $this->redirectUrl !== null ? $this->redirectUrl : $request->getUri(); + $this->redirectUrl = null !== $this->redirectUrl ? $this->redirectUrl : $request->getUri(); + return new RedirectResponse($this->redirectUrl); } } catch (BadFormRequestException $e) { @@ -358,6 +343,7 @@ public function handle(?callable $onValid = null): ?Response 'errors' => (string) $this->form->getErrors(), 'errorsPerForm' => $errorPerForm, ]; + /* * BC: Still return 200 if form is not valid for Ajax forms */ @@ -367,6 +353,7 @@ public function handle(?callable $onValid = null): ?Response ); } } + return null; } @@ -382,20 +369,20 @@ protected function handleFiles(): void */ foreach ($request->files as $files) { /** - * @var string $name + * @var string $name * @var UploadedFile|array $uploadedFile */ foreach ($files as $name => $uploadedFile) { if (null !== $uploadedFile) { if (is_array($uploadedFile)) { /** - * @var string $singleName + * @var string $singleName * @var UploadedFile|array $singleUploadedFile */ foreach ($uploadedFile as $singleName => $singleUploadedFile) { if (is_array($singleUploadedFile)) { /** - * @var string $singleName2 + * @var string $singleName2 * @var UploadedFile $singleUploadedFile2 */ foreach ($singleUploadedFile as $singleName2 => $singleUploadedFile2) { @@ -414,24 +401,18 @@ protected function handleFiles(): void } /** - * @param string $name - * @param UploadedFile $uploadedFile * @return $this + * * @throws BadFormRequestException */ protected function addUploadedFile(string $name, UploadedFile $uploadedFile): ContactFormManager { if ( - !$uploadedFile->isValid() || - !in_array($uploadedFile->getMimeType(), $this->allowedMimeTypes) || - $uploadedFile->getSize() > $this->maxFileSize + !$uploadedFile->isValid() + || !in_array($uploadedFile->getMimeType(), $this->allowedMimeTypes) + || $uploadedFile->getSize() > $this->maxFileSize ) { - throw new BadFormRequestException( - $this->translator->trans('file.not.accepted'), - Response::HTTP_FORBIDDEN, - 'danger', - $name - ); + throw new BadFormRequestException($this->translator->trans('file.not.accepted'), Response::HTTP_FORBIDDEN, 'danger', $name); } else { $this->uploadedFiles[$name] = $uploadedFile; } @@ -439,29 +420,24 @@ protected function addUploadedFile(string $name, UploadedFile $uploadedFile): Co return $this; } - /** - * @param array $formData - * @return string|null - */ protected function findEmailData(array $formData): ?string { foreach ($formData as $key => $value) { if ( - (new UnicodeString($key))->containsAny('email') && - is_string($value) && - filter_var($value, FILTER_VALIDATE_EMAIL) + (new UnicodeString($key))->containsAny('email') + && is_string($value) + && filter_var($value, FILTER_VALIDATE_EMAIL) ) { return $value; } elseif (is_array($value) && null !== $email = $this->findEmailData($value)) { return $email; } } + return null; } /** - * @param FormInterface $form - * * @throws \Exception */ protected function handleFormData(FormInterface $form): void @@ -478,14 +454,14 @@ protected function handleFormData(FormInterface $form): void } /** - * @var string $key + * @var string $key * @var UploadedFile $uploadedFile */ foreach ($this->uploadedFiles as $key => $uploadedFile) { $fields[] = [ 'name' => strip_tags((string) $key), - 'value' => (strip_tags($uploadedFile->getClientOriginalName()) . - ' [' . $uploadedFile->guessExtension() . ']'), + 'value' => (strip_tags($uploadedFile->getClientOriginalName()). + ' ['.$uploadedFile->guessExtension().']'), ]; } /* @@ -517,26 +493,22 @@ protected function isFieldPrivate(FormInterface $form): bool $key = $form->getName(); $privateFieldNames = [ Recaptcha::FORM_NAME, - 'recaptcha' + 'recaptcha', ]; + return - is_string($key) && - (\mb_substr($key, 0, 1) === '_' || \in_array($key, $privateFieldNames)) + is_string($key) + && ('_' === \mb_substr($key, 0, 1) || \in_array($key, $privateFieldNames)) ; } - /** - * @param FormInterface $form - * @param array $fields - * @return array - */ protected function flattenFormData(FormInterface $form, array $fields): array { /** @var FormInterface $formItem */ foreach ($form as $formItem) { $key = $formItem->getName(); $value = $formItem->getData(); - $displayName = $formItem->getConfig()->getOption("label") ?? + $displayName = $formItem->getConfig()->getOption('label') ?? (is_numeric($key) ? null : strip_tags(trim((string) $key))); if ($this->isFieldPrivate($formItem) || $value instanceof UploadedFile) { @@ -566,17 +538,15 @@ protected function flattenFormData(FormInterface $form, array $fields): array return $fields; } - /** * Send contact form data by email. * - * @return void * @throws \RuntimeException */ public function send(): void { if (empty($this->assignation)) { - throw new \RuntimeException("Can’t send a contact form without data."); + throw new \RuntimeException('Can’t send a contact form without data.'); } $this->message = $this->createMessage(); @@ -601,7 +571,7 @@ public function send(): void } /** - * @return null|array
+ * @return array
|null */ public function getReceiver(): ?array { @@ -609,13 +579,12 @@ public function getReceiver(): ?array throw new \InvalidArgumentException('Main "email_sender" is not configured for this website.'); } $defaultReceivers = [new Address($this->settingsBag->get('email_sender'))]; + return parent::getReceiver() ?? $defaultReceivers; } /** * Gets the value of redirectUrl. - * - * @return string|null */ public function getRedirectUrl(): ?string { @@ -626,8 +595,6 @@ public function getRedirectUrl(): ?string * Sets the value of redirectUrl. * * @param string|null $redirectUrl Redirect url - * - * @return self */ public function setRedirectUrl(?string $redirectUrl): self { @@ -638,8 +605,6 @@ public function setRedirectUrl(?string $redirectUrl): self /** * Gets the value of maxFileSize. - * - * @return int */ public function getMaxFileSize(): int { @@ -650,8 +615,6 @@ public function getMaxFileSize(): int * Sets the value of maxFileSize. * * @param int $maxFileSize the max file size - * - * @return self */ public function setMaxFileSize($maxFileSize): self { @@ -662,8 +625,6 @@ public function setMaxFileSize($maxFileSize): self /** * Gets the value of allowedMimeTypes. - * - * @return array */ public function getAllowedMimeTypes(): array { @@ -674,8 +635,6 @@ public function getAllowedMimeTypes(): array * Sets the value of allowedMimeTypes. * * @param array $allowedMimeTypes the allowed mime types - * - * @return self */ public function setAllowedMimeTypes(array $allowedMimeTypes): self { @@ -684,17 +643,12 @@ public function setAllowedMimeTypes(array $allowedMimeTypes): self return $this; } - /** - * @return array - */ public function getOptions(): array { return $this->options; } /** - * @param array $options - * * @return $this */ public function setOptions(array $options): self @@ -704,21 +658,18 @@ public function setOptions(array $options): self return $this; } - /** - * @return bool - */ public function useRealResponseCode(): bool { return $this->useRealResponseCode; } /** - * @param bool $useRealResponseCode Return a real 400 response if form is not valid. - * @return ContactFormManager + * @param bool $useRealResponseCode return a real 400 response if form is not valid */ public function setUseRealResponseCode(bool $useRealResponseCode): ContactFormManager { $this->useRealResponseCode = $useRealResponseCode; + return $this; } } diff --git a/src/Mailer/ContactFormManagerFactory.php b/src/Mailer/ContactFormManagerFactory.php index 53a146a0..6d277a7d 100644 --- a/src/Mailer/ContactFormManagerFactory.php +++ b/src/Mailer/ContactFormManagerFactory.php @@ -13,19 +13,19 @@ use Symfony\Contracts\Translation\TranslatorInterface; use Twig\Environment; -final class ContactFormManagerFactory +final readonly class ContactFormManagerFactory { public function __construct( - private readonly RequestStack $requestStack, - private readonly TranslatorInterface $translator, - private readonly Environment $templating, - private readonly MailerInterface $mailer, - private readonly Settings $settingsBag, - private readonly DocumentUrlGeneratorInterface $documentUrlGenerator, - private readonly FormFactoryInterface $formFactory, - private readonly FormErrorSerializerInterface $formErrorSerializer, - private readonly ?string $recaptchaPrivateKey, - private readonly ?string $recaptchaPublicKey + private RequestStack $requestStack, + private TranslatorInterface $translator, + private Environment $templating, + private MailerInterface $mailer, + private Settings $settingsBag, + private DocumentUrlGeneratorInterface $documentUrlGenerator, + private FormFactoryInterface $formFactory, + private FormErrorSerializerInterface $formErrorSerializer, + private ?string $recaptchaPrivateKey, + private ?string $recaptchaPublicKey, ) { } diff --git a/src/Mailer/EmailManager.php b/src/Mailer/EmailManager.php index 67e9daee..fc147533 100644 --- a/src/Mailer/EmailManager.php +++ b/src/Mailer/EmailManager.php @@ -22,16 +22,16 @@ use Twig\Error\SyntaxError; /** - * @internal Use EmailManagerFactory to create a new instance. + * @internal use EmailManagerFactory to create a new instance */ class EmailManager { protected ?string $subject = null; protected ?string $emailTitle = null; protected ?string $emailType = null; - /** @var Address[]|null */ + /** @var Address[]|null */ protected ?array $receiver = null; - /** @var Address[]|null */ + /** @var Address[]|null */ protected ?array $sender = null; protected ?Address $origin = null; protected string $successMessage = 'email.successfully.sent'; @@ -43,7 +43,6 @@ class EmailManager protected ?Email $message; /** @var File[] */ protected array $files = []; - /** @var array */ protected array $resources = []; /* @@ -56,18 +55,17 @@ public function __construct( protected readonly Environment $templating, protected readonly MailerInterface $mailer, protected readonly Settings $settingsBag, - protected readonly DocumentUrlGeneratorInterface $documentUrlGenerator + protected readonly DocumentUrlGeneratorInterface $documentUrlGenerator, ) { $this->assignation = []; $this->message = null; /* * Sets a default CSS for emails. */ - $this->emailStylesheet = dirname(__DIR__) . '/../css/transactionalStyles.css'; + $this->emailStylesheet = dirname(__DIR__).'/../css/transactionalStyles.css'; } /** - * @return string * @throws LoaderError * @throws RuntimeError * @throws SyntaxError @@ -78,7 +76,6 @@ public function renderHtmlEmailBody(): string } /** - * @return string * @throws LoaderError * @throws RuntimeError * @throws SyntaxError @@ -102,7 +99,6 @@ public function renderHtmlEmailBodyWithCss(): string } /** - * @return string * @throws LoaderError * @throws RuntimeError * @throws SyntaxError @@ -113,17 +109,12 @@ public function renderPlainTextEmailBody(): string } /** - * Added mainColor and headerImageSrc assignation - * to display email header. + * Added headerImageSrc assignation to display email header. * * @return $this */ public function appendWebsiteIcon(): static { - if (empty($this->assignation['mainColor']) && null !== $this->settingsBag) { - $this->assignation['mainColor'] = $this->settingsBag->get('main_color'); - } - if (empty($this->assignation['headerImageSrc']) && null !== $this->settingsBag) { $adminImage = $this->settingsBag->getDocument('admin_image'); if ($adminImage instanceof DocumentInterface && null !== $this->documentUrlGenerator) { @@ -136,7 +127,6 @@ public function appendWebsiteIcon(): static } /** - * @return Email * @throws LoaderError * @throws RuntimeError * @throws SyntaxError @@ -173,7 +163,6 @@ public function createMessage(): Email /** * Send email. * - * @return void * @throws TransportExceptionInterface * @throws LoaderError * @throws RuntimeError @@ -182,7 +171,7 @@ public function createMessage(): Email public function send(): void { if (empty($this->assignation)) { - throw new \RuntimeException("Can’t send a contact form without data."); + throw new \RuntimeException('Can’t send a contact form without data.'); } if (null === $this->message) { @@ -204,46 +193,40 @@ public function send(): void $this->mailer->send($this->message); } - /** - * @return null|string - */ public function getSubject(): ?string { return null !== $this->subject ? trim(strip_tags($this->subject)) : null; } /** - * @param null|string $subject * @return $this */ public function setSubject(?string $subject): static { $this->subject = $subject; + return $this; } - /** - * @return null|string - */ public function getEmailTitle(): ?string { return null !== $this->emailTitle ? trim(strip_tags($this->emailTitle)) : null; } /** - * @param null|string $emailTitle * @return $this */ public function setEmailTitle(?string $emailTitle): static { $this->emailTitle = $emailTitle; + return $this; } /** * Message destination email(s). * - * @return null|Address[] + * @return Address[]|null */ public function getReceiver(): ?array { @@ -252,8 +235,6 @@ public function getReceiver(): ?array /** * Return only one email as string. - * - * @return null|string */ public function getReceiverEmail(): ?string { @@ -270,6 +251,7 @@ public function getReceiverEmail(): ?string * @param Address|string|array|array
$receiver the receiver * * @return $this + * * @throws \Exception */ public function setReceiver(mixed $receiver): static @@ -299,7 +281,7 @@ public function setReceiver(mixed $receiver): static * * This email will be used as ReplyTo: and ReturnPath: * - * @return null|Address[] + * @return Address[]|null */ public function getSender(): ?array { @@ -308,8 +290,6 @@ public function getSender(): ?array /** * Return only one email as string. - * - * @return null|string */ public function getSenderEmail(): ?string { @@ -324,7 +304,9 @@ public function getSenderEmail(): ?string * Sets the value of sender. * * @param Address|string|array|array $sender + * * @return $this + * * @throws \Exception */ public function setSender(mixed $sender): static @@ -351,123 +333,96 @@ public function setSender(mixed $sender): static return $this; } - /** - * @return string - */ public function getSuccessMessage(): string { return $this->successMessage; } /** - * @param string $successMessage * @return $this */ public function setSuccessMessage(string $successMessage): static { $this->successMessage = $successMessage; + return $this; } - /** - * @return string - */ public function getFailMessage(): string { return $this->failMessage; } /** - * @param string $failMessage * @return $this */ public function setFailMessage(string $failMessage): static { $this->failMessage = $failMessage; + return $this; } - /** - * @return TranslatorInterface - */ public function getTranslator(): TranslatorInterface { return $this->translator; } - /** - * @return Environment - */ public function getTemplating(): Environment { return $this->templating; } - /** - * @return MailerInterface - */ public function getMailer(): MailerInterface { return $this->mailer; } - /** - * @return string|null - */ public function getEmailTemplate(): ?string { return $this->emailTemplate; } /** - * @param string|null $emailTemplate * @return $this */ public function setEmailTemplate(?string $emailTemplate = null): static { $this->emailTemplate = $emailTemplate; + return $this; } - /** - * @return string|null - */ public function getEmailPlainTextTemplate(): ?string { return $this->emailPlainTextTemplate; } /** - * @param string|null $emailPlainTextTemplate * @return $this */ public function setEmailPlainTextTemplate(?string $emailPlainTextTemplate = null): static { $this->emailPlainTextTemplate = $emailPlainTextTemplate; + return $this; } - /** - * @return string|null - */ public function getEmailStylesheet(): ?string { return $this->emailStylesheet; } /** - * @param string|null $emailStylesheet * @return $this */ public function setEmailStylesheet(?string $emailStylesheet = null): static { $this->emailStylesheet = $emailStylesheet; + return $this; } - /** - * @return Request - */ public function getRequest(): Request { return $this->requestStack->getMainRequest(); @@ -478,8 +433,6 @@ public function getRequest(): Request * * This must be an email address with a know * domain name to be validated on your SMTP server. - * - * @return null|Address */ public function getOrigin(): ?Address { @@ -489,52 +442,47 @@ public function getOrigin(): ?Address $defaultSender = $this->settingsBag->get('email_sender'); $defaultSenderName = $this->settingsBag->get('site_name', '') ?? ''; } + return $this->origin ?? new Address($defaultSender, $defaultSenderName); } /** - * @param string $origin * @return $this */ public function setOrigin(string $origin): static { $this->origin = new Address($origin); + return $this; } - /** - * @return array - */ public function getAssignation(): array { return $this->assignation; } /** - * @param array $assignation * @return $this */ public function setAssignation(array $assignation): static { $this->assignation = $assignation; + return $this; } - /** - * @return null|string - */ public function getEmailType(): ?string { return $this->emailType; } /** - * @param null|string $emailType * @return $this */ public function setEmailType(?string $emailType): static { $this->emailType = $emailType; + return $this; } @@ -548,11 +496,13 @@ public function getFiles(): array /** * @param File[] $files + * * @return $this */ public function setFiles(array $files): static { $this->files = $files; + return $this; } @@ -566,13 +516,13 @@ public function getResources(): array /** * @param resource $resource - * @param string $filename - * @param string $mimeType + * * @return $this */ public function addResource($resource, string $filename, string $mimeType): static { $this->resources[] = [$resource, $filename, $mimeType]; + return $this; } } diff --git a/src/Mailer/EmailManagerFactory.php b/src/Mailer/EmailManagerFactory.php index 3227946e..da4fd5d8 100644 --- a/src/Mailer/EmailManagerFactory.php +++ b/src/Mailer/EmailManagerFactory.php @@ -11,15 +11,15 @@ use Symfony\Contracts\Translation\TranslatorInterface; use Twig\Environment; -final class EmailManagerFactory +final readonly class EmailManagerFactory { public function __construct( - private readonly RequestStack $requestStack, - private readonly TranslatorInterface $translator, - private readonly Environment $templating, - private readonly MailerInterface $mailer, - private readonly Settings $settingsBag, - private readonly DocumentUrlGeneratorInterface $documentUrlGenerator + private RequestStack $requestStack, + private TranslatorInterface $translator, + private Environment $templating, + private MailerInterface $mailer, + private Settings $settingsBag, + private DocumentUrlGeneratorInterface $documentUrlGenerator, ) { } diff --git a/src/Message/ApplyRealmNodeInheritanceMessage.php b/src/Message/ApplyRealmNodeInheritanceMessage.php index f00d994c..a9d28eed 100644 --- a/src/Message/ApplyRealmNodeInheritanceMessage.php +++ b/src/Message/ApplyRealmNodeInheritanceMessage.php @@ -4,25 +4,19 @@ namespace RZ\Roadiz\CoreBundle\Message; -final class ApplyRealmNodeInheritanceMessage implements AsyncMessage +final readonly class ApplyRealmNodeInheritanceMessage implements AsyncMessage { public function __construct( - private readonly int|string|null $nodeId, - private readonly int|string|null $realmId + private int|string|null $nodeId, + private int|string|null $realmId, ) { } - /** - * @return int|string|null - */ public function getNodeId(): int|string|null { return $this->nodeId; } - /** - * @return int|string|null - */ public function getRealmId(): int|string|null { return $this->realmId; diff --git a/src/Message/CleanRealmNodeInheritanceMessage.php b/src/Message/CleanRealmNodeInheritanceMessage.php index 107e5b76..28b936f8 100644 --- a/src/Message/CleanRealmNodeInheritanceMessage.php +++ b/src/Message/CleanRealmNodeInheritanceMessage.php @@ -4,25 +4,19 @@ namespace RZ\Roadiz\CoreBundle\Message; -final class CleanRealmNodeInheritanceMessage implements AsyncMessage +final readonly class CleanRealmNodeInheritanceMessage implements AsyncMessage { public function __construct( - private readonly int|string|null $nodeId, - private readonly int|string|null $realmId + private int|string|null $nodeId, + private int|string|null $realmId, ) { } - /** - * @return int|string|null - */ public function getNodeId(): int|string|null { return $this->nodeId; } - /** - * @return int|string|null - */ public function getRealmId(): int|string|null { return $this->realmId; diff --git a/src/Message/DeleteNodeTypeMessage.php b/src/Message/DeleteNodeTypeMessage.php index ca7566d8..9e995862 100644 --- a/src/Message/DeleteNodeTypeMessage.php +++ b/src/Message/DeleteNodeTypeMessage.php @@ -4,15 +4,12 @@ namespace RZ\Roadiz\CoreBundle\Message; -final class DeleteNodeTypeMessage implements AsyncMessage +final readonly class DeleteNodeTypeMessage implements AsyncMessage { - public function __construct(private readonly int|string|null $nodeTypeId) + public function __construct(private int|string|null $nodeTypeId) { } - /** - * @return int|string|null - */ public function getNodeTypeId(): int|string|null { return $this->nodeTypeId; diff --git a/src/Message/GuzzleRequestMessage.php b/src/Message/GuzzleRequestMessage.php deleted file mode 100644 index 65bb93f7..00000000 --- a/src/Message/GuzzleRequestMessage.php +++ /dev/null @@ -1,42 +0,0 @@ -options = array_merge([ - 'debug' => false, - 'timeout' => 3 - ], $options); - } - - /** - * @return RequestInterface - */ - public function getRequest(): RequestInterface - { - return $this->request; - } - - /** - * @return array - */ - public function getOptions(): array - { - return $this->options; - } -} diff --git a/src/Message/Handler/ApplyRealmNodeInheritanceMessageHandler.php b/src/Message/Handler/ApplyRealmNodeInheritanceMessageHandler.php index bae2c618..18ef9df5 100644 --- a/src/Message/Handler/ApplyRealmNodeInheritanceMessageHandler.php +++ b/src/Message/Handler/ApplyRealmNodeInheritanceMessageHandler.php @@ -11,20 +11,21 @@ use RZ\Roadiz\CoreBundle\Message\ApplyRealmNodeInheritanceMessage; use RZ\Roadiz\CoreBundle\Model\RealmInterface; use RZ\Roadiz\CoreBundle\Node\NodeOffspringResolverInterface; +use Symfony\Component\Messenger\Attribute\AsMessageHandler; use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; -use Symfony\Component\Messenger\Handler\MessageHandlerInterface; -final class ApplyRealmNodeInheritanceMessageHandler implements MessageHandlerInterface +#[AsMessageHandler] +final readonly class ApplyRealmNodeInheritanceMessageHandler { public function __construct( - private readonly ManagerRegistry $managerRegistry, - private readonly NodeOffspringResolverInterface $nodeOffspringResolver + private ManagerRegistry $managerRegistry, + private NodeOffspringResolverInterface $nodeOffspringResolver, ) { } public function __invoke(ApplyRealmNodeInheritanceMessage $message): void { - if ($message->getRealmId() === null) { + if (null === $message->getRealmId()) { return; } $node = $this->managerRegistry->getRepository(Node::class)->find($message->getNodeId()); @@ -45,7 +46,7 @@ public function __invoke(ApplyRealmNodeInheritanceMessage $message): void /* * Do not propagate if realm node inheritance type is not ROOT */ - if (null === $realmNode || $realmNode->getInheritanceType() !== RealmInterface::INHERITANCE_ROOT) { + if (null === $realmNode || RealmInterface::INHERITANCE_ROOT !== $realmNode->getInheritanceType()) { return; } diff --git a/src/Message/Handler/CleanRealmNodeInheritanceMessageHandler.php b/src/Message/Handler/CleanRealmNodeInheritanceMessageHandler.php index 166d52e7..5ed0caec 100644 --- a/src/Message/Handler/CleanRealmNodeInheritanceMessageHandler.php +++ b/src/Message/Handler/CleanRealmNodeInheritanceMessageHandler.php @@ -10,20 +10,21 @@ use RZ\Roadiz\CoreBundle\Entity\RealmNode; use RZ\Roadiz\CoreBundle\Message\CleanRealmNodeInheritanceMessage; use RZ\Roadiz\CoreBundle\Node\NodeOffspringResolverInterface; +use Symfony\Component\Messenger\Attribute\AsMessageHandler; use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; -use Symfony\Component\Messenger\Handler\MessageHandlerInterface; -final class CleanRealmNodeInheritanceMessageHandler implements MessageHandlerInterface +#[AsMessageHandler] +final readonly class CleanRealmNodeInheritanceMessageHandler { public function __construct( - private readonly ManagerRegistry $managerRegistry, - private readonly NodeOffspringResolverInterface $nodeOffspringResolver + private ManagerRegistry $managerRegistry, + private NodeOffspringResolverInterface $nodeOffspringResolver, ) { } public function __invoke(CleanRealmNodeInheritanceMessage $message): void { - if ($message->getRealmId() === null) { + if (null === $message->getRealmId()) { return; } $node = $this->managerRegistry->getRepository(Node::class)->find($message->getNodeId()); diff --git a/src/Message/Handler/DeleteNodeTypeMessageHandler.php b/src/Message/Handler/DeleteNodeTypeMessageHandler.php index 9a9c4723..e8ff96f0 100644 --- a/src/Message/Handler/DeleteNodeTypeMessageHandler.php +++ b/src/Message/Handler/DeleteNodeTypeMessageHandler.php @@ -12,17 +12,18 @@ use RZ\Roadiz\CoreBundle\EntityHandler\NodeTypeHandler; use RZ\Roadiz\CoreBundle\Message\DeleteNodeTypeMessage; use RZ\Roadiz\CoreBundle\Message\UpdateDoctrineSchemaMessage; +use Symfony\Component\Messenger\Attribute\AsMessageHandler; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; -use Symfony\Component\Messenger\Handler\MessageHandlerInterface; use Symfony\Component\Messenger\MessageBusInterface; -final class DeleteNodeTypeMessageHandler implements MessageHandlerInterface +#[AsMessageHandler] +final readonly class DeleteNodeTypeMessageHandler { public function __construct( - private readonly ManagerRegistry $managerRegistry, - private readonly HandlerFactoryInterface $handlerFactory, - private readonly MessageBusInterface $messageBus + private ManagerRegistry $managerRegistry, + private HandlerFactoryInterface $handlerFactory, + private MessageBusInterface $messageBus, ) { } @@ -43,7 +44,7 @@ public function __invoke(DeleteNodeTypeMessage $message): void $handler->deleteWithAssociations(); $this->messageBus->dispatch( - (new Envelope(new UpdateDoctrineSchemaMessage())) + new Envelope(new UpdateDoctrineSchemaMessage()) ); $this->managerRegistry->getManager()->clear(); } diff --git a/src/Message/Handler/HttpRequestMessageHandler.php b/src/Message/Handler/HttpRequestMessageHandler.php index 35f275e5..e0d349bf 100644 --- a/src/Message/Handler/HttpRequestMessageHandler.php +++ b/src/Message/Handler/HttpRequestMessageHandler.php @@ -4,31 +4,37 @@ namespace RZ\Roadiz\CoreBundle\Message\Handler; -use GuzzleHttp\Client; -use GuzzleHttp\Exception\GuzzleException; use Psr\Log\LoggerInterface; -use RZ\Roadiz\CoreBundle\Message\HttpRequestMessage; +use RZ\Roadiz\CoreBundle\Message\HttpRequestMessageInterface; +use Symfony\Component\Messenger\Attribute\AsMessageHandler; use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; -use Symfony\Component\Messenger\Handler\MessageHandlerInterface; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; -final class HttpRequestMessageHandler implements MessageHandlerInterface +#[AsMessageHandler] +final readonly class HttpRequestMessageHandler { public function __construct( - private readonly LoggerInterface $logger + private HttpClientInterface $client, + private LoggerInterface $logger, ) { } - public function __invoke(HttpRequestMessage $message): void + public function __invoke(HttpRequestMessageInterface $message): void { try { $this->logger->debug(sprintf( 'HTTP request executed: %s %s', - $message->getRequest()->getMethod(), - $message->getRequest()->getUri() + $message->getMethod(), + $message->getUri() )); - $client = new Client(); - $client->send($message->getRequest(), $message->getOptions()); - } catch (GuzzleException $exception) { + $response = $this->client->request( + $message->getMethod(), + $message->getUri(), + $message->getOptions(), + ); + $response->getStatusCode(); + } catch (ClientExceptionInterface $exception) { throw new UnrecoverableMessageHandlingException($exception->getMessage(), 0, $exception); } } diff --git a/src/Message/Handler/PurgeReverseProxyCacheMessageHandler.php b/src/Message/Handler/PurgeReverseProxyCacheMessageHandler.php index 13da36f7..c884f3cc 100644 --- a/src/Message/Handler/PurgeReverseProxyCacheMessageHandler.php +++ b/src/Message/Handler/PurgeReverseProxyCacheMessageHandler.php @@ -7,24 +7,26 @@ use Doctrine\Persistence\ManagerRegistry; use RZ\Roadiz\CoreBundle\Cache\ReverseProxyCacheLocator; use RZ\Roadiz\CoreBundle\Entity\NodesSources; -use RZ\Roadiz\CoreBundle\Message\GuzzleRequestMessage; +use RZ\Roadiz\CoreBundle\Message\HttpRequestMessage; +use RZ\Roadiz\CoreBundle\Message\HttpRequestMessageInterface; use RZ\Roadiz\CoreBundle\Message\PurgeReverseProxyCacheMessage; use Symfony\Cmf\Component\Routing\RouteObjectInterface; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Messenger\Attribute\AsMessageHandler; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Exception\NoHandlerForMessageException; use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; -use Symfony\Component\Messenger\Handler\MessageHandlerInterface; use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -final class PurgeReverseProxyCacheMessageHandler implements MessageHandlerInterface +#[AsMessageHandler] +final readonly class PurgeReverseProxyCacheMessageHandler { public function __construct( - private readonly MessageBusInterface $bus, - private readonly UrlGeneratorInterface $urlGenerator, - private readonly ReverseProxyCacheLocator $reverseProxyCacheLocator, - private readonly ManagerRegistry $managerRegistry + private MessageBusInterface $bus, + private UrlGeneratorInterface $urlGenerator, + private ReverseProxyCacheLocator $reverseProxyCacheLocator, + private ManagerRegistry $managerRegistry, ) { } @@ -32,6 +34,7 @@ public function __invoke(PurgeReverseProxyCacheMessage $message): void { $nodeSource = $this->managerRegistry ->getRepository(NodesSources::class) + ->setDisplayingAllNodesStatuses(true) ->find($message->getNodeSourceId()); if (null === $nodeSource) { throw new UnrecoverableMessageHandlingException('NodesSources does not exist anymore.'); @@ -56,36 +59,33 @@ public function __invoke(PurgeReverseProxyCacheMessage $message): void } /** - * @param string $path - * - * @return \GuzzleHttp\Psr7\Request[] + * @return HttpRequestMessageInterface[] */ - protected function createPurgeRequests(string $path = "/"): array + protected function createPurgeRequests(string $path = '/'): array { $requests = []; foreach ($this->reverseProxyCacheLocator->getFrontends() as $frontend) { - $requests[$frontend->getName()] = new \GuzzleHttp\Psr7\Request( + $host = $frontend->getHost(); + str_starts_with($host, 'http') || $host = 'http://'.$host; + $requests[$frontend->getName()] = new HttpRequestMessage( Request::METHOD_PURGE, - 'http://' . $frontend->getHost() . $path, + $host.$path, [ - 'Host' => $frontend->getDomainName() + 'timeout' => 3, + 'headers' => [ + 'Host' => $frontend->getDomainName(), + ], ] ); } + return $requests; } - /** - * @param \GuzzleHttp\Psr7\Request $request - * @return void - */ - protected function sendRequest(\GuzzleHttp\Psr7\Request $request): void + protected function sendRequest(HttpRequestMessageInterface $requestMessage): void { try { - $this->bus->dispatch(new Envelope(new GuzzleRequestMessage($request, [ - 'debug' => false, - 'timeout' => 3 - ]))); + $this->bus->dispatch(new Envelope($requestMessage)); } catch (NoHandlerForMessageException $exception) { throw new UnrecoverableMessageHandlingException($exception->getMessage(), 0, $exception); } diff --git a/src/Message/Handler/SearchRealmNodeInheritanceMessageHandler.php b/src/Message/Handler/SearchRealmNodeInheritanceMessageHandler.php index 277bf6a5..efbe8aa1 100644 --- a/src/Message/Handler/SearchRealmNodeInheritanceMessageHandler.php +++ b/src/Message/Handler/SearchRealmNodeInheritanceMessageHandler.php @@ -14,18 +14,19 @@ use RZ\Roadiz\CoreBundle\Message\CleanRealmNodeInheritanceMessage; use RZ\Roadiz\CoreBundle\Message\SearchRealmNodeInheritanceMessage; use RZ\Roadiz\CoreBundle\Model\RealmInterface; +use Symfony\Component\Messenger\Attribute\AsMessageHandler; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; -use Symfony\Component\Messenger\Handler\MessageHandlerInterface; use Symfony\Component\Messenger\MessageBusInterface; -final class SearchRealmNodeInheritanceMessageHandler implements MessageHandlerInterface +#[AsMessageHandler] +final readonly class SearchRealmNodeInheritanceMessageHandler { public function __construct( - private readonly ManagerRegistry $managerRegistry, - private readonly HandlerFactoryInterface $handlerFactory, - private readonly MessageBusInterface $bus, - private readonly LoggerInterface $logger + private ManagerRegistry $managerRegistry, + private HandlerFactoryInterface $handlerFactory, + private MessageBusInterface $bus, + private LoggerInterface $logger, ) { } @@ -46,7 +47,7 @@ private function clearAnyExistingRealmNodes(Node $node): void /** @var RealmNode[] $autoRealmNodes */ $autoRealmNodes = $this->managerRegistry->getRepository(RealmNode::class)->findBy([ 'node' => $node, - 'inheritanceType' => RealmInterface::INHERITANCE_AUTO + 'inheritanceType' => RealmInterface::INHERITANCE_AUTO, ]); /* @@ -67,7 +68,7 @@ private function applyRootRealmNodes(Node $node): void $nodeHandler = $this->handlerFactory->getHandler($node); $parents = $nodeHandler->getParents(); - if (count($parents) === 0) { + if (0 === count($parents)) { return; } diff --git a/src/Message/Handler/UpdateDoctrineSchemaMessageHandler.php b/src/Message/Handler/UpdateDoctrineSchemaMessageHandler.php index e9fc413d..15be3e82 100644 --- a/src/Message/Handler/UpdateDoctrineSchemaMessageHandler.php +++ b/src/Message/Handler/UpdateDoctrineSchemaMessageHandler.php @@ -6,11 +6,12 @@ use RZ\Roadiz\CoreBundle\Doctrine\SchemaUpdater; use RZ\Roadiz\CoreBundle\Message\UpdateDoctrineSchemaMessage; -use Symfony\Component\Messenger\Handler\MessageHandlerInterface; +use Symfony\Component\Messenger\Attribute\AsMessageHandler; -final class UpdateDoctrineSchemaMessageHandler implements MessageHandlerInterface +#[AsMessageHandler] +final readonly class UpdateDoctrineSchemaMessageHandler { - public function __construct(private readonly SchemaUpdater $schemaUpdater) + public function __construct(private SchemaUpdater $schemaUpdater) { } diff --git a/src/Message/Handler/UpdateNodeTypeSchemaMessageHandler.php b/src/Message/Handler/UpdateNodeTypeSchemaMessageHandler.php index a14b07d1..6de1b105 100644 --- a/src/Message/Handler/UpdateNodeTypeSchemaMessageHandler.php +++ b/src/Message/Handler/UpdateNodeTypeSchemaMessageHandler.php @@ -10,17 +10,18 @@ use RZ\Roadiz\CoreBundle\EntityHandler\NodeTypeHandler; use RZ\Roadiz\CoreBundle\Message\UpdateDoctrineSchemaMessage; use RZ\Roadiz\CoreBundle\Message\UpdateNodeTypeSchemaMessage; +use Symfony\Component\Messenger\Attribute\AsMessageHandler; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; -use Symfony\Component\Messenger\Handler\MessageHandlerInterface; use Symfony\Component\Messenger\MessageBusInterface; -final class UpdateNodeTypeSchemaMessageHandler implements MessageHandlerInterface +#[AsMessageHandler] +final readonly class UpdateNodeTypeSchemaMessageHandler { public function __construct( - private readonly ManagerRegistry $managerRegistry, - private readonly HandlerFactoryInterface $handlerFactory, - private readonly MessageBusInterface $messageBus + private ManagerRegistry $managerRegistry, + private HandlerFactoryInterface $handlerFactory, + private MessageBusInterface $messageBus, ) { } @@ -38,7 +39,7 @@ public function __invoke(UpdateNodeTypeSchemaMessage $message): void $this->managerRegistry->getManager()->clear(); $this->messageBus->dispatch( - (new Envelope(new UpdateDoctrineSchemaMessage())) + new Envelope(new UpdateDoctrineSchemaMessage()) ); } } diff --git a/src/Message/HttpRequestMessage.php b/src/Message/HttpRequestMessage.php index 1e021314..4b28a7ae 100644 --- a/src/Message/HttpRequestMessage.php +++ b/src/Message/HttpRequestMessage.php @@ -4,10 +4,32 @@ namespace RZ\Roadiz\CoreBundle\Message; -use Psr\Http\Message\RequestInterface; - -interface HttpRequestMessage +final readonly class HttpRequestMessage implements AsyncMessage, HttpRequestMessageInterface { - public function getRequest(): RequestInterface; - public function getOptions(): array; + private array $options; + + public function __construct( + private string $method, + private string $uri, + array $options = [], + ) { + $this->options = array_merge([ + 'timeout' => 3, + ], $options); + } + + public function getOptions(): array + { + return $this->options; + } + + public function getMethod(): string + { + return $this->method; + } + + public function getUri(): string + { + return $this->uri; + } } diff --git a/src/Message/HttpRequestMessageInterface.php b/src/Message/HttpRequestMessageInterface.php new file mode 100644 index 00000000..0c7d8885 --- /dev/null +++ b/src/Message/HttpRequestMessageInterface.php @@ -0,0 +1,14 @@ +nodeSourceId; diff --git a/src/Message/SearchRealmNodeInheritanceMessage.php b/src/Message/SearchRealmNodeInheritanceMessage.php index a1a634f2..6fa56165 100644 --- a/src/Message/SearchRealmNodeInheritanceMessage.php +++ b/src/Message/SearchRealmNodeInheritanceMessage.php @@ -4,15 +4,12 @@ namespace RZ\Roadiz\CoreBundle\Message; -final class SearchRealmNodeInheritanceMessage implements AsyncMessage +final readonly class SearchRealmNodeInheritanceMessage implements AsyncMessage { - public function __construct(private readonly int|string|null $nodeId) + public function __construct(private int|string|null $nodeId) { } - /** - * @return int|string|null - */ public function getNodeId(): int|string|null { return $this->nodeId; diff --git a/src/Message/UpdateNodeTypeSchemaMessage.php b/src/Message/UpdateNodeTypeSchemaMessage.php index 33b36324..97026bd2 100644 --- a/src/Message/UpdateNodeTypeSchemaMessage.php +++ b/src/Message/UpdateNodeTypeSchemaMessage.php @@ -7,15 +7,12 @@ /* * UpdateNodeTypeSchemaMessage must be handled synchronous */ -final class UpdateNodeTypeSchemaMessage +final readonly class UpdateNodeTypeSchemaMessage { - public function __construct(private readonly int|string|null $nodeTypeId) + public function __construct(private int|string|null $nodeTypeId) { } - /** - * @return int|string|null - */ public function getNodeTypeId(): int|string|null { return $this->nodeTypeId; diff --git a/src/Model/AttributableInterface.php b/src/Model/AttributableInterface.php index 6024140c..50effd46 100644 --- a/src/Model/AttributableInterface.php +++ b/src/Model/AttributableInterface.php @@ -10,42 +10,29 @@ interface AttributableInterface extends PersistableInterface { - /** - * @return Collection - */ public function getAttributeValues(): Collection; /** - * @param TranslationInterface $translation - * * @return Collection */ public function getAttributesValuesForTranslation(TranslationInterface $translation): Collection; /** - * @param TranslationInterface $translation - * * @return Collection */ public function getAttributesValuesTranslations(TranslationInterface $translation): Collection; /** - * @param Collection $attributes - * * @return $this */ public function setAttributeValues(Collection $attributes): static; /** - * @param AttributeValueInterface $attribute - * * @return $this */ public function addAttributeValue(AttributeValueInterface $attribute): static; /** - * @param AttributeValueInterface $attribute - * * @return $this */ public function removeAttributeValue(AttributeValueInterface $attribute): static; diff --git a/src/Model/AttributableTrait.php b/src/Model/AttributableTrait.php index ec5ebbf5..0196631f 100644 --- a/src/Model/AttributableTrait.php +++ b/src/Model/AttributableTrait.php @@ -18,8 +18,6 @@ public function getAttributeValues(): Collection } /** - * @param TranslationInterface $translation - * * @return Collection */ public function getAttributesValuesForTranslation(TranslationInterface $translation): Collection @@ -31,13 +29,12 @@ public function getAttributesValuesForTranslation(TranslationInterface $translat return true; } } + return false; }); } /** - * @param TranslationInterface $translation - * * @return Collection */ public function getAttributesValuesTranslations(TranslationInterface $translation): Collection @@ -51,29 +48,28 @@ public function getAttributesValuesTranslations(TranslationInterface $translatio return $attributeValueTranslation; } } + return null; }) ->filter(function (?AttributeValueTranslationInterface $attributeValueTranslation) { return null !== $attributeValueTranslation; }) ; + return $values; // phpstan does not understand return type after filtering } /** - * @param Collection $attributes - * * @return $this */ public function setAttributeValues(Collection $attributes): static { $this->attributeValues = $attributes; + return $this; } /** - * @param AttributeValueInterface $attribute - * * @return $this */ public function addAttributeValue(AttributeValueInterface $attribute): static @@ -81,13 +77,11 @@ public function addAttributeValue(AttributeValueInterface $attribute): static if (!$this->getAttributeValues()->contains($attribute)) { $this->getAttributeValues()->add($attribute); } + return $this; } - /** - * @param AttributeValueInterface $attribute - * * @return $this */ public function removeAttributeValue(AttributeValueInterface $attribute): static @@ -95,6 +89,7 @@ public function removeAttributeValue(AttributeValueInterface $attribute): static if ($this->getAttributeValues()->contains($attribute)) { $this->getAttributeValues()->removeElement($attribute); } + return $this; } } diff --git a/src/Model/AttributeGroupInterface.php b/src/Model/AttributeGroupInterface.php index 18081048..77deb630 100644 --- a/src/Model/AttributeGroupInterface.php +++ b/src/Model/AttributeGroupInterface.php @@ -11,15 +11,20 @@ interface AttributeGroupInterface extends PersistableInterface { public function getName(): ?string; + public function getTranslatedName(TranslationInterface $translation): ?string; + public function setName(string $name): self; public function getCanonicalName(): ?string; + public function setCanonicalName(string $canonicalName): self; public function getAttributes(): Collection; + public function setAttributes(Collection $attributes): self; public function getAttributeGroupTranslations(): Collection; + public function setAttributeGroupTranslations(Collection $attributeGroupTranslations): self; } diff --git a/src/Model/AttributeGroupTrait.php b/src/Model/AttributeGroupTrait.php index 398d03d5..99bd65ef 100644 --- a/src/Model/AttributeGroupTrait.php +++ b/src/Model/AttributeGroupTrait.php @@ -5,21 +5,18 @@ namespace RZ\Roadiz\CoreBundle\Model; use Doctrine\Common\Collections\Collection; -use RZ\Roadiz\Core\AbstractEntities\TranslationInterface; -use RZ\Roadiz\Utils\StringHandler; use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation as Serializer; +use RZ\Roadiz\Core\AbstractEntities\TranslationInterface; +use RZ\Roadiz\Utils\StringHandler; use Symfony\Component\Validator\Constraints as Assert; -/** - * @package RZ\Roadiz\CoreBundle\Model - */ trait AttributeGroupTrait { #[ - ORM\Column(name: "canonical_name", type: "string", length: 255, unique: true, nullable: false), - Serializer\Groups(["attribute_group", "attribute", "node", "nodes_sources"]), - Serializer\Type("string"), + ORM\Column(name: 'canonical_name', type: 'string', length: 255, unique: true, nullable: false), + Serializer\Groups(['attribute_group', 'attribute', 'node', 'nodes_sources']), + Serializer\Type('string'), Assert\NotNull(), Assert\Length(max: 255), Assert\NotBlank() @@ -30,8 +27,8 @@ trait AttributeGroupTrait * @var Collection */ #[ - ORM\OneToMany(mappedBy: "group", targetEntity: AttributeInterface::class), - Serializer\Groups(["attribute_group"]), + ORM\OneToMany(mappedBy: 'group', targetEntity: AttributeInterface::class), + Serializer\Groups(['attribute_group']), Serializer\Type("ArrayCollection") ] protected Collection $attributes; @@ -41,14 +38,14 @@ trait AttributeGroupTrait */ #[ ORM\OneToMany( - mappedBy: "attributeGroup", + mappedBy: 'attributeGroup', targetEntity: AttributeGroupTranslationInterface::class, - cascade: ["all"], + cascade: ['all'], orphanRemoval: true ), - Serializer\Groups(["attribute_group", "attribute", "node", "nodes_sources"]), + Serializer\Groups(['attribute_group', 'attribute', 'node', 'nodes_sources']), Serializer\Type("ArrayCollection"), - Serializer\Accessor(getter: "getAttributeGroupTranslations", setter: "setAttributeGroupTranslations") + Serializer\Accessor(getter: 'getAttributeGroupTranslations', setter: 'setAttributeGroupTranslations') ] protected Collection $attributeGroupTranslations; @@ -57,6 +54,7 @@ public function getName(): ?string if ($this->getAttributeGroupTranslations()->first()) { return $this->getAttributeGroupTranslations()->first()->getName(); } + return $this->getCanonicalName(); } @@ -71,24 +69,27 @@ function (AttributeGroupTranslationInterface $attributeGroupTranslation) use ($t if ($attributeGroupTranslation->getTranslation() === $translation) { return true; } + return false; } ); - if ($attributeGroupTranslation->count() > 0 && $attributeGroupTranslation->first()->getName() !== '') { + if ($attributeGroupTranslation->count() > 0 && '' !== $attributeGroupTranslation->first()->getName()) { return $attributeGroupTranslation->first()->getName(); } + return $this->getCanonicalName(); } public function setName(?string $name): self { - if ($this->getAttributeGroupTranslations()->count() === 0) { + if (0 === $this->getAttributeGroupTranslations()->count()) { $this->getAttributeGroupTranslations()->add( $this->createAttributeGroupTranslation()->setName($name) ); } $this->canonicalName = StringHandler::slugify($name ?? ''); + return $this; } @@ -98,12 +99,12 @@ public function getCanonicalName(): ?string } /** - * @param string|null $canonicalName * @return $this */ public function setCanonicalName(?string $canonicalName): self { $this->canonicalName = StringHandler::slugify($canonicalName ?? ''); + return $this; } @@ -113,12 +114,12 @@ public function getAttributes(): Collection } /** - * @param Collection $attributes * @return $this */ public function setAttributes(Collection $attributes): self { $this->attributes = $attributes; + return $this; } @@ -128,7 +129,6 @@ public function getAttributeGroupTranslations(): Collection } /** - * @param Collection $attributeGroupTranslations * @return $this */ public function setAttributeGroupTranslations(Collection $attributeGroupTranslations): self @@ -138,11 +138,11 @@ public function setAttributeGroupTranslations(Collection $attributeGroupTranslat foreach ($this->attributeGroupTranslations as $attributeGroupTranslation) { $attributeGroupTranslation->setAttributeGroup($this); } + return $this; } /** - * @param AttributeGroupTranslationInterface $attributeGroupTranslation * @return $this */ public function addAttributeGroupTranslation(AttributeGroupTranslationInterface $attributeGroupTranslation): self @@ -151,11 +151,11 @@ public function addAttributeGroupTranslation(AttributeGroupTranslationInterface $this->getAttributeGroupTranslations()->add($attributeGroupTranslation); $attributeGroupTranslation->setAttributeGroup($this); } + return $this; } /** - * @param AttributeGroupTranslationInterface $attributeGroupTranslation * @return $this */ public function removeAttributeGroupTranslation(AttributeGroupTranslationInterface $attributeGroupTranslation): self @@ -163,6 +163,7 @@ public function removeAttributeGroupTranslation(AttributeGroupTranslationInterfa if ($this->getAttributeGroupTranslations()->contains($attributeGroupTranslation)) { $this->getAttributeGroupTranslations()->removeElement($attributeGroupTranslation); } + return $this; } diff --git a/src/Model/AttributeGroupTranslationInterface.php b/src/Model/AttributeGroupTranslationInterface.php index 9371733a..02160d1b 100644 --- a/src/Model/AttributeGroupTranslationInterface.php +++ b/src/Model/AttributeGroupTranslationInterface.php @@ -9,39 +9,24 @@ interface AttributeGroupTranslationInterface extends PersistableInterface { - /** - * @return string - */ public function getName(): string; /** - * @param string $value - * - * @return mixed + * @return $this */ - public function setName(string $value); + public function setName(string $value): self; /** - * @param TranslationInterface $translation - * - * @return mixed + * @return $this */ - public function setTranslation(TranslationInterface $translation); + public function setTranslation(TranslationInterface $translation): self; - /** - * @return TranslationInterface|null - */ public function getTranslation(): ?TranslationInterface; - /** - * @return AttributeGroupInterface - */ public function getAttributeGroup(): AttributeGroupInterface; /** - * @param AttributeGroupInterface $attributeGroup - * - * @return mixed + * @return $this */ - public function setAttributeGroup(AttributeGroupInterface $attributeGroup); + public function setAttributeGroup(AttributeGroupInterface $attributeGroup): self; } diff --git a/src/Model/AttributeGroupTranslationTrait.php b/src/Model/AttributeGroupTranslationTrait.php index 34ec8324..b76f0cc6 100644 --- a/src/Model/AttributeGroupTranslationTrait.php +++ b/src/Model/AttributeGroupTranslationTrait.php @@ -13,53 +13,50 @@ trait AttributeGroupTranslationTrait { #[ ORM\ManyToOne(targetEntity: "RZ\Roadiz\Core\AbstractEntities\TranslationInterface"), - ORM\JoinColumn(name: "translation_id", referencedColumnName: "id", nullable: false, onDelete: "CASCADE"), - Serializer\Groups(["attribute_group", "attribute", "node", "nodes_sources"]), + ORM\JoinColumn(name: 'translation_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE'), + Serializer\Groups(['attribute_group', 'attribute', 'node', 'nodes_sources']), Serializer\Type("RZ\Roadiz\Core\AbstractEntities\TranslationInterface"), - Serializer\Accessor(getter: "getTranslation", setter: "setTranslation") + Serializer\Accessor(getter: 'getTranslation', setter: 'setTranslation') ] protected TranslationInterface $translation; #[ - ORM\Column(type: "string", length: 255, unique: false, nullable: false), - Serializer\Groups(["attribute_group", "attribute", "node", "nodes_sources"]), - Serializer\Type("string"), + ORM\Column(type: 'string', length: 255, unique: false, nullable: false), + Serializer\Groups(['attribute_group', 'attribute', 'node', 'nodes_sources']), + Serializer\Type('string'), Assert\Length(max: 255) ] protected string $name = ''; #[ - ORM\ManyToOne(targetEntity: AttributeGroupInterface::class, cascade: ["persist"], inversedBy: "attributeGroupTranslations"), - ORM\JoinColumn(name: "attribute_group_id", referencedColumnName: "id", nullable: false, onDelete: "CASCADE"), + ORM\ManyToOne(targetEntity: AttributeGroupInterface::class, cascade: ['persist'], inversedBy: 'attributeGroupTranslations'), + ORM\JoinColumn(name: 'attribute_group_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE'), Serializer\Exclude ] protected AttributeGroupInterface $attributeGroup; - /** - * @return string - */ public function getName(): string { return $this->name; } /** - * @param string $value - * @return self + * @return $this */ - public function setName(string $value) + public function setName(string $value): self { $this->name = $value; + return $this; } /** - * @param TranslationInterface $translation - * @return self + * @return $this */ - public function setTranslation(TranslationInterface $translation) + public function setTranslation(TranslationInterface $translation): self { $this->translation = $translation; + return $this; } @@ -68,21 +65,18 @@ public function getTranslation(): TranslationInterface return $this->translation; } - /** - * @return AttributeGroupInterface - */ public function getAttributeGroup(): AttributeGroupInterface { return $this->attributeGroup; } /** - * @param AttributeGroupInterface $attributeGroup - * @return self + * @return $this */ - public function setAttributeGroup(AttributeGroupInterface $attributeGroup) + public function setAttributeGroup(AttributeGroupInterface $attributeGroup): self { $this->attributeGroup = $attributeGroup; + return $this; } } diff --git a/src/Model/AttributeInterface.php b/src/Model/AttributeInterface.php index 1da81a62..56ca21c6 100644 --- a/src/Model/AttributeInterface.php +++ b/src/Model/AttributeInterface.php @@ -53,27 +53,17 @@ interface AttributeInterface extends PersistableInterface */ public const DATE_T = 22; /** - * ISO Country + * ISO Country. */ public const COUNTRY_T = 25; - /** - * @return string - */ public function getCode(): string; /** - * @param string $code - * * @return $this */ public function setCode(string $code): self; - /** - * @param TranslationInterface|null $translation - * - * @return string - */ public function getLabelOrCode(?TranslationInterface $translation = null): string; /** @@ -89,135 +79,68 @@ public function getAttributeTranslations(): Collection; public function setAttributeTranslations(Collection $attributeTranslations): self; /** - * @param AttributeTranslationInterface $attributeTranslation - * * @return $this */ public function addAttributeTranslation(AttributeTranslationInterface $attributeTranslation): self; /** - * @param AttributeTranslationInterface $attributeTranslation - * * @return $this */ public function removeAttributeTranslation(AttributeTranslationInterface $attributeTranslation): self; - /** - * @return bool - */ public function isSearchable(): bool; - /** - * @param bool $searchable - */ public function setSearchable(bool $searchable): self; - /** - * @param TranslationInterface $translation - * - * @return array|null - */ public function getOptions(TranslationInterface $translation): ?array; - /** - * @return int - */ public function getType(): int; - /** - * @return string|null - */ public function getColor(): ?string; public function getWeight(): int; - /** - * @param string|null $color - */ public function setColor(?string $color): self; - /** - * @return AttributeGroupInterface|null - */ public function getGroup(): ?AttributeGroupInterface; /** - * @param AttributeGroupInterface|null $group * @return $this */ public function setGroup(?AttributeGroupInterface $group): self; - /** - * @return Collection - */ public function getDocuments(): Collection; /** - * @param int $type * @return $this */ public function setType(int $type): self; - /** - * @return bool - */ public function isString(): bool; - /** - * @return bool - */ public function isDate(): bool; - /** - * @return bool - */ public function isDateTime(): bool; - /** - * @return bool - */ public function isBoolean(): bool; - /** - * @return bool - */ public function isInteger(): bool; - /** - * @return bool - */ public function isDecimal(): bool; - /** - * @return bool - */ public function isPercent(): bool; - /** - * @return bool - */ public function isEmail(): bool; - /** - * @return bool - */ public function isColor(): bool; - /** - * @return bool - */ public function isColour(): bool; - /** - * @return bool - */ public function isEnum(): bool; - /** - * @return bool - */ public function isCountry(): bool; public function getDefaultRealm(): ?RealmInterface; + public function setDefaultRealm(?RealmInterface $defaultRealm): self; } diff --git a/src/Model/AttributeTrait.php b/src/Model/AttributeTrait.php index bb52d5e3..a8a7833d 100644 --- a/src/Model/AttributeTrait.php +++ b/src/Model/AttributeTrait.php @@ -5,22 +5,22 @@ namespace RZ\Roadiz\CoreBundle\Model; use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\Mapping as ORM; +use JMS\Serializer\Annotation as Serializer; use RZ\Roadiz\Core\AbstractEntities\TranslationInterface; use RZ\Roadiz\CoreBundle\Entity\AttributeGroup; use RZ\Roadiz\CoreBundle\Entity\AttributeTranslation; use RZ\Roadiz\Utils\StringHandler; -use Doctrine\ORM\Mapping as ORM; -use JMS\Serializer\Annotation as Serializer; use Symfony\Component\Serializer\Annotation as SymfonySerializer; use Symfony\Component\Validator\Constraints as Assert; trait AttributeTrait { #[ - ORM\Column(type: "string", length: 255, unique: true, nullable: false), - Serializer\Groups(["attribute", "node", "nodes_sources"]), - SymfonySerializer\Groups(["attribute", "node", "nodes_sources"]), - Serializer\Type("string"), + ORM\Column(type: 'string', length: 255, unique: true, nullable: false), + Serializer\Groups(['attribute', 'node', 'nodes_sources']), + SymfonySerializer\Groups(['attribute', 'node', 'nodes_sources']), + Serializer\Type('string'), Assert\NotNull(), Assert\NotBlank(), Assert\Length(max: 255) @@ -28,26 +28,26 @@ trait AttributeTrait protected string $code = ''; #[ - ORM\Column(type: "boolean", unique: false, nullable: false, options: ["default" => false]), - Serializer\Groups(["attribute"]), - SymfonySerializer\Groups(["attribute"]), - Serializer\Type("boolean") + ORM\Column(type: 'boolean', unique: false, nullable: false, options: ['default' => false]), + Serializer\Groups(['attribute']), + SymfonySerializer\Groups(['attribute']), + Serializer\Type('boolean') ] protected bool $searchable = false; #[ - ORM\Column(type: "integer", unique: false, nullable: false), - Serializer\Groups(["attribute"]), - SymfonySerializer\Groups(["attribute"]), - Serializer\Type("integer") + ORM\Column(type: 'integer', unique: false, nullable: false), + Serializer\Groups(['attribute']), + SymfonySerializer\Groups(['attribute']), + Serializer\Type('integer') ] protected int $type = AttributeInterface::STRING_T; #[ - ORM\Column(type: "string", length: 7, unique: false, nullable: true), - Serializer\Groups(["attribute", "node", "nodes_sources"]), - SymfonySerializer\Groups(["attribute", "node", "nodes_sources"]), - Serializer\Type("string"), + ORM\Column(type: 'string', length: 7, unique: false, nullable: true), + Serializer\Groups(['attribute', 'node', 'nodes_sources']), + SymfonySerializer\Groups(['attribute', 'node', 'nodes_sources']), + Serializer\Type('string'), Assert\Length(max: 7) ] protected ?string $color = null; @@ -55,32 +55,32 @@ trait AttributeTrait #[ ORM\ManyToOne( targetEntity: AttributeGroupInterface::class, - cascade: ["persist", "merge"], - fetch: "EAGER", - inversedBy: "attributes" + cascade: ['persist', 'merge'], + fetch: 'EAGER', + inversedBy: 'attributes' ), - ORM\JoinColumn(name: "group_id", onDelete: "SET NULL"), - Serializer\Groups(["attribute", "node", "nodes_sources"]), - SymfonySerializer\Groups(["attribute", "node", "nodes_sources"]), + ORM\JoinColumn(name: 'group_id', onDelete: 'SET NULL'), + Serializer\Groups(['attribute', 'node', 'nodes_sources']), + SymfonySerializer\Groups(['attribute', 'node', 'nodes_sources']), Serializer\Type(AttributeGroup::class) ] protected ?AttributeGroupInterface $group = null; /** - * @var Collection + * @var Collection */ #[ ORM\OneToMany( - mappedBy: "attribute", + mappedBy: 'attribute', targetEntity: AttributeTranslationInterface::class, - cascade: ["all"], - fetch: "EAGER", + cascade: ['all'], + fetch: 'EAGER', orphanRemoval: true ), - Serializer\Groups(["attribute", "node", "nodes_sources"]), - SymfonySerializer\Groups(["attribute", "node", "nodes_sources"]), - Serializer\Type("ArrayCollection<" . AttributeTranslation::class . ">"), - Serializer\Accessor(getter: "getAttributeTranslations", setter: "setAttributeTranslations") + Serializer\Groups(['attribute', 'node', 'nodes_sources']), + SymfonySerializer\Groups(['attribute', 'node', 'nodes_sources']), + Serializer\Type('ArrayCollection<'.AttributeTranslation::class.'>'), + Serializer\Accessor(getter: 'getAttributeTranslations', setter: 'setAttributeTranslations') ] protected Collection $attributeTranslations; @@ -89,10 +89,10 @@ trait AttributeTrait */ #[ ORM\OneToMany( - mappedBy: "attribute", + mappedBy: 'attribute', targetEntity: AttributeValueInterface::class, - cascade: ["persist", "remove"], - fetch: "EXTRA_LAZY", + cascade: ['persist', 'remove'], + fetch: 'EXTRA_LAZY', orphanRemoval: true ), Serializer\Exclude, @@ -100,106 +100,81 @@ trait AttributeTrait ] protected Collection $attributeValues; - /** - * @return string - */ public function getCode(): string { return $this->code; } /** - * @param string|null $code - * * @return $this */ public function setCode(?string $code): self { $this->code = StringHandler::slugify($code ?? ''); + return $this; } - /** - * @return int - */ public function getType(): int { return $this->type; } /** - * @param int $type - * * @return $this */ public function setType(int $type): self { $this->type = $type; + return $this; } - /** - * @return string|null - */ public function getColor(): ?string { return $this->color; } /** - * @param string|null $color - * * @return $this */ public function setColor(?string $color): self { $this->color = $color; + return $this; } - /** - * @return AttributeGroupInterface|null - */ public function getGroup(): ?AttributeGroupInterface { return $this->group; } /** - * @param AttributeGroupInterface|null $group - * * @return $this */ public function setGroup(?AttributeGroupInterface $group): self { $this->group = $group; + return $this; } - /** - * @return bool - */ public function isSearchable(): bool { return (bool) $this->searchable; } /** - * @param bool $searchable - * * @return $this */ public function setSearchable(bool $searchable): self { $this->searchable = $searchable; + return $this; } - /** - * @param TranslationInterface|null $translation - * - * @return string - */ public function getLabelOrCode(?TranslationInterface $translation = null): string { if (null !== $translation) { @@ -210,8 +185,8 @@ function (AttributeTranslationInterface $attributeTranslation) use ($translation ); if ( - $attributeTranslation->first() && - $attributeTranslation->first()->getLabel() !== '' + $attributeTranslation->first() + && '' !== $attributeTranslation->first()->getLabel() ) { return $attributeTranslation->first()->getLabel(); } @@ -220,11 +195,6 @@ function (AttributeTranslationInterface $attributeTranslation) use ($translation return $this->getCode(); } - /** - * @param TranslationInterface $translation - * - * @return array|null - */ public function getOptions(TranslationInterface $translation): ?array { $attributeTranslation = $this->getAttributeTranslations()->filter( @@ -248,8 +218,6 @@ public function getAttributeTranslations(): Collection } /** - * @param Collection $attributeTranslations - * * @return $this */ public function setAttributeTranslations(Collection $attributeTranslations): self @@ -259,12 +227,11 @@ public function setAttributeTranslations(Collection $attributeTranslations): sel foreach ($this->attributeTranslations as $attributeTranslation) { $attributeTranslation->setAttribute($this); } + return $this; } /** - * @param AttributeTranslationInterface $attributeTranslation - * * @return $this */ public function addAttributeTranslation(AttributeTranslationInterface $attributeTranslation): self @@ -273,12 +240,11 @@ public function addAttributeTranslation(AttributeTranslationInterface $attribute $this->getAttributeTranslations()->add($attributeTranslation); $attributeTranslation->setAttribute($this); } + return $this; } /** - * @param AttributeTranslationInterface $attributeTranslation - * * @return $this */ public function removeAttributeTranslation(AttributeTranslationInterface $attributeTranslation): self @@ -286,52 +252,53 @@ public function removeAttributeTranslation(AttributeTranslationInterface $attrib if ($this->getAttributeTranslations()->contains($attributeTranslation)) { $this->getAttributeTranslations()->removeElement($attributeTranslation); } + return $this; } public function isString(): bool { - return $this->getType() === AttributeInterface::STRING_T; + return AttributeInterface::STRING_T === $this->getType(); } public function isDate(): bool { - return $this->getType() === AttributeInterface::DATE_T; + return AttributeInterface::DATE_T === $this->getType(); } public function isDateTime(): bool { - return $this->getType() === AttributeInterface::DATETIME_T; + return AttributeInterface::DATETIME_T === $this->getType(); } public function isBoolean(): bool { - return $this->getType() === AttributeInterface::BOOLEAN_T; + return AttributeInterface::BOOLEAN_T === $this->getType(); } public function isInteger(): bool { - return $this->getType() === AttributeInterface::INTEGER_T; + return AttributeInterface::INTEGER_T === $this->getType(); } public function isDecimal(): bool { - return $this->getType() === AttributeInterface::DECIMAL_T; + return AttributeInterface::DECIMAL_T === $this->getType(); } public function isPercent(): bool { - return $this->getType() === AttributeInterface::PERCENT_T; + return AttributeInterface::PERCENT_T === $this->getType(); } public function isEmail(): bool { - return $this->getType() === AttributeInterface::EMAIL_T; + return AttributeInterface::EMAIL_T === $this->getType(); } public function isColor(): bool { - return $this->getType() === AttributeInterface::COLOUR_T; + return AttributeInterface::COLOUR_T === $this->getType(); } public function isColour(): bool @@ -341,28 +308,28 @@ public function isColour(): bool public function isEnum(): bool { - return $this->getType() === AttributeInterface::ENUM_T; + return AttributeInterface::ENUM_T === $this->getType(); } public function isCountry(): bool { - return $this->getType() === AttributeInterface::COUNTRY_T; + return AttributeInterface::COUNTRY_T === $this->getType(); } public function getTypeLabel(): string { return match ($this->getType()) { - AttributeInterface::DATETIME_T => 'attributes.form.type.datetime', - AttributeInterface::BOOLEAN_T => 'attributes.form.type.boolean', - AttributeInterface::INTEGER_T => 'attributes.form.type.integer', - AttributeInterface::DECIMAL_T => 'attributes.form.type.decimal', - AttributeInterface::PERCENT_T => 'attributes.form.type.percent', - AttributeInterface::EMAIL_T => 'attributes.form.type.email', - AttributeInterface::COLOUR_T => 'attributes.form.type.colour', - AttributeInterface::ENUM_T => 'attributes.form.type.enum', - AttributeInterface::DATE_T => 'attributes.form.type.date', - AttributeInterface::COUNTRY_T => 'attributes.form.type.country', - default => 'attributes.form.type.string', + AttributeInterface::DATETIME_T => 'attributes.form.type.datetime', + AttributeInterface::BOOLEAN_T => 'attributes.form.type.boolean', + AttributeInterface::INTEGER_T => 'attributes.form.type.integer', + AttributeInterface::DECIMAL_T => 'attributes.form.type.decimal', + AttributeInterface::PERCENT_T => 'attributes.form.type.percent', + AttributeInterface::EMAIL_T => 'attributes.form.type.email', + AttributeInterface::COLOUR_T => 'attributes.form.type.colour', + AttributeInterface::ENUM_T => 'attributes.form.type.enum', + AttributeInterface::DATE_T => 'attributes.form.type.date', + AttributeInterface::COUNTRY_T => 'attributes.form.type.country', + default => 'attributes.form.type.string', }; } diff --git a/src/Model/AttributeTranslationInterface.php b/src/Model/AttributeTranslationInterface.php index c96ce5ba..730e8850 100644 --- a/src/Model/AttributeTranslationInterface.php +++ b/src/Model/AttributeTranslationInterface.php @@ -9,52 +9,31 @@ interface AttributeTranslationInterface extends PersistableInterface { - /** - * @return string|null - */ public function getLabel(): ?string; /** - * @param string|null $label - * - * @return mixed + * @return $this */ - public function setLabel(?string $label); + public function setLabel(?string $label): self; /** - * @param TranslationInterface $translation - * - * @return mixed + * @return $this */ - public function setTranslation(TranslationInterface $translation); + public function setTranslation(TranslationInterface $translation): self; - /** - * @return TranslationInterface|null - */ public function getTranslation(): ?TranslationInterface; - /** - * @return AttributeInterface - */ public function getAttribute(): AttributeInterface; /** - * @param AttributeInterface $attribute - * - * @return mixed + * @return $this */ - public function setAttribute(AttributeInterface $attribute); - + public function setAttribute(AttributeInterface $attribute): self; - /** - * @return array|null - */ public function getOptions(): ?array; /** - * @param array|null $options - * - * @return mixed + * @return $this */ - public function setOptions(?array $options); + public function setOptions(?array $options): self; } diff --git a/src/Model/AttributeTranslationTrait.php b/src/Model/AttributeTranslationTrait.php index 9926436f..24866495 100644 --- a/src/Model/AttributeTranslationTrait.php +++ b/src/Model/AttributeTranslationTrait.php @@ -13,17 +13,17 @@ trait AttributeTranslationTrait { #[ ORM\ManyToOne(targetEntity: TranslationInterface::class), - ORM\JoinColumn(name: "translation_id", referencedColumnName: "id", nullable: false, onDelete: "CASCADE"), - Serializer\Groups(["attribute", "node", "nodes_sources"]), + ORM\JoinColumn(name: 'translation_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE'), + Serializer\Groups(['attribute', 'node', 'nodes_sources']), Serializer\Type("RZ\Roadiz\Core\AbstractEntities\TranslationInterface"), - Serializer\Accessor(getter: "getTranslation", setter: "setTranslation") + Serializer\Accessor(getter: 'getTranslation', setter: 'setTranslation') ] protected TranslationInterface $translation; #[ - ORM\Column(type: "string", length: 250, unique: false, nullable: false), - Serializer\Groups(["attribute", "node", "nodes_sources"]), - Serializer\Type("string"), + ORM\Column(type: 'string', length: 250, unique: false, nullable: false), + Serializer\Groups(['attribute', 'node', 'nodes_sources']), + Serializer\Type('string'), Assert\Length(max: 250) ] protected string $label = ''; @@ -32,45 +32,41 @@ trait AttributeTranslationTrait * @var array|null */ #[ - ORM\Column(type: "simple_array", unique: false, nullable: true), - Serializer\Groups(["attribute"]), - Serializer\Type("array") + ORM\Column(type: 'simple_array', unique: false, nullable: true), + Serializer\Groups(['attribute']), + Serializer\Type('array') ] protected ?array $options = []; #[ - ORM\ManyToOne(targetEntity: AttributeInterface::class, cascade: ["persist"], inversedBy: "attributeTranslations"), - ORM\JoinColumn(name: "attribute_id", referencedColumnName: "id", nullable: false, onDelete: "CASCADE"), + ORM\ManyToOne(targetEntity: AttributeInterface::class, cascade: ['persist'], inversedBy: 'attributeTranslations'), + ORM\JoinColumn(name: 'attribute_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE'), Serializer\Exclude ] protected AttributeInterface $attribute; - /** - * @return string|null - */ public function getLabel(): ?string { return $this->label; } /** - * @param string|null $label - * * @return $this */ - public function setLabel(?string $label) + public function setLabel(?string $label): self { $this->label = null !== $label ? trim($label) : null; + return $this; } /** - * @param TranslationInterface $translation * @return $this */ - public function setTranslation(TranslationInterface $translation) + public function setTranslation(TranslationInterface $translation): self { $this->translation = $translation; + return $this; } @@ -79,25 +75,21 @@ public function getTranslation(): TranslationInterface return $this->translation; } - /** - * @return AttributeInterface - */ public function getAttribute(): AttributeInterface { return $this->attribute; } /** - * @param AttributeInterface $attribute * @return $this */ - public function setAttribute(AttributeInterface $attribute) + public function setAttribute(AttributeInterface $attribute): self { $this->attribute = $attribute; + return $this; } - /** * @return array|null */ @@ -111,9 +103,10 @@ public function getOptions(): ?array * * @return $this */ - public function setOptions(?array $options) + public function setOptions(?array $options): self { $this->options = $options; + return $this; } } diff --git a/src/Model/AttributeValueInterface.php b/src/Model/AttributeValueInterface.php index aab86a8c..9c7061db 100644 --- a/src/Model/AttributeValueInterface.php +++ b/src/Model/AttributeValueInterface.php @@ -12,23 +12,19 @@ interface AttributeValueInterface extends PositionedInterface, PersistableInterface { public function getRealm(): ?RealmInterface; - public function setRealm(?RealmInterface $realm): self; /** - * @return AttributeInterface|null + * @return $this */ + public function setRealm(?RealmInterface $realm): self; + public function getAttribute(): ?AttributeInterface; /** - * @param AttributeInterface $attribute - * - * @return mixed + * @return $this */ - public function setAttribute(AttributeInterface $attribute); + public function setAttribute(AttributeInterface $attribute): self; - /** - * @return int - */ public function getType(): int; /** @@ -36,29 +32,19 @@ public function getType(): int; */ public function getAttributeValueTranslations(): Collection; - /** - * @param TranslationInterface $translation - * - * @return AttributeValueTranslationInterface|null - */ public function getAttributeValueTranslation(TranslationInterface $translation): ?AttributeValueTranslationInterface; /** * @param Collection $attributeValueTranslations * - * @return mixed + * @return $this */ - public function setAttributeValueTranslations(Collection $attributeValueTranslations); + public function setAttributeValueTranslations(Collection $attributeValueTranslations): self; - /** - * @return AttributableInterface|null - */ public function getAttributable(): ?AttributableInterface; /** - * @param AttributableInterface|null $attributable - * - * @return mixed + * @return $this */ - public function setAttributable(?AttributableInterface $attributable); + public function setAttributable(?AttributableInterface $attributable): self; } diff --git a/src/Model/AttributeValueTrait.php b/src/Model/AttributeValueTrait.php index ef154cfc..47f9f39e 100644 --- a/src/Model/AttributeValueTrait.php +++ b/src/Model/AttributeValueTrait.php @@ -4,38 +4,38 @@ namespace RZ\Roadiz\CoreBundle\Model; +use ApiPlatform\Doctrine\Orm\Filter as BaseFilter; use ApiPlatform\Metadata\ApiFilter; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation as Serializer; use RZ\Roadiz\Core\AbstractEntities\TranslationInterface; -use ApiPlatform\Doctrine\Orm\Filter as BaseFilter; trait AttributeValueTrait { #[ - ORM\ManyToOne(targetEntity: AttributeInterface::class, fetch: "EAGER", inversedBy: "attributeValues"), - ORM\JoinColumn(name: "attribute_id", referencedColumnName: "id", nullable: false, onDelete: "CASCADE"), - Serializer\Groups(["attribute", "node", "nodes_sources"]), + ORM\ManyToOne(targetEntity: AttributeInterface::class, fetch: 'EAGER', inversedBy: 'attributeValues'), + ORM\JoinColumn(name: 'attribute_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE'), + Serializer\Groups(['attribute', 'node', 'nodes_sources']), Serializer\Type("RZ\Roadiz\CoreBundle\Entity\Attribute"), ApiFilter(BaseFilter\SearchFilter::class, properties: [ - "attribute.id" => "exact", - "attribute.code" => "exact", - "attribute.color" => "exact", - "attribute.type" => "exact", - "attribute.group" => "exact", - "attribute.group.canonicalName" => "exact", + 'attribute.id' => 'exact', + 'attribute.code' => 'exact', + 'attribute.color' => 'exact', + 'attribute.type' => 'exact', + 'attribute.group' => 'exact', + 'attribute.group.canonicalName' => 'exact', ]), ApiFilter(BaseFilter\BooleanFilter::class, properties: [ - "attribute.visible", - "attribute.searchable" + 'attribute.visible', + 'attribute.searchable', ]), ApiFilter(BaseFilter\ExistsFilter::class, properties: [ - "attribute.color", - "attribute.group" + 'attribute.color', + 'attribute.group', ]), ApiFilter(BaseFilter\OrderFilter::class, properties: [ - "attribute.weight" => "DESC", + 'attribute.weight' => 'DESC', ]) ] protected AttributeInterface $attribute; @@ -45,48 +45,39 @@ trait AttributeValueTrait */ #[ ORM\OneToMany( - mappedBy: "attributeValue", + mappedBy: 'attributeValue', targetEntity: AttributeValueTranslationInterface::class, - cascade: ["persist", "remove"], - fetch: "EAGER", + cascade: ['persist', 'remove'], + fetch: 'EAGER', orphanRemoval: true ), - Serializer\Groups(["attribute", "node", "nodes_sources"]), + Serializer\Groups(['attribute', 'node', 'nodes_sources']), Serializer\Type("ArrayCollection"), - Serializer\Accessor(getter: "getAttributeValueTranslations", setter: "setAttributeValueTranslations"), + Serializer\Accessor(getter: 'getAttributeValueTranslations', setter: 'setAttributeValueTranslations'), ApiFilter(BaseFilter\SearchFilter::class, properties: [ - "attributeValueTranslations.value" => "partial", + 'attributeValueTranslations.value' => 'partial', ]), ApiFilter(BaseFilter\RangeFilter::class, properties: [ - "attributeValueTranslations.value", + 'attributeValueTranslations.value', ]), ApiFilter(BaseFilter\ExistsFilter::class, properties: [ - "attributeValueTranslations.value", + 'attributeValueTranslations.value', ]), ] protected Collection $attributeValueTranslations; - /** - * @return AttributeInterface|null - */ public function getAttribute(): ?AttributeInterface { return $this->attribute; } - /** - * @param AttributeInterface $attribute - * @return self - */ - public function setAttribute(AttributeInterface $attribute) + public function setAttribute(AttributeInterface $attribute): self { $this->attribute = $attribute; + return $this; } - /** - * @return int - */ public function getType(): int { return $this->getAttribute()->getType(); @@ -101,25 +92,19 @@ public function getAttributeValueTranslations(): Collection } /** - * @param Collection $attributeValueTranslations - * * @return static */ - public function setAttributeValueTranslations(Collection $attributeValueTranslations) + public function setAttributeValueTranslations(Collection $attributeValueTranslations): self { $this->attributeValueTranslations = $attributeValueTranslations; /** @var AttributeValueTranslationInterface $attributeValueTranslation */ foreach ($this->attributeValueTranslations as $attributeValueTranslation) { $attributeValueTranslation->setAttributeValue($this); } + return $this; } - /** - * @param TranslationInterface $translation - * - * @return AttributeValueTranslationInterface|null - */ public function getAttributeValueTranslation(TranslationInterface $translation): ?AttributeValueTranslationInterface { return $this->getAttributeValueTranslations() @@ -127,14 +112,12 @@ public function getAttributeValueTranslation(TranslationInterface $translation): if ($attributeValueTranslation->getTranslation() === $translation) { return true; } + return false; }) ->first() ?: null; } - /** - * @return AttributeValueTranslationInterface|null - */ public function getAttributeValueDefaultTranslation(): ?AttributeValueTranslationInterface { return $this->getAttributeValueTranslations() diff --git a/src/Model/AttributeValueTranslationInterface.php b/src/Model/AttributeValueTranslationInterface.php index c0ad7e74..cb0938fb 100644 --- a/src/Model/AttributeValueTranslationInterface.php +++ b/src/Model/AttributeValueTranslationInterface.php @@ -9,44 +9,26 @@ interface AttributeValueTranslationInterface extends PersistableInterface { - /** - * @return mixed - */ - public function getValue(); + public function getValue(): mixed; /** - * @param mixed $value - * - * @return mixed + * @return $this */ - public function setValue($value); + public function setValue(mixed $value): self; /** - * @param TranslationInterface $translation - * - * @return mixed + * @return $this */ - public function setTranslation(TranslationInterface $translation); + public function setTranslation(TranslationInterface $translation): self; - /** - * @return TranslationInterface|null - */ public function getTranslation(): ?TranslationInterface; - /** - * @return AttributeInterface|null - */ public function getAttribute(): ?AttributeInterface; - /** - * @return AttributeValueInterface - */ public function getAttributeValue(): AttributeValueInterface; /** - * @param AttributeValueInterface $attributeValue - * - * @return mixed + * @return $this */ - public function setAttributeValue(AttributeValueInterface $attributeValue); + public function setAttributeValue(AttributeValueInterface $attributeValue): self; } diff --git a/src/Model/AttributeValueTranslationTrait.php b/src/Model/AttributeValueTranslationTrait.php index 57cb8ae2..06d2a060 100644 --- a/src/Model/AttributeValueTranslationTrait.php +++ b/src/Model/AttributeValueTranslationTrait.php @@ -4,39 +4,38 @@ namespace RZ\Roadiz\CoreBundle\Model; -use RZ\Roadiz\Core\AbstractEntities\TranslationInterface; use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation as Serializer; +use RZ\Roadiz\Core\AbstractEntities\TranslationInterface; use Symfony\Component\Validator\Constraints as Assert; trait AttributeValueTranslationTrait { #[ ORM\ManyToOne(targetEntity: TranslationInterface::class), - ORM\JoinColumn(name: "translation_id", referencedColumnName: "id", nullable: false, onDelete: "CASCADE"), - Serializer\Groups(["attribute", "node", "nodes_sources"]), + ORM\JoinColumn(name: 'translation_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE'), + Serializer\Groups(['attribute', 'node', 'nodes_sources']), Serializer\Type("RZ\Roadiz\Core\AbstractEntities\TranslationInterface"), - Serializer\Accessor(getter: "getTranslation", setter: "setTranslation") + Serializer\Accessor(getter: 'getTranslation', setter: 'setTranslation') ] protected TranslationInterface $translation; #[ - ORM\Column(type: "string", length: 255, unique: false, nullable: true), - Serializer\Groups(["attribute", "node", "nodes_sources"]), - Serializer\Type("string"), + ORM\Column(type: 'string', length: 255, unique: false, nullable: true), + Serializer\Groups(['attribute', 'node', 'nodes_sources']), + Serializer\Type('string'), Assert\Length(max: 255) ] protected ?string $value = null; #[ - ORM\ManyToOne(targetEntity: AttributeValueInterface::class, cascade: ["persist"], inversedBy: "attributeValueTranslations"), - ORM\JoinColumn(name: "attribute_value", referencedColumnName: "id", nullable: false, onDelete: "CASCADE"), + ORM\ManyToOne(targetEntity: AttributeValueInterface::class, cascade: ['persist'], inversedBy: 'attributeValueTranslations'), + ORM\JoinColumn(name: 'attribute_value', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE'), Serializer\Exclude ] protected AttributeValueInterface $attributeValue; /** - * @return bool|\DateTime|float|int|string|null * @throws \Exception */ public function getValue(): bool|\DateTime|float|int|string|null @@ -44,6 +43,7 @@ public function getValue(): bool|\DateTime|float|int|string|null if (null === $this->value) { return null; } + return match ($this->getAttributeValue()->getType()) { AttributeInterface::DECIMAL_T => (float) $this->value, AttributeInterface::INTEGER_T => (int) $this->value, @@ -56,9 +56,9 @@ public function getValue(): bool|\DateTime|float|int|string|null /** * @param mixed|null $value * - * @return self + * @return $this */ - public function setValue(mixed $value) + public function setValue(mixed $value): self { if (null === $value) { $this->value = null; @@ -69,6 +69,7 @@ public function setValue(mixed $value) throw new \InvalidArgumentException('Email is not valid'); } $this->value = (string) $value; + return $this; case AttributeInterface::DATETIME_T: case AttributeInterface::DATE_T: @@ -77,20 +78,22 @@ public function setValue(mixed $value) } else { $this->value = (string) $value; } + return $this; default: $this->value = (string) $value; + return $this; } } /** - * @param TranslationInterface $translation - * @return self + * @return $this */ - public function setTranslation(TranslationInterface $translation) + public function setTranslation(TranslationInterface $translation): self { $this->translation = $translation; + return $this; } @@ -99,21 +102,18 @@ public function getTranslation(): TranslationInterface return $this->translation; } - /** - * @return AttributeValueInterface - */ public function getAttributeValue(): AttributeValueInterface { return $this->attributeValue; } /** - * @param AttributeValueInterface $attributeValue - * @return self + * @return $this */ - public function setAttributeValue(AttributeValueInterface $attributeValue) + public function setAttributeValue(AttributeValueInterface $attributeValue): self { $this->attributeValue = $attributeValue; + return $this; } diff --git a/src/Model/NodeTreeDto.php b/src/Model/NodeTreeDto.php new file mode 100644 index 00000000..82a2e38e --- /dev/null +++ b/src/Model/NodeTreeDto.php @@ -0,0 +1,143 @@ +nodeType = new NodeTypeTreeDto( + $nodeTypeName, + $nodeTypePublishable, + $nodeTypeReachable, + $nodeTypeDisplayName, + $nodeTypeColor, + $nodeTypeHidingNodes, + $nodeTypeHidingNonReachableNodes + ); + $this->nodeSource = new NodesSourcesTreeDto( + $sourceId, + $title, + $publishedAt, + ); + } + + public function getId(): int + { + return $this->id; + } + + public function getChildrenOrder(): string + { + return $this->childrenOrder; + } + + public function getChildrenOrderDirection(): string + { + return $this->childrenOrderDirection; + } + + public function getNodeName(): string + { + return $this->nodeName; + } + + public function getParentId(): ?int + { + return $this->parentId; + } + + public function isHidingChildren(): bool + { + return $this->hideChildren; + } + + public function isHome(): bool + { + return $this->home; + } + + public function isVisible(): bool + { + return $this->visible; + } + + public function getStatus(): NodeStatus + { + return $this->status; + } + + public function getStatusAsString(): string + { + return $this->status->name; + } + + public function isLocked(): bool + { + return $this->locked; + } + + public function isPublished(): bool + { + return $this->status->isPublished(); + } + + public function isPending(): bool + { + return $this->status->isPending(); + } + + public function isDraft(): bool + { + return $this->status->isDraft(); + } + + public function isDeleted(): bool + { + return $this->status->isDeleted(); + } + + public function getNodeType(): NodeTypeInterface + { + return $this->nodeType; + } + + public function getNodeSource(): NodesSourcesTreeDto + { + return $this->nodeSource; + } +} diff --git a/src/Model/NodeTypeTreeDto.php b/src/Model/NodeTypeTreeDto.php new file mode 100644 index 00000000..824dbebb --- /dev/null +++ b/src/Model/NodeTypeTreeDto.php @@ -0,0 +1,113 @@ +name; + } + + public function isPublishable(): bool + { + return $this->publishable; + } + + public function getDisplayName(): string + { + return $this->displayName; + } + + public function getColor(): string + { + return $this->color; + } + + public function isHidingNodes(): bool + { + return $this->hidingNodes; + } + + public function isHidingNonReachableNodes(): bool + { + return $this->hidingNonReachableNodes; + } + + public function getLabel(): string + { + return $this->getDisplayName(); + } + + public function isReachable(): bool + { + return $this->reachable; + } + + public function getDescription(): ?string + { + throw new \RuntimeException('NodeTypeTreeDto does not implement getDescription method.'); + } + + public function isVisible(): bool + { + throw new \RuntimeException('NodeTypeTreeDto does not implement isVisible method.'); + } + + public function getSourceEntityClassName(): string + { + throw new \RuntimeException('NodeTypeTreeDto does not implement getSourceEntityClassName method.'); + } + + public function getSourceEntityFullQualifiedClassName(): string + { + throw new \RuntimeException('NodeTypeTreeDto does not implement getSourceEntityFullQualifiedClassName method.'); + } + + public function getSourceEntityTableName(): string + { + throw new \RuntimeException('NodeTypeTreeDto does not implement getSourceEntityTableName method.'); + } + + public function getFieldsNames(): array + { + throw new \RuntimeException('NodeTypeTreeDto does not implement getFieldsNames method.'); + } + + public function getFields(): Collection + { + throw new \RuntimeException('NodeTypeTreeDto does not implement getFields method.'); + } + + public function getSearchableFields(): Collection + { + throw new \RuntimeException('NodeTypeTreeDto does not implement getSearchableFields method.'); + } + + public function getFieldByName(string $name): ?NodeTypeFieldInterface + { + throw new \RuntimeException('NodeTypeTreeDto does not implement getFieldByName method.'); + } + + public function isSearchable(): bool + { + throw new \RuntimeException('NodeTypeTreeDto does not implement isSearchable method.'); + } +} diff --git a/src/Model/NodesSourcesTreeDto.php b/src/Model/NodesSourcesTreeDto.php new file mode 100644 index 00000000..0601cc6b --- /dev/null +++ b/src/Model/NodesSourcesTreeDto.php @@ -0,0 +1,32 @@ +id; + } + + public function getTitle(): ?string + { + return $this->title; + } + + public function getPublishedAt(): ?\DateTime + { + return $this->publishedAt; + } +} diff --git a/src/Model/RealmInterface.php b/src/Model/RealmInterface.php index 6518eca8..f6322078 100644 --- a/src/Model/RealmInterface.php +++ b/src/Model/RealmInterface.php @@ -33,20 +33,24 @@ interface RealmInterface extends PersistableInterface public function getType(): string; /** - * @return string * @see https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml */ public function getAuthenticationScheme(): string; /** - * @return string * @see https://developer.mozilla.org/fr/docs/Web/HTTP/Headers/WWW-Authenticate */ public function getChallenge(): string; + public function getBehaviour(): string; + public function getName(): string; + public function getPlainPassword(): ?string; + public function getRole(): ?string; + public function getUsers(): Collection; + public function getSerializationGroup(): ?string; } diff --git a/src/Model/TagTreeDto.php b/src/Model/TagTreeDto.php new file mode 100644 index 00000000..0a0f70db --- /dev/null +++ b/src/Model/TagTreeDto.php @@ -0,0 +1,53 @@ +id; + } + + public function getTagName(): string + { + return $this->tagName; + } + + public function getName(): ?string + { + return $this->name; + } + + public function getColor(): string + { + return $this->color; + } + + public function isVisible(): bool + { + return $this->visible; + } + + public function getParentId(): ?int + { + return $this->parentId; + } +} diff --git a/src/Node/CachedNodeOffspringResolver.php b/src/Node/CachedNodeOffspringResolver.php index 52571ccd..229b10c1 100644 --- a/src/Node/CachedNodeOffspringResolver.php +++ b/src/Node/CachedNodeOffspringResolver.php @@ -8,6 +8,7 @@ use Psr\Cache\CacheException; use Psr\Cache\CacheItemPoolInterface; use Psr\Cache\InvalidArgumentException; +use RZ\Roadiz\Core\AbstractEntities\NodeInterface; use RZ\Roadiz\CoreBundle\Entity\Node; use Symfony\Contracts\Cache\ItemInterface; use Symfony\Contracts\Cache\TagAwareCacheInterface; @@ -16,18 +17,17 @@ final class CachedNodeOffspringResolver implements CachedNodeOffspringResolverIn { public function __construct( private readonly CacheItemPoolInterface $cache, - private readonly ManagerRegistry $managerRegistry + private readonly ManagerRegistry $managerRegistry, ) { } /** - * @inheritDoc * @throws InvalidArgumentException * @throws CacheException */ - public function getAllOffspringIds(Node $ancestor): array + public function getAllOffspringIds(NodeInterface $ancestor): array { - $cacheItem = $this->cache->getItem(self::CACHE_PREFIX . $ancestor->getId()); + $cacheItem = $this->cache->getItem(self::CACHE_PREFIX.$ancestor->getId()); if (!$cacheItem->isHit()) { $nodeRepository = $this->managerRegistry->getRepository(Node::class); $offspringIds = $nodeRepository->findAllOffspringIdByNode($ancestor); @@ -35,33 +35,34 @@ public function getAllOffspringIds(Node $ancestor): array $cacheItem->expiresAfter(300); if ($cacheItem instanceof ItemInterface && $this->cache instanceof TagAwareCacheInterface) { $cacheItem->tag(array_map(function (int $nodeId) { - return self::CACHE_TAG_PREFIX . $nodeId; + return self::CACHE_TAG_PREFIX.$nodeId; }, $offspringIds)); } $this->cache->save($cacheItem); } else { $offspringIds = $cacheItem->get(); } + return $offspringIds; } /** * @throws InvalidArgumentException */ - public function purgeOffspringCache(Node $node): void + public function purgeOffspringCache(NodeInterface $node): void { - $this->cache->deleteItem(self::CACHE_PREFIX . $node->getId()); + $this->cache->deleteItem(self::CACHE_PREFIX.$node->getId()); if ($this->cache instanceof TagAwareCacheInterface) { /* * If cache pool supports tags, we can invalidate all nodes at once. */ - $this->cache->invalidateTags([self::CACHE_TAG_PREFIX . $node->getId()]); - } else { + $this->cache->invalidateTags([self::CACHE_TAG_PREFIX.$node->getId()]); + } elseif ($node instanceof Node) { $ancestorsId = $this->managerRegistry ->getRepository(Node::class) ->findAllParentsIdByNode($node); foreach ($ancestorsId as $ancestorId) { - $this->cache->deleteItem(self::CACHE_PREFIX . $ancestorId); + $this->cache->deleteItem(self::CACHE_PREFIX.$ancestorId); } } } diff --git a/src/Node/CachedNodeOffspringResolverInterface.php b/src/Node/CachedNodeOffspringResolverInterface.php index 5e79bc61..424c0290 100644 --- a/src/Node/CachedNodeOffspringResolverInterface.php +++ b/src/Node/CachedNodeOffspringResolverInterface.php @@ -4,11 +4,12 @@ namespace RZ\Roadiz\CoreBundle\Node; -use RZ\Roadiz\CoreBundle\Entity\Node; +use RZ\Roadiz\Core\AbstractEntities\NodeInterface; interface CachedNodeOffspringResolverInterface extends NodeOffspringResolverInterface { public const CACHE_PREFIX = 'node_offspring_ids_'; public const CACHE_TAG_PREFIX = 'node_'; - public function purgeOffspringCache(Node $node): void; + + public function purgeOffspringCache(NodeInterface $node): void; } diff --git a/src/Node/NodeDuplicator.php b/src/Node/NodeDuplicator.php index f1b6c5a6..55fd9ddb 100644 --- a/src/Node/NodeDuplicator.php +++ b/src/Node/NodeDuplicator.php @@ -10,25 +10,24 @@ use RZ\Roadiz\CoreBundle\Entity\NodesSources; use RZ\Roadiz\CoreBundle\Entity\NodesSourcesDocuments; use RZ\Roadiz\CoreBundle\Entity\NodesToNodes; +use RZ\Roadiz\CoreBundle\Enum\NodeStatus; use Symfony\Component\DependencyInjection\Attribute\Exclude; /** * Handles node duplication. */ #[Exclude] -final class NodeDuplicator +final readonly class NodeDuplicator { public function __construct( - private readonly Node $originalNode, - private readonly ObjectManager $objectManager, - private readonly NodeNamePolicyInterface $nodeNamePolicy + private Node $originalNode, + private ObjectManager $objectManager, + private NodeNamePolicyInterface $nodeNamePolicy, ) { } /** * Warning this method flush entityManager at its end. - * - * @return Node */ public function duplicate(): Node { @@ -45,13 +44,13 @@ public function duplicate(): Node $this->objectManager->clear(); } - if ($parent !== null) { + if (null !== $parent) { /** @var Node $parent */ $parent = $this->objectManager->find(Node::class, $parent->getId()); $node->setParent($parent); } // Demote cloned node to draft - $node->setStatus(Node::DRAFT); + $node->setStatus(NodeStatus::DRAFT); $node = $this->doDuplicate($node); $this->objectManager->flush(); @@ -62,9 +61,6 @@ public function duplicate(): Node /** * Warning, do not do any FLUSH here to preserve transactional integrity. - * - * @param Node $node - * @return Node */ private function doDuplicate(Node &$node): Node { @@ -123,8 +119,6 @@ private function doDuplicate(Node &$node): Node * Duplicate Node to Node relationship. * * Warning, do not do any FLUSH here to preserve transactional integrity. - * - * @param Node $node */ private function doDuplicateNodeRelations(Node $node): void { diff --git a/src/Node/NodeFactory.php b/src/Node/NodeFactory.php index 1cbc852b..dce62a6d 100644 --- a/src/Node/NodeFactory.php +++ b/src/Node/NodeFactory.php @@ -15,11 +15,11 @@ use RZ\Roadiz\CoreBundle\Repository\NodeRepository; use RZ\Roadiz\CoreBundle\Repository\UrlAliasRepository; -final class NodeFactory +final readonly class NodeFactory { public function __construct( - private readonly ManagerRegistry $managerRegistry, - private readonly NodeNamePolicyInterface $nodeNamePolicy + private ManagerRegistry $managerRegistry, + private NodeNamePolicyInterface $nodeNamePolicy, ) { } @@ -28,21 +28,21 @@ public function create( ?NodeTypeInterface $type = null, ?TranslationInterface $translation = null, ?Node $node = null, - ?Node $parent = null + ?Node $parent = null, ): Node { /** @var NodeRepository $repository */ $repository = $this->managerRegistry->getRepository(Node::class) ->setDisplayingAllNodesStatuses(true); - if ($node === null && $type === null) { + if (null === $node && null === $type) { throw new \RuntimeException('Cannot create node from null NodeType and null Node.'); } - if ($translation === null) { + if (null === $translation) { $translation = $this->managerRegistry->getRepository(Translation::class)->findDefault(); } - if ($node === null) { + if (null === $node) { $node = new Node(); $node->setNodeType($type); } @@ -90,7 +90,7 @@ public function createWithUrlAlias( ?NodeTypeInterface $type = null, ?TranslationInterface $translation = null, ?Node $node = null, - ?Node $parent = null + ?Node $parent = null, ): Node { $node = $this->create($title, $type, $translation, $node, $parent); $nodeSource = $node->getNodeSources()->first(); diff --git a/src/Node/NodeMover.php b/src/Node/NodeMover.php index 8deaff0d..9dbda8cd 100644 --- a/src/Node/NodeMover.php +++ b/src/Node/NodeMover.php @@ -8,17 +8,15 @@ use Doctrine\Persistence\ObjectManager; use Psr\Cache\CacheItemPoolInterface; use Psr\Log\LoggerInterface; -use Psr\Log\NullLogger; +use RZ\Roadiz\Core\Handlers\HandlerFactoryInterface; use RZ\Roadiz\CoreBundle\Entity\Node; use RZ\Roadiz\CoreBundle\Entity\NodesSources; use RZ\Roadiz\CoreBundle\Entity\Redirection; -use RZ\Roadiz\Core\Handlers\HandlerFactoryInterface; use RZ\Roadiz\CoreBundle\EntityHandler\NodeHandler; -use RZ\Roadiz\CoreBundle\Event\Redirection\PostCreatedRedirectionEvent; use RZ\Roadiz\CoreBundle\Event\Redirection\PostUpdatedRedirectionEvent; +use RZ\Roadiz\CoreBundle\Node\Exception\SameNodeUrlException; use RZ\Roadiz\CoreBundle\Repository\EntityRepository; use RZ\Roadiz\CoreBundle\Routing\NodeRouter; -use RZ\Roadiz\CoreBundle\Node\Exception\SameNodeUrlException; use Symfony\Cmf\Component\Routing\RouteObjectInterface; use Symfony\Component\Cache\ResettableInterface; use Symfony\Component\HttpFoundation\Response; @@ -26,37 +24,16 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; -class NodeMover +final readonly class NodeMover { - protected ManagerRegistry $managerRegistry; - protected UrlGeneratorInterface $urlGenerator; - protected HandlerFactoryInterface $handlerFactory; - protected EventDispatcherInterface $dispatcher; - protected CacheItemPoolInterface $cacheAdapter; - protected LoggerInterface $logger; - - /** - * @param ManagerRegistry $managerRegistry - * @param UrlGeneratorInterface $urlGenerator - * @param HandlerFactoryInterface $handlerFactory - * @param EventDispatcherInterface $dispatcher - * @param CacheItemPoolInterface $cacheAdapter - * @param LoggerInterface|null $logger - */ public function __construct( - ManagerRegistry $managerRegistry, - UrlGeneratorInterface $urlGenerator, - HandlerFactoryInterface $handlerFactory, - EventDispatcherInterface $dispatcher, - CacheItemPoolInterface $cacheAdapter, - ?LoggerInterface $logger = null + private ManagerRegistry $managerRegistry, + private UrlGeneratorInterface $urlGenerator, + private HandlerFactoryInterface $handlerFactory, + private EventDispatcherInterface $dispatcher, + private CacheItemPoolInterface $cacheAdapter, + private LoggerInterface $logger, ) { - $this->urlGenerator = $urlGenerator; - $this->logger = $logger ?? new NullLogger(); - $this->dispatcher = $dispatcher; - $this->handlerFactory = $handlerFactory; - $this->managerRegistry = $managerRegistry; - $this->cacheAdapter = $cacheAdapter; } private function getManager(): ObjectManager @@ -65,28 +42,21 @@ private function getManager(): ObjectManager if (null === $manager) { throw new \RuntimeException('No manager was found during transtyping.'); } + return $manager; } /** * Warning: this method DOES NOT flush entity manager. - * - * @param Node $node - * @param Node|null $parentNode - * @param float $position - * @param bool $force - * @param bool $cleanPosition - * - * @return Node */ public function move( Node $node, ?Node $parentNode, float $position, bool $force = false, - bool $cleanPosition = true + bool $cleanPosition = true, ): Node { - if ($node->isLocked() && $force === false) { + if ($node->isLocked() && false === $force) { throw new BadRequestHttpException('Locked node cannot be moved.'); } @@ -111,11 +81,6 @@ public function move( return $node; } - /** - * @param Node $node - * - * @return array - */ public function getNodeSourcesUrls(Node $node): array { $paths = []; @@ -133,18 +98,14 @@ public function getNodeSourcesUrls(Node $node): array } $paths[$nodeSource->getTranslation()->getLocale()] = $url; $this->logger->debug( - 'Redirect ' . $nodeSource->getId() . ' ' . $nodeSource->getTranslation()->getLocale() . ': ' . $url + 'Redirect '.$nodeSource->getId().' '.$nodeSource->getTranslation()->getLocale().': '.$url ); $lastUrl = $url; } + return $paths; } - /** - * @param Node $node - * @param array $previousPaths - * @param bool $permanently - */ public function redirectAll(Node $node, array $previousPaths, bool $permanently = true): void { if (count($previousPaths) > 0) { @@ -163,17 +124,12 @@ public function redirectAll(Node $node, array $previousPaths, bool $permanently /** * Warning: this method DOES NOT flush entity manager. - * - * @param NodesSources $nodeSource - * @param string $previousPath - * @param bool $permanently - * - * @return NodesSources */ protected function redirect(NodesSources $nodeSource, string $previousPath, bool $permanently = true): NodesSources { - if (empty($previousPath) || $previousPath === '/') { - $this->logger->warning('Cannot redirect empty or root path: ' . $nodeSource->getTitle()); + if (empty($previousPath) || '/' === $previousPath) { + $this->logger->warning('Cannot redirect empty or root path: '.$nodeSource->getTitle()); + return $nodeSource; } @@ -181,7 +137,7 @@ protected function redirect(NodesSources $nodeSource, string $previousPath, bool RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, [ RouteObjectInterface::ROUTE_OBJECT => $nodeSource, - NodeRouter::NO_CACHE_PARAMETER => true // do not use nodeSourceUrl cache provider + NodeRouter::NO_CACHE_PARAMETER => true, // do not use nodeSourceUrl cache provider ] ); diff --git a/src/Node/NodeNameChecker.php b/src/Node/NodeNameChecker.php index b9b54d77..2a535799 100644 --- a/src/Node/NodeNameChecker.php +++ b/src/Node/NodeNameChecker.php @@ -12,44 +12,41 @@ use RZ\Roadiz\CoreBundle\Repository\UrlAliasRepository; use RZ\Roadiz\Utils\StringHandler; -class NodeNameChecker implements NodeNamePolicyInterface +final readonly class NodeNameChecker implements NodeNamePolicyInterface { public const MAX_LENGTH = 250; - protected bool $useTypedSuffix; - private ManagerRegistry $managerRegistry; - /** - * @param ManagerRegistry $managerRegistry - * @param bool $useTypedSuffix - */ - public function __construct(ManagerRegistry $managerRegistry, bool $useTypedSuffix = false) - { - $this->useTypedSuffix = $useTypedSuffix; - $this->managerRegistry = $managerRegistry; + public function __construct( + private ManagerRegistry $managerRegistry, + private bool $useTypedSuffix = false, + ) { } public function getCanonicalNodeName(NodesSources $nodeSource): string { $nodeTypeSuffix = StringHandler::slugify($nodeSource->getNodeTypeName()); - if ($nodeSource->getTitle() !== '') { + if ('' !== $nodeSource->getTitle()) { $title = StringHandler::slugify($nodeSource->getTitle()); if ($nodeSource->isReachable() || !$this->useTypedSuffix) { // truncate title to 250 chars if needed if (\mb_strlen($title) > self::MAX_LENGTH) { $title = \mb_substr($title, 0, self::MAX_LENGTH); } + return $title; } // truncate title if title + suffix + 1 exceed 250 chars if ((\mb_strlen($title) + \mb_strlen($nodeTypeSuffix) + 1) > self::MAX_LENGTH) { $title = \mb_substr($title, 0, self::MAX_LENGTH - (\mb_strlen($nodeTypeSuffix) + 1)); } + return sprintf( '%s-%s', $title, $nodeTypeSuffix, ); } + return sprintf( '%s-%s', $nodeTypeSuffix, @@ -102,13 +99,12 @@ public function getDatestampedNodeName(NodesSources $nodeSource): string /** * Test if current node name is suffixed with a 13 chars Unique ID (uniqid()). * - * @param string $canonicalNodeName Node name without uniqid after. - * @param string $nodeName Node name to test - * @return bool + * @param string $canonicalNodeName node name without uniqid after + * @param string $nodeName Node name to test */ public function isNodeNameWithUniqId(string $canonicalNodeName, string $nodeName): bool { - $pattern = '#^' . preg_quote($canonicalNodeName) . '\-[0-9a-z]{13}$#'; + $pattern = '#^'.preg_quote($canonicalNodeName).'\-[0-9a-z]{13}$#'; $returnState = preg_match_all($pattern, $nodeName); if (1 === $returnState) { @@ -118,25 +114,18 @@ public function isNodeNameWithUniqId(string $canonicalNodeName, string $nodeName return false; } - /** - * @param string $nodeName - * - * @return bool - */ public function isNodeNameValid(string $nodeName): bool { - if (preg_match('#^[a-zA-Z0-9\-]+$#', $nodeName) === 1) { + if (1 === preg_match('#^[a-zA-Z0-9\-]+$#', $nodeName)) { return true; } + return false; } /** * Test if node’s name is already used as a name or an url-alias. * - * @param string $nodeName - * - * @return bool * @throws \Doctrine\ORM\NoResultException * @throws \Doctrine\ORM\NonUniqueResultException */ @@ -151,11 +140,12 @@ public function isNodeNameAlreadyUsed(string $nodeName): bool ->setDisplayingNotPublishedNodes(true); if ( - false === $urlAliasRepo->exists($nodeName) && - false === $nodeRepo->exists($nodeName) + false === $urlAliasRepo->exists($nodeName) + && false === $nodeRepo->exists($nodeName) ) { return false; } + return true; } } diff --git a/src/Node/NodeNamePolicyFactory.php b/src/Node/NodeNamePolicyFactory.php index 2eefaa2a..96d13903 100644 --- a/src/Node/NodeNamePolicyFactory.php +++ b/src/Node/NodeNamePolicyFactory.php @@ -6,11 +6,11 @@ use Doctrine\Persistence\ManagerRegistry; -final class NodeNamePolicyFactory +final readonly class NodeNamePolicyFactory { public function __construct( - private readonly ManagerRegistry $registry, - private readonly bool $useTypedNodeNames + private ManagerRegistry $registry, + private bool $useTypedNodeNames, ) { } diff --git a/src/Node/NodeNamePolicyInterface.php b/src/Node/NodeNamePolicyInterface.php index 14a5572d..4c85ab4d 100644 --- a/src/Node/NodeNamePolicyInterface.php +++ b/src/Node/NodeNamePolicyInterface.php @@ -9,20 +9,17 @@ interface NodeNamePolicyInterface { /** - * @param NodesSources $nodeSource - * @return string Return a canonical node name built against a NS title and node-type. + * @return string return a canonical node name built against a NS title and node-type */ public function getCanonicalNodeName(NodesSources $nodeSource): string; /** - * @param NodesSources $nodeSource - * @return string Return a canonical node' name built against a NS title, node-type and a unique suffix. + * @return string return a canonical node' name built against a NS title, node-type and a unique suffix */ public function getSafeNodeName(NodesSources $nodeSource): string; /** - * @param NodesSources $nodeSource - * @return string Return a canonical node' name built against a NS title, node-type and a date suffix. + * @return string return a canonical node' name built against a NS title, node-type and a date suffix */ public function getDatestampedNodeName(NodesSources $nodeSource): string; diff --git a/src/Node/NodeOffspringResolverInterface.php b/src/Node/NodeOffspringResolverInterface.php index 138c8958..b7556630 100644 --- a/src/Node/NodeOffspringResolverInterface.php +++ b/src/Node/NodeOffspringResolverInterface.php @@ -4,13 +4,12 @@ namespace RZ\Roadiz\CoreBundle\Node; -use RZ\Roadiz\CoreBundle\Entity\Node; +use RZ\Roadiz\Core\AbstractEntities\NodeInterface; interface NodeOffspringResolverInterface { /** - * @param Node $ancestor * @return array */ - public function getAllOffspringIds(Node $ancestor): array; + public function getAllOffspringIds(NodeInterface $ancestor): array; } diff --git a/src/Node/NodeTranslator.php b/src/Node/NodeTranslator.php index be1d63ca..47358786 100644 --- a/src/Node/NodeTranslator.php +++ b/src/Node/NodeTranslator.php @@ -15,7 +15,7 @@ final class NodeTranslator { public function __construct( private readonly ManagerRegistry $managerRegistry, - private readonly EventDispatcherInterface $dispatcher + private readonly EventDispatcherInterface $dispatcher, ) { } @@ -23,7 +23,7 @@ public function translateNode( ?Translation $sourceTranslation, Translation $destinationTranslation, Node $node, - bool $translateChildren = false + bool $translateChildren = false, ): Node { $this->translateSingleNode($sourceTranslation, $destinationTranslation, $node); @@ -40,7 +40,7 @@ public function translateNode( private function translateSingleNode( ?Translation $sourceTranslation, Translation $destinationTranslation, - Node $node + Node $node, ): NodesSources { /** @var NodesSources|null $existing */ $existing = $this->managerRegistry diff --git a/src/Node/NodeTranstyper.php b/src/Node/NodeTranstyper.php index 2109757e..16663f74 100644 --- a/src/Node/NodeTranstyper.php +++ b/src/Node/NodeTranstyper.php @@ -26,13 +26,9 @@ final class NodeTranstyper private ManagerRegistry $managerRegistry; private LoggerInterface $logger; - /** - * @param ManagerRegistry $managerRegistry - * @param LoggerInterface|null $logger - */ public function __construct( ManagerRegistry $managerRegistry, - ?LoggerInterface $logger = null + ?LoggerInterface $logger = null, ) { $this->logger = $logger ?? new NullLogger(); $this->managerRegistry = $managerRegistry; @@ -44,24 +40,23 @@ private function getManager(): ObjectManager if (null === $manager) { throw new \RuntimeException('No manager was found during trans-typing.'); } + return $manager; } /** - * @param NodeTypeFieldInterface $oldField - * @param NodeTypeInterface $destinationNodeType - * * @return NodeTypeField|null */ private function getMatchingNodeTypeField( NodeTypeFieldInterface $oldField, - NodeTypeInterface $destinationNodeType + NodeTypeInterface $destinationNodeType, ): ?NodeTypeFieldInterface { $criteria = Criteria::create(); $criteria->andWhere(Criteria::expr()->eq('name', $oldField->getName())) ->andWhere(Criteria::expr()->eq('type', $oldField->getType())) ->setMaxResults(1); $field = $destinationNodeType->getFields()->matching($criteria)->first(); + return $field ? $field : null; } @@ -69,13 +64,8 @@ private function getMatchingNodeTypeField( * Warning, this method DOES NOT flush entityManager at the end. * * Trans-typing SHOULD be executed in one single transaction - * @see https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/transactions-and-concurrency.html * - * @param Node $node - * @param NodeTypeInterface $destinationNodeType - * @param bool $mock - * - * @return Node + * @see https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/transactions-and-concurrency.html */ public function transtype(Node $node, NodeTypeInterface $destinationNodeType, bool $mock = true): Node { @@ -118,6 +108,7 @@ public function transtype(Node $node, NodeTypeInterface $destinationNodeType, bo foreach ($existingSources as $existingSource) { $existingRedirections[$existingSource->getTranslation()->getLocale()] = array_map(function (Redirection $redirection) { $this->managerRegistry->getManager()->detach($redirection); + return $redirection; }, $existingSource->getRedirections()->toArray()); } @@ -135,17 +126,14 @@ public function transtype(Node $node, NodeTypeInterface $destinationNodeType, bo $fieldAssociations, $existingRedirections ); - $this->logger->debug('Transtyped: ' . $existingSource->getTranslation()->getLocale()); + $this->logger->debug('Transtyped: '.$existingSource->getTranslation()->getLocale()); } $node->setNodeType($destinationNodeType); + return $node; } - /** - * @param Node $node - * @param array $sources - */ protected function removeOldSources(Node $node, array &$sources): void { /** @var NodesSources $existingSource */ @@ -162,13 +150,7 @@ protected function removeOldSources(Node $node, array &$sources): void /** * Warning, this method DO NOT flush entityManager at the end. * - * @param Node $node - * @param NodesSources $existingSource - * @param TranslationInterface $translation * @param class-string $sourceClass - * @param array $fieldAssociations - * @param array $existingRedirections - * @return NodesSources */ protected function doTranstypeSingleSource( Node $node, @@ -176,7 +158,7 @@ protected function doTranstypeSingleSource( TranslationInterface $translation, string $sourceClass, array &$fieldAssociations, - array &$existingRedirections + array &$existingRedirections, ): NodesSources { /** @var NodesSources $source */ $source = new $sourceClass($node, $translation); @@ -196,7 +178,7 @@ protected function doTranstypeSingleSource( $setter = $oldField->getSetterName(); $getter = $oldField->getGetterName(); $source->$setter($existingSource->$getter()); - } elseif ($oldField->getType() === AbstractField::DOCUMENTS_T) { + } elseif (AbstractField::DOCUMENTS_T === $oldField->getType()) { /* * Copy documents. */ @@ -243,14 +225,13 @@ protected function doTranstypeSingleSource( /** * Warning, this method flushes entityManager. * - * @param NodeTypeInterface $nodeType - * @throws \InvalidArgumentException If mock fails due to Source class not existing. + * @throws \InvalidArgumentException if mock fails due to Source class not existing */ protected function mockTranstype(NodeTypeInterface $nodeType): void { $sourceClass = $nodeType->getSourceEntityFullQualifiedClassName(); if (!class_exists($sourceClass)) { - throw new \InvalidArgumentException($sourceClass . ' node-source class does not exist.'); + throw new \InvalidArgumentException($sourceClass.' node-source class does not exist.'); } $uniqueId = uniqid(); /* @@ -260,18 +241,18 @@ protected function mockTranstype(NodeTypeInterface $nodeType): void */ $node = new Node(); $node->setNodeType($nodeType); - $node->setNodeName('testing_before_transtype' . $uniqueId); + $node->setNodeName('testing_before_transtype'.$uniqueId); $this->getManager()->persist($node); $translation = new Translation(); $translation->setAvailable(true); $translation->setLocale(\mb_substr($uniqueId, 0, 10)); - $translation->setName('test' . $uniqueId); + $translation->setName('test'.$uniqueId); $this->getManager()->persist($translation); /** @var NodesSources $testSource */ $testSource = new $sourceClass($node, $translation); - $testSource->setTitle('testing_before_transtype' . $uniqueId); + $testSource->setTitle('testing_before_transtype'.$uniqueId); $this->getManager()->persist($testSource); $this->getManager()->flush(); diff --git a/src/Node/UniqueNodeGenerator.php b/src/Node/UniqueNodeGenerator.php index 718cea75..486ce3be 100644 --- a/src/Node/UniqueNodeGenerator.php +++ b/src/Node/UniqueNodeGenerator.php @@ -4,7 +4,6 @@ namespace RZ\Roadiz\CoreBundle\Node; -use DateTime; use Doctrine\ORM\OptimisticLockException; use Doctrine\ORM\ORMException; use Doctrine\Persistence\ManagerRegistry; @@ -15,40 +14,34 @@ use RZ\Roadiz\CoreBundle\Entity\Tag; use RZ\Roadiz\CoreBundle\Entity\Translation; use RZ\Roadiz\CoreBundle\Security\Authorization\Voter\NodeVoter; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Security\Core\Exception\AccessDeniedException; -use Symfony\Bundle\SecurityBundle\Security; -class UniqueNodeGenerator +final readonly class UniqueNodeGenerator { public function __construct( - protected ManagerRegistry $managerRegistry, - protected NodeNamePolicyInterface $nodeNamePolicy, - protected Security $security, + private ManagerRegistry $managerRegistry, + private NodeNamePolicyInterface $nodeNamePolicy, + private Security $security, ) { } /** * Generate a node with a unique name. * - * This method flush entity-manager. - * - * @param NodeType $nodeType - * @param TranslationInterface $translation - * @param Node|null $parent - * @param Tag|null $tag - * @param bool $pushToTop - * @return NodesSources + * This method flush entity-manager by default. */ public function generate( NodeType $nodeType, TranslationInterface $translation, - Node $parent = null, - Tag $tag = null, - bool $pushToTop = false + ?Node $parent = null, + ?Tag $tag = null, + bool $pushToTop = false, + bool $flush = true, ): NodesSources { - $name = $nodeType->getDisplayName() . " " . uniqid(); + $name = $nodeType->getDisplayName().' '.uniqid(); $node = new Node(); $node->setNodeType($nodeType); $node->setTtl($nodeType->getDefaultTtl()); @@ -65,19 +58,21 @@ public function generate( $node->setPosition(0.5); } - /** @var class-string $sourceClass */ # phpstan hint - $sourceClass = NodeType::getGeneratedEntitiesNamespace() . "\\" . $nodeType->getSourceEntityClassName(); + /** @var class-string $sourceClass */ // phpstan hint + $sourceClass = NodeType::getGeneratedEntitiesNamespace().'\\'.$nodeType->getSourceEntityClassName(); $source = new $sourceClass($node, $translation); $source->setTitle($name); - $source->setPublishedAt(new DateTime()); + $source->setPublishedAt(new \DateTime()); $node->setNodeName($this->nodeNamePolicy->getCanonicalNodeName($source)); $manager = $this->managerRegistry->getManagerForClass(Node::class); if (null !== $manager) { $manager->persist($node); $manager->persist($source); - $manager->flush(); + if ($flush) { + $manager->flush(); + } } return $source; @@ -86,9 +81,6 @@ public function generate( /** * Try to generate a unique node from request variables. * - * @param Request $request - * - * @return NodesSources * @throws ORMException * @throws OptimisticLockException */ @@ -96,7 +88,7 @@ public function generateFromRequest(Request $request): NodesSources { $pushToTop = false; - if ($request->get('pushTop') == 1) { + if (1 == $request->get('pushTop')) { $pushToTop = true; } @@ -113,7 +105,7 @@ public function generateFromRequest(Request $request): NodesSources ->getRepository(Node::class) ->find((int) $request->get('parentNodeId')); if (null === $parent || !$this->security->isGranted(NodeVoter::CREATE, $parent)) { - throw new BadRequestHttpException("Parent node does not exist."); + throw new BadRequestHttpException('Parent node does not exist.'); } } else { if (!$this->security->isGranted(NodeVoter::CREATE_AT_ROOT)) { @@ -124,7 +116,7 @@ public function generateFromRequest(Request $request): NodesSources $nodeTypeId = $request->get('nodeTypeId'); if (!is_numeric($nodeTypeId) || $nodeTypeId < 1) { - throw new BadRequestHttpException("No node-type ID has been given."); + throw new BadRequestHttpException('No node-type ID has been given.'); } /** @var NodeType|null $nodeType */ @@ -133,7 +125,7 @@ public function generateFromRequest(Request $request): NodesSources ->find((int) $nodeTypeId); if (null === $nodeType) { - throw new BadRequestHttpException("Node-type does not exist."); + throw new BadRequestHttpException('Node-type does not exist.'); } if ($request->get('translationId') > 0) { diff --git a/src/Node/UniversalDataDuplicator.php b/src/Node/UniversalDataDuplicator.php index 0f8c9803..b9f16216 100644 --- a/src/Node/UniversalDataDuplicator.php +++ b/src/Node/UniversalDataDuplicator.php @@ -14,9 +14,9 @@ use RZ\Roadiz\CoreBundle\Repository\NodesSourcesRepository; use RZ\Roadiz\CoreBundle\Repository\TranslationRepository; -final class UniversalDataDuplicator +final readonly class UniversalDataDuplicator { - public function __construct(private readonly ManagerRegistry $managerRegistry) + public function __construct(private ManagerRegistry $managerRegistry) { } @@ -25,8 +25,6 @@ public function __construct(private readonly ManagerRegistry $managerRegistry) * * **Be careful, this method does not flush.** * - * @param NodesSources $source - * @return bool * @throws \Doctrine\ORM\NoResultException * @throws \Doctrine\ORM\NonUniqueResultException * @throws \Doctrine\ORM\ORMException @@ -72,6 +70,7 @@ public function duplicateUniversalContents(NodesSources $source): bool } } } + return true; } } @@ -80,9 +79,6 @@ public function duplicateUniversalContents(NodesSources $source): bool } /** - * @param NodesSources $source - * - * @return bool * @throws \Doctrine\ORM\NoResultException * @throws \Doctrine\ORM\NonUniqueResultException */ @@ -102,13 +98,13 @@ private function hasDefaultTranslation(NodesSources $source): bool 'translation' => $defaultTranslation, ]); - return $sourceCount === 1; + return 1 === $sourceCount; } protected function duplicateNonVirtualField( NodesSources $universalSource, NodesSources $destSource, - NodeTypeFieldInterface $field + NodeTypeFieldInterface $field, ): void { $getter = $field->getGetterName(); $setter = $field->getSetterName(); @@ -119,7 +115,7 @@ protected function duplicateNonVirtualField( protected function duplicateDocumentsField( NodesSources $universalSource, NodesSources $destSource, - NodeTypeFieldInterface $field + NodeTypeFieldInterface $field, ): void { $newDocuments = $this->managerRegistry ->getRepository(NodesSourcesDocuments::class) @@ -147,7 +143,7 @@ protected function duplicateDocumentsField( foreach ($newDocuments as $newDocument) { $nsDoc = new NodesSourcesDocuments($destSource, $newDocument->getDocument(), $field); $nsDoc->setPosition($position); - $position++; + ++$position; $manager->persist($nsDoc); } diff --git a/src/NodeType/ApiResourceGenerator.php b/src/NodeType/ApiResourceGenerator.php index 6506c450..8a24d0ba 100644 --- a/src/NodeType/ApiResourceGenerator.php +++ b/src/NodeType/ApiResourceGenerator.php @@ -7,7 +7,6 @@ use ApiPlatform\Metadata\Get; use ApiPlatform\Metadata\GetCollection; use Doctrine\Inflector\InflectorFactory; -use LogicException; use Psr\Log\LoggerInterface; use RZ\Roadiz\Contracts\NodeType\NodeTypeInterface; use RZ\Roadiz\CoreBundle\Api\Controller\GetWebResponseByPathController; @@ -16,32 +15,28 @@ use Symfony\Component\String\UnicodeString; use Symfony\Component\Yaml\Yaml; -final class ApiResourceGenerator +final readonly class ApiResourceGenerator { /** - * @param ApiResourceOperationNameGenerator $apiResourceOperationNameGenerator - * @param string $apiResourcesDir - * @param LoggerInterface $logger * @param class-string $webResponseClass */ public function __construct( - private readonly ApiResourceOperationNameGenerator $apiResourceOperationNameGenerator, - private readonly string $apiResourcesDir, - private readonly LoggerInterface $logger, - private readonly string $webResponseClass + private ApiResourceOperationNameGenerator $apiResourceOperationNameGenerator, + private string $apiResourcesDir, + private LoggerInterface $logger, + private string $webResponseClass, ) { } /** - * @param NodeTypeInterface $nodeType - * @return string|null Generated resource file path or null if nothing done. + * @return string|null generated resource file path or null if nothing done */ public function generate(NodeTypeInterface $nodeType): ?string { $filesystem = new Filesystem(); if (!$filesystem->exists($this->apiResourcesDir)) { - throw new LogicException($this->apiResourcesDir . ' folder does not exist.'); + throw new \LogicException($this->apiResourcesDir.' folder does not exist.'); } $resourcePath = $this->getResourcePath($nodeType); @@ -54,8 +49,8 @@ public function generate(NodeTypeInterface $nodeType): ?string 'resources' => [ $this->webResponseClass => [ 'operations' => [], - ] - ] + ], + ], ], 7) ); } @@ -78,6 +73,7 @@ public function generate(NodeTypeInterface $nodeType): ?string 'file' => $resourcePath, ]); \clearstatcache(true, $resourcePath); + return $resourcePath; } else { return null; @@ -89,7 +85,7 @@ public function remove(NodeTypeInterface $nodeType): void $filesystem = new Filesystem(); if (!$filesystem->exists($this->apiResourcesDir)) { - throw new LogicException($this->apiResourcesDir . ' folder does not exist.'); + throw new \LogicException($this->apiResourcesDir.' folder does not exist.'); } $resourcePath = $this->getResourcePath($nodeType); @@ -118,7 +114,7 @@ public function remove(NodeTypeInterface $nodeType): void public function getResourcePath(NodeTypeInterface $nodeType): string { - return $this->apiResourcesDir . '/' . (new UnicodeString($nodeType->getName())) + return $this->apiResourcesDir.'/'.(new UnicodeString($nodeType->getName())) ->lower() ->prepend('ns') ->append('.yml') @@ -127,7 +123,7 @@ public function getResourcePath(NodeTypeInterface $nodeType): string protected function getWebResponseResourcePath(): string { - return $this->apiResourcesDir . '/web_response.yml'; + return $this->apiResourcesDir.'/web_response.yml'; } protected function getResourceName(string $nodeTypeName): string @@ -141,7 +137,8 @@ protected function getResourceName(string $nodeTypeName): string protected function getResourceUriPrefix(NodeTypeInterface $nodeType): string { $pluralNodeTypeName = InflectorFactory::create()->build()->pluralize($nodeType->getName()); - return '/' . $this->getResourceName($pluralNodeTypeName); + + return '/'.$this->getResourceName($pluralNodeTypeName); } protected function getApiResourceDefinition(NodeTypeInterface $nodeType): array @@ -157,10 +154,10 @@ protected function getApiResourceDefinition(NodeTypeInterface $nodeType): array 'types' => [$nodeType->getName()], 'operations' => [ ...$this->getCollectionOperations($nodeType), - ...$this->getItemOperations($nodeType) + ...$this->getItemOperations($nodeType), ], - ] - ] + ], + ], ]; } @@ -176,7 +173,7 @@ protected function addWebResponseResourceOperation(NodeTypeInterface $nodeType, 'resources' => [ $this->webResponseClass => [ 'operations' => [], - ] + ], ], ]; } @@ -213,13 +210,13 @@ protected function addWebResponseResourceOperation(NodeTypeInterface $nodeType, 'web_response', 'walker', 'children', - ] - ] + ], + ], ], 'openapiContext' => [ 'tags' => ['WebResponse'], - 'summary' => 'Get a ' . $nodeType->getName() . ' by its path wrapped in a WebResponse object', - 'description' => 'Get a ' . $nodeType->getName() . ' by its path wrapped in a WebResponse', + 'summary' => 'Get a '.$nodeType->getName().' by its path wrapped in a WebResponse object', + 'description' => 'Get a '.$nodeType->getName().' by its path wrapped in a WebResponse', 'parameters' => [ [ 'type' => 'string', @@ -230,12 +227,13 @@ protected function addWebResponseResourceOperation(NodeTypeInterface $nodeType, 'schema' => [ 'type' => 'string', ], - ] - ] - ] + ], + ], + ], ]; $webResponseResource['resources'][$this->webResponseClass]['operations'] = $operations; + return $webResponseResource; } @@ -261,6 +259,7 @@ protected function removeWebResponseResourceOperation(NodeTypeInterface $nodeTyp unset($operations[$getByPathOperationName]); $webResponseResource['resources'][$this->webResponseClass]['operations'] = array_filter($operations); + return $webResponseResource; } @@ -269,15 +268,15 @@ protected function getCollectionOperations(NodeTypeInterface $nodeType): array $operations = []; if ($nodeType->isReachable()) { $groups = [ - "nodes_sources_base", - "nodes_sources_default", - "urls", - "tag_base", - "translation_base", - "document_display", - "document_thumbnails", - "document_display_sources", - ...$this->getGroupedFieldsSerializationGroups($nodeType) + 'nodes_sources_base', + 'nodes_sources_default', + 'urls', + 'tag_base', + 'translation_base', + 'document_display', + 'document_thumbnails', + 'document_display_sources', + ...$this->getGroupedFieldsSerializationGroups($nodeType), ]; $collectionOperationName = $this->apiResourceOperationNameGenerator->generate( @@ -293,9 +292,9 @@ protected function getCollectionOperations(NodeTypeInterface $nodeType): array 'shortName' => $nodeType->getName(), 'normalizationContext' => [ 'enable_max_depth' => true, - 'groups' => array_values(array_filter(array_unique($groups))) + 'groups' => array_values(array_filter(array_unique($groups))), ], - ] + ], ] ); } @@ -311,7 +310,7 @@ protected function getCollectionOperations(NodeTypeInterface $nodeType): array 'method' => 'GET', 'class' => GetCollection::class, 'shortName' => $nodeType->getName(), - 'uriTemplate' => $this->getResourceUriPrefix($nodeType) . '/archives', + 'uriTemplate' => $this->getResourceUriPrefix($nodeType).'/archives', 'extraProperties' => [ 'archive_enabled' => true, ], @@ -321,25 +320,26 @@ protected function getCollectionOperations(NodeTypeInterface $nodeType): array $nodeType->getName() ), ], - ] + ], ] ); } + return $operations; } protected function getItemOperationSerializationGroups(NodeTypeInterface $nodeType): array { return [ - "nodes_sources", - "node_listing", - "urls", - "tag_base", - "translation_base", - "document_display", - "document_thumbnails", - "document_display_sources", - ...$this->getGroupedFieldsSerializationGroups($nodeType) + 'nodes_sources', + 'node_listing', + 'urls', + 'tag_base', + 'translation_base', + 'document_display', + 'document_thumbnails', + 'document_display_sources', + ...$this->getGroupedFieldsSerializationGroups($nodeType), ]; } @@ -350,15 +350,16 @@ protected function getItemOperations(NodeTypeInterface $nodeType): array $nodeType->getSourceEntityFullQualifiedClassName(), 'get' ); + return [ $itemOperationName => [ 'method' => 'GET', 'class' => Get::class, 'shortName' => $nodeType->getName(), 'normalizationContext' => [ - 'groups' => array_values(array_filter(array_unique($groups))) + 'groups' => array_values(array_filter(array_unique($groups))), ], - ] + ], ]; } @@ -375,6 +376,7 @@ protected function getGroupedFieldsSerializationGroups(NodeTypeInterface $nodeTy ; } } + return $groups; } } diff --git a/src/NodeType/DefaultValuesResolver.php b/src/NodeType/DefaultValuesResolver.php index 28739dd7..ee933302 100644 --- a/src/NodeType/DefaultValuesResolver.php +++ b/src/NodeType/DefaultValuesResolver.php @@ -10,11 +10,11 @@ use RZ\Roadiz\CoreBundle\Entity\NodeTypeField; use RZ\Roadiz\EntityGenerator\Field\DefaultValuesResolverInterface; -final class DefaultValuesResolver implements DefaultValuesResolverInterface +final readonly class DefaultValuesResolver implements DefaultValuesResolverInterface { public function __construct( - private readonly ManagerRegistry $managerRegistry, - private readonly string $inheritanceType + private ManagerRegistry $managerRegistry, + private string $inheritanceType, ) { } @@ -24,7 +24,7 @@ public function getDefaultValuesAmongAllFields(NodeTypeFieldInterface $field): a * With joined inheritance, we can use current field default values because * SQL field won't be shared between all node types. */ - if ($this->inheritanceType === Configuration::INHERITANCE_TYPE_JOINED) { + if (Configuration::INHERITANCE_TYPE_JOINED === $this->inheritanceType) { return array_map('trim', explode(',', $field->getDefaultValues() ?? '')); } else { /* @@ -39,6 +39,7 @@ public function getDefaultValuesAmongAllFields(NodeTypeFieldInterface $field): a foreach ($nodeTypeFields as $nodeTypeField) { $defaultValues = array_merge($defaultValues, array_map('trim', explode(',', $nodeTypeField->getDefaultValues() ?? ''))); } + return $defaultValues; } } diff --git a/src/NodeType/NodeTypeResolver.php b/src/NodeType/NodeTypeResolver.php index 687fa7b9..702a1093 100644 --- a/src/NodeType/NodeTypeResolver.php +++ b/src/NodeType/NodeTypeResolver.php @@ -9,30 +9,30 @@ use RZ\Roadiz\Contracts\NodeType\NodeTypeFieldInterface; use RZ\Roadiz\Contracts\NodeType\NodeTypeInterface; -final class NodeTypeResolver +final readonly class NodeTypeResolver { - public function __construct(private readonly CacheItemPoolInterface $cacheAdapter) + public function __construct(private CacheItemPoolInterface $cacheAdapter) { } /** - * @param NodeTypeFieldInterface $field * @return array */ protected function getNodeTypeList(NodeTypeFieldInterface $field): array { $nodeTypesNames = array_map('trim', explode(',', $field->getDefaultValues() ?? '')); + return array_filter($nodeTypesNames); } /** - * @param NodeTypeInterface $nodeType * @return array + * * @throws InvalidArgumentException */ public function getChildrenNodeTypeList(NodeTypeInterface $nodeType): array { - $cacheKey = 'children_' . $nodeType->getName(); + $cacheKey = 'children_'.$nodeType->getName(); $cacheItem = $this->cacheAdapter->getItem($cacheKey); if ($cacheItem->isHit()) { diff --git a/src/Preview/EventSubscriber/PreviewBarSubscriber.php b/src/Preview/EventSubscriber/PreviewBarSubscriber.php index a3ab4354..725c1a01 100644 --- a/src/Preview/EventSubscriber/PreviewBarSubscriber.php +++ b/src/Preview/EventSubscriber/PreviewBarSubscriber.php @@ -10,35 +10,27 @@ use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; -final class PreviewBarSubscriber implements EventSubscriberInterface +final readonly class PreviewBarSubscriber implements EventSubscriberInterface { - public function __construct(private readonly PreviewResolverInterface $previewResolver) + public function __construct(private PreviewResolverInterface $previewResolver) { } - /** - * @return array - */ public static function getSubscribedEvents(): array { return [ - KernelEvents::RESPONSE => ['onKernelResponse', -128] + KernelEvents::RESPONSE => ['onKernelResponse', -128], ]; } - /** - * @param ResponseEvent $event - * - * @return bool - */ protected function supports(ResponseEvent $event): bool { $response = $event->getResponse(); if ( - $this->previewResolver->isPreview() && - $event->isMainRequest() && - $response->getStatusCode() === Response::HTTP_OK && - str_contains($response->headers->get('Content-Type'), 'text/html') + $this->previewResolver->isPreview() + && $event->isMainRequest() + && Response::HTTP_OK === $response->getStatusCode() + && str_contains($response->headers->get('Content-Type'), 'text/html') ) { return true; } @@ -46,27 +38,24 @@ protected function supports(ResponseEvent $event): bool return false; } - /** - * @param ResponseEvent $event - */ public function onKernelResponse(ResponseEvent $event): void { if ($this->supports($event)) { $response = $event->getResponse(); $content = $response->getContent(); if ( - is_string($content) && - str_contains($content, '') && - str_contains($content, '') + is_string($content) + && str_contains($content, '') + && str_contains($content, '') ) { $content = str_replace( '', - "", + '', $content ); $content = str_replace( '', - "
Preview
", + '
Preview
', $content ); $response->setContent($content); diff --git a/src/Preview/EventSubscriber/PreviewModeSubscriber.php b/src/Preview/EventSubscriber/PreviewModeSubscriber.php index 82540443..b2390efe 100644 --- a/src/Preview/EventSubscriber/PreviewModeSubscriber.php +++ b/src/Preview/EventSubscriber/PreviewModeSubscriber.php @@ -19,13 +19,10 @@ final class PreviewModeSubscriber implements EventSubscriberInterface public function __construct( private readonly PreviewResolverInterface $previewResolver, - private readonly Security $security + private readonly Security $security, ) { } - /** - * @return array - */ public static function getSubscribedEvents(): array { return [ @@ -36,24 +33,18 @@ public static function getSubscribedEvents(): array ]; } - /** - * @return bool - */ protected function supports(): bool { return $this->previewResolver->isPreview(); } - /** - * @param RequestEvent $event - */ public function onKernelRequest(RequestEvent $event): void { $request = $event->getRequest(); if ( - $event->isMainRequest() && - $request->query->has(self::QUERY_PARAM_NAME) && - \in_array( + $event->isMainRequest() + && $request->query->has(self::QUERY_PARAM_NAME) + && \in_array( $request->query->get(self::QUERY_PARAM_NAME, 0), ['true', true, '1', 1, 'on', 'yes', 'y'], true @@ -68,7 +59,6 @@ public function onKernelRequest(RequestEvent $event): void * You MUST check here is user can use preview mode BEFORE going * any further into your app logic. * - * @param ControllerEvent $event * @throws PreviewNotAllowedException */ public function onControllerMatched(ControllerEvent $event): void @@ -82,8 +72,6 @@ public function onControllerMatched(ControllerEvent $event): void /** * Enforce cache disabling. - * - * @param ResponseEvent $event */ public function onResponse(ResponseEvent $event): void { diff --git a/src/Preview/Exception/PreviewNotAllowedException.php b/src/Preview/Exception/PreviewNotAllowedException.php index 07da1c7b..d4b325e4 100644 --- a/src/Preview/Exception/PreviewNotAllowedException.php +++ b/src/Preview/Exception/PreviewNotAllowedException.php @@ -12,7 +12,7 @@ */ class PreviewNotAllowedException extends AccessDeniedHttpException { - public function __construct(string $message = "You are not allowed to use preview mode.") + public function __construct(string $message = 'You are not allowed to use preview mode.') { parent::__construct($message); } diff --git a/src/Preview/PreviewResolverInterface.php b/src/Preview/PreviewResolverInterface.php index 9347ab52..ec133317 100644 --- a/src/Preview/PreviewResolverInterface.php +++ b/src/Preview/PreviewResolverInterface.php @@ -7,5 +7,6 @@ interface PreviewResolverInterface { public function isPreview(): bool; + public function getRequiredRole(): string; } diff --git a/src/Preview/RequestPreviewRevolver.php b/src/Preview/RequestPreviewRevolver.php index 46ff3646..9d952dd7 100644 --- a/src/Preview/RequestPreviewRevolver.php +++ b/src/Preview/RequestPreviewRevolver.php @@ -8,26 +8,22 @@ /** * BC Preview resolver to check Request-time then Kernel boot-time preview param. - * - * @package RZ\Roadiz\CoreBundle\Preview */ -final class RequestPreviewRevolver implements PreviewResolverInterface +final readonly class RequestPreviewRevolver implements PreviewResolverInterface { public function __construct( - private readonly RequestStack $requestStack, - private readonly string $requiredRole + private RequestStack $requestStack, + private string $requiredRole, ) { } - /** - * @return bool - */ public function isPreview(): bool { $request = $this->requestStack->getMainRequest(); if (null === $request) { return false; } + return $request->attributes->getBoolean('preview'); } diff --git a/src/Preview/User/PreviewUser.php b/src/Preview/User/PreviewUser.php index 5d3fc9e1..2f513dd3 100644 --- a/src/Preview/User/PreviewUser.php +++ b/src/Preview/User/PreviewUser.php @@ -6,56 +6,34 @@ use Symfony\Component\Security\Core\User\UserInterface; -class PreviewUser implements UserInterface +final readonly class PreviewUser implements UserInterface { - protected string $username; - protected array $roles = []; - - /** - * @param string $username - * @param array $roles - */ - public function __construct(string $username, array $roles) - { - $this->username = $username; - $this->roles = $roles; + public function __construct( + private string $username, + private array $roles = [], + ) { } - /** - * @inheritDoc - */ public function getRoles(): array { return $this->roles; } - /** - * @inheritDoc - */ public function getPassword(): string { throw new \BadMethodCallException('Preview user does not have a password'); } - /** - * @inheritDoc - */ public function getSalt(): string { throw new \BadMethodCallException('Preview user does not have a password salt'); } - /** - * @inheritDoc - */ public function eraseCredentials(): void { throw new \BadMethodCallException('Preview user cannot erase its credentials'); } - /** - * @inheritDoc - */ public function getUsername(): string { return $this->username; diff --git a/src/Preview/User/PreviewUserProvider.php b/src/Preview/User/PreviewUserProvider.php index 9184f8ef..b5776b35 100644 --- a/src/Preview/User/PreviewUserProvider.php +++ b/src/Preview/User/PreviewUserProvider.php @@ -5,27 +5,26 @@ namespace RZ\Roadiz\CoreBundle\Preview\User; use RZ\Roadiz\CoreBundle\Preview\PreviewResolverInterface; -use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Bundle\SecurityBundle\Security; +use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Core\User\UserInterface; -final class PreviewUserProvider implements PreviewUserProviderInterface +final readonly class PreviewUserProvider implements PreviewUserProviderInterface { public function __construct( - private readonly PreviewResolverInterface $previewResolver, - private readonly Security $security + private PreviewResolverInterface $previewResolver, + private Security $security, ) { } public function createFromSecurity(): UserInterface { if (!$this->security->isGranted($this->previewResolver->getRequiredRole())) { - throw new AccessDeniedException( - 'Cannot create a preview user proxy from a user that is not allowed to preview.' - ); + throw new AccessDeniedException('Cannot create a preview user proxy from a user that is not allowed to preview.'); } + return new PreviewUser($this->security->getUser()->getUserIdentifier(), [ - $this->previewResolver->getRequiredRole() + $this->previewResolver->getRequiredRole(), ]); } } diff --git a/src/Preview/User/PreviewUserProviderInterface.php b/src/Preview/User/PreviewUserProviderInterface.php index 7aff0210..c34d2628 100644 --- a/src/Preview/User/PreviewUserProviderInterface.php +++ b/src/Preview/User/PreviewUserProviderInterface.php @@ -10,7 +10,6 @@ interface PreviewUserProviderInterface { /** - * @return UserInterface * @throws AccessDeniedException If original user is not allowed to preview */ public function createFromSecurity(): UserInterface; diff --git a/src/Realm/RealmResolver.php b/src/Realm/RealmResolver.php index d900db6b..feca0c1f 100644 --- a/src/Realm/RealmResolver.php +++ b/src/Realm/RealmResolver.php @@ -10,16 +10,16 @@ use RZ\Roadiz\CoreBundle\Entity\Realm; use RZ\Roadiz\CoreBundle\Model\RealmInterface; use RZ\Roadiz\CoreBundle\Security\Authorization\Voter\RealmVoter; -use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; use Symfony\Bundle\SecurityBundle\Security; +use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; use Symfony\Component\String\Slugger\AsciiSlugger; -final class RealmResolver implements RealmResolverInterface +final readonly class RealmResolver implements RealmResolverInterface { public function __construct( - private readonly ManagerRegistry $managerRegistry, - private readonly Security $security, - private readonly CacheItemPoolInterface $cache + private ManagerRegistry $managerRegistry, + private Security $security, + private CacheItemPoolInterface $cache, ) { } @@ -28,6 +28,7 @@ public function getRealms(?Node $node): array if (null === $node) { return []; } + return $this->managerRegistry->getRepository(Realm::class)->findByNode($node); } @@ -36,6 +37,7 @@ public function getRealmsWithSerializationGroup(?Node $node): array if (null === $node) { return []; } + return $this->managerRegistry->getRepository(Realm::class)->findByNodeWithSerializationGroup($node); } @@ -47,10 +49,7 @@ public function isGranted(RealmInterface $realm): bool public function denyUnlessGranted(RealmInterface $realm): void { if (!$this->isGranted($realm)) { - throw new UnauthorizedHttpException( - $realm->getChallenge(), - 'WebResponse was denied by Realm authorization, check Www-Authenticate header' - ); + throw new UnauthorizedHttpException($realm->getChallenge(), 'WebResponse was denied by Realm authorization, check Www-Authenticate header'); } } @@ -63,25 +62,27 @@ private function getUserCacheKey(): string public function getGrantedRealms(): array { - $cacheItem = $this->cache->getItem('granted_realms_' . $this->getUserCacheKey()); + $cacheItem = $this->cache->getItem('granted_realms_'.$this->getUserCacheKey()); if (!$cacheItem->isHit()) { $allRealms = $this->managerRegistry->getRepository(Realm::class)->findBy([]); - $cacheItem->set(array_filter($allRealms, fn(RealmInterface $realm) => $this->isGranted($realm))); + $cacheItem->set(array_filter($allRealms, fn (RealmInterface $realm) => $this->isGranted($realm))); $cacheItem->expiresAfter(new \DateInterval('PT1H')); $this->cache->save($cacheItem); } + return $cacheItem->get(); } public function getDeniedRealms(): array { - $cacheItem = $this->cache->getItem('denied_realms_' . $this->getUserCacheKey()); + $cacheItem = $this->cache->getItem('denied_realms_'.$this->getUserCacheKey()); if (!$cacheItem->isHit()) { $allRealms = $this->managerRegistry->getRepository(Realm::class)->findBy([]); - $cacheItem->set(array_filter($allRealms, fn(RealmInterface $realm) => !$this->isGranted($realm))); + $cacheItem->set(array_filter($allRealms, fn (RealmInterface $realm) => !$this->isGranted($realm))); $cacheItem->expiresAfter(new \DateInterval('PT1H')); $this->cache->save($cacheItem); } + return $cacheItem->get(); } @@ -94,6 +95,7 @@ public function hasRealms(): bool $cacheItem->expiresAfter(new \DateInterval('PT2H')); $this->cache->save($cacheItem); } + return $cacheItem->get(); } @@ -106,6 +108,7 @@ public function hasRealmsWithSerializationGroup(): bool $cacheItem->expiresAfter(new \DateInterval('PT2H')); $this->cache->save($cacheItem); } + return $cacheItem->get(); } } diff --git a/src/Realm/RealmResolverInterface.php b/src/Realm/RealmResolverInterface.php index 0124db98..5c5527bd 100644 --- a/src/Realm/RealmResolverInterface.php +++ b/src/Realm/RealmResolverInterface.php @@ -14,36 +14,36 @@ interface RealmResolverInterface * @return bool Does current application has realms? */ public function hasRealms(): bool; + /** * @return bool Does current application has realms with serialization groups? */ public function hasRealmsWithSerializationGroup(): bool; + /** - * @param Node|null $node * @return RealmInterface[] */ public function getRealms(?Node $node): array; + /** - * @param Node|null $node * @return RealmInterface[] */ public function getRealmsWithSerializationGroup(?Node $node): array; + public function isGranted(RealmInterface $realm): bool; /** - * @param RealmInterface $realm - * @return void * @throws UnauthorizedHttpException */ public function denyUnlessGranted(RealmInterface $realm): void; /** - * @return RealmInterface[] Return all realms granted to current user. + * @return RealmInterface[] return all realms granted to current user */ public function getGrantedRealms(): array; /** - * @return RealmInterface[] Return all realms denied from current user. + * @return RealmInterface[] return all realms denied from current user */ public function getDeniedRealms(): array; } diff --git a/src/Repository/AttributeDocumentsRepository.php b/src/Repository/AttributeDocumentsRepository.php index eeeae623..8f5249a4 100644 --- a/src/Repository/AttributeDocumentsRepository.php +++ b/src/Repository/AttributeDocumentsRepository.php @@ -16,15 +16,12 @@ final class AttributeDocumentsRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, AttributeDocuments::class, $dispatcher); } /** - * @param AttributeInterface $attribute - * - * @return int * @throws \Doctrine\ORM\NoResultException * @throws \Doctrine\ORM\NonUniqueResultException */ diff --git a/src/Repository/AttributeGroupRepository.php b/src/Repository/AttributeGroupRepository.php index 45dd1b0c..1b5fa338 100644 --- a/src/Repository/AttributeGroupRepository.php +++ b/src/Repository/AttributeGroupRepository.php @@ -15,7 +15,7 @@ final class AttributeGroupRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, AttributeGroup::class, $dispatcher); } diff --git a/src/Repository/AttributeGroupTranslationRepository.php b/src/Repository/AttributeGroupTranslationRepository.php index 00f6e0b1..84898526 100644 --- a/src/Repository/AttributeGroupTranslationRepository.php +++ b/src/Repository/AttributeGroupTranslationRepository.php @@ -16,7 +16,7 @@ final class AttributeGroupTranslationRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, AttributeGroupTranslation::class, $dispatcher); } @@ -24,6 +24,7 @@ public function __construct( public function findOneByNameAndLocale(string $name, string $locale): ?AttributeGroupTranslationInterface { $qb = $this->createQueryBuilder('agt'); + return $qb->innerJoin('agt.translation', 't') ->andWhere($qb->expr()->eq('t.locale', ':locale')) ->andWhere($qb->expr()->eq('agt.name', ':name')) diff --git a/src/Repository/AttributeRepository.php b/src/Repository/AttributeRepository.php index 111e992f..235a5b23 100644 --- a/src/Repository/AttributeRepository.php +++ b/src/Repository/AttributeRepository.php @@ -15,7 +15,7 @@ final class AttributeRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, Attribute::class, $dispatcher); } diff --git a/src/Repository/AttributeTranslationRepository.php b/src/Repository/AttributeTranslationRepository.php index 0fcb735a..d77825f6 100644 --- a/src/Repository/AttributeTranslationRepository.php +++ b/src/Repository/AttributeTranslationRepository.php @@ -15,7 +15,7 @@ final class AttributeTranslationRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, AttributeTranslation::class, $dispatcher); } diff --git a/src/Repository/AttributeValueRepository.php b/src/Repository/AttributeValueRepository.php index c49f0774..9e784a9a 100644 --- a/src/Repository/AttributeValueRepository.php +++ b/src/Repository/AttributeValueRepository.php @@ -17,19 +17,17 @@ final class AttributeValueRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, AttributeValue::class, $dispatcher); } /** - * @param AttributableInterface $attributable - * @param bool $orderByWeight * @return array */ public function findByAttributable( AttributableInterface $attributable, - bool $orderByWeight = false + bool $orderByWeight = false, ): array { $qb = $this->createQueryBuilder('av'); $qb = $qb->addSelect('avt') @@ -61,17 +59,12 @@ public function findByAttributable( ->getResult(); } - /** - * @param AttributableInterface $attributable - * @param TranslationInterface $translation - * - * @return array - */ public function findByAttributableAndTranslation( AttributableInterface $attributable, - TranslationInterface $translation + TranslationInterface $translation, ): array { $qb = $this->createQueryBuilder('av'); + return $qb->addSelect('avt') ->addSelect('a') ->addSelect('at') @@ -90,7 +83,7 @@ public function findByAttributableAndTranslation( ->addOrderBy('av.position', 'ASC') ->setParameters([ 'attributable' => $attributable, - 'translation' => $translation + 'translation' => $translation, ]) ->setCacheable(true) ->getQuery() diff --git a/src/Repository/AttributeValueTranslationRepository.php b/src/Repository/AttributeValueTranslationRepository.php index 553db03c..f28c87b0 100644 --- a/src/Repository/AttributeValueTranslationRepository.php +++ b/src/Repository/AttributeValueTranslationRepository.php @@ -15,7 +15,7 @@ final class AttributeValueTranslationRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, AttributeValueTranslation::class, $dispatcher); } diff --git a/src/Repository/CustomFormAnswerRepository.php b/src/Repository/CustomFormAnswerRepository.php index 36870df2..a245e703 100644 --- a/src/Repository/CustomFormAnswerRepository.php +++ b/src/Repository/CustomFormAnswerRepository.php @@ -17,7 +17,7 @@ final class CustomFormAnswerRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, CustomFormAnswer::class, $dispatcher); } @@ -25,13 +25,12 @@ public function __construct( protected function getCustomFormSubmittedBeforeQueryBuilder(): QueryBuilder { $qb = $this->createQueryBuilder('cfa'); + return $qb->andWhere($qb->expr()->eq('cfa.customForm', ':customForm')) ->andWhere($qb->expr()->lte('cfa.submittedAt', ':submittedAt')); } /** - * @param CustomForm $customForm - * @param \DateTime $submittedAt * @return Paginator */ public function findByCustomFormSubmittedBefore(CustomForm $customForm, \DateTime $submittedAt): Paginator @@ -39,13 +38,11 @@ public function findByCustomFormSubmittedBefore(CustomForm $customForm, \DateTim $qb = $this->getCustomFormSubmittedBeforeQueryBuilder() ->setParameter(':customForm', $customForm) ->setParameter(':submittedAt', $submittedAt); + return new Paginator($qb->getQuery()); } /** - * @param CustomForm $customForm - * @param \DateTime $submittedAt - * @return int * @throws NoResultException * @throws NonUniqueResultException */ @@ -55,6 +52,7 @@ public function deleteByCustomFormSubmittedBefore(CustomForm $customForm, \DateT ->delete() ->setParameter(':customForm', $customForm) ->setParameter(':submittedAt', $submittedAt); + return (int) $qb->getQuery()->getSingleScalarResult(); } } diff --git a/src/Repository/CustomFormFieldAttributeRepository.php b/src/Repository/CustomFormFieldAttributeRepository.php index f89b32bd..979f8aed 100644 --- a/src/Repository/CustomFormFieldAttributeRepository.php +++ b/src/Repository/CustomFormFieldAttributeRepository.php @@ -15,7 +15,7 @@ final class CustomFormFieldAttributeRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, CustomFormFieldAttribute::class, $dispatcher); } diff --git a/src/Repository/CustomFormFieldRepository.php b/src/Repository/CustomFormFieldRepository.php index 117fe365..64765383 100644 --- a/src/Repository/CustomFormFieldRepository.php +++ b/src/Repository/CustomFormFieldRepository.php @@ -16,7 +16,7 @@ final class CustomFormFieldRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, CustomFormField::class, $dispatcher); } @@ -29,6 +29,7 @@ public function findDistinctGroupNamesInCustomForm(CustomForm $customForm): arra ->setParameter('customForm', $customForm); $result = $qb->getQuery()->getResult(); + return array_map(fn (array $row) => $row['groupName'], $result); } } diff --git a/src/Repository/CustomFormRepository.php b/src/Repository/CustomFormRepository.php index 62df6b92..6cf99b68 100644 --- a/src/Repository/CustomFormRepository.php +++ b/src/Repository/CustomFormRepository.php @@ -17,7 +17,7 @@ final class CustomFormRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, CustomForm::class, $dispatcher); } @@ -28,15 +28,15 @@ public function __construct( public function findAllWithRetentionTime(): array { $qb = $this->createQueryBuilder('cf'); + return $qb->andWhere($qb->expr()->isNotNull('cf.retentionTime')) ->getQuery() ->getResult(); } /** - * @param Node $node - * @param NodeTypeFieldInterface $field * @return CustomForm[] + * * @deprecated Use findByNodeAndFieldName instead */ public function findByNodeAndField(Node $node, NodeTypeFieldInterface $field): array @@ -53,8 +53,6 @@ public function findByNodeAndField(Node $node, NodeTypeFieldInterface $field): a } /** - * @param Node $node - * @param string $fieldName * @return CustomForm[] */ public function findByNodeAndFieldName(Node $node, string $fieldName): array diff --git a/src/Repository/DocumentRepository.php b/src/Repository/DocumentRepository.php index dccd2688..216edd00 100644 --- a/src/Repository/DocumentRepository.php +++ b/src/Repository/DocumentRepository.php @@ -11,29 +11,30 @@ use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\Tools\Pagination\Paginator; use Doctrine\Persistence\ManagerRegistry; -use RZ\Roadiz\CoreBundle\Entity\CustomFormFieldAttribute; -use RZ\Roadiz\Documents\Repository\DocumentRepositoryInterface; use RZ\Roadiz\Contracts\NodeType\NodeTypeFieldInterface; use RZ\Roadiz\Core\AbstractEntities\AbstractField; use RZ\Roadiz\Core\AbstractEntities\TranslationInterface; use RZ\Roadiz\CoreBundle\Doctrine\ORM\SimpleQueryBuilder; use RZ\Roadiz\CoreBundle\Entity\CustomForm; +use RZ\Roadiz\CoreBundle\Entity\CustomFormFieldAttribute; use RZ\Roadiz\CoreBundle\Entity\Document; use RZ\Roadiz\CoreBundle\Entity\DocumentTranslation; use RZ\Roadiz\CoreBundle\Entity\Folder; use RZ\Roadiz\CoreBundle\Entity\NodesSources; use RZ\Roadiz\CoreBundle\Entity\Setting; +use RZ\Roadiz\Documents\Repository\DocumentRepositoryInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * @extends EntityRepository + * * @implements DocumentRepositoryInterface */ final class DocumentRepository extends EntityRepository implements DocumentRepositoryInterface { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, Document::class, $dispatcher); } @@ -41,8 +42,6 @@ public function __construct( /** * Get a document with its translation id. * - * @param int $id - * @return Document|null * @throws NonUniqueResultException */ public function findOneByDocumentTranslationId(int $id): ?Document @@ -60,6 +59,7 @@ public function findOneByDocumentTranslationId(int $id): ?Document protected function getCustomFormSubmittedBeforeQueryBuilder(): QueryBuilder { $qb = $this->createQueryBuilder('d'); + return $qb->innerJoin('d.customFormFieldAttributes', 'cffa') ->innerJoin('cffa.customFormAnswer', 'cfa') ->andWhere($qb->expr()->eq('cfa.customForm', ':customForm')) @@ -67,8 +67,6 @@ protected function getCustomFormSubmittedBeforeQueryBuilder(): QueryBuilder } /** - * @param CustomForm $customForm - * @param \DateTime $submittedAt * @return array */ public function findByCustomFormSubmittedBefore(CustomForm $customForm, \DateTime $submittedAt): array @@ -76,15 +74,12 @@ public function findByCustomFormSubmittedBefore(CustomForm $customForm, \DateTim $qb = $this->getCustomFormSubmittedBeforeQueryBuilder() ->setParameter(':customForm', $customForm) ->setParameter(':submittedAt', $submittedAt); + return $qb->getQuery()->getResult(); } /** * Add a folder filtering to queryBuilder. - * - * @param array $criteria - * @param QueryBuilder $qb - * @param string $prefix */ protected function filterByFolder(array &$criteria, QueryBuilder $qb, string $prefix = 'd'): void { @@ -100,12 +95,12 @@ protected function filterByFolder(array &$criteria, QueryBuilder $qb, string $pr /* * Do not filter if folder array is empty. */ - if (count($criteria['folders']) === 0) { + if (0 === count($criteria['folders'])) { return; } if ( - in_array("folderExclusive", array_keys($criteria)) - && $criteria["folderExclusive"] === true + in_array('folderExclusive', array_keys($criteria)) + && true === $criteria['folderExclusive'] ) { // To get an exclusive folder filter // we need to filter against each folder id @@ -113,16 +108,16 @@ protected function filterByFolder(array &$criteria, QueryBuilder $qb, string $pr // with AND operator foreach ($criteria['folders'] as $index => $folder) { if (null !== $folder && $folder instanceof Folder) { - $alias = 'fd' . $index; - $qb->innerJoin($prefix . '.folders', $alias); - $qb->andWhere($qb->expr()->eq($alias . '.id', $folder->getId())); + $alias = 'fd'.$index; + $qb->innerJoin($prefix.'.folders', $alias); + $qb->andWhere($qb->expr()->eq($alias.'.id', $folder->getId())); } } - unset($criteria["folderExclusive"]); + unset($criteria['folderExclusive']); unset($criteria['folders']); } else { $qb->innerJoin( - $prefix . '.folders', + $prefix.'.folders', 'fd', 'WITH', 'fd.id IN (:folders)' @@ -130,7 +125,7 @@ protected function filterByFolder(array &$criteria, QueryBuilder $qb, string $pr } } else { $qb->innerJoin( - $prefix . '.folders', + $prefix.'.folders', 'fd', 'WITH', 'fd.id = :folders' @@ -140,7 +135,7 @@ protected function filterByFolder(array &$criteria, QueryBuilder $qb, string $pr } /** - * Reimplementing findBy features… with extra things + * Reimplementing findBy features… with extra things. * * * key => array('<=', $value) * * key => array('<', $value) @@ -155,9 +150,6 @@ protected function filterByFolder(array &$criteria, QueryBuilder $qb, string $pr * * * `translation => $object` * * `translation.locale => 'fr_FR'` - * - * @param array $criteria - * @param QueryBuilder $qb */ protected function filterByCriteria(array &$criteria, QueryBuilder $qb): void { @@ -166,7 +158,7 @@ protected function filterByCriteria(array &$criteria, QueryBuilder $qb): void * Reimplementing findBy features… */ foreach ($criteria as $key => $value) { - if ($key == "folders" || $key == "folderExclusive") { + if ('folders' == $key || 'folderExclusive' == $key) { continue; } @@ -190,7 +182,7 @@ protected function filterByCriteria(array &$criteria, QueryBuilder $qb): void */ $prefix = 'dt.'; $key = str_replace('documentTranslations.', '', $key); - } elseif ($key == 'translation') { + } elseif ('translation' == $key) { $prefix = 'dt.'; } @@ -201,18 +193,16 @@ protected function filterByCriteria(array &$criteria, QueryBuilder $qb): void /** * Create a Criteria object from a search pattern and additional fields. * - * @param string $pattern Search pattern - * @param QueryBuilder $qb QueryBuilder to pass - * @param array $criteria Additional criteria - * @param string $alias SQL query table alias - * - * @return QueryBuilder + * @param string $pattern Search pattern + * @param QueryBuilder $qb QueryBuilder to pass + * @param array $criteria Additional criteria + * @param string $alias SQL query table alias */ protected function createSearchBy( string $pattern, QueryBuilder $qb, array &$criteria = [], - string $alias = "obj" + string $alias = 'obj', ): QueryBuilder { $this->filterByFolder($criteria, $qb, $alias); $this->applyFilterByFolder($criteria, $qb); @@ -221,15 +211,15 @@ protected function createSearchBy( /* * Search in translations */ - $qb->leftJoin($alias . '.documentTranslations', 'dt'); + $qb->leftJoin($alias.'.documentTranslations', 'dt'); $criteriaFields = []; foreach (self::getSearchableColumnsNames($this->_em->getClassMetadata(DocumentTranslation::class)) as $field) { - $criteriaFields[$field] = '%' . strip_tags(\mb_strtolower($pattern)) . '%'; + $criteriaFields[$field] = '%'.strip_tags(\mb_strtolower($pattern)).'%'; } foreach ($criteriaFields as $key => $value) { - $fullKey = sprintf('LOWER(%s)', 'dt.' . $key); + $fullKey = sprintf('LOWER(%s)', 'dt.'.$key); $qb->orWhere($qb->expr()->like($fullKey, $qb->expr()->literal($value))); } @@ -238,9 +228,6 @@ protected function createSearchBy( /** * Bind parameters to generated query. - * - * @param array $criteria - * @param QueryBuilder $qb */ protected function applyFilterByCriteria(array &$criteria, QueryBuilder $qb): void { @@ -249,7 +236,7 @@ protected function applyFilterByCriteria(array &$criteria, QueryBuilder $qb): vo */ $simpleQB = new SimpleQueryBuilder($qb); foreach ($criteria as $key => $value) { - if ($key == "folders" || $key == "folderExclusive") { + if ('folders' == $key || 'folderExclusive' == $key) { continue; } $simpleQB->bindValue($key, $value); @@ -257,10 +244,7 @@ protected function applyFilterByCriteria(array &$criteria, QueryBuilder $qb): vo } /** - * Bind tag parameter to final query - * - * @param array $criteria - * @param QueryBuilder $qb + * Bind tag parameter to final query. */ protected function applyFilterByFolder(array &$criteria, QueryBuilder $qb): void { @@ -274,19 +258,16 @@ protected function applyFilterByFolder(array &$criteria, QueryBuilder $qb): void } elseif (is_integer($criteria['folders'])) { $qb->setParameter('folders', (int) $criteria['folders']); } - unset($criteria["folders"]); + unset($criteria['folders']); } } /** - * Bind translation parameter to final query - * - * @param QueryBuilder $qb - * @param null|TranslationInterface $translation + * Bind translation parameter to final query. */ protected function applyTranslationByFolder( QueryBuilder $qb, - TranslationInterface $translation = null + ?TranslationInterface $translation = null, ): void { if (null !== $translation) { $qb->setParameter('translation', $translation); @@ -295,35 +276,27 @@ protected function applyTranslationByFolder( /** * Restrict documents to their copyright valid datetime range or null. - * - * @param QueryBuilder $qb - * @param string $alias - * @return QueryBuilder */ public function alterQueryBuilderWithCopyrightLimitations(QueryBuilder $qb, string $alias = 'd'): QueryBuilder { return $qb->andWhere($qb->expr()->orX( - $qb->expr()->isNull($alias . '.copyrightValidSince'), - $qb->expr()->lte($alias . '.copyrightValidSince', ':now') + $qb->expr()->isNull($alias.'.copyrightValidSince'), + $qb->expr()->lte($alias.'.copyrightValidSince', ':now') ))->andWhere($qb->expr()->orX( - $qb->expr()->isNull($alias . '.copyrightValidUntil'), - $qb->expr()->gte($alias . '.copyrightValidUntil', ':now') + $qb->expr()->isNull($alias.'.copyrightValidUntil'), + $qb->expr()->gte($alias.'.copyrightValidUntil', ':now') ))->setParameter(':now', new \DateTime()); } /** * Create filters according to any translation criteria OR argument. - * - * @param array $criteria - * @param QueryBuilder $qb - * @param TranslationInterface|null $translation */ - protected function filterByTranslation(array &$criteria, QueryBuilder $qb, TranslationInterface $translation = null): void + protected function filterByTranslation(array &$criteria, QueryBuilder $qb, ?TranslationInterface $translation = null): void { if ( - isset($criteria['translation']) || - isset($criteria['translation.locale']) || - isset($criteria['translation.id']) + isset($criteria['translation']) + || isset($criteria['translation.locale']) + || isset($criteria['translation.id']) ) { $qb->leftJoin('d.documentTranslations', 'dt'); $qb->leftJoin('dt.translation', 't'); @@ -356,21 +329,13 @@ protected function filterByTranslation(array &$criteria, QueryBuilder $qb, Trans /** * This method allows to pre-filter Documents with a given translation. - * - * @param array $criteria - * @param array|null $orderBy - * @param int|null $limit - * @param int|null $offset - * @param TranslationInterface|null $translation - * - * @return QueryBuilder */ protected function getContextualQueryWithTranslation( array &$criteria, - array $orderBy = null, + ?array $orderBy = null, ?int $limit = null, ?int $offset = null, - TranslationInterface $translation = null + ?TranslationInterface $translation = null, ): QueryBuilder { $qb = $this->createQueryBuilder('d'); $qb->andWhere($qb->expr()->eq('d.raw', ':raw')) @@ -386,7 +351,7 @@ protected function getContextualQueryWithTranslation( // Add ordering if (null !== $orderBy) { foreach ($orderBy as $key => $value) { - $qb->addOrderBy('d.' . $key, $value); + $qb->addOrderBy('d.'.$key, $value); } } @@ -402,38 +367,29 @@ protected function getContextualQueryWithTranslation( /** * This method allows to pre-filter Documents with a given translation. - * - * @param array $criteria - * @param TranslationInterface|null $translation - * - * @return QueryBuilder */ protected function getCountContextualQueryWithTranslation( array &$criteria, - TranslationInterface $translation = null + ?TranslationInterface $translation = null, ): QueryBuilder { $qb = $this->getContextualQueryWithTranslation($criteria, null, null, null, $translation); + return $qb->select($qb->expr()->countDistinct('d.id')); } /** * Just like the findBy method but with relational criteria. * - * @param array $criteria - * @param array|null $orderBy * @param int|null $limit * @param int|null $offset - * @param TranslationInterface|null $translation - * - * @return array|Paginator */ public function findBy( array $criteria, - array $orderBy = null, + ?array $orderBy = null, $limit = null, $offset = null, - TranslationInterface $translation = null - ): array|Paginator { + ?TranslationInterface $translation = null, + ): array { $qb = $this->getContextualQueryWithTranslation( $criteria, $orderBy, @@ -449,14 +405,14 @@ public function findBy( $this->dispatchQueryEvent($query); if ( - null !== $limit && - null !== $offset + null !== $limit + && null !== $offset ) { /* * We need to use Doctrine paginator * if a limit is set because of the default inner join */ - return new Paginator($query); + return (new Paginator($query))->getIterator()->getArrayCopy(); } else { return $query->getResult(); } @@ -465,17 +421,12 @@ public function findBy( /** * Just like the findOneBy method but with relational criteria. * - * @param array $criteria - * @param array|null $orderBy - * @param TranslationInterface|null $translation - * - * @return Document|null - * @throws \Doctrine\ORM\NonUniqueResultException + * @throws NonUniqueResultException */ public function findOneBy( array $criteria, - array $orderBy = null, - TranslationInterface $translation = null + ?array $orderBy = null, + ?TranslationInterface $translation = null, ): ?Document { $qb = $this->getContextualQueryWithTranslation( $criteria, @@ -498,18 +449,17 @@ public function findOneBy( * Just like the countBy method but with relational criteria. * * @param Criteria|mixed|array $criteria - * @param TranslationInterface|null $translation * - * @return int * @throws NonUniqueResultException * @throws NoResultException */ public function countBy( mixed $criteria, - TranslationInterface $translation = null + ?TranslationInterface $translation = null, ): int { if ($criteria instanceof Criteria) { $collection = $this->matching($criteria); + return $collection->count(); } elseif (\is_array($criteria)) { $query = $this->getCountContextualQueryWithTranslation( @@ -523,18 +473,41 @@ public function countBy( return (int) $query->getQuery()->getSingleScalarResult(); } + return 0; } /** - * @param NodesSources $nodeSource - * @param NodeTypeFieldInterface $field + * @throws NonUniqueResultException + */ + public function findOneDisplayableByNodeSource( + NodesSources|int $nodeSource, + TranslationInterface|int $translation, + ): ?Document { + $qb = $this->createQueryBuilder('d'); + $qb->addSelect('dt') + ->leftJoin('d.documentTranslations', 'dt', 'WITH', 'dt.translation = :translation') + ->innerJoin('d.nodesSourcesByFields', 'nsf', 'WITH', 'nsf.nodeSource = :nodeSource') + ->andWhere($qb->expr()->eq('d.raw', ':raw')) + ->andWhere($qb->expr()->in('d.mimeType', ':mimeType')) + ->setParameter('nodeSource', $nodeSource) + ->setParameter('translation', $translation) + ->setParameter('raw', false) + ->setParameter('mimeType', ['image/webp', 'image/jpeg', 'image/png', 'image/gif', 'image/svg+xml']) + ->setMaxResults(1) + ->setCacheable(true); + + return $qb->getQuery()->getOneOrNullResult(); + } + + /** * @return array + * * @deprecated Use findByNodeSourceAndFieldName instead */ public function findByNodeSourceAndField( NodesSources $nodeSource, - NodeTypeFieldInterface $field + NodeTypeFieldInterface $field, ): array { $qb = $this->createQueryBuilder('d'); $qb->addSelect('dt') @@ -553,13 +526,11 @@ public function findByNodeSourceAndField( } /** - * @param NodesSources $nodeSource - * @param string $fieldName * @return array */ public function findByNodeSourceAndFieldName( NodesSources $nodeSource, - string $fieldName + string $fieldName, ): array { $qb = $this->createQueryBuilder('d'); $qb->addSelect('dt') @@ -653,9 +624,6 @@ protected function getAllDocumentsIdUsedInCustomFormAnswers(): array return $idArray; } - /** - * @return QueryBuilder - */ public function getAllUnusedQueryBuilder(): QueryBuilder { $qb1 = $this->createQueryBuilder('d1'); @@ -701,6 +669,7 @@ public function getAllUnusedQueryBuilder(): QueryBuilder public function findAllWithoutFileHash(): array { $qb = $this->createQueryBuilder('d'); + return $qb->andWhere($qb->expr()->isNull('d.fileHash')) ->getQuery() ->getResult(); @@ -716,7 +685,6 @@ public function getDuplicatesQueryBuilder(): QueryBuilder ->andHaving($qb->expr()->gt($qb->expr()->count('d2.fileHash'), 1)) ->andHaving($qb->expr()->gt($qb->expr()->count('d2.fileHashAlgorithm'), 1)); - $qb2 = $this->createQueryBuilder('d'); $qb2->andWhere($qb2->expr()->in('d.fileHash', $qb->getDQL())) ->setParameter(':raw', false) diff --git a/src/Repository/DocumentTranslationRepository.php b/src/Repository/DocumentTranslationRepository.php index c6a6906f..5f4d60ea 100644 --- a/src/Repository/DocumentTranslationRepository.php +++ b/src/Repository/DocumentTranslationRepository.php @@ -16,14 +16,12 @@ final class DocumentTranslationRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, DocumentTranslation::class, $dispatcher); } /** - * @param int $id - * @return DocumentTranslation|null * @throws NonUniqueResultException */ public function findOneWithDocument(int $id): ?DocumentTranslation diff --git a/src/Repository/EntityRepository.php b/src/Repository/EntityRepository.php index 1b0e0223..84ad5bc7 100644 --- a/src/Repository/EntityRepository.php +++ b/src/Repository/EntityRepository.php @@ -4,10 +4,9 @@ namespace RZ\Roadiz\CoreBundle\Repository; -use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepositoryInterface; +use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Criteria; -use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\ClassMetadataInfo; use Doctrine\ORM\NonUniqueResultException; use Doctrine\ORM\NoResultException; @@ -16,7 +15,6 @@ use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\Tools\Pagination\Paginator; use Doctrine\Persistence\ManagerRegistry; -use LogicException; use RZ\Roadiz\Core\AbstractEntities\PersistableInterface; use RZ\Roadiz\CoreBundle\Doctrine\Event\QueryBuilder\QueryBuilderApplyEvent; use RZ\Roadiz\CoreBundle\Doctrine\Event\QueryBuilder\QueryBuilderBuildEvent; @@ -29,30 +27,20 @@ /** * @template TEntityClass of object - * @extends \Doctrine\ORM\EntityRepository + * + * @extends ServiceEntityRepository */ -abstract class EntityRepository extends \Doctrine\ORM\EntityRepository implements ServiceEntityRepositoryInterface +abstract class EntityRepository extends ServiceEntityRepository { - protected EventDispatcherInterface $dispatcher; - /** - * @param ManagerRegistry $registry * @param class-string $entityClass - * @param EventDispatcherInterface $dispatcher */ - public function __construct(ManagerRegistry $registry, string $entityClass, EventDispatcherInterface $dispatcher) - { - $this->dispatcher = $dispatcher; - $manager = $registry->getManagerForClass($entityClass); - - if (!($manager instanceof EntityManagerInterface)) { - throw new LogicException(sprintf( - 'Could not find the entity manager for class "%s". Check your Doctrine configuration to make sure it is configured to load this entity’s metadata.', - $entityClass - )); - } - - parent::__construct($manager, $manager->getClassMetadata($entityClass)); + public function __construct( + ManagerRegistry $registry, + string $entityClass, + protected readonly EventDispatcherInterface $dispatcher, + ) { + parent::__construct($registry, $entityClass); } /** @@ -86,7 +74,6 @@ public function __construct(ManagerRegistry $registry, string $entityClass, Even public const NODETYPE_ALIAS = 'nt'; /** - * @param QueryBuilder $qb * @param class-string $entityClass */ protected function dispatchQueryBuilderEvent(QueryBuilder $qb, string $entityClass): void @@ -96,10 +83,6 @@ protected function dispatchQueryBuilderEvent(QueryBuilder $qb, string $entityCla } /** - * @param QueryBuilder $qb - * @param string $property - * @param mixed $value - * * @return Event */ protected function dispatchQueryBuilderBuildEvent(QueryBuilder $qb, string $property, mixed $value): object @@ -115,8 +98,6 @@ protected function dispatchQueryBuilderBuildEvent(QueryBuilder $qb, string $prop } /** - * @param Query $query - * * @return Event */ protected function dispatchQueryEvent(Query $query): object @@ -129,10 +110,6 @@ protected function dispatchQueryEvent(Query $query): object } /** - * @param QueryBuilder $qb - * @param string $property - * @param mixed $value - * * @return Event */ protected function dispatchQueryBuilderApplyEvent(QueryBuilder $qb, string $property, mixed $value): object @@ -147,14 +124,7 @@ protected function dispatchQueryBuilderApplyEvent(QueryBuilder $qb, string $prop )); } - /** - * - * @param array $criteria - * @param QueryBuilder $qb - * @param string $alias - * @return QueryBuilder - */ - protected function prepareComparisons(array &$criteria, QueryBuilder $qb, string $alias) + protected function prepareComparisons(array &$criteria, QueryBuilder $qb, string $alias): QueryBuilder { $simpleQB = new SimpleQueryBuilder($qb); foreach ($criteria as $key => $value) { @@ -165,17 +135,13 @@ protected function prepareComparisons(array &$criteria, QueryBuilder $qb, string $event = $this->dispatchQueryBuilderBuildEvent($qb, $key, $value); if (!$event->isPropagationStopped()) { - $qb->andWhere($simpleQB->buildExpressionWithoutBinding($value, $alias . '.', $key)); + $qb->andWhere($simpleQB->buildExpressionWithoutBinding($value, $alias.'.', $key)); } } return $qb; } - /** - * @param array $criteria - * @param QueryBuilder $qb - */ protected function applyFilterByCriteria(array &$criteria, QueryBuilder $qb): void { $simpleQB = new SimpleQueryBuilder($qb); @@ -187,14 +153,6 @@ protected function applyFilterByCriteria(array &$criteria, QueryBuilder $qb): vo } } - /** - * @param QueryBuilder $qb - * @param string $name - * @param string $key - * @param mixed $value - * - * @return Query\Expr\Func - */ protected function directExprIn(QueryBuilder $qb, string $name, string $key, mixed $value): Query\Expr\Func { $newValue = []; @@ -216,34 +174,30 @@ protected function directExprIn(QueryBuilder $qb, string $name, string $key, mix * Count entities using a Criteria object or a simple filter array. * * @param Criteria|mixed|array $criteria or array - * - * @return int */ public function countBy(mixed $criteria): int { if ($criteria instanceof Criteria) { $collection = $this->matching($criteria); + return $collection->count(); } elseif (is_array($criteria)) { $qb = $this->createQueryBuilder(static::DEFAULT_ALIAS); - $qb->select($qb->expr()->countDistinct(static::DEFAULT_ALIAS . '.id')); + $qb->select($qb->expr()->countDistinct(static::DEFAULT_ALIAS.'.id')); $qb = $this->prepareComparisons($criteria, $qb, static::DEFAULT_ALIAS); $this->dispatchQueryBuilderEvent($qb, $this->getEntityName()); $this->applyFilterByCriteria($criteria, $qb); try { return (int) $qb->getQuery()->getSingleScalarResult(); - } catch (NoResultException | NonUniqueResultException $e) { + } catch (NoResultException|NonUniqueResultException $e) { return 0; } } + return 0; } - /** - * @param ClassMetadataInfo $metadata - * @return array - */ public static function getSearchableColumnsNames(ClassMetadataInfo $metadata): array { /* @@ -255,15 +209,15 @@ public static function getSearchableColumnsNames(ClassMetadataInfo $metadata): a $field = $metadata->getFieldName($col); $type = $metadata->getTypeOfField($field); if ( - in_array($type, ['string', 'text']) && - !in_array($field, [ + in_array($type, ['string', 'text']) + && !in_array($field, [ 'color', 'folder', 'childrenOrder', 'childrenOrderDirection', 'password', 'token', - 'confirmationToken' + 'confirmationToken', ]) ) { $criteriaFields[] = $field; @@ -275,24 +229,19 @@ public static function getSearchableColumnsNames(ClassMetadataInfo $metadata): a /** * Create a LIKE comparison with entity texts colunms. - * - * @param string $pattern - * @param QueryBuilder $qb - * @param string $alias - * @return QueryBuilder */ protected function classicLikeComparison( string $pattern, QueryBuilder $qb, - string $alias = EntityRepository::DEFAULT_ALIAS + string $alias = EntityRepository::DEFAULT_ALIAS, ): QueryBuilder { $criteriaFields = []; foreach (static::getSearchableColumnsNames($this->getClassMetadata()) as $field) { - $criteriaFields[$field] = '%' . strip_tags(\mb_strtolower($pattern)) . '%'; + $criteriaFields[$field] = '%'.strip_tags(\mb_strtolower($pattern)).'%'; } foreach ($criteriaFields as $key => $value) { - $fullKey = sprintf('LOWER(%s)', $alias . '.' . $key); + $fullKey = sprintf('LOWER(%s)', $alias.'.'.$key); $qb->orWhere($qb->expr()->like($fullKey, $qb->expr()->literal($value))); } @@ -302,17 +251,16 @@ protected function classicLikeComparison( /** * Create a Criteria object from a search pattern and additional fields. * - * @param string $pattern Search pattern - * @param QueryBuilder $qb QueryBuilder to pass - * @param array $criteria Additional criteria - * @param string $alias SQL query table alias - * @return QueryBuilder + * @param string $pattern Search pattern + * @param QueryBuilder $qb QueryBuilder to pass + * @param array $criteria Additional criteria + * @param string $alias SQL query table alias */ protected function createSearchBy( string $pattern, QueryBuilder $qb, array &$criteria = [], - string $alias = EntityRepository::DEFAULT_ALIAS + string $alias = EntityRepository::DEFAULT_ALIAS, ): QueryBuilder { $this->classicLikeComparison($pattern, $qb, $alias); $this->prepareComparisons($criteria, $qb, $alias); @@ -321,15 +269,12 @@ protected function createSearchBy( } /** - * @param string $pattern Search pattern - * @param array $criteria Additional criteria - * @param array $orders - * @param int|null $limit - * @param int|null $offset - * @param string $alias + * @param string $pattern Search pattern + * @param array $criteria Additional criteria * - * @return array|Paginator - * @psalm-return array|Paginator + * @return array + * + * @throws \Exception */ public function searchBy( string $pattern, @@ -337,26 +282,26 @@ public function searchBy( array $orders = [], ?int $limit = null, ?int $offset = null, - string $alias = EntityRepository::DEFAULT_ALIAS - ): array|Paginator { + string $alias = EntityRepository::DEFAULT_ALIAS, + ): array { $qb = $this->createQueryBuilder($alias); $qb = $this->createSearchBy($pattern, $qb, $criteria, $alias); // Add ordering foreach ($orders as $key => $value) { if ( - (\str_starts_with($key, 'node.') || \str_starts_with($key, static::NODE_ALIAS . '.')) && - $this->hasJoinedNode($qb, $alias) + (\str_starts_with($key, 'node.') || \str_starts_with($key, static::NODE_ALIAS.'.')) + && $this->hasJoinedNode($qb, $alias) ) { - $key = preg_replace('#^node\.#', static::NODE_ALIAS . '.', $key); + $key = preg_replace('#^node\.#', static::NODE_ALIAS.'.', $key); $qb->addOrderBy($key, $value); } elseif ( - \str_starts_with($key, static::NODESSOURCES_ALIAS . '.') && - $this->hasJoinedNodesSources($qb, $alias) + \str_starts_with($key, static::NODESSOURCES_ALIAS.'.') + && $this->hasJoinedNodesSources($qb, $alias) ) { $qb->addOrderBy($key, $value); } else { - $qb->addOrderBy($alias . '.' . $key, $value); + $qb->addOrderBy($alias.'.'.$key, $value); } } if (null !== $offset) { @@ -372,28 +317,27 @@ public function searchBy( $this->dispatchQueryEvent($query); if ( - null !== $limit && - null !== $offset + null !== $limit + && null !== $offset ) { /* * We need to use Doctrine paginator * if a limit is set because of the default inner join */ - return new Paginator($query); + return (new Paginator($query))->getIterator()->getArrayCopy(); } else { return $query->getResult(); } } /** - * @param string $pattern Search pattern - * @param array $criteria Additional criteria - * @return int + * @param string $pattern Search pattern + * @param array $criteria Additional criteria */ public function countSearchBy(string $pattern, array $criteria = []): int { $qb = $this->createQueryBuilder(static::DEFAULT_ALIAS); - $qb->select($qb->expr()->countDistinct(static::DEFAULT_ALIAS . '.id')); + $qb->select($qb->expr()->countDistinct(static::DEFAULT_ALIAS.'.id')); $qb = $this->createSearchBy($pattern, $qb, $criteria); $this->dispatchQueryBuilderEvent($qb, $this->getEntityName()); @@ -401,16 +345,11 @@ public function countSearchBy(string $pattern, array $criteria = []): int try { return (int) $qb->getQuery()->getSingleScalarResult(); - } catch (NoResultException | NonUniqueResultException $e) { + } catch (NoResultException|NonUniqueResultException $e) { return 0; } } - /** - * @param array $criteria - * @param QueryBuilder $qb - * @param string $nodeAlias - */ protected function buildTagFiltering(array &$criteria, QueryBuilder $qb, string $nodeAlias = 'n'): void { if (key_exists('tags', $criteria)) { @@ -425,33 +364,33 @@ protected function buildTagFiltering(array &$criteria, QueryBuilder $qb, string /* * Do not filter if tag array is empty. */ - if (count($criteria['tags']) === 0) { + if (0 === count($criteria['tags'])) { return; } if ( - in_array("tagExclusive", array_keys($criteria)) - && $criteria["tagExclusive"] === true + in_array('tagExclusive', array_keys($criteria)) + && true === $criteria['tagExclusive'] ) { // To get an exclusive tag filter // we need to filter against each tag id // and to inner join with a different alias for each tag // with AND operator /** - * @var int $index + * @var int $index * @var Tag|null $tag Tag can be null if not found */ foreach ($criteria['tags'] as $index => $tag) { if ($tag instanceof Tag) { - $alias = 'ntg_' . $index; - $qb->innerJoin($nodeAlias . '.nodesTags', $alias); - $qb->andWhere($qb->expr()->eq($alias . '.tag', $tag->getId())); + $alias = 'ntg_'.$index; + $qb->innerJoin($nodeAlias.'.nodesTags', $alias); + $qb->andWhere($qb->expr()->eq($alias.'.tag', $tag->getId())); } } - unset($criteria["tagExclusive"]); + unset($criteria['tagExclusive']); unset($criteria['tags']); } else { $qb->innerJoin( - $nodeAlias . '.nodesTags', + $nodeAlias.'.nodesTags', 'ntg_0', 'WITH', 'ntg_0.tag IN (:tags)' @@ -459,7 +398,7 @@ protected function buildTagFiltering(array &$criteria, QueryBuilder $qb, string } } else { $qb->innerJoin( - $nodeAlias . '.nodesTags', + $nodeAlias.'.nodesTags', 'ntg_0', 'WITH', 'ntg_0.tag = :tags' @@ -469,10 +408,7 @@ protected function buildTagFiltering(array &$criteria, QueryBuilder $qb, string } /** - * Bind tag parameters to final query - * - * @param array $criteria - * @param QueryBuilder $qb + * Bind tag parameters to final query. */ protected function applyFilterByTag(array &$criteria, QueryBuilder $qb): void { @@ -492,54 +428,35 @@ protected function applyFilterByTag(array &$criteria, QueryBuilder $qb): void /** * Ensure that node table is joined only once. - * - * @param QueryBuilder $qb - * @param string $alias - * @return bool */ - protected function hasJoinedNode(QueryBuilder $qb, string $alias) + protected function hasJoinedNode(QueryBuilder $qb, string $alias): bool { return $this->joinExists($qb, $alias, static::NODE_ALIAS); } /** * Ensure that nodes_sources table is joined only once. - * - * @param QueryBuilder $qb - * @param string $alias - * @return bool */ - protected function hasJoinedNodesSources(QueryBuilder $qb, string $alias) + protected function hasJoinedNodesSources(QueryBuilder $qb, string $alias): bool { return $this->joinExists($qb, $alias, static::NODESSOURCES_ALIAS); } /** * Ensure that nodes_sources table is joined only once. - * - * @param QueryBuilder $qb - * @param string $alias - * @return bool */ - protected function hasJoinedNodeType(QueryBuilder $qb, string $alias) + protected function hasJoinedNodeType(QueryBuilder $qb, string $alias): bool { return $this->joinExists($qb, $alias, static::NODETYPE_ALIAS); } - /** - * @param QueryBuilder $qb - * @param string $rootAlias - * @param string $joinAlias - * @return bool - */ - protected function joinExists(QueryBuilder $qb, string $rootAlias, string $joinAlias) + protected function joinExists(QueryBuilder $qb, string $rootAlias, string $joinAlias): bool { if (isset($qb->getDQLPart('join')[$rootAlias])) { foreach ($qb->getDQLPart('join')[$rootAlias] as $join) { if ( - null !== $join && - $join instanceof Join && - $join->getAlias() === $joinAlias + $join instanceof Join + && $join->getAlias() === $joinAlias ) { return true; } diff --git a/src/Repository/FolderRepository.php b/src/Repository/FolderRepository.php index c4a0f64a..a748e433 100644 --- a/src/Repository/FolderRepository.php +++ b/src/Repository/FolderRepository.php @@ -25,7 +25,7 @@ final class FolderRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, Folder::class, $dispatcher); } @@ -33,10 +33,6 @@ public function __construct( /** * Find a folder according to the given path or create it. * - * @param string $folderPath - * @param TranslationInterface|null $translation - * - * @return Folder|null * @throws ORMException * @throws OptimisticLockException */ @@ -46,7 +42,7 @@ public function findOrCreateByPath(string $folderPath, ?TranslationInterface $tr $folders = explode('/', $folderPath); $folders = array_filter($folders); - if (count($folders) === 0) { + if (0 === count($folders)) { return null; } @@ -92,9 +88,6 @@ public function findOrCreateByPath(string $folderPath, ?TranslationInterface $tr /** * Find a folder according to the given path. * - * @param string $folderPath - * - * @return Folder|null * @throws NonUniqueResultException */ public function findByPath(string $folderPath): ?Folder @@ -108,12 +101,7 @@ public function findByPath(string $folderPath): ?Folder return $this->findOneByFolderName($folderName); } - /** - * @param Folder $folder - * @param TranslationInterface|null $translation - * @return array - */ - public function findAllChildrenFromFolder(Folder $folder, TranslationInterface $translation = null): array + public function findAllChildrenFromFolder(Folder $folder, ?TranslationInterface $translation = null): array { $ids = $this->findAllChildrenIdFromFolder($folder); if (count($ids) > 0) { @@ -128,19 +116,17 @@ public function findAllChildrenFromFolder(Folder $folder, TranslationInterface $ ->andWhere($qb->expr()->eq('tf.translation', ':translation')) ->setParameter(':translation', $translation); } + return $qb->getQuery()->getResult(); } + return []; } /** - * @param string $folderName - * @param TranslationInterface|null $translation - * - * @return Folder|null * @throws NonUniqueResultException */ - public function findOneByFolderName(string $folderName, TranslationInterface $translation = null): ?Folder + public function findOneByFolderName(string $folderName, ?TranslationInterface $translation = null): ?Folder { $qb = $this->createQueryBuilder('f'); $qb->addSelect('f') @@ -158,10 +144,6 @@ public function findOneByFolderName(string $folderName, TranslationInterface $tr return $qb->getQuery()->getOneOrNullResult(); } - /** - * @param Folder $folder - * @return array - */ public function findAllChildrenIdFromFolder(Folder $folder): array { $idsArray = $this->findChildrenIdFromFolder($folder); @@ -174,10 +156,6 @@ public function findAllChildrenIdFromFolder(Folder $folder): array return $idsArray; } - /** - * @param Folder $folder - * @return array - */ public function findChildrenIdFromFolder(Folder $folder): array { $qb = $this->createQueryBuilder('f'); @@ -191,17 +169,16 @@ public function findChildrenIdFromFolder(Folder $folder): array /** * Create a Criteria object from a search pattern and additionnal fields. * - * @param string $pattern Search pattern - * @param QueryBuilder $qb QueryBuilder to pass - * @param array $criteria Additional criteria - * @param string $alias SQL query table alias - * @return QueryBuilder + * @param string $pattern Search pattern + * @param QueryBuilder $qb QueryBuilder to pass + * @param array $criteria Additional criteria + * @param string $alias SQL query table alias */ protected function createSearchBy( string $pattern, QueryBuilder $qb, array &$criteria = [], - string $alias = "obj" + string $alias = 'obj', ): QueryBuilder { $this->classicLikeComparison($pattern, $qb, $alias); @@ -212,11 +189,11 @@ protected function createSearchBy( $criteriaFields = []; foreach (self::getSearchableColumnsNames($this->_em->getClassMetadata(FolderTranslation::class)) as $field) { - $criteriaFields[$field] = '%' . strip_tags(\mb_strtolower($pattern)) . '%'; + $criteriaFields[$field] = '%'.strip_tags(\mb_strtolower($pattern)).'%'; } foreach ($criteriaFields as $key => $value) { - $fullKey = sprintf('LOWER(%s)', 'tf.' . $key); + $fullKey = sprintf('LOWER(%s)', 'tf.'.$key); $qb->orWhere($qb->expr()->like($fullKey, $qb->expr()->literal($value))); } @@ -224,14 +201,10 @@ protected function createSearchBy( } /** - * @param string $pattern - * @param array $criteria - * @param string $alias - * @return int * @throws \Doctrine\ORM\NoResultException * @throws NonUniqueResultException */ - public function countSearchBy(string $pattern, array $criteria = [], string $alias = "obj"): int + public function countSearchBy(string $pattern, array $criteria = [], string $alias = 'obj'): int { $qb = $this->createQueryBuilder($alias); $qb->select($qb->expr()->countDistinct($alias)); @@ -240,12 +213,7 @@ public function countSearchBy(string $pattern, array $criteria = [], string $ali return (int) $qb->getQuery()->getSingleScalarResult(); } - /** - * @param Document $document - * @param TranslationInterface|null $translation - * @return array - */ - public function findByDocumentAndTranslation(Document $document, TranslationInterface $translation = null): array + public function findByDocumentAndTranslation(Document $document, ?TranslationInterface $translation = null): array { $qb = $this->createQueryBuilder('f'); $qb->innerJoin('f.documents', 'd') @@ -266,12 +234,7 @@ public function findByDocumentAndTranslation(Document $document, TranslationInte return $qb->getQuery()->getResult(); } - /** - * @param Folder|null $parent - * @param TranslationInterface|null $translation - * @return array - */ - public function findByParentAndTranslation(Folder $parent = null, TranslationInterface $translation = null): array + public function findByParentAndTranslation(?Folder $parent = null, ?TranslationInterface $translation = null): array { $qb = $this->createQueryBuilder('f'); $qb->addOrderBy('f.position', 'ASC'); diff --git a/src/Repository/FolderTranslationRepository.php b/src/Repository/FolderTranslationRepository.php index 3b78c003..692df669 100644 --- a/src/Repository/FolderTranslationRepository.php +++ b/src/Repository/FolderTranslationRepository.php @@ -15,7 +15,7 @@ final class FolderTranslationRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, FolderTranslation::class, $dispatcher); } diff --git a/src/Repository/GroupRepository.php b/src/Repository/GroupRepository.php index 557e0166..55c4b44c 100644 --- a/src/Repository/GroupRepository.php +++ b/src/Repository/GroupRepository.php @@ -14,13 +14,14 @@ * @method Group|null findOneBy(array $criteria, array $orderBy = null) * @method Group[] findAll() * @method Group[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + * * @extends EntityRepository */ final class GroupRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, Group::class, $dispatcher); } diff --git a/src/Repository/LogRepository.php b/src/Repository/LogRepository.php index 3419bca8..a8bc0bde 100644 --- a/src/Repository/LogRepository.php +++ b/src/Repository/LogRepository.php @@ -20,16 +20,13 @@ final class LogRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, Log::class, $dispatcher); } /** * Find the latest Log with NodesSources. - * - * @param int $maxResult - * @return Paginator */ public function findLatestByNodesSources(int $maxResult = 5): Paginator { @@ -62,6 +59,7 @@ public function findLatestByNodesSources(int $maxResult = 5): Paginator public function findByNode(Node $node): array { $qb = $this->getAllRelatedToNodeQueryBuilder($node); + return $qb->getQuery()->getResult(); } @@ -85,6 +83,7 @@ public function getAllRelatedToNodeQueryBuilder(Node $node): QueryBuilder $qb->setParameter('nodeSourceId', $node->getNodeSources()->map(function (NodesSources $ns) { return $ns->getId(); })->toArray()); + return $qb; } } diff --git a/src/Repository/NodeRepository.php b/src/Repository/NodeRepository.php index 441ade0f..3c76eecd 100644 --- a/src/Repository/NodeRepository.php +++ b/src/Repository/NodeRepository.php @@ -13,6 +13,7 @@ use Doctrine\ORM\Tools\Pagination\Paginator; use Doctrine\Persistence\ManagerRegistry; use RZ\Roadiz\Contracts\NodeType\NodeTypeFieldInterface; +use RZ\Roadiz\Core\AbstractEntities\NodeInterface; use RZ\Roadiz\Core\AbstractEntities\PersistableInterface; use RZ\Roadiz\Core\AbstractEntities\TranslationInterface; use RZ\Roadiz\CoreBundle\Doctrine\Event\QueryBuilder\QueryBuilderApplyEvent; @@ -20,6 +21,7 @@ use RZ\Roadiz\CoreBundle\Doctrine\ORM\SimpleQueryBuilder; use RZ\Roadiz\CoreBundle\Entity\Node; use RZ\Roadiz\CoreBundle\Entity\NodesSources; +use RZ\Roadiz\CoreBundle\Model\NodeTreeDto; use RZ\Roadiz\CoreBundle\Preview\PreviewResolverInterface; use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\String\Slugger\AsciiSlugger; @@ -35,16 +37,12 @@ public function __construct( ManagerRegistry $registry, PreviewResolverInterface $previewResolver, EventDispatcherInterface $dispatcher, - Security $security + Security $security, ) { parent::__construct($registry, Node::class, $previewResolver, $dispatcher, $security); } /** - * @param QueryBuilder $qb - * @param string $property - * @param mixed $value - * * @return Event */ protected function dispatchQueryBuilderBuildEvent(QueryBuilder $qb, string $property, mixed $value): object @@ -56,10 +54,6 @@ protected function dispatchQueryBuilderBuildEvent(QueryBuilder $qb, string $prop } /** - * @param QueryBuilder $qb - * @param string $property - * @param mixed $value - * * @return Event */ protected function dispatchQueryBuilderApplyEvent(QueryBuilder $qb, string $property, mixed $value): object @@ -74,15 +68,13 @@ protected function dispatchQueryBuilderApplyEvent(QueryBuilder $qb, string $prop * Just like the countBy method but with relational criteria. * * @param Criteria|mixed|array $criteria - * @param TranslationInterface|null $translation * - * @return int * @throws NonUniqueResultException - * @throws \Doctrine\ORM\NoResultException + * @throws NoResultException */ public function countBy( mixed $criteria, - TranslationInterface $translation = null + ?TranslationInterface $translation = null, ): int { $qb = $this->createQueryBuilder(self::NODE_ALIAS); $qb->select($qb->expr()->countDistinct(self::NODE_ALIAS)); @@ -109,24 +101,22 @@ public function countBy( /** * Create filters according to any translation criteria OR argument. - * - * @param array $criteria - * @param QueryBuilder $qb - * @param TranslationInterface|null $translation */ protected function filterByTranslation( array $criteria, QueryBuilder $qb, - TranslationInterface $translation = null + ?TranslationInterface $translation = null, ): void { if ( - isset($criteria['translation']) || - isset($criteria['translation.locale']) || - isset($criteria['translation.id']) || - isset($criteria['translation.available']) + isset($criteria['translation']) + || isset($criteria['translation.locale']) + || isset($criteria['translation.id']) + || isset($criteria['translation.available']) ) { - $qb->innerJoin(self::NODE_ALIAS . '.nodeSources', self::NODESSOURCES_ALIAS); - $qb->innerJoin(self::NODESSOURCES_ALIAS . '.translation', self::TRANSLATION_ALIAS); + if (!$this->hasJoinedNodesSources($qb, self::NODE_ALIAS)) { + $qb->innerJoin(self::NODE_ALIAS.'.nodeSources', self::NODESSOURCES_ALIAS); + } + $qb->innerJoin(self::NODESSOURCES_ALIAS.'.translation', self::TRANSLATION_ALIAS); } else { if (null !== $translation) { /* @@ -136,23 +126,22 @@ protected function filterByTranslation( 'n.nodeSources', self::NODESSOURCES_ALIAS, 'WITH', - self::NODESSOURCES_ALIAS . '.translation = :translation' + self::NODESSOURCES_ALIAS.'.translation = :translation' ); } else { /* * With a null translation, not filter by translation to enable * nodes with only one translation which is not the default one. */ - $qb->innerJoin(self::NODE_ALIAS . '.nodeSources', self::NODESSOURCES_ALIAS); + if (!$this->hasJoinedNodesSources($qb, self::NODE_ALIAS)) { + $qb->innerJoin(self::NODE_ALIAS.'.nodeSources', self::NODESSOURCES_ALIAS); + } } } } /** * Add a tag filtering to queryBuilder. - * - * @param array $criteria - * @param QueryBuilder $qb */ protected function filterByTag(array &$criteria, QueryBuilder $qb): void { @@ -177,9 +166,6 @@ protected function filterByTag(array &$criteria, QueryBuilder $qb): void * * * `translation => $object` * * `translation.locale => 'fr_FR'` - * - * @param array $criteria - * @param QueryBuilder $qb */ protected function filterByCriteria(array &$criteria, QueryBuilder $qb): void { @@ -188,7 +174,7 @@ protected function filterByCriteria(array &$criteria, QueryBuilder $qb): void * Reimplementing findBy features… */ foreach ($criteria as $key => $value) { - if ($key == "tags" || $key == "tagExclusive") { + if ('tags' == $key || 'tagExclusive' == $key) { continue; } /* @@ -202,7 +188,7 @@ protected function filterByCriteria(array &$criteria, QueryBuilder $qb): void * compute prefix for * filtering node, and sources relation fields */ - $prefix = self::NODE_ALIAS . '.'; + $prefix = self::NODE_ALIAS.'.'; // Dots are forbidden in field definitions $baseKey = $simpleQB->getParameterKey($key); $qb->andWhere($simpleQB->buildExpressionWithoutBinding($value, $prefix, $key, $baseKey)); @@ -212,9 +198,6 @@ protected function filterByCriteria(array &$criteria, QueryBuilder $qb): void /** * Bind parameters to generated query. - * - * @param array $criteria - * @param QueryBuilder $qb */ protected function applyFilterByCriteria(array &$criteria, QueryBuilder $qb): void { @@ -223,7 +206,7 @@ protected function applyFilterByCriteria(array &$criteria, QueryBuilder $qb): vo */ $simpleQB = new SimpleQueryBuilder($qb); foreach ($criteria as $key => $value) { - if ($key == "tags" || $key == "tagExclusive") { + if ('tags' == $key || 'tagExclusive' == $key) { continue; } @@ -236,48 +219,16 @@ protected function applyFilterByCriteria(array &$criteria, QueryBuilder $qb): vo /** * Bind translation parameter to final query. - * - * @param QueryBuilder $qb - * @param TranslationInterface|null $translation */ protected function applyTranslationByTag( QueryBuilder $qb, - TranslationInterface $translation = null + ?TranslationInterface $translation = null, ): void { if (null !== $translation) { $qb->setParameter('translation', $translation); } } - /** - * Just like the findBy method but with a given Translation - * - * If no translation nor authorizationChecker is given, the vanilla `findBy` - * method will be called instead. - * - * @param array $criteria - * @param array|null $orderBy - * @param int|null $limit - * @param int|null $offset - * @param TranslationInterface|null $translation - * @return array|Paginator - */ - public function findByWithTranslation( - array $criteria, - array $orderBy = null, - ?int $limit = null, - ?int $offset = null, - TranslationInterface $translation = null - ): array|Paginator { - return $this->findBy( - $criteria, - $orderBy, - $limit, - $offset, - $translation - ); - } - /** * Just like the findBy method but with relational criteria. * @@ -303,20 +254,18 @@ public function findByWithTranslation( * * `tags => [$tag1, $tag2]` * * `tags => [$tag1, $tag2], tagExclusive => true` * - * @param array $criteria - * @param array|null $orderBy * @param int|null $limit * @param int|null $offset - * @param TranslationInterface|null $translation - * @return array|Paginator + * + * @return array */ public function findBy( array $criteria, - array $orderBy = null, + ?array $orderBy = null, $limit = null, $offset = null, - TranslationInterface $translation = null - ): array|Paginator { + ?TranslationInterface $translation = null, + ): array { $qb = $this->getContextualQueryWithTranslation( $criteria, $orderBy, @@ -335,38 +284,178 @@ public function findBy( $this->dispatchQueryEvent($query); if ( - null !== $limit && - null !== $offset + null !== $limit + && null !== $offset ) { /* * We need to use Doctrine paginator * if a limit is set because of the default inner join */ - return new Paginator($query); + return (new Paginator($query))->getIterator()->getArrayCopy(); } else { return $query->getResult(); } } + /** + * @return array + */ + public function findByAsNodeTreeDto( + array $criteria, + ?array $orderBy = null, + ?int $limit = null, + ?int $offset = null, + ?TranslationInterface $translation = null, + ): array { + $qb = $this->getContextualQueryWithTranslation( + $criteria, + $orderBy, + $limit, + $offset, + $translation + ); + + $qb->setCacheable(true); + $this->dispatchQueryBuilderEvent($qb, $this->getEntityName()); + $this->applyFilterByTag($criteria, $qb); + $this->applyFilterByCriteria($criteria, $qb); + $this->applyTranslationByTag($qb, $translation); + + $this->alterQueryBuilderAsNodeTreeDto($qb); + + // @phpstan-ignore-next-line + $query = $qb->getQuery(); + $this->dispatchQueryEvent($query); + + return $query->getResult(); + } + + /** + * @param string $pattern Search pattern + * @param array $criteria Additional criteria + * + * @return array + * + * @psalm-return array + */ + public function searchByAsNodeTreeDto( + string $pattern, + array $criteria = [], + array $orders = [], + ?int $limit = null, + ?int $offset = null, + string $alias = EntityRepository::DEFAULT_ALIAS, + ): array { + $qb = $this->createQueryBuilder($alias); + $qb = $this->createSearchBy($pattern, $qb, $criteria, $alias); + + // Add ordering + foreach ($orders as $key => $value) { + if ( + (\str_starts_with($key, 'node.') || \str_starts_with($key, static::NODE_ALIAS.'.')) + && $this->hasJoinedNode($qb, $alias) + ) { + $key = preg_replace('#^node\.#', static::NODE_ALIAS.'.', $key); + $qb->addOrderBy($key, $value); + } elseif ( + \str_starts_with($key, static::NODESSOURCES_ALIAS.'.') + && $this->hasJoinedNodesSources($qb, $alias) + ) { + $qb->addOrderBy($key, $value); + } else { + $qb->addOrderBy($alias.'.'.$key, $value); + } + } + if (null !== $offset) { + $qb->setFirstResult($offset); + } + if (null !== $limit) { + $qb->setMaxResults($limit); + } + + $this->dispatchQueryBuilderEvent($qb, $this->getEntityName()); + $this->applyFilterByCriteria($criteria, $qb); + + $this->alterQueryBuilderAsNodeTreeDto($qb, $alias); + + $query = $qb->getQuery(); + $this->dispatchQueryEvent($query); + + return $query->getResult(); + } + + protected function alterQueryBuilderAsNodeTreeDto(QueryBuilder $qb, string $alias = self::NODE_ALIAS): QueryBuilder + { + if (!$this->hasJoinedNodeType($qb, $alias)) { + $qb->innerJoin($alias.'.nodeType', self::NODETYPE_ALIAS); + } + if (!$this->hasJoinedNodesSources($qb, $alias)) { + $qb->innerJoin($alias.'.nodeSources', self::NODESSOURCES_ALIAS); + } + + $qb->select(sprintf( + <<createQueryBuilder(self::NODE_ALIAS); $qb->addSelect(self::NODESSOURCES_ALIAS); @@ -382,15 +471,15 @@ protected function getContextualQueryWithTranslation( // Add ordering if (null !== $orderBy) { foreach ($orderBy as $key => $value) { - if (str_starts_with($key, self::NODESSOURCES_ALIAS . '.')) { + if (str_starts_with($key, self::NODESSOURCES_ALIAS.'.')) { $qb->addOrderBy($key, $value); - } elseif (str_starts_with($key, self::NODETYPE_ALIAS . '.')) { + } elseif (str_starts_with($key, self::NODETYPE_ALIAS.'.')) { if (!$this->hasJoinedNodeType($qb, self::NODE_ALIAS)) { - $qb->innerJoin(self::NODE_ALIAS . '.nodeType', self::NODETYPE_ALIAS); + $qb->innerJoin(self::NODE_ALIAS.'.nodeType', self::NODETYPE_ALIAS); } $qb->addOrderBy($key, $value); } else { - $qb->addOrderBy(self::NODE_ALIAS . '.' . $key, $value); + $qb->addOrderBy(self::NODE_ALIAS.'.'.$key, $value); } } } @@ -411,14 +500,11 @@ protected function getContextualQueryWithTranslation( * If no translation nor authorizationChecker is given, the vanilla `findOneBy` * method will be called instead. * - * @param array $criteria - * @param TranslationInterface|null $translation - * @return null|Node * @throws NonUniqueResultException */ public function findOneByWithTranslation( array $criteria, - TranslationInterface $translation = null + ?TranslationInterface $translation = null, ): ?Node { return $this->findOneBy( $criteria, @@ -430,16 +516,12 @@ public function findOneByWithTranslation( /** * Just like the findOneBy method but with relational criteria. * - * @param array $criteria - * @param array|null $orderBy - * @param TranslationInterface|null $translation - * @return null|Node * @throws NonUniqueResultException */ public function findOneBy( array $criteria, - array $orderBy = null, - TranslationInterface $translation = null + ?array $orderBy = null, + ?TranslationInterface $translation = null, ): ?Node { $qb = $this->getContextualQueryWithTranslation( $criteria, @@ -464,14 +546,11 @@ public function findOneBy( /** * Find one Node with its Id and a given translation. * - * @param int $nodeId - * @param TranslationInterface $translation - * @return null|Node * @throws NonUniqueResultException */ public function findWithTranslation( int $nodeId, - TranslationInterface $translation + TranslationInterface $translation, ): ?Node { $qb = $this->createQueryBuilder(self::NODE_ALIAS); $qb->select('n, ns') @@ -491,12 +570,10 @@ public function findWithTranslation( /** * Find one Node with its Id and the default translation. * - * @param int $nodeId - * @return null|Node * @throws NonUniqueResultException */ public function findWithDefaultTranslation( - int $nodeId + int $nodeId, ): ?Node { $qb = $this->createQueryBuilder(self::NODE_ALIAS); $qb->select('n, ns') @@ -517,16 +594,13 @@ public function findWithDefaultTranslation( /** * Find one Node with its nodeName and a given translation. * - * @param string $nodeName - * @param TranslationInterface $translation - * - * @return null|Node * @throws NonUniqueResultException + * * @deprecated Use findNodeTypeNameAndSourceIdByIdentifier */ public function findByNodeNameWithTranslation( string $nodeName, - TranslationInterface $translation + TranslationInterface $translation, ): ?Node { $qb = $this->createQueryBuilder(self::NODE_ALIAS); $qb->select('n, ns') @@ -546,18 +620,15 @@ public function findByNodeNameWithTranslation( /** * Find one node using its nodeName and a translation, or a unique URL alias. * - * @param string $identifier - * @param TranslationInterface|null $translation - * @param bool $availableTranslation - * @param bool $allowNonReachableNodes * @return array|null Array with node-type "name" and node-source "id" + * * @throws NonUniqueResultException */ public function findNodeTypeNameAndSourceIdByIdentifier( string $identifier, ?TranslationInterface $translation, bool $availableTranslation = false, - bool $allowNonReachableNodes = true + bool $allowNonReachableNodes = true, ): ?array { $qb = $this->createQueryBuilder(self::NODE_ALIAS); $qb->select('nt.name, ns.id') @@ -591,20 +662,19 @@ public function findNodeTypeNameAndSourceIdByIdentifier( $query = $qb->getQuery(); $query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true); $query->setHydrationMode(Query::HYDRATE_ARRAY); + return $query->getOneOrNullResult(); } /** * Find one Node with its nodeName and the default translation. * - * @param string $nodeName - * - * @return null|Node * @throws NonUniqueResultException + * * @deprecated Use findNodeTypeNameAndSourceIdByIdentifier */ public function findByNodeNameWithDefaultTranslation( - string $nodeName + string $nodeName, ): ?Node { $qb = $this->createQueryBuilder(self::NODE_ALIAS); $qb->select('n, ns') @@ -625,12 +695,10 @@ public function findByNodeNameWithDefaultTranslation( /** * Find the Home node with a given translation. * - * @param TranslationInterface|null $translation - * @return null|Node * @throws NonUniqueResultException */ public function findHomeWithTranslation( - TranslationInterface $translation = null + ?TranslationInterface $translation = null, ): ?Node { if (null === $translation) { return $this->findHomeWithDefaultTranslation(); @@ -654,7 +722,6 @@ public function findHomeWithTranslation( /** * Find the Home node with the default translation. * - * @return null|Node * @throws NonUniqueResultException */ public function findHomeWithDefaultTranslation(): ?Node @@ -675,25 +742,20 @@ public function findHomeWithDefaultTranslation(): ?Node return $qb->getQuery()->getOneOrNullResult(); } - /** - * @param TranslationInterface $translation - * @param Node|null $parent - * @return array - */ public function findByParentWithTranslation( TranslationInterface $translation, - Node $parent = null + ?Node $parent = null, ): array { $qb = $this->createQueryBuilder(self::NODE_ALIAS); $qb->select('n, ns, ua') ->innerJoin('n.nodeSources', self::NODESSOURCES_ALIAS) - ->leftJoin(self::NODESSOURCES_ALIAS . '.urlAliases', 'ua') + ->leftJoin(self::NODESSOURCES_ALIAS.'.urlAliases', 'ua') ->andWhere($qb->expr()->eq('ns.translation', ':translation')) ->setParameter('translation', $translation) ->addOrderBy('n.position', 'ASC') ->setCacheable(true); - if ($parent === null) { + if (null === $parent) { $qb->andWhere($qb->expr()->isNull('n.parent')); } else { $qb->andWhere($qb->expr()->eq('n.parent', ':parent')) @@ -706,10 +768,9 @@ public function findByParentWithTranslation( } /** - * @param Node|null $parent * @return Node[] */ - public function findByParentWithDefaultTranslation(Node $parent = null): array + public function findByParentWithDefaultTranslation(?Node $parent = null): array { $qb = $this->createQueryBuilder(self::NODE_ALIAS); $qb->select('n, ns') @@ -719,7 +780,7 @@ public function findByParentWithDefaultTranslation(Node $parent = null): array ->addOrderBy('n.position', 'ASC') ->setCacheable(true); - if ($parent === null) { + if (null === $parent) { $qb->andWhere($qb->expr()->isNull('n.parent')); } else { $qb->andWhere($qb->expr()->eq('n.parent', ':parent')) @@ -732,9 +793,6 @@ public function findByParentWithDefaultTranslation(Node $parent = null): array } /** - * @param string $urlAliasAlias - * - * @return null|Node * @throws NonUniqueResultException */ public function findOneWithAliasAndAvailableTranslation(string $urlAliasAlias): ?Node @@ -759,7 +817,6 @@ public function findOneWithAliasAndAvailableTranslation(string $urlAliasAlias): /** * @param string $urlAliasAlias * - * @return null|Node * @throws NonUniqueResultException */ public function findOneWithAlias($urlAliasAlias): ?Node @@ -782,8 +839,7 @@ public function findOneWithAlias($urlAliasAlias): ?Node /** * @param string $nodeName * - * @return bool - * @throws NonUniqueResultException|\Doctrine\ORM\NoResultException + * @throws NonUniqueResultException|NoResultException */ public function exists($nodeName): bool { @@ -798,13 +854,11 @@ public function exists($nodeName): bool } /** - * @param Node $node - * @param NodeTypeFieldInterface $field * @return Node[] */ public function findByNodeAndField( Node $node, - NodeTypeFieldInterface $field + NodeTypeFieldInterface $field, ): array { $qb = $this->createQueryBuilder(self::NODE_ALIAS); $qb->select(self::NODE_ALIAS) @@ -822,16 +876,10 @@ public function findByNodeAndField( return $qb->getQuery()->getResult(); } - /** - * @param Node $node - * @param NodeTypeFieldInterface $field - * @param TranslationInterface $translation - * @return array - */ public function findByNodeAndFieldAndTranslation( Node $node, NodeTypeFieldInterface $field, - TranslationInterface $translation + TranslationInterface $translation, ): array { $qb = $this->createQueryBuilder(self::NODE_ALIAS); $qb->select('n, ns') @@ -852,14 +900,9 @@ public function findByNodeAndFieldAndTranslation( return $qb->getQuery()->getResult(); } - /** - * @param Node $node - * @param NodeTypeFieldInterface $field - * @return array - */ public function findByReverseNodeAndField( Node $node, - NodeTypeFieldInterface $field + NodeTypeFieldInterface $field, ): array { $qb = $this->createQueryBuilder(self::NODE_ALIAS); $qb->select(self::NODE_ALIAS) @@ -877,16 +920,10 @@ public function findByReverseNodeAndField( return $qb->getQuery()->getResult(); } - /** - * @param Node $node - * @param NodeTypeFieldInterface $field - * @param TranslationInterface $translation - * @return array - */ public function findByReverseNodeAndFieldAndTranslation( Node $node, NodeTypeFieldInterface $field, - TranslationInterface $translation + TranslationInterface $translation, ): array { $qb = $this->createQueryBuilder(self::NODE_ALIAS); $qb->select('n, ns') @@ -908,11 +945,11 @@ public function findByReverseNodeAndFieldAndTranslation( } /** - * @param Node $node * @return array + * * @internal Use NodeOffspringResolverInterface service instead */ - public function findAllOffspringIdByNode(Node $node): array + public function findAllOffspringIdByNode(NodeInterface $node): array { $theOffsprings = []; $in = \array_filter([(int) $node->getId()]); @@ -927,32 +964,25 @@ public function findAllOffspringIdByNode(Node $node): array $result = $subQb->getQuery()->getScalarResult(); $in = []; - //For memory optimizations + // For memory optimizations foreach ($result as $item) { $in[] = (int) $item['id']; } } while (!empty($in)); + return $theOffsprings; } /** * Find all node’ parents with criteria and ordering. - * - * @param Node $node - * @param array $criteria - * @param array|null $orderBy - * @param int|null $limit - * @param int|null $offset - * @param TranslationInterface|null $translation - * @return array|Paginator|null */ public function findAllNodeParentsBy( Node $node, array $criteria, - array $orderBy = null, + ?array $orderBy = null, ?int $limit = null, ?int $offset = null, - TranslationInterface $translation = null + ?TranslationInterface $translation = null, ): array|Paginator|null { $parentsId = $this->findAllParentsIdByNode($node); if (count($parentsId) > 0) { @@ -971,7 +1001,6 @@ public function findAllNodeParentsBy( } /** - * @param Node $node * @return array */ public function findAllParentsIdByNode(Node $node): array @@ -994,27 +1023,25 @@ public function findAllParentsIdByNode(Node $node): array * @param QueryBuilder $qb QueryBuilder to pass * @param array $criteria Additional criteria * @param string $alias SQL query table alias - * - * @return QueryBuilder */ protected function createSearchBy( string $pattern, QueryBuilder $qb, array &$criteria = [], - string $alias = "obj" + string $alias = 'obj', ): QueryBuilder { $this->classicLikeComparison($pattern, $qb, $alias); /* * Search in translations */ - $qb->innerJoin($alias . '.nodeSources', self::NODESSOURCES_ALIAS); + $qb->innerJoin($alias.'.nodeSources', self::NODESSOURCES_ALIAS); $criteriaFields = []; foreach (self::getSearchableColumnsNames($this->_em->getClassMetadata(NodesSources::class)) as $field) { - $criteriaFields[$field] = '%' . strip_tags(\mb_strtolower($pattern)) . '%'; + $criteriaFields[$field] = '%'.strip_tags(\mb_strtolower($pattern)).'%'; } foreach ($criteriaFields as $key => $value) { - $fullKey = sprintf('LOWER(%s)', self::NODESSOURCES_ALIAS . '.' . $key); + $fullKey = sprintf('LOWER(%s)', self::NODESSOURCES_ALIAS.'.'.$key); $qb->orWhere($qb->expr()->like($fullKey, $qb->expr()->literal($value))); } @@ -1024,21 +1051,21 @@ protected function createSearchBy( if (isset($criteria['tags'])) { if ($criteria['tags'] instanceof PersistableInterface) { $qb->innerJoin( - $alias . '.nodesTags', + $alias.'.nodesTags', 'ntg', Expr\Join::WITH, $qb->expr()->eq('ntg.tag', (int) $criteria['tags']->getId()) ); } elseif (is_array($criteria['tags'])) { $qb->innerJoin( - $alias . '.nodesTags', + $alias.'.nodesTags', 'ntg', Expr\Join::WITH, $qb->expr()->in('ntg.tag', $criteria['tags']) ); } elseif (is_integer($criteria['tags'])) { $qb->innerJoin( - $alias . '.nodesTags', + $alias.'.nodesTags', 'ntg', Expr\Join::WITH, $qb->expr()->eq('ntg.tag', (int) $criteria['tags']) @@ -1068,20 +1095,20 @@ protected function prepareComparisons(array &$criteria, QueryBuilder $qb, string if (!$event->isPropagationStopped()) { $baseKey = $simpleQB->getParameterKey($key); - if ($key == 'translation') { + if ('translation' == $key) { if (!$this->hasJoinedNodesSources($qb, $alias)) { - $qb->innerJoin($alias . '.nodeSources', self::NODESSOURCES_ALIAS); + $qb->innerJoin($alias.'.nodeSources', self::NODESSOURCES_ALIAS); } $qb->andWhere($simpleQB->buildExpressionWithoutBinding( $value, - self::NODESSOURCES_ALIAS . '.', + self::NODESSOURCES_ALIAS.'.', $key, $baseKey )); } else { $qb->andWhere($simpleQB->buildExpressionWithoutBinding( $value, - $alias . '.', + $alias.'.', $key, $baseKey )); @@ -1097,12 +1124,10 @@ protected function prepareComparisons(array &$criteria, QueryBuilder $qb, string * * Parent can be null for node root * - * @param Node|null $parent - * @return int * @throws NonUniqueResultException * @throws NoResultException */ - public function findLatestPositionInParent(Node $parent = null): int + public function findLatestPositionInParent(?Node $parent = null): int { $qb = $this->createQueryBuilder('n'); $qb->select($qb->expr()->max('n.position')); @@ -1120,14 +1145,12 @@ public function findLatestPositionInParent(Node $parent = null): int /** * Use by UniqueEntity Validator to bypass node status query filtering. * - * @param array $criteria - * @return Node|null * @throws NonUniqueResultException */ public function findOneWithoutSecurity(array $criteria): ?Node { $this->setDisplayingAllNodesStatuses(true); - if (count($criteria) === 1 && !empty($criteria['nodeName'])) { + if (1 === count($criteria) && !empty($criteria['nodeName'])) { /* * Test if nodeName is used as an url-alias too */ @@ -1143,35 +1166,37 @@ public function findOneWithoutSecurity(array $criteria): ?Node ->setParameter('nodeName', $nodeName) ->setMaxResults(1) ->setCacheable(true); - ; + return $qb->getQuery()->getOneOrNullResult(); } + return $this->findOneBy($criteria); } protected function classicLikeComparison( string $pattern, QueryBuilder $qb, - string $alias = EntityRepository::DEFAULT_ALIAS + string $alias = EntityRepository::DEFAULT_ALIAS, ): QueryBuilder { $qb = parent::classicLikeComparison($pattern, $qb, $alias); $qb - ->leftJoin($alias . '.attributeValues', 'av') + ->leftJoin($alias.'.attributeValues', 'av') ->leftJoin('av.attributeValueTranslations', 'avt') ; - $value = '%' . strip_tags(\mb_strtolower($pattern)) . '%'; + $value = '%'.strip_tags(\mb_strtolower($pattern)).'%'; $qb->orWhere($qb->expr()->like('LOWER(avt.value)', $qb->expr()->literal($value))); - $qb->orWhere($qb->expr()->like('LOWER(' . $alias . '.nodeName)', $qb->expr()->literal($value))); + $qb->orWhere($qb->expr()->like('LOWER('.$alias.'.nodeName)', $qb->expr()->literal($value))); + return $qb; } /** - * Get previous node from hierarchy + * Get previous node from hierarchy. */ public function findPreviousNode( Node $node, ?array $criteria = null, - ?array $order = null + ?array $order = null, ): ?Node { if ($node->getPosition() <= 1) { return null; @@ -1208,7 +1233,7 @@ public function findPreviousNode( public function findNextNode( Node $node, ?array $criteria = null, - ?array $order = null + ?array $order = null, ): ?Node { if (null === $criteria) { $criteria = []; diff --git a/src/Repository/NodeTypeFieldRepository.php b/src/Repository/NodeTypeFieldRepository.php index 3e219678..75ad2266 100644 --- a/src/Repository/NodeTypeFieldRepository.php +++ b/src/Repository/NodeTypeFieldRepository.php @@ -12,22 +12,17 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** - * @package RZ\Roadiz\CoreBundle\Repository * @extends EntityRepository */ final class NodeTypeFieldRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, NodeTypeField::class, $dispatcher); } - /** - * @param NodeTypeInterface|null $nodeType - * @return array - */ public function findAvailableGroupsForNodeType(?NodeTypeInterface $nodeType): array { if (null === $nodeType) { @@ -44,10 +39,6 @@ public function findAvailableGroupsForNodeType(?NodeTypeInterface $nodeType): ar return $query->getScalarResult(); } - /** - * @param NodeTypeInterface|null $nodeType - * @return array - */ public function findAllNotUniversal(?NodeTypeInterface $nodeType): array { if (null === $nodeType) { @@ -63,10 +54,6 @@ public function findAllNotUniversal(?NodeTypeInterface $nodeType): array return $qb->getQuery()->getResult(); } - /** - * @param NodeTypeInterface|null $nodeType - * @return array - */ public function findAllUniversal(?NodeTypeInterface $nodeType): array { if (null === $nodeType) { @@ -87,9 +74,6 @@ public function findAllUniversal(?NodeTypeInterface $nodeType): array * * Parent can be null for tag root * - * @param NodeTypeInterface|null $nodeType - * - * @return int * @throws NoResultException * @throws NonUniqueResultException */ diff --git a/src/Repository/NodeTypeRepository.php b/src/Repository/NodeTypeRepository.php index 5b15f4d3..39d5f868 100644 --- a/src/Repository/NodeTypeRepository.php +++ b/src/Repository/NodeTypeRepository.php @@ -9,20 +9,17 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** - * @package RZ\Roadiz\CoreBundle\Repository * @extends EntityRepository */ final class NodeTypeRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, NodeType::class, $dispatcher); } - /** - * @return array - */ + public function findAll(): array { $qb = $this->createQueryBuilder('nt'); diff --git a/src/Repository/NodesCustomFormsRepository.php b/src/Repository/NodesCustomFormsRepository.php index 0164634b..ce7b6b13 100644 --- a/src/Repository/NodesCustomFormsRepository.php +++ b/src/Repository/NodesCustomFormsRepository.php @@ -11,24 +11,21 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** - * @package RZ\Roadiz\CoreBundle\Repository * @extends EntityRepository<\RZ\Roadiz\CoreBundle\Entity\NodesCustomForms> */ final class NodesCustomFormsRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, NodesCustomForms::class, $dispatcher); } /** - * @param Node $node - * @param NodeTypeFieldInterface $field - * @return int * @throws \Doctrine\ORM\NoResultException * @throws \Doctrine\ORM\NonUniqueResultException + * * @deprecated Use getLatestPositionForFieldName instead */ public function getLatestPosition(Node $node, NodeTypeFieldInterface $field): int diff --git a/src/Repository/NodesSourcesDocumentsRepository.php b/src/Repository/NodesSourcesDocumentsRepository.php index 81ba862a..b357cf49 100644 --- a/src/Repository/NodesSourcesDocumentsRepository.php +++ b/src/Repository/NodesSourcesDocumentsRepository.php @@ -19,17 +19,15 @@ final class NodesSourcesDocumentsRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, NodesSourcesDocuments::class, $dispatcher); } /** - * @param NodesSources $nodeSource - * @param NodeTypeFieldInterface $field - * @return int * @throws NoResultException * @throws NonUniqueResultException + * * @deprecated Use getLatestPositionForFieldName instead */ public function getLatestPosition(NodesSources $nodeSource, NodeTypeFieldInterface $field): int diff --git a/src/Repository/NodesSourcesRepository.php b/src/Repository/NodesSourcesRepository.php index 088a52cd..e520b814 100644 --- a/src/Repository/NodesSourcesRepository.php +++ b/src/Repository/NodesSourcesRepository.php @@ -17,6 +17,7 @@ use RZ\Roadiz\CoreBundle\Doctrine\ORM\SimpleQueryBuilder; use RZ\Roadiz\CoreBundle\Entity\Node; use RZ\Roadiz\CoreBundle\Entity\NodesSources; +use RZ\Roadiz\CoreBundle\Enum\NodeStatus; use RZ\Roadiz\CoreBundle\Exception\SolrServerNotAvailableException; use RZ\Roadiz\CoreBundle\Logger\Entity\Log; use RZ\Roadiz\CoreBundle\Preview\PreviewResolverInterface; @@ -32,7 +33,9 @@ * EntityRepository that implements search engine query with Solr. * * @template T of NodesSources + * * @extends StatusAwareRepository + * * @template-extends StatusAwareRepository */ class NodesSourcesRepository extends StatusAwareRepository @@ -40,28 +43,21 @@ class NodesSourcesRepository extends StatusAwareRepository private ?NodeSourceSearchHandlerInterface $nodeSourceSearchHandler; /** - * @param ManagerRegistry $registry - * @param PreviewResolverInterface $previewResolver - * @param EventDispatcherInterface $dispatcher - * @param Security $security - * @param NodeSourceSearchHandlerInterface|null $nodeSourceSearchHandler + * @param class-string $entityClass */ public function __construct( ManagerRegistry $registry, PreviewResolverInterface $previewResolver, EventDispatcherInterface $dispatcher, Security $security, - ?NodeSourceSearchHandlerInterface $nodeSourceSearchHandler + ?NodeSourceSearchHandlerInterface $nodeSourceSearchHandler, + string $entityClass = NodesSources::class, ) { - parent::__construct($registry, NodesSources::class, $previewResolver, $dispatcher, $security); + parent::__construct($registry, $entityClass, $previewResolver, $dispatcher, $security); $this->nodeSourceSearchHandler = $nodeSourceSearchHandler; } /** - * @param QueryBuilder $qb - * @param string $property - * @param mixed $value - * * @return Event */ protected function dispatchQueryBuilderBuildEvent(QueryBuilder $qb, string $property, mixed $value): object @@ -73,10 +69,6 @@ protected function dispatchQueryBuilderBuildEvent(QueryBuilder $qb, string $prop } /** - * @param QueryBuilder $qb - * @param string $property - * @param mixed $value - * * @return Event */ protected function dispatchQueryBuilderApplyEvent(QueryBuilder $qb, string $property, mixed $value): object @@ -88,8 +80,6 @@ protected function dispatchQueryBuilderApplyEvent(QueryBuilder $qb, string $prop } /** - * @param Query $query - * * @return Event */ protected function dispatchQueryEvent(Query $query): object @@ -102,16 +92,13 @@ protected function dispatchQueryEvent(Query $query): object /** * Add a tag filtering to queryBuilder. - * - * @param array $criteria - * @param QueryBuilder $qb */ protected function filterByTag(array &$criteria, QueryBuilder $qb): void { if (key_exists('tags', $criteria)) { if (!$this->hasJoinedNode($qb, static::NODESSOURCES_ALIAS)) { $qb->innerJoin( - static::NODESSOURCES_ALIAS . '.node', + static::NODESSOURCES_ALIAS.'.node', static::NODE_ALIAS ); } @@ -136,25 +123,23 @@ protected function filterByTag(array &$criteria, QueryBuilder $qb): void * * * `node.published => true` * * `node.nodeName => 'page1'` - * - * @param array $criteria - * @param QueryBuilder $qb */ protected function filterByCriteria( array &$criteria, - QueryBuilder $qb + QueryBuilder $qb, ): void { $simpleQB = new SimpleQueryBuilder($qb); /* * Reimplementing findBy features… */ foreach ($criteria as $key => $value) { - if ($key == "tags" || $key == "tagExclusive") { + if ('tags' == $key || 'tagExclusive' == $key) { continue; } /** * Main QueryBuilder dispatch loop for * custom properties criteria. + * * @var QueryBuilderNodesSourcesBuildEvent $event */ $event = $this->dispatchQueryBuilderBuildEvent($qb, $key, $value); @@ -164,7 +149,7 @@ protected function filterByCriteria( * compute prefix for * filtering node relation fields */ - $prefix = static::NODESSOURCES_ALIAS . '.'; + $prefix = static::NODESSOURCES_ALIAS.'.'; // Dots are forbidden in field definitions $baseKey = $simpleQB->getParameterKey($key); $qb->andWhere($simpleQB->buildExpressionWithoutBinding($value, $prefix, $key, $baseKey)); @@ -174,9 +159,6 @@ protected function filterByCriteria( /** * Bind parameters to generated query. - * - * @param array $criteria - * @param QueryBuilder $qb */ protected function applyFilterByCriteria(array &$criteria, QueryBuilder $qb): void { @@ -185,7 +167,7 @@ protected function applyFilterByCriteria(array &$criteria, QueryBuilder $qb): vo */ $simpleQB = new SimpleQueryBuilder($qb); foreach ($criteria as $key => $value) { - if ($key == "tags" || $key == "tagExclusive") { + if ('tags' == $key || 'tagExclusive' == $key) { continue; } @@ -197,20 +179,15 @@ protected function applyFilterByCriteria(array &$criteria, QueryBuilder $qb): vo } } - - /** - * @param QueryBuilder $qb - * @param string $prefix - * @return QueryBuilder - */ public function alterQueryBuilderWithAuthorizationChecker( QueryBuilder $qb, - string $prefix = EntityRepository::NODESSOURCES_ALIAS + string $prefix = EntityRepository::NODESSOURCES_ALIAS, ): QueryBuilder { if (true === $this->isDisplayingAllNodesStatuses()) { if (!$this->hasJoinedNode($qb, $prefix)) { - $qb->innerJoin($prefix . '.node', static::NODE_ALIAS); + $qb->innerJoin($prefix.'.node', static::NODE_ALIAS); } + return $qb; } @@ -219,36 +196,32 @@ public function alterQueryBuilderWithAuthorizationChecker( * Forbid deleted node for backend user when authorizationChecker not null. */ if (!$this->hasJoinedNode($qb, $prefix)) { - $qb->innerJoin($prefix . '.node', static::NODE_ALIAS); + $qb->innerJoin($prefix.'.node', static::NODE_ALIAS); } - $qb->andWhere($qb->expr()->lte(static::NODE_ALIAS . '.status', Node::PUBLISHED)); + $qb->andWhere($qb->expr()->lte(static::NODE_ALIAS.'.status', ':node_status')); } else { /* * Forbid unpublished node for anonymous and not backend users. */ if (!$this->hasJoinedNode($qb, $prefix)) { - $qb->innerJoin($prefix . '.node', static::NODE_ALIAS); + $qb->innerJoin($prefix.'.node', static::NODE_ALIAS); } - $qb->andWhere($qb->expr()->eq(static::NODE_ALIAS . '.status', Node::PUBLISHED)); + $qb->andWhere($qb->expr()->eq(static::NODE_ALIAS.'.status', ':node_status')); } + $qb->setParameter('node_status', NodeStatus::PUBLISHED); + return $qb; } /** * Create a secure query with node.published = true if user is * not a Backend user. - * - * @param array $criteria - * @param array|null $orderBy - * @param int|null $limit - * @param int|null $offset - * @return QueryBuilder */ protected function getContextualQuery( array &$criteria, - array $orderBy = null, - $limit = null, - $offset = null + ?array $orderBy = null, + ?int $limit = null, + ?int $offset = null, ): QueryBuilder { $qb = $this->createQueryBuilder(static::NODESSOURCES_ALIAS); $this->alterQueryBuilderWithAuthorizationChecker($qb, static::NODESSOURCES_ALIAS); @@ -264,9 +237,9 @@ protected function getContextualQuery( foreach ($orderBy as $key => $value) { if (\str_contains($key, 'node.')) { $simpleKey = str_replace('node.', '', $key); - $qb->addOrderBy(static::NODE_ALIAS . '.' . $simpleKey, $value); + $qb->addOrderBy(static::NODE_ALIAS.'.'.$simpleKey, $value); } else { - $qb->addOrderBy(static::NODESSOURCES_ALIAS . '.' . $key, $value); + $qb->addOrderBy(static::NODESSOURCES_ALIAS.'.'.$key, $value); } } } @@ -287,7 +260,6 @@ protected function getContextualQuery( * * This method allows to pre-filter Nodes with a given translation. * - * @param array $criteria * @return QueryBuilder */ protected function getCountContextualQuery(array &$criteria) @@ -300,7 +272,7 @@ protected function getCountContextualQuery(array &$criteria) $this->filterByTag($criteria, $qb); $this->filterByCriteria($criteria, $qb); - return $qb->select($qb->expr()->countDistinct(static::NODESSOURCES_ALIAS . '.id')); + return $qb->select($qb->expr()->countDistinct(static::NODESSOURCES_ALIAS.'.id')); } /** @@ -308,9 +280,8 @@ protected function getCountContextualQuery(array &$criteria) * * @param array $criteria * - * @return int * @throws \Doctrine\ORM\NoResultException - * @throws \Doctrine\ORM\NonUniqueResultException + * @throws NonUniqueResultException */ public function countBy(mixed $criteria): int { @@ -348,18 +319,17 @@ public function countBy(mixed $criteria): int * * `tags => [$tag1, $tag2]` * * `tags => [$tag1, $tag2], tagExclusive => true` * - * @param array $criteria - * @param array|null $orderBy * @param int|null $limit * @param int|null $offset - * @return array|Paginator + * + * @return array */ public function findBy( array $criteria, - array $orderBy = null, + ?array $orderBy = null, $limit = null, - $offset = null - ) { + $offset = null, + ): array { $qb = $this->getContextualQuery( $criteria, $orderBy, @@ -370,7 +340,7 @@ public function findBy( * Eagerly fetch UrlAliases * to limit SQL query count */ - $qb->leftJoin(static::NODESSOURCES_ALIAS . '.urlAliases', 'ua') + $qb->leftJoin(static::NODESSOURCES_ALIAS.'.urlAliases', 'ua') ->addSelect('ua') ; $qb->setCacheable(true); @@ -381,14 +351,14 @@ public function findBy( $this->dispatchQueryEvent($query); if ( - null !== $limit && - null !== $offset + null !== $limit + && null !== $offset ) { /* * We need to use Doctrine paginator * if a limit is set because of the default inner join */ - return new Paginator($query); + return (new Paginator($query))->getIterator()->getArrayCopy(); } else { return $query->getResult(); } @@ -398,15 +368,11 @@ public function findBy( * A secure findOneBy with which user must be a backend user * to see unpublished nodes. * - * @param array $criteria - * @param array|null $orderBy - * - * @return null|NodesSources - * @throws \Doctrine\ORM\NonUniqueResultException + * @throws NonUniqueResultException */ public function findOneBy( array $criteria, - array $orderBy = null + ?array $orderBy = null, ): ?NodesSources { $qb = $this->getContextualQuery( $criteria, @@ -418,7 +384,7 @@ public function findOneBy( * Eagerly fetch UrlAliases * to limit SQL query count */ - $qb->leftJoin(static::NODESSOURCES_ALIAS . '.urlAliases', 'ua') + $qb->leftJoin(static::NODESSOURCES_ALIAS.'.urlAliases', 'ua') ->addSelect('ua') ; $qb->setCacheable(true); @@ -435,7 +401,8 @@ public function findOneBy( * Search nodes sources by using Solr search engine. * * @param string $query Solr query string (for example: `text:Lorem Ipsum`) - * @param int $limit Result number to fetch (default: all) + * @param int $limit Result number to fetch (default: all) + * * @return array> */ public function findBySearchQuery(string $query, int $limit = 25): array @@ -445,20 +412,22 @@ public function findBySearchQuery(string $query, int $limit = 25): array $this->nodeSourceSearchHandler->boostByUpdateDate(); $arguments = []; if ($this->isDisplayingNotPublishedNodes()) { - $arguments['status'] = ['<=', Node::PUBLISHED]; + $arguments['status'] = ['<=', NodeStatus::PUBLISHED]; } if ($this->isDisplayingAllNodesStatuses()) { - $arguments['status'] = ['<=', Node::DELETED]; + $arguments['status'] = ['<=', NodeStatus::DELETED]; } if ($limit > 0) { return $this->nodeSourceSearchHandler->search($query, $arguments, $limit)->getResultItems(); } + return $this->nodeSourceSearchHandler->search($query, $arguments, 999999)->getResultItems(); } catch (SolrServerNotAvailableException $exception) { return []; } } + return []; } @@ -466,9 +435,10 @@ public function findBySearchQuery(string $query, int $limit = 25): array * Search nodes sources by using Solr search engine * and a specific translation. * - * @param string $query Solr query string (for example: `text:Lorem Ipsum`) + * @param string $query Solr query string (for example: `text:Lorem Ipsum`) * @param TranslationInterface $translation Current translation - * @param int $limit + * @param int $limit + * * @return SearchResultsInterface */ public function findBySearchQueryAndTranslation($query, TranslationInterface $translation, $limit = 25) @@ -488,6 +458,7 @@ public function findBySearchQueryAndTranslation($query, TranslationInterface $tr return new SolrSearchResults([], $this->_em); } } + return new SolrSearchResults([], $this->_em); } @@ -495,11 +466,6 @@ public function findBySearchQueryAndTranslation($query, TranslationInterface $tr * Search Nodes-Sources using LIKE condition on title * meta-title, meta-keywords, meta-description. * - * @param string $textQuery - * @param int $limit - * @param array $nodeTypes - * @param bool $onlyVisible - * @param array $additionalCriteria * @return array */ public function findByTextQuery( @@ -507,19 +473,19 @@ public function findByTextQuery( int $limit = 0, array $nodeTypes = [], bool $onlyVisible = false, - array $additionalCriteria = [] + array $additionalCriteria = [], ) { $qb = $this->createQueryBuilder(static::NODESSOURCES_ALIAS); $qb->addSelect(static::NODE_ALIAS) ->addSelect('ua') - ->leftJoin(static::NODESSOURCES_ALIAS . '.urlAliases', 'ua') + ->leftJoin(static::NODESSOURCES_ALIAS.'.urlAliases', 'ua') ->andWhere($qb->expr()->orX( - $qb->expr()->like(static::NODESSOURCES_ALIAS . '.title', ':query'), - $qb->expr()->like(static::NODESSOURCES_ALIAS . '.metaTitle', ':query'), - $qb->expr()->like(static::NODESSOURCES_ALIAS . '.metaDescription', ':query') + $qb->expr()->like(static::NODESSOURCES_ALIAS.'.title', ':query'), + $qb->expr()->like(static::NODESSOURCES_ALIAS.'.metaTitle', ':query'), + $qb->expr()->like(static::NODESSOURCES_ALIAS.'.metaDescription', ':query') )) - ->orderBy(static::NODESSOURCES_ALIAS . '.title', 'ASC') - ->setParameter(':query', '%' . $textQuery . '%'); + ->orderBy(static::NODESSOURCES_ALIAS.'.title', 'ASC') + ->setParameter(':query', '%'.$textQuery.'%'); if ($limit > 0) { $qb->setMaxResults($limit); @@ -553,9 +519,6 @@ public function findByTextQuery( /** * Find latest updated NodesSources using Log table. - * - * @param int $maxResult - * @return Paginator */ public function findByLatestUpdated(int $maxResult = 5): Paginator { @@ -567,7 +530,7 @@ public function findByLatestUpdated(int $maxResult = 5): Paginator $query = $this->createQueryBuilder(static::NODESSOURCES_ALIAS); $query - ->andWhere($query->expr()->in(static::NODESSOURCES_ALIAS . '.id', $subQuery->getQuery()->getDQL())) + ->andWhere($query->expr()->in(static::NODESSOURCES_ALIAS.'.id', $subQuery->getQuery()->getDQL())) ->setParameter(':entityClass', NodesSources::class) ->setMaxResults($maxResult) ; @@ -578,20 +541,19 @@ public function findByLatestUpdated(int $maxResult = 5): Paginator /** * Get node-source parent according to its translation. * - * @param NodesSources $nodeSource - * * @return NodesSources|null - * @throws \Doctrine\ORM\NonUniqueResultException + * + * @throws NonUniqueResultException */ public function findParent(NodesSources $nodeSource) { $qb = $this->createQueryBuilder(static::NODESSOURCES_ALIAS); - $qb->select(static::NODESSOURCES_ALIAS . ', n, ua') - ->innerJoin(static::NODESSOURCES_ALIAS . '.node', static::NODE_ALIAS) + $qb->select(static::NODESSOURCES_ALIAS.', n, ua') + ->innerJoin(static::NODESSOURCES_ALIAS.'.node', static::NODE_ALIAS) ->innerJoin('n.children', 'cn') - ->leftJoin(static::NODESSOURCES_ALIAS . '.urlAliases', 'ua') + ->leftJoin(static::NODESSOURCES_ALIAS.'.urlAliases', 'ua') ->andWhere($qb->expr()->eq('cn.id', ':childNodeId')) - ->andWhere($qb->expr()->eq(static::NODESSOURCES_ALIAS . '.translation', ':translation')) + ->andWhere($qb->expr()->eq(static::NODESSOURCES_ALIAS.'.translation', ':translation')) ->setParameter('childNodeId', $nodeSource->getNode()->getId()) ->setParameter('translation', $nodeSource->getTranslation()) ->setMaxResults(1) @@ -601,8 +563,6 @@ public function findParent(NodesSources $nodeSource) } /** - * @param Node $node - * @param TranslationInterface|null $translation * @return mixed|null */ public function findOneByNodeAndTranslation(Node $node, ?TranslationInterface $translation) @@ -610,13 +570,13 @@ public function findOneByNodeAndTranslation(Node $node, ?TranslationInterface $t $qb = $this->createQueryBuilder(static::NODESSOURCES_ALIAS); $qb->select(static::NODESSOURCES_ALIAS) - ->andWhere($qb->expr()->eq(static::NODESSOURCES_ALIAS . '.node', ':node')) + ->andWhere($qb->expr()->eq(static::NODESSOURCES_ALIAS.'.node', ':node')) ->setMaxResults(1) ->setParameter('node', $node) ->setCacheable(true); if (null !== $translation) { - $qb->andWhere($qb->expr()->eq(static::NODESSOURCES_ALIAS . '.translation', ':translation')) + $qb->andWhere($qb->expr()->eq(static::NODESSOURCES_ALIAS.'.translation', ':translation')) ->setParameter('translation', $translation); } @@ -624,12 +584,12 @@ public function findOneByNodeAndTranslation(Node $node, ?TranslationInterface $t } /** - * @inheritdoc + * {@inheritdoc} * * Extends EntityRepository to make join possible with «node.» prefix. * Required if making search with EntityListManager and filtering by node criteria. */ - protected function prepareComparisons(array &$criteria, QueryBuilder $qb, $alias) + protected function prepareComparisons(array &$criteria, QueryBuilder $qb, string $alias): QueryBuilder { $simpleQB = new SimpleQueryBuilder($qb); @@ -644,23 +604,23 @@ protected function prepareComparisons(array &$criteria, QueryBuilder $qb, $alias $baseKey = $simpleQB->getParameterKey($key); if (\str_contains($key, 'node.nodeType.')) { if (!$this->hasJoinedNode($qb, $alias)) { - $qb->innerJoin($alias . '.node', static::NODE_ALIAS); + $qb->innerJoin($alias.'.node', static::NODE_ALIAS); } if (!$this->hasJoinedNodeType($qb, $alias)) { - $qb->innerJoin(static::NODE_ALIAS . '.nodeType', static::NODETYPE_ALIAS); + $qb->innerJoin(static::NODE_ALIAS.'.nodeType', static::NODETYPE_ALIAS); } - $prefix = static::NODETYPE_ALIAS . '.'; + $prefix = static::NODETYPE_ALIAS.'.'; $simpleKey = str_replace('node.nodeType.', '', $key); $qb->andWhere($simpleQB->buildExpressionWithoutBinding($value, $prefix, $simpleKey, $baseKey)); } elseif (\str_contains($key, 'node.')) { if (!$this->hasJoinedNode($qb, $alias)) { - $qb->innerJoin($alias . '.node', static::NODE_ALIAS); + $qb->innerJoin($alias.'.node', static::NODE_ALIAS); } - $prefix = static::NODE_ALIAS . '.'; + $prefix = static::NODE_ALIAS.'.'; $simpleKey = str_replace('node.', '', $key); $qb->andWhere($simpleQB->buildExpressionWithoutBinding($value, $prefix, $simpleKey, $baseKey)); } else { - $qb->andWhere($simpleQB->buildExpressionWithoutBinding($value, $alias . '.', $key, $baseKey)); + $qb->andWhere($simpleQB->buildExpressionWithoutBinding($value, $alias.'.', $key, $baseKey)); } } } @@ -668,14 +628,11 @@ protected function prepareComparisons(array &$criteria, QueryBuilder $qb, $alias return $qb; } - /** - * @inheritDoc - */ protected function createSearchBy( string $pattern, QueryBuilder $qb, array &$criteria = [], - string $alias = EntityRepository::DEFAULT_ALIAS + string $alias = EntityRepository::DEFAULT_ALIAS, ): QueryBuilder { $qb = parent::createSearchBy($pattern, $qb, $criteria, $alias); $this->alterQueryBuilderWithAuthorizationChecker($qb, $alias); @@ -683,29 +640,23 @@ protected function createSearchBy( return $qb; } - /** - * @inheritDoc - */ public function searchBy( string $pattern, array $criteria = [], array $orders = [], - $limit = null, - $offset = null, - string $alias = EntityRepository::DEFAULT_ALIAS - ): array|Paginator { + ?int $limit = null, + ?int $offset = null, + string $alias = EntityRepository::DEFAULT_ALIAS, + ): array { return parent::searchBy($pattern, $criteria, $orders, $limit, $offset, static::NODESSOURCES_ALIAS); } /** - * @param NodesSources $nodesSources - * @param NodeTypeFieldInterface $field * @deprecated Use findByNodesSourcesAndFieldNameAndTranslation instead - * @return array|null */ public function findByNodesSourcesAndFieldAndTranslation( NodesSources $nodesSources, - NodeTypeFieldInterface $field + NodeTypeFieldInterface $field, ): ?array { $qb = $this->createQueryBuilder(static::NODESSOURCES_ALIAS); $qb->select('ns, n, ua') @@ -727,15 +678,9 @@ public function findByNodesSourcesAndFieldAndTranslation( return $qb->getQuery()->getResult(); } - /** - * @param NodesSources $nodesSources - * @param string $fieldName - * - * @return array|null - */ public function findByNodesSourcesAndFieldNameAndTranslation( NodesSources $nodesSources, - string $fieldName + string $fieldName, ): ?array { $qb = $this->createQueryBuilder(static::NODESSOURCES_ALIAS); $qb->select('ns, n, ua') @@ -765,14 +710,14 @@ public function findByNode(Node $node): array ->innerJoin('ns.translation', static::TRANSLATION_ALIAS) ->leftJoin('ns.urlAliases', 'ua') ->andWhere($qb->expr()->eq('n.id', ':node')) - ->addOrderBy(static::TRANSLATION_ALIAS . '.defaultTranslation', 'DESC') - ->addOrderBy(static::TRANSLATION_ALIAS . '.locale', 'ASC') + ->addOrderBy(static::TRANSLATION_ALIAS.'.defaultTranslation', 'DESC') + ->addOrderBy(static::TRANSLATION_ALIAS.'.locale', 'ASC') ->setParameter('node', $node) ->setCacheable(true); $this->alterQueryBuilderWithAuthorizationChecker($qb); if (!$this->previewResolver->isPreview()) { - $qb->andWhere($qb->expr()->eq(static::TRANSLATION_ALIAS . '.available', ':available')) + $qb->andWhere($qb->expr()->eq(static::TRANSLATION_ALIAS.'.available', ':available')) ->setParameter('available', true); } @@ -782,31 +727,31 @@ public function findByNode(Node $node): array protected function classicLikeComparison( string $pattern, QueryBuilder $qb, - string $alias = EntityRepository::DEFAULT_ALIAS + string $alias = EntityRepository::DEFAULT_ALIAS, ): QueryBuilder { $qb = parent::classicLikeComparison($pattern, $qb, $alias); $qb - ->innerJoin($alias . '.node', static::NODE_ALIAS) - ->leftJoin(static::NODE_ALIAS . '.attributeValues', 'av') + ->innerJoin($alias.'.node', static::NODE_ALIAS) + ->leftJoin(static::NODE_ALIAS.'.attributeValues', 'av') ->leftJoin('av.attributeValueTranslations', 'avt') ; - $value = '%' . strip_tags(\mb_strtolower($pattern)) . '%'; + $value = '%'.strip_tags(\mb_strtolower($pattern)).'%'; $qb->orWhere($qb->expr()->like('LOWER(avt.value)', $qb->expr()->literal($value))); - $qb->orWhere($qb->expr()->like('LOWER(' . static::NODE_ALIAS . '.nodeName)', $qb->expr()->literal($value))); + $qb->orWhere($qb->expr()->like('LOWER('.static::NODE_ALIAS.'.nodeName)', $qb->expr()->literal($value))); + return $qb; } /** * Get every nodeSources parents from direct parent to farthest ancestor. * - * @param NodesSources $nodeSource - * @param array|null $criteria * @return array - * @throws \Doctrine\ORM\NonUniqueResultException + * + * @throws NonUniqueResultException */ public function findParents( NodesSources $nodeSource, - ?array $criteria = null + ?array $criteria = null, ): array { $parentsNodeSources = []; @@ -842,16 +787,15 @@ public function findParents( /** * Get children nodes sources to lock with current translation. * - * @param NodesSources $nodeSource * @param array|null $criteria Additional criteria - * @param array|null $order Non default ordering + * @param array|null $order Non default ordering * * @return Paginator|array */ public function findChildren( NodesSources $nodeSource, - array $criteria = null, - array $order = null + ?array $criteria = null, + ?array $order = null, ): Paginator|array { $defaultCriteria = [ 'node.parent' => $nodeSource->getNode(), @@ -879,17 +823,12 @@ public function findChildren( /** * Get first node-source among current node-source children. * - * @param NodesSources|null $nodeSource - * @param array|null $criteria - * @param array|null $order - * - * @return NodesSources|null * @throws NonUniqueResultException */ public function findFirstChild( ?NodesSources $nodeSource, - array $criteria = null, - array $order = null + ?array $criteria = null, + ?array $order = null, ): ?NodesSources { $defaultCriteria = [ 'node.parent' => $nodeSource?->getNode() ?? null, @@ -920,17 +859,12 @@ public function findFirstChild( /** * Get last node-source among current node-source children. * - * @param NodesSources|null $nodeSource - * @param array|null $criteria - * @param array|null $order - * - * @return NodesSources|null * @throws NonUniqueResultException */ public function findLastChild( ?NodesSources $nodeSource, - array $criteria = null, - array $order = null + ?array $criteria = null, + ?array $order = null, ): ?NodesSources { $defaultCriteria = [ 'node.parent' => $nodeSource?->getNode() ?? null, @@ -961,59 +895,46 @@ public function findLastChild( /** * Get first node-source in the same parent as current node-source. * - * @param NodesSources $nodeSource - * @param array|null $criteria - * @param array|null $order - * - * @return NodesSources|null * @throws NonUniqueResultException */ public function findFirstSibling( NodesSources $nodeSource, - array $criteria = null, - array $order = null + ?array $criteria = null, + ?array $order = null, ): ?NodesSources { if (null !== $nodeSource->getParent()) { return $this->findFirstChild($nodeSource->getParent(), $criteria, $order); } + return $this->findFirstChild(null, $criteria, $order); } /** * Get last node-source in the same parent as current node-source. * - * @param NodesSources $nodeSource - * @param array|null $criteria - * @param array|null $order - * - * @return NodesSources|null * @throws NonUniqueResultException */ public function findLastSibling( NodesSources $nodeSource, - array $criteria = null, - array $order = null + ?array $criteria = null, + ?array $order = null, ): ?NodesSources { if (null !== $nodeSource->getParent()) { return $this->findLastChild($nodeSource->getParent(), $criteria, $order); } + return $this->findLastChild(null, $criteria, $order); } /** * Get previous node-source from hierarchy. * - * @param NodesSources $nodeSource - * @param array|null $criteria - * @param array|null $order - * - * @return NodesSources|null * @throws NonUniqueResultException */ public function findPrevious( NodesSources $nodeSource, - array $criteria = null, - array $order = null + ?array $criteria = null, + ?array $order = null, ): ?NodesSources { if ($nodeSource->getNode()->getPosition() <= 1) { return null; @@ -1052,17 +973,12 @@ public function findPrevious( /** * Get next node-source from hierarchy. * - * @param NodesSources $nodeSource - * @param array|null $criteria - * @param array|null $order - * - * @return NodesSources|null * @throws NonUniqueResultException */ public function findNext( NodesSources $nodeSource, - array $criteria = null, - array $order = null + ?array $criteria = null, + ?array $order = null, ): ?NodesSources { $defaultCriteria = [ /* diff --git a/src/Repository/NodesTagsRepository.php b/src/Repository/NodesTagsRepository.php index 540478e0..f9f698f2 100644 --- a/src/Repository/NodesTagsRepository.php +++ b/src/Repository/NodesTagsRepository.php @@ -15,7 +15,7 @@ class NodesTagsRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, NodesTags::class, $dispatcher); } diff --git a/src/Repository/NodesToNodesRepository.php b/src/Repository/NodesToNodesRepository.php index edb68b93..ba1cb81e 100644 --- a/src/Repository/NodesToNodesRepository.php +++ b/src/Repository/NodesToNodesRepository.php @@ -13,24 +13,21 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** - * @package RZ\Roadiz\CoreBundle\Repository * @extends EntityRepository */ final class NodesToNodesRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, NodesToNodes::class, $dispatcher); } /** - * @param Node $node - * @param NodeTypeFieldInterface $field - * @return int * @throws NoResultException * @throws NonUniqueResultException + * * @deprecated Use getLatestPositionForFieldName instead */ public function getLatestPosition(Node $node, NodeTypeFieldInterface $field): int diff --git a/src/Repository/PrefixAwareRepository.php b/src/Repository/PrefixAwareRepository.php index 8db2f7bc..fcde69c9 100644 --- a/src/Repository/PrefixAwareRepository.php +++ b/src/Repository/PrefixAwareRepository.php @@ -4,16 +4,15 @@ namespace RZ\Roadiz\CoreBundle\Repository; -use Doctrine\ORM\Mapping\Entity; use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\Tools\Pagination\Paginator; use RZ\Roadiz\CoreBundle\Doctrine\ORM\SimpleQueryBuilder; -use RZ\Roadiz\CoreBundle\Entity\FolderTranslation; /** * Class PrefixAwareRepository for defining join-queries prefixes. * * @template TEntityClass of object + * * @extends EntityRepository */ abstract class PrefixAwareRepository extends EntityRepository @@ -33,17 +32,11 @@ abstract class PrefixAwareRepository extends EntityRepository */ private array $prefixes = []; - /** - * @return array - */ public function getPrefixes(): array { return $this->prefixes; } - /** - * @return string - */ public function getDefaultPrefix(): string { return EntityRepository::DEFAULT_ALIAS; @@ -51,8 +44,9 @@ public function getDefaultPrefix(): string /** * @param string $prefix Ex. 'node' - * @param array $joins Ex. ['n': 'obj.node'] - * @param string $type Ex. 'inner'|'left', default 'left' + * @param array $joins Ex. ['n': 'obj.node'] + * @param string $type Ex. 'inner'|'left', default 'left' + * * @return $this */ public function addPrefix(string $prefix, array $joins, string $type = 'left'): self @@ -64,14 +58,13 @@ public function addPrefix(string $prefix, array $joins, string $type = 'left'): if (!array_key_exists($prefix, $this->prefixes)) { $this->prefixes[$prefix] = [ 'joins' => $joins, - 'type' => $type + 'type' => $type, ]; } return $this; } - protected function prepareComparisons(array &$criteria, QueryBuilder $qb, string $alias): QueryBuilder { $simpleQB = new SimpleQueryBuilder($qb); @@ -92,11 +85,6 @@ protected function prepareComparisons(array &$criteria, QueryBuilder $qb, string return $qb; } - /** - * @param QueryBuilder $qb - * @param string $key - * @return array - */ protected function getRealKey(QueryBuilder $qb, string $key): array { $keyParts = explode('.', $key); @@ -117,26 +105,22 @@ protected function getRealKey(QueryBuilder $qb, string $key): array $lastPrefix = $prefix; } + return [ - 'prefix' => $lastPrefix . '.', - 'key' => $keyParts[1] + 'prefix' => $lastPrefix.'.', + 'key' => $keyParts[1], ]; } - throw new \InvalidArgumentException('"' . $keyParts[0] . '" prefix is not known for initiating joined queries.'); + throw new \InvalidArgumentException('"'.$keyParts[0].'" prefix is not known for initiating joined queries.'); } return [ - 'prefix' => $this->getDefaultPrefix() . '.', - 'key' => $key + 'prefix' => $this->getDefaultPrefix().'.', + 'key' => $key, ]; } - /** - * @param QueryBuilder $qb - * @param string $prefix - * @return bool - */ protected function hasJoinedPrefix(QueryBuilder $qb, string $prefix): bool { return $this->joinExists($qb, $this->getDefaultPrefix(), $prefix); @@ -145,19 +129,19 @@ protected function hasJoinedPrefix(QueryBuilder $qb, string $prefix): bool /** * Count entities using a Criteria object or a simple filter array. * - * @param array $criteria - * @param array|null $orderBy * @param int|null $limit * @param int|null $offset - * @return array|Paginator - * @psalm-return array|Paginator + * + * @return array + * + * @throws \Exception */ public function findBy( array $criteria, - array $orderBy = null, + ?array $orderBy = null, $limit = null, - $offset = null - ): array|Paginator { + $offset = null, + ): array { $qb = $this->createQueryBuilder($this->getDefaultPrefix()); $qb->select($this->getDefaultPrefix()); $qb = $this->prepareComparisons($criteria, $qb, $this->getDefaultPrefix()); @@ -166,7 +150,7 @@ public function findBy( if (null !== $orderBy) { foreach ($orderBy as $key => $value) { $realKey = $this->getRealKey($qb, $key); - $qb->addOrderBy($realKey['prefix'] . $realKey['key'], $value); + $qb->addOrderBy($realKey['prefix'].$realKey['key'], $value); } } if (null !== $offset) { @@ -182,14 +166,14 @@ public function findBy( $this->dispatchQueryEvent($query); if ( - null !== $limit && - null !== $offset + null !== $limit + && null !== $offset ) { /* * We need to use Doctrine paginator * if a limit is set because of the default inner join */ - return new Paginator($query); + return (new Paginator($query))->getIterator()->getArrayCopy(); } else { return $query->getResult(); } @@ -198,17 +182,14 @@ public function findBy( /** * Count entities using a Criteria object or a simple filter array. * - * @param array $criteria - * @param array|null $orderBy - * - * @return Entity * @psalm-return TEntityClass + * * @throws \Doctrine\ORM\NonUniqueResultException */ public function findOneBy( array $criteria, - array $orderBy = null - ) { + ?array $orderBy = null, + ): ?object { $qb = $this->createQueryBuilder($this->getDefaultPrefix()); $qb->select($this->getDefaultPrefix()); $qb = $this->prepareComparisons($criteria, $qb, $this->getDefaultPrefix()); @@ -217,7 +198,7 @@ public function findOneBy( if (null !== $orderBy) { foreach ($orderBy as $key => $value) { $realKey = $this->getRealKey($qb, $key); - $qb->addOrderBy($realKey['prefix'] . $realKey['key'], $value); + $qb->addOrderBy($realKey['prefix'].$realKey['key'], $value); } } @@ -231,15 +212,12 @@ public function findOneBy( } /** - * @param string $pattern Search pattern - * @param array $criteria Additional criteria - * @param array $orders - * @param integer $limit - * @param integer $offset - * @param string $alias + * @param string $pattern Search pattern + * @param array $criteria Additional criteria + * @param int $limit + * @param int $offset * - * @return array|Paginator - * @psalm-return array|Paginator + * @return array */ public function searchBy( string $pattern, @@ -247,8 +225,8 @@ public function searchBy( array $orders = [], $limit = null, $offset = null, - string $alias = EntityRepository::DEFAULT_ALIAS - ): array|Paginator { + string $alias = EntityRepository::DEFAULT_ALIAS, + ): array { $qb = $this->createQueryBuilder($alias); $qb->select($alias); $qb = $this->createSearchBy($pattern, $qb, $criteria, $alias); @@ -257,7 +235,7 @@ public function searchBy( if (null !== $orders) { foreach ($orders as $key => $value) { $realKey = $this->getRealKey($qb, $key); - $qb->addOrderBy($realKey['prefix'] . $realKey['key'], $value); + $qb->addOrderBy($realKey['prefix'].$realKey['key'], $value); } } @@ -274,14 +252,14 @@ public function searchBy( $this->dispatchQueryEvent($query); if ( - null !== $limit && - null !== $offset + null !== $limit + && null !== $offset ) { /* * We need to use Doctrine paginator * if a limit is set because of the default inner join */ - return new Paginator($query); + return (new Paginator($query))->getIterator()->getArrayCopy(); } else { return $query->getResult(); } @@ -290,7 +268,7 @@ public function searchBy( public function countSearchBy(string $pattern, array $criteria = []): int { $qb = $this->createQueryBuilder($this->getDefaultPrefix()); - $qb->select($qb->expr()->countDistinct($this->getDefaultPrefix() . '.id')); + $qb->select($qb->expr()->countDistinct($this->getDefaultPrefix().'.id')); $qb = $this->createSearchBy($pattern, $qb, $criteria); $this->dispatchQueryBuilderEvent($qb, $this->getEntityName()); @@ -301,32 +279,28 @@ public function countSearchBy(string $pattern, array $criteria = []): int /** * Create a LIKE comparison with entity texts columns. - * - * @param string $pattern - * @param QueryBuilder $qb - * @param string $alias - * @return QueryBuilder */ protected function classicLikeComparison( string $pattern, QueryBuilder $qb, - string $alias = "obj" + string $alias = 'obj', ): QueryBuilder { /* * Get fields needed for a search query */ $criteriaFields = []; foreach (static::getSearchableColumnsNames($this->getClassMetadata()) as $field) { - $criteriaFields[$field] = '%' . strip_tags(\mb_strtolower($pattern)) . '%'; + $criteriaFields[$field] = '%'.strip_tags(\mb_strtolower($pattern)).'%'; } foreach ($criteriaFields as $key => $value) { if (\is_string($key)) { $realKey = $this->getRealKey($qb, $key); - $fullKey = sprintf('LOWER(%s)', $realKey['prefix'] . $realKey['key']); + $fullKey = sprintf('LOWER(%s)', $realKey['prefix'].$realKey['key']); $qb->orWhere($qb->expr()->like($fullKey, $qb->expr()->literal($value))); } } + return $qb; } } diff --git a/src/Repository/RealmNodeRepository.php b/src/Repository/RealmNodeRepository.php index 4af3e76f..dd587146 100644 --- a/src/Repository/RealmNodeRepository.php +++ b/src/Repository/RealmNodeRepository.php @@ -13,6 +13,7 @@ * @method RealmNode|null findOneBy(array $criteria, array $orderBy = null) * @method RealmNode[] findAll() * @method RealmNode[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + * * @extends EntityRepository */ final class RealmNodeRepository extends EntityRepository diff --git a/src/Repository/RealmRepository.php b/src/Repository/RealmRepository.php index 1222df4b..3be72660 100644 --- a/src/Repository/RealmRepository.php +++ b/src/Repository/RealmRepository.php @@ -4,9 +4,10 @@ namespace RZ\Roadiz\CoreBundle\Repository; -use Doctrine\ORM\EntityRepository; +use Doctrine\Persistence\ManagerRegistry; use RZ\Roadiz\CoreBundle\Entity\Node; use RZ\Roadiz\CoreBundle\Entity\Realm; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * @method Realm|null findOneByName(string $name) @@ -14,10 +15,16 @@ * @method Realm|null findOneBy(array $criteria, array $orderBy = null) * @method Realm[] findAll() * @method Realm[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + * * @extends EntityRepository */ final class RealmRepository extends EntityRepository { + public function __construct(ManagerRegistry $registry, EventDispatcherInterface $dispatcher) + { + parent::__construct($registry, Realm::class, $dispatcher); + } + public function findByNode(Node $node): array { $qb = $this->createQueryBuilder('r'); @@ -26,30 +33,30 @@ public function findByNode(Node $node): array ->andWhere($qb->expr()->isNotNull('rn.realm')) ->setParameter('node', $node); - return $qb->getQuery()->getResult(); + return $qb->getQuery()->setCacheable(true)->getResult(); } - public function findByNodeAndBehaviour(Node $node, string $realmBehaviour): array + public function findByNodeWithSerializationGroup(Node $node): array { $qb = $this->createQueryBuilder('r'); $qb->innerJoin('r.realmNodes', 'rn') ->andWhere($qb->expr()->in('rn.node', ':node')) - ->andWhere($qb->expr()->eq('r.behaviour', ':behaviour')) ->andWhere($qb->expr()->isNotNull('rn.realm')) - ->setParameter('node', $node) - ->setParameter('behaviour', $realmBehaviour); + ->andWhere($qb->expr()->isNotNull('r.serializationGroup')) + ->setParameter('node', $node); - return $qb->getQuery()->getResult(); + return $qb->getQuery()->setCacheable(true)->getResult(); } - public function findByNodeWithSerializationGroup(Node $node): array + public function findByNodeAndBehaviour(Node $node, string $realmBehaviour): array { $qb = $this->createQueryBuilder('r'); $qb->innerJoin('r.realmNodes', 'rn') ->andWhere($qb->expr()->in('rn.node', ':node')) + ->andWhere($qb->expr()->eq('r.behaviour', ':behaviour')) ->andWhere($qb->expr()->isNotNull('rn.realm')) - ->andWhere($qb->expr()->isNotNull('r.serializationGroup')) - ->setParameter('node', $node); + ->setParameter('node', $node) + ->setParameter('behaviour', $realmBehaviour); return $qb->getQuery()->setCacheable(true)->getResult(); } diff --git a/src/Repository/RedirectionRepository.php b/src/Repository/RedirectionRepository.php index 24cf7709..bc937791 100644 --- a/src/Repository/RedirectionRepository.php +++ b/src/Repository/RedirectionRepository.php @@ -14,13 +14,14 @@ * @method Redirection|null findOneBy(array $criteria, array $orderBy = null) * @method Redirection[] findAll() * @method Redirection[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + * * @extends EntityRepository */ final class RedirectionRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, Redirection::class, $dispatcher); } diff --git a/src/Repository/RoleRepository.php b/src/Repository/RoleRepository.php index 7a0cb83d..db273a93 100644 --- a/src/Repository/RoleRepository.php +++ b/src/Repository/RoleRepository.php @@ -6,11 +6,9 @@ use Doctrine\ORM\NonUniqueResultException; use Doctrine\ORM\NoResultException; -use Doctrine\ORM\OptimisticLockException; use Doctrine\ORM\ORMException; use Doctrine\Persistence\ManagerRegistry; use RZ\Roadiz\CoreBundle\Entity\Role; -use RZ\Roadiz\CoreBundle\Entity\SettingGroup; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** @@ -20,20 +18,19 @@ * @method Role|null findOneBy(array $criteria, array $orderBy = null) * @method Role[] findAll() * @method Role[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + * * @extends EntityRepository */ final class RoleRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, Role::class, $dispatcher); } /** - * @param string $roleName - * @return int * @throws NoResultException * @throws NonUniqueResultException */ @@ -50,8 +47,6 @@ public function countByName(string $roleName): int } /** - * @param string $roleName - * @return Role * @throws NonUniqueResultException * @throws ORMException */ @@ -76,8 +71,6 @@ public function findOneByName(string $roleName): Role /** * Get every Role names except for ROLE_SUPERADMIN. - * - * @return array */ public function getAllBasicRoleName(): array { @@ -93,9 +86,7 @@ public function getAllBasicRoleName(): array } /** - * Get every Role names - * - * @return array + * Get every Role names. */ public function getAllRoleName(): array { diff --git a/src/Repository/SettingGroupRepository.php b/src/Repository/SettingGroupRepository.php index 35be698f..2623d2bf 100644 --- a/src/Repository/SettingGroupRepository.php +++ b/src/Repository/SettingGroupRepository.php @@ -14,21 +14,19 @@ * @method SettingGroup|null findOneBy(array $criteria, array $orderBy = null) * @method SettingGroup[] findAll() * @method SettingGroup[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + * * @extends EntityRepository */ final class SettingGroupRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, SettingGroup::class, $dispatcher); } /** - * @param string $name - * - * @return bool * @throws \Doctrine\ORM\NoResultException * @throws \Doctrine\ORM\NonUniqueResultException */ @@ -42,12 +40,10 @@ public function exists(string $name): bool return (bool) $query->getSingleScalarResult(); } - /** - * @return array - */ public function findAllNames(): array { $query = $this->_em->createQuery('SELECT s.name FROM RZ\Roadiz\CoreBundle\Entity\SettingGroup s'); + return array_map('current', $query->getScalarResult()); } } diff --git a/src/Repository/SettingRepository.php b/src/Repository/SettingRepository.php index 19483196..680e7d94 100644 --- a/src/Repository/SettingRepository.php +++ b/src/Repository/SettingRepository.php @@ -16,21 +16,19 @@ * @method Setting|null findOneBy(array $criteria, array $orderBy = null) * @method Setting[] findAll() * @method Setting[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + * * @extends EntityRepository */ final class SettingRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, Setting::class, $dispatcher); } /** - * @param string $name - * - * @return mixed * @throws NoResultException * @throws NonUniqueResultException */ @@ -42,15 +40,12 @@ public function getValue(string $name): mixed ->setParameter(':name', $name); $query = $builder->getQuery(); - $query->enableResultCache(3600, 'RZSettingValue_' . $name); + $query->enableResultCache(3600, 'RZSettingValue_'.$name); return $query->getSingleScalarResult(); } /** - * @param string $name - * - * @return bool * @throws NoResultException * @throws NonUniqueResultException */ @@ -62,15 +57,13 @@ public function exists(string $name): bool ->setParameter(':name', $name); $query = $builder->getQuery(); - $query->enableResultCache(3600, 'RZSettingExists_' . $name); + $query->enableResultCache(3600, 'RZSettingExists_'.$name); return (bool) $query->getSingleScalarResult(); } /** - * Get every Setting names - * - * @return array + * Get every Setting names. */ public function findAllNames(): array { diff --git a/src/Repository/StatusAwareRepository.php b/src/Repository/StatusAwareRepository.php index 8aaf6ede..252b4773 100644 --- a/src/Repository/StatusAwareRepository.php +++ b/src/Repository/StatusAwareRepository.php @@ -6,66 +6,52 @@ use Doctrine\ORM\QueryBuilder; use Doctrine\Persistence\ManagerRegistry; -use RZ\Roadiz\CoreBundle\Entity\Node; +use RZ\Roadiz\CoreBundle\Enum\NodeStatus; use RZ\Roadiz\CoreBundle\Preview\PreviewResolverInterface; use Symfony\Bundle\SecurityBundle\Security; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * @template TEntityClass of object + * * @extends EntityRepository */ abstract class StatusAwareRepository extends EntityRepository { private bool $displayNotPublishedNodes; private bool $displayAllNodesStatuses; - protected Security $security; - protected PreviewResolverInterface $previewResolver; /** - * @param ManagerRegistry $registry * @param class-string $entityClass - * @param PreviewResolverInterface $previewResolver - * @param EventDispatcherInterface $dispatcher - * @param Security $security */ public function __construct( ManagerRegistry $registry, string $entityClass, - PreviewResolverInterface $previewResolver, + protected readonly PreviewResolverInterface $previewResolver, EventDispatcherInterface $dispatcher, - Security $security + protected readonly Security $security, ) { parent::__construct($registry, $entityClass, $dispatcher); $this->displayNotPublishedNodes = false; $this->displayAllNodesStatuses = false; - $this->security = $security; - $this->previewResolver = $previewResolver; } - - /** - * @return bool - */ public function isDisplayingNotPublishedNodes(): bool { return $this->displayNotPublishedNodes; } /** - * @param bool $displayNotPublishedNodes - * @return static + * @return $this */ - public function setDisplayingNotPublishedNodes(bool $displayNotPublishedNodes) + public function setDisplayingNotPublishedNodes(bool $displayNotPublishedNodes): self { $this->displayNotPublishedNodes = $displayNotPublishedNodes; + return $this; } - /** - * @return bool - */ public function isDisplayingAllNodesStatuses(): bool { return $this->displayAllNodesStatuses; @@ -75,24 +61,18 @@ public function isDisplayingAllNodesStatuses(): bool * Switch repository to disable any security on Node status. To use ONLY in order to * view deleted and archived nodes. * - * @param bool $displayAllNodesStatuses - * - * @return static + * @return $this */ - public function setDisplayingAllNodesStatuses(bool $displayAllNodesStatuses) + public function setDisplayingAllNodesStatuses(bool $displayAllNodesStatuses): self { $this->displayAllNodesStatuses = $displayAllNodesStatuses; + return $this; } - /** - * @param QueryBuilder $qb - * @param string $prefix - * @return QueryBuilder - */ public function alterQueryBuilderWithAuthorizationChecker( QueryBuilder $qb, - string $prefix = EntityRepository::NODE_ALIAS + string $prefix = EntityRepository::NODE_ALIAS, ): QueryBuilder { if (true === $this->isDisplayingAllNodesStatuses()) { // do not filter on status @@ -103,10 +83,11 @@ public function alterQueryBuilderWithAuthorizationChecker( * and context. */ if (true === $this->isDisplayingNotPublishedNodes() || $this->previewResolver->isPreview()) { - $qb->andWhere($qb->expr()->lte($prefix . '.status', Node::PUBLISHED)); + $qb->andWhere($qb->expr()->lte($prefix.'.status', ':status')); } else { - $qb->andWhere($qb->expr()->eq($prefix . '.status', Node::PUBLISHED)); + $qb->andWhere($qb->expr()->eq($prefix.'.status', ':status')); } + $qb->setParameter('status', NodeStatus::PUBLISHED); return $qb; } diff --git a/src/Repository/TagRepository.php b/src/Repository/TagRepository.php index 6d0eef31..cdaad87e 100644 --- a/src/Repository/TagRepository.php +++ b/src/Repository/TagRepository.php @@ -17,6 +17,7 @@ use RZ\Roadiz\CoreBundle\Entity\Tag; use RZ\Roadiz\CoreBundle\Entity\TagTranslation; use RZ\Roadiz\CoreBundle\Entity\Translation; +use RZ\Roadiz\CoreBundle\Model\TagTreeDto; use RZ\Roadiz\Utils\StringHandler; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; @@ -24,22 +25,20 @@ * @method Tag|null findOneByName(string $query) * @method Tag|null find($id, $lockMode = null, $lockVersion = null) * @method Tag[] findAll() + * * @extends EntityRepository */ final class TagRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, Tag::class, $dispatcher); } /** * Add a node filtering to queryBuilder. - * - * @param array $criteria - * @param QueryBuilder $qb */ protected function filterByNodes(array &$criteria, QueryBuilder $qb): void { @@ -63,10 +62,7 @@ protected function filterByNodes(array &$criteria, QueryBuilder $qb): void } /** - * Bind node parameter to final query - * - * @param array $criteria - * @param QueryBuilder $qb + * Bind node parameter to final query. */ protected function applyFilterByNodes(array &$criteria, QueryBuilder $qb): void { @@ -74,8 +70,8 @@ protected function applyFilterByNodes(array &$criteria, QueryBuilder $qb): void if ($criteria['nodes'] instanceof Node) { $qb->setParameter('nodes', $criteria['nodes']->getId()); } elseif ( - is_array($criteria['nodes']) || - $criteria['nodes'] instanceof Collection + is_array($criteria['nodes']) + || $criteria['nodes'] instanceof Collection ) { $qb->setParameter('nodes', $criteria['nodes']); } elseif (is_integer($criteria['nodes'])) { @@ -87,9 +83,6 @@ protected function applyFilterByNodes(array &$criteria, QueryBuilder $qb): void /** * Bind parameters to generated query. - * - * @param array $criteria - * @param QueryBuilder $qb */ protected function applyFilterByCriteria(array &$criteria, QueryBuilder $qb): void { @@ -107,20 +100,16 @@ protected function applyFilterByCriteria(array &$criteria, QueryBuilder $qb): vo /** * Create filters according to any translation criteria OR argument. - * - * @param array $criteria - * @param QueryBuilder $qb - * @param TranslationInterface|null $translation */ protected function filterByTranslation( array &$criteria, QueryBuilder $qb, - TranslationInterface $translation = null + ?TranslationInterface $translation = null, ): void { if ( - isset($criteria['translation']) || - isset($criteria['translation.locale']) || - isset($criteria['translation.id']) + isset($criteria['translation']) + || isset($criteria['translation.locale']) + || isset($criteria['translation.id']) ) { $qb->leftJoin('tg.translatedTags', 'tt'); $qb->leftJoin('tt.translation', static::TRANSLATION_ALIAS); @@ -151,14 +140,11 @@ protected function filterByTranslation( } /** - * Bind translation parameter to final query - * - * @param QueryBuilder $qb - * @param TranslationInterface|null $translation + * Bind translation parameter to final query. */ protected function applyTranslationByTag( QueryBuilder $qb, - TranslationInterface $translation = null + ?TranslationInterface $translation = null, ): void { if (null !== $translation) { $qb->setParameter('translation', $translation); @@ -167,21 +153,13 @@ protected function applyTranslationByTag( /** * This method allows to pre-filter Nodes with a given translation. - * - * @param array $criteria - * @param array|null $orderBy - * @param int|null $limit - * @param int|null $offset - * @param TranslationInterface|null $translation - * - * @return QueryBuilder */ protected function getContextualQueryWithTranslation( array &$criteria, - array $orderBy = null, + ?array $orderBy = null, ?int $limit = null, ?int $offset = null, - TranslationInterface $translation = null + ?TranslationInterface $translation = null, ): QueryBuilder { $qb = $this->createQueryBuilder(EntityRepository::TAG_ALIAS); $qb->addSelect('tt'); @@ -192,7 +170,7 @@ protected function getContextualQueryWithTranslation( // Add ordering if (null !== $orderBy) { foreach ($orderBy as $key => $value) { - $qb->addOrderBy(EntityRepository::TAG_ALIAS . '.' . $key, $value); + $qb->addOrderBy(EntityRepository::TAG_ALIAS.'.'.$key, $value); } } @@ -205,17 +183,13 @@ protected function getContextualQueryWithTranslation( return $qb; } + /** * This method allows to pre-filter Nodes with a given translation. - * - * @param array $criteria - * @param TranslationInterface|null $translation - * - * @return QueryBuilder */ protected function getCountContextualQueryWithTranslation( array &$criteria, - TranslationInterface $translation = null + ?TranslationInterface $translation = null, ): QueryBuilder { $qb = $this->createQueryBuilder(EntityRepository::TAG_ALIAS); $this->filterByNodes($criteria, $qb); @@ -228,21 +202,19 @@ protected function getCountContextualQueryWithTranslation( /** * Just like the findBy method but with relational criteria. * - * @param array $criteria - * @param array|string[]|null $orderBy - * @param integer|null $limit - * @param integer|null $offset - * @param TranslationInterface|null $translation + * @param array|string[]|null $orderBy + * @param int|null $limit + * @param int|null $offset * - * @return array|Paginator + * @return array */ public function findBy( array $criteria, - array $orderBy = null, + ?array $orderBy = null, $limit = null, $offset = null, - TranslationInterface $translation = null - ): array|Paginator { + ?TranslationInterface $translation = null, + ): array { $qb = $this->getContextualQueryWithTranslation( $criteria, $orderBy, @@ -260,34 +232,88 @@ public function findBy( $this->dispatchQueryEvent($query); if ( - null !== $limit && - null !== $offset + null !== $limit + && null !== $offset ) { /* * We need to use Doctrine paginator * if a limit is set because of the default inner join */ - return new Paginator($query); + return (new Paginator($query))->getIterator()->getArrayCopy(); } else { return $query->getResult(); } } /** - * Just like the findOneBy method but with relational criteria. + * Just like the findBy method but with relational criteria. * - * @param array $criteria - * @param array|null $orderBy - * @param TranslationInterface|null $translation + * @param array|string[]|null $orderBy + * + * @return array + */ + public function findByAsTagTreeDto( + array $criteria, + ?array $orderBy = null, + ?int $limit = null, + ?int $offset = null, + ?TranslationInterface $translation = null, + ): array { + $qb = $this->getContextualQueryWithTranslation( + $criteria, + $orderBy, + $limit, + $offset, + $translation + ); + + $this->dispatchQueryBuilderEvent($qb, $this->getEntityName()); + $this->applyFilterByNodes($criteria, $qb); + $this->applyFilterByCriteria($criteria, $qb); + $this->applyTranslationByTag($qb, $translation); + $this->alterQueryBuilderAsTagTreeDto($qb); + // @phpstan-ignore-next-line + $query = $qb->getQuery(); + $this->dispatchQueryEvent($query); + + return $query->getResult(); + } + + protected function alterQueryBuilderAsTagTreeDto(QueryBuilder $qb, string $alias = self::TAG_ALIAS): QueryBuilder + { + $qb->select(sprintf( + <<getContextualQueryWithTranslation( $criteria, $orderBy, @@ -311,14 +337,13 @@ public function findOneBy( * Just like the countBy method but with relational criteria. * * @param array $criteria - * @param TranslationInterface|null $translation - * @return int + * * @throws NonUniqueResultException * @throws NoResultException */ public function countBy( mixed $criteria, - TranslationInterface $translation = null + ?TranslationInterface $translation = null, ): int { $query = $this->getCountContextualQueryWithTranslation( $criteria, @@ -335,9 +360,9 @@ public function countBy( /** * @param int $tagId - * @param TranslationInterface $translation * * @return Tag|null + * * @throws NonUniqueResultException */ public function findWithTranslation($tagId, TranslationInterface $translation) @@ -356,7 +381,6 @@ public function findWithTranslation($tagId, TranslationInterface $translation) } /** - * @param TranslationInterface $translation * @return Tag[] */ public function findAllWithTranslation(TranslationInterface $translation) @@ -426,13 +450,11 @@ public function findAllColored() '#ffffff', ]) ; + return $qb->getQuery()->getResult(); } /** - * @param Node $parentNode - * @param TranslationInterface|null $translation - * * @return Tag[] */ public function findAllLinkedToNodeChildren(Node $parentNode, ?TranslationInterface $translation = null) @@ -456,6 +478,7 @@ public function findAllLinkedToNodeChildren(Node $parentNode, ?TranslationInterf ->andWhere($qb->expr()->eq('ns.translation', ':translation')) ->setParameter('translation', $translation); } + return $qb->getQuery() ->setHint(\Doctrine\ORM\Query::HINT_FORCE_PARTIAL_LOAD, true) ->getResult() @@ -463,12 +486,9 @@ public function findAllLinkedToNodeChildren(Node $parentNode, ?TranslationInterf } /** - * @param TranslationInterface $translation - * @param Tag $parent - * * @return Tag[] */ - public function findByParentWithTranslation(TranslationInterface $translation, Tag $parent = null) + public function findByParentWithTranslation(TranslationInterface $translation, ?Tag $parent = null) { $qb = $this->createQueryBuilder('t'); $qb->select('t, tt') @@ -489,11 +509,9 @@ public function findByParentWithTranslation(TranslationInterface $translation, T } /** - * @param Tag|null $parent - * * @return Tag[] */ - public function findByParentWithDefaultTranslation(Tag $parent = null) + public function findByParentWithDefaultTranslation(?Tag $parent = null) { $qb = $this->createQueryBuilder('t'); $qb->select('t, tt') @@ -517,10 +535,9 @@ public function findByParentWithDefaultTranslation(Tag $parent = null) /** * Returns only Tags that have children. * - * @param Tag|null $parent * @return Tag[] */ - public function findByParentWithChildrenAndDefaultTranslation(Tag $parent = null) + public function findByParentWithChildrenAndDefaultTranslation(?Tag $parent = null) { $qb = $this->createQueryBuilder('t'); $qb->select('t, tt') @@ -546,45 +563,37 @@ public function findByParentWithChildrenAndDefaultTranslation(Tag $parent = null /** * Create a Criteria object from a search pattern and additional fields. * - * @param string $pattern Search pattern - * @param QueryBuilder $qb QueryBuilder to pass - * @param array $criteria Additional criteria - * @param string $alias SQL query table alias - * - * @return QueryBuilder + * @param string $pattern Search pattern + * @param QueryBuilder $qb QueryBuilder to pass + * @param array $criteria Additional criteria + * @param string $alias SQL query table alias */ protected function createSearchBy( string $pattern, QueryBuilder $qb, array &$criteria = [], - string $alias = EntityRepository::DEFAULT_ALIAS + string $alias = EntityRepository::DEFAULT_ALIAS, ): QueryBuilder { $this->classicLikeComparison($pattern, $qb, $alias); /* * Search in translations */ - $qb->leftJoin($alias . '.translatedTags', 'tt'); + $qb->leftJoin($alias.'.translatedTags', 'tt'); $criteriaFields = []; foreach (self::getSearchableColumnsNames($this->_em->getClassMetadata(TagTranslation::class)) as $field) { - $criteriaFields[$field] = '%' . strip_tags(\mb_strtolower($pattern)) . '%'; + $criteriaFields[$field] = '%'.strip_tags(\mb_strtolower($pattern)).'%'; } foreach ($criteriaFields as $key => $value) { - $fullKey = sprintf('LOWER(%s)', 'tt.' . $key); + $fullKey = sprintf('LOWER(%s)', 'tt.'.$key); $qb->orWhere($qb->expr()->like($fullKey, $qb->expr()->literal($value))); } return $this->prepareComparisons($criteria, $qb, $alias); } - /** - * @param array $criteria - * @param QueryBuilder $qb - * @param string $alias - * @return QueryBuilder - */ - protected function prepareComparisons(array &$criteria, QueryBuilder $qb, $alias) + protected function prepareComparisons(array &$criteria, QueryBuilder $qb, string $alias): QueryBuilder { $simpleQB = new SimpleQueryBuilder($qb); foreach ($criteria as $key => $value) { @@ -598,7 +607,7 @@ protected function prepareComparisons(array &$criteria, QueryBuilder $qb, $alias /* * Search in node fields */ - if ($key == 'nodes') { + if ('nodes' == $key) { continue; } @@ -615,13 +624,13 @@ protected function prepareComparisons(array &$criteria, QueryBuilder $qb, $alias /* * Search in translation fields */ - $prefix = static::TRANSLATION_ALIAS . '.'; + $prefix = static::TRANSLATION_ALIAS.'.'; $key = str_replace('translation.', '', $key); } elseif (\str_contains($key, 'nodes.')) { /* * Search in node fields */ - $prefix = static::NODE_ALIAS . '.'; + $prefix = static::NODE_ALIAS.'.'; $key = str_replace('nodes.', '', $key); } elseif (\str_contains($key, 'translatedTag.')) { /* @@ -629,7 +638,7 @@ protected function prepareComparisons(array &$criteria, QueryBuilder $qb, $alias */ $prefix = 'tt.'; $key = str_replace('translatedTag.', '', $key); - } elseif ($key === 'translation') { + } elseif ('translation' === $key) { /* * Search in translation fields */ @@ -645,10 +654,8 @@ protected function prepareComparisons(array &$criteria, QueryBuilder $qb, $alias /** * Find a tag according to the given path or create it. * - * @param string $tagPath - * @param TranslationInterface|null $translation - * * @return Tag|null + * * @throws \Doctrine\ORM\ORMException * @throws \Doctrine\ORM\OptimisticLockException */ @@ -658,7 +665,7 @@ public function findOrCreateByPath(string $tagPath, ?TranslationInterface $trans $tags = explode('/', $tagPath); $tags = array_filter($tags); - if (count($tags) === 0) { + if (0 === count($tags)) { return null; } @@ -716,10 +723,6 @@ public function findOrCreateByPath(string $tagPath, ?TranslationInterface $trans /** * Find a tag according to the given path. - * - * @param string $tagPath - * - * @return Tag|null */ public function findByPath(string $tagPath): ?Tag { @@ -746,12 +749,10 @@ public function findByPath(string $tagPath): ?Tag * * Parent can be null for tag root * - * @param Tag|null $parent - * @return int * @throws NoResultException * @throws NonUniqueResultException */ - public function findLatestPositionInParent(Tag $parent = null): int + public function findLatestPositionInParent(?Tag $parent = null): int { $qb = $this->createQueryBuilder('t'); $qb->select($qb->expr()->max('t.position')); @@ -770,8 +771,8 @@ public function findByNodesSources(NodesSources $nodesSources): array|Paginator { // @phpstan-ignore-next-line return $this->findBy([ - "nodes" => $nodesSources->getNode(), - "translation" => $nodesSources->getTranslation(), + 'nodes' => $nodesSources->getNode(), + 'translation' => $nodesSources->getTranslation(), ], [ 'position' => 'ASC', ]); diff --git a/src/Repository/TagTranslationDocumentsRepository.php b/src/Repository/TagTranslationDocumentsRepository.php index e693ca4d..f1c233d9 100644 --- a/src/Repository/TagTranslationDocumentsRepository.php +++ b/src/Repository/TagTranslationDocumentsRepository.php @@ -15,20 +15,23 @@ * @method TagTranslationDocuments|null findOneBy(array $criteria, array $orderBy = null) * @method TagTranslationDocuments[] findAll() * @method TagTranslationDocuments[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + * * @extends EntityRepository */ final class TagTranslationDocumentsRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, TagTranslationDocuments::class, $dispatcher); } + /** * @param TagTranslation $tagTranslation * - * @return integer + * @return int + * * @throws \Doctrine\ORM\NoResultException * @throws \Doctrine\ORM\NonUniqueResultException */ diff --git a/src/Repository/TagTranslationRepository.php b/src/Repository/TagTranslationRepository.php index 1683b98f..a612b924 100644 --- a/src/Repository/TagTranslationRepository.php +++ b/src/Repository/TagTranslationRepository.php @@ -14,13 +14,14 @@ * @method TagTranslation|null findOneBy(array $criteria, array $orderBy = null) * @method TagTranslation[] findAll() * @method TagTranslation[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + * * @extends EntityRepository */ final class TagTranslationRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, TagTranslation::class, $dispatcher); } diff --git a/src/Repository/TranslationRepository.php b/src/Repository/TranslationRepository.php index 75555f3f..2bcf847a 100644 --- a/src/Repository/TranslationRepository.php +++ b/src/Repository/TranslationRepository.php @@ -20,13 +20,14 @@ * @method Translation|null findOneBy(array $criteria, array $orderBy = null) * @method Translation[] findAll() * @method Translation[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + * * @extends EntityRepository */ final class TranslationRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, Translation::class, $dispatcher); } @@ -37,13 +38,12 @@ public function isLocaleValid(?string $locale): bool return false; } - return preg_match('/^[A-Za-z]{2,4}([_-][A-Za-z]{4})?([_-]([A-Za-z]{2}|[0-9]{3}))?$/', $locale) === 1; + return 1 === preg_match('/^[A-Za-z]{2,4}([_-][A-Za-z]{4})?([_-]([A-Za-z]{2}|[0-9]{3}))?$/', $locale); } /** * Get single default translation. * - * @return TranslationInterface|null * @throws NonUniqueResultException */ public function findDefault(): ?TranslationInterface @@ -83,9 +83,6 @@ public function findAllAvailable(): array } /** - * @param string $locale - * - * @return bool * @throws NonUniqueResultException * @throws NoResultException */ @@ -102,15 +99,13 @@ public function exists(string $locale): bool ->setCacheable(true); $query = $qb->getQuery(); - $query->enableResultCache(120, 'RZTranslationExists-' . $locale); + $query->enableResultCache(120, 'RZTranslationExists-'.$locale); return (bool) $query->getSingleScalarResult(); } /** * Get all available locales. - * - * @return array */ public function getAvailableLocales(): array { @@ -130,8 +125,6 @@ public function getAvailableLocales(): array /** * Get all locales. - * - * @return array */ public function getAllLocales(): array { @@ -149,8 +142,6 @@ public function getAllLocales(): array /** * Get all available locales. - * - * @return array */ public function getAvailableOverrideLocales(): array { @@ -173,8 +164,6 @@ public function getAvailableOverrideLocales(): array /** * Get all available locales. - * - * @return array */ public function getAllOverrideLocales(): array { @@ -196,8 +185,6 @@ public function getAllOverrideLocales(): array /** * Get all available translations by locale. * - * @param string $locale - * * @return TranslationInterface[] */ public function findByLocaleAndAvailable(string $locale): array @@ -206,8 +193,8 @@ public function findByLocaleAndAvailable(string $locale): array return []; } $qb = $this->createQueryBuilder(self::TRANSLATION_ALIAS); - $qb->andWhere($qb->expr()->eq(self::TRANSLATION_ALIAS . '.available', ':available')) - ->andWhere($qb->expr()->eq(self::TRANSLATION_ALIAS . '.locale', ':locale')) + $qb->andWhere($qb->expr()->eq(self::TRANSLATION_ALIAS.'.available', ':available')) + ->andWhere($qb->expr()->eq(self::TRANSLATION_ALIAS.'.locale', ':locale')) ->setParameter('available', true) ->setParameter('locale', $locale) ->setCacheable(true); @@ -215,7 +202,7 @@ public function findByLocaleAndAvailable(string $locale): array $query = $qb->getQuery(); $query->enableResultCache( 120, - 'RZTranslationAllByLocaleAndAvailable-' . $locale + 'RZTranslationAllByLocaleAndAvailable-'.$locale ); return $query->getResult(); @@ -224,7 +211,6 @@ public function findByLocaleAndAvailable(string $locale): array /** * Get all available translations by overrideLocale. * - * @param string $overrideLocale * @return TranslationInterface[] */ public function findByOverrideLocaleAndAvailable(string $overrideLocale): array @@ -233,8 +219,8 @@ public function findByOverrideLocaleAndAvailable(string $overrideLocale): array return []; } $qb = $this->createQueryBuilder(self::TRANSLATION_ALIAS); - $qb->andWhere($qb->expr()->eq(self::TRANSLATION_ALIAS . '.available', ':available')) - ->andWhere($qb->expr()->eq(self::TRANSLATION_ALIAS . '.overrideLocale', ':overrideLocale')) + $qb->andWhere($qb->expr()->eq(self::TRANSLATION_ALIAS.'.available', ':available')) + ->andWhere($qb->expr()->eq(self::TRANSLATION_ALIAS.'.overrideLocale', ':overrideLocale')) ->setParameter('available', true) ->setParameter('overrideLocale', $overrideLocale) ->setCacheable(true); @@ -242,7 +228,7 @@ public function findByOverrideLocaleAndAvailable(string $overrideLocale): array $query = $qb->getQuery(); $query->enableResultCache( 120, - 'RZTranslationAllByOverrideAndAvailable-' . $overrideLocale + 'RZTranslationAllByOverrideAndAvailable-'.$overrideLocale ); return $query->getResult(); @@ -251,30 +237,26 @@ public function findByOverrideLocaleAndAvailable(string $overrideLocale): array /** * Get one translation by locale or override locale. * - * @param string $locale - * @param string $alias - * - * @return TranslationInterface|null * @throws NonUniqueResultException */ public function findOneByLocaleOrOverrideLocale( string $locale, - string $alias = TranslationRepository::TRANSLATION_ALIAS + string $alias = TranslationRepository::TRANSLATION_ALIAS, ): ?TranslationInterface { if (!$this->isLocaleValid($locale)) { return null; } $qb = $this->createQueryBuilder($alias); $qb->andWhere($qb->expr()->orX( - $qb->expr()->eq($alias . '.locale', ':locale'), - $qb->expr()->eq($alias . '.overrideLocale', ':locale') + $qb->expr()->eq($alias.'.locale', ':locale'), + $qb->expr()->eq($alias.'.overrideLocale', ':locale') )) ->setParameter('locale', $locale) ->setMaxResults(1) ->setCacheable(true); $query = $qb->getQuery(); - $query->enableResultCache(120, 'findOneByLocaleOrOverrideLocale_' . $locale); + $query->enableResultCache(120, 'findOneByLocaleOrOverrideLocale_'.$locale); return $query->getOneOrNullResult(); } @@ -282,9 +264,6 @@ public function findOneByLocaleOrOverrideLocale( /** * Get one available translation by locale or override locale. * - * @param string $locale - * - * @return TranslationInterface|null * @throws NonUniqueResultException */ public function findOneAvailableByLocaleOrOverrideLocale(string $locale): ?TranslationInterface @@ -294,17 +273,17 @@ public function findOneAvailableByLocaleOrOverrideLocale(string $locale): ?Trans } $qb = $this->createQueryBuilder(self::TRANSLATION_ALIAS); $qb->andWhere($qb->expr()->orX( - $qb->expr()->eq(self::TRANSLATION_ALIAS . '.locale', ':locale'), - $qb->expr()->eq(self::TRANSLATION_ALIAS . '.overrideLocale', ':locale') + $qb->expr()->eq(self::TRANSLATION_ALIAS.'.locale', ':locale'), + $qb->expr()->eq(self::TRANSLATION_ALIAS.'.overrideLocale', ':locale') )) - ->andWhere($qb->expr()->eq(self::TRANSLATION_ALIAS . '.available', ':available')) + ->andWhere($qb->expr()->eq(self::TRANSLATION_ALIAS.'.available', ':available')) ->setParameter('available', true) ->setParameter('locale', $locale) ->setMaxResults(1) ->setCacheable(true); $query = $qb->getQuery(); - $query->enableResultCache(120, 'findOneAvailableByLocaleOrOverrideLocale_' . $locale); + $query->enableResultCache(120, 'findOneAvailableByLocaleOrOverrideLocale_'.$locale); return $query->getOneOrNullResult(); } @@ -312,9 +291,6 @@ public function findOneAvailableByLocaleOrOverrideLocale(string $locale): ?Trans /** * Get one available translation by locale. * - * @param string $locale - * - * @return TranslationInterface|null * @throws NonUniqueResultException */ public function findOneByLocaleAndAvailable(string $locale): ?TranslationInterface @@ -323,15 +299,15 @@ public function findOneByLocaleAndAvailable(string $locale): ?TranslationInterfa return null; } $qb = $this->createQueryBuilder(self::TRANSLATION_ALIAS); - $qb->andWhere($qb->expr()->eq(self::TRANSLATION_ALIAS . '.available', ':available')) - ->andWhere($qb->expr()->eq(self::TRANSLATION_ALIAS . '.locale', ':locale')) + $qb->andWhere($qb->expr()->eq(self::TRANSLATION_ALIAS.'.available', ':available')) + ->andWhere($qb->expr()->eq(self::TRANSLATION_ALIAS.'.locale', ':locale')) ->setParameter('available', true) ->setParameter('locale', $locale) ->setMaxResults(1) ->setCacheable(true); $query = $qb->getQuery(); - $query->enableResultCache(120, 'RZTranslationOneByLocaleAndAvailable-' . $locale); + $query->enableResultCache(120, 'RZTranslationOneByLocaleAndAvailable-'.$locale); return $query->getOneOrNullResult(); } @@ -339,9 +315,6 @@ public function findOneByLocaleAndAvailable(string $locale): ?TranslationInterfa /** * Get one available translation by overrideLocale. * - * @param string $overrideLocale - * - * @return TranslationInterface|null * @throws NonUniqueResultException */ public function findOneByOverrideLocaleAndAvailable(string $overrideLocale): ?TranslationInterface @@ -350,8 +323,8 @@ public function findOneByOverrideLocaleAndAvailable(string $overrideLocale): ?Tr return null; } $qb = $this->createQueryBuilder(self::TRANSLATION_ALIAS); - $qb->andWhere($qb->expr()->eq(self::TRANSLATION_ALIAS . '.available', ':available')) - ->andWhere($qb->expr()->eq(self::TRANSLATION_ALIAS . '.overrideLocale', ':overrideLocale')) + $qb->andWhere($qb->expr()->eq(self::TRANSLATION_ALIAS.'.available', ':available')) + ->andWhere($qb->expr()->eq(self::TRANSLATION_ALIAS.'.overrideLocale', ':overrideLocale')) ->setParameter('available', true) ->setParameter('overrideLocale', $overrideLocale) ->setMaxResults(1) @@ -360,21 +333,20 @@ public function findOneByOverrideLocaleAndAvailable(string $overrideLocale): ?Tr $query = $qb->getQuery(); $query->enableResultCache( 120, - 'RZTranslationOneByOverrideAndAvailable-' . $overrideLocale + 'RZTranslationOneByOverrideAndAvailable-'.$overrideLocale ); return $query->getOneOrNullResult(); } /** - * @param Node $node * @return TranslationInterface[] */ public function findAvailableTranslationsForNode(Node $node): array { $qb = $this->createQueryBuilder(self::TRANSLATION_ALIAS); $qb->innerJoin('t.nodeSources', self::NODESSOURCES_ALIAS) - ->andWhere($qb->expr()->eq(self::NODESSOURCES_ALIAS . '.node', ':node')) + ->andWhere($qb->expr()->eq(self::NODESSOURCES_ALIAS.'.node', ':node')) ->addOrderBy('t.defaultTranslation', 'DESC') ->addOrderBy('t.locale', 'ASC') ->setParameter('node', $node) @@ -384,7 +356,6 @@ public function findAvailableTranslationsForNode(Node $node): array } /** - * @param Tag $tag * @return TranslationInterface[] */ public function findAvailableTranslationsForTag(Tag $tag): array @@ -400,7 +371,6 @@ public function findAvailableTranslationsForTag(Tag $tag): array } /** - * @param Folder $folder * @return TranslationInterface[] */ public function findAvailableTranslationsForFolder(Folder $folder): array @@ -418,15 +388,14 @@ public function findAvailableTranslationsForFolder(Folder $folder): array /** * Find available node translations which are available too. * - * @param Node $node * @return TranslationInterface[] */ public function findStrictlyAvailableTranslationsForNode(Node $node): array { $qb = $this->createQueryBuilder(self::TRANSLATION_ALIAS); $qb->innerJoin('t.nodeSources', self::NODESSOURCES_ALIAS) - ->andWhere($qb->expr()->eq(self::NODESSOURCES_ALIAS . '.node', ':node')) - ->andWhere($qb->expr()->eq(self::TRANSLATION_ALIAS . '.available', ':available')) + ->andWhere($qb->expr()->eq(self::NODESSOURCES_ALIAS.'.node', ':node')) + ->andWhere($qb->expr()->eq(self::TRANSLATION_ALIAS.'.available', ':available')) ->addOrderBy('t.defaultTranslation', 'DESC') ->addOrderBy('t.locale', 'ASC') ->setParameter('node', $node) @@ -436,9 +405,7 @@ public function findStrictlyAvailableTranslationsForNode(Node $node): array return $qb->getQuery()->getResult(); } - /** - * @param Node $node * @return TranslationInterface[] */ public function findUnavailableTranslationsForNode(Node $node): array @@ -451,16 +418,12 @@ public function findUnavailableTranslationsForNode(Node $node): array return $qb->getQuery()->getResult(); } - /** - * @param Node $node - * @return array - */ public function findAvailableTranslationIdForNode(Node $node): array { $qb = $this->createQueryBuilder(self::TRANSLATION_ALIAS); - $qb->select(self::TRANSLATION_ALIAS . '.id') + $qb->select(self::TRANSLATION_ALIAS.'.id') ->innerJoin('t.nodeSources', self::NODESSOURCES_ALIAS) - ->andWhere($qb->expr()->eq(self::NODESSOURCES_ALIAS . '.node', ':node')) + ->andWhere($qb->expr()->eq(self::NODESSOURCES_ALIAS.'.node', ':node')) ->addOrderBy('t.defaultTranslation', 'DESC') ->addOrderBy('t.locale', 'ASC') ->setParameter('node', $node) @@ -469,14 +432,10 @@ public function findAvailableTranslationIdForNode(Node $node): array return array_map('current', $qb->getQuery()->getScalarResult()); } - /** - * @param Node $node - * @return array - */ public function findUnavailableTranslationIdForNode(Node $node): array { $qb = $this->createQueryBuilder(self::TRANSLATION_ALIAS); - $qb->select(self::TRANSLATION_ALIAS . '.id') + $qb->select(self::TRANSLATION_ALIAS.'.id') ->andWhere($qb->expr()->notIn('t.id', ':translationsId')) ->setParameter('translationsId', $this->findAvailableTranslationIdForNode($node)) ->setCacheable(true); diff --git a/src/Repository/UrlAliasRepository.php b/src/Repository/UrlAliasRepository.php index 86815976..bfef788c 100644 --- a/src/Repository/UrlAliasRepository.php +++ b/src/Repository/UrlAliasRepository.php @@ -16,13 +16,14 @@ * @method UrlAlias|null findOneBy(array $criteria, array $orderBy = null) * @method UrlAlias[] findAll() * @method UrlAlias[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + * * @extends EntityRepository */ final class UrlAliasRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, UrlAlias::class, $dispatcher); } @@ -30,8 +31,6 @@ public function __construct( /** * Get all url aliases linked to given node. * - * @param int|string|null $nodeId - * * @return iterable */ public function findAllFromNode(int|string|null $nodeId): iterable @@ -50,9 +49,6 @@ public function findAllFromNode(int|string|null $nodeId): iterable } /** - * @param string $alias - * - * @return boolean * @throws NoResultException * @throws NonUniqueResultException */ diff --git a/src/Repository/UserLogEntryRepository.php b/src/Repository/UserLogEntryRepository.php index a3a3a171..7f672ba8 100644 --- a/src/Repository/UserLogEntryRepository.php +++ b/src/Repository/UserLogEntryRepository.php @@ -9,7 +9,6 @@ use Doctrine\ORM\NoResultException; use Doctrine\Persistence\ManagerRegistry; use Gedmo\Loggable\Entity\Repository\LogEntryRepository; -use LogicException; use RZ\Roadiz\CoreBundle\Entity\UserLogEntry; /** @@ -27,24 +26,22 @@ public function __construct(ManagerRegistry $registry) $manager = $registry->getManagerForClass($entityClass); if (!$manager instanceof \Doctrine\ORM\EntityManagerInterface) { - throw new LogicException(sprintf( - 'Could not find the entity manager for class "%s". Check your Doctrine configuration to make sure it is configured to load this entity’s metadata.', - $entityClass - )); + throw new \LogicException(sprintf('Could not find the entity manager for class "%s". Check your Doctrine configuration to make sure it is configured to load this entity’s metadata.', $entityClass)); } parent::__construct($manager, $manager->getClassMetadata($entityClass)); } /** - * @param \DateTime $dateTime * @return int The number of entries + * * @throws NoResultException * @throws NonUniqueResultException */ public function countAllBeforeLoggedIn(\DateTime $dateTime): int { $qb = $this->createQueryBuilder('l'); + // @phpstan-ignore-next-line return $qb ->select($qb->expr()->countDistinct('l')) @@ -56,12 +53,12 @@ public function countAllBeforeLoggedIn(\DateTime $dateTime): int } /** - * @param \DateTime $dateTime * @return int The number of deleted entries */ public function deleteAllBeforeLoggedIn(\DateTime $dateTime): int { $qb = $this->createQueryBuilder('l'); + return $qb->delete(UserLogEntry::class, 'l') ->where($qb->expr()->lt('l.loggedAt', ':loggedAt')) ->setParameter('loggedAt', $dateTime) @@ -97,7 +94,7 @@ public function deleteAllExceptCount(int $count): int $deleteCount += $deleteQuery->execute([ 'objectId' => $object['objectId'], 'objectClass' => $object['objectClass'], - 'lowestVersion' => $lowestVersion + 'lowestVersion' => $lowestVersion, ]); } } diff --git a/src/Repository/UserRepository.php b/src/Repository/UserRepository.php index efc78acb..6b40b963 100644 --- a/src/Repository/UserRepository.php +++ b/src/Repository/UserRepository.php @@ -14,13 +14,14 @@ * @method User|null findOneBy(array $criteria, array $orderBy = null) * @method User[] findAll() * @method User[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + * * @extends EntityRepository */ final class UserRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, User::class, $dispatcher); } @@ -28,7 +29,6 @@ public function __construct( /** * @param string $username * - * @return bool * @throws \Doctrine\ORM\NoResultException * @throws \Doctrine\ORM\NonUniqueResultException */ @@ -44,8 +44,6 @@ public function usernameExists($username): bool } /** - * @param string $email - * @return bool * @throws \Doctrine\ORM\NoResultException * @throws \Doctrine\ORM\NonUniqueResultException */ @@ -59,4 +57,27 @@ public function emailExists(string $email): bool return (bool) $qb->getQuery()->getSingleScalarResult(); } + + /** + * Find all users that did not logged-in since a number of days, including users that never logged-in using + * their creation date. + * + * @return User[] + * + * @throws \Exception + */ + public function findAllInactiveSinceDays(int $days): array + { + $qb = $this->createQueryBuilder('u'); + $qb->andWhere($qb->expr()->orX( + // If user never logged in, we compare with creation date + $qb->expr()->andX( + $qb->expr()->isNull('u.lastLogin'), + $qb->expr()->lt('u.createdAt', ':lastLogin') + ), + $qb->expr()->lt('u.lastLogin', ':lastLogin'), + ))->setParameter('lastLogin', new \DateTimeImmutable('-'.$days.' days')); + + return $qb->getQuery()->getResult(); + } } diff --git a/src/Repository/WebhookRepository.php b/src/Repository/WebhookRepository.php index cecbbc79..d9c3724c 100644 --- a/src/Repository/WebhookRepository.php +++ b/src/Repository/WebhookRepository.php @@ -14,13 +14,14 @@ * @method Webhook|null findOneBy(array $criteria, array $orderBy = null) * @method Webhook[] findAll() * @method Webhook[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + * * @extends EntityRepository */ final class WebhookRepository extends EntityRepository { public function __construct( ManagerRegistry $registry, - EventDispatcherInterface $dispatcher + EventDispatcherInterface $dispatcher, ) { parent::__construct($registry, Webhook::class, $dispatcher); } diff --git a/src/Routing/ChainResourcePathResolver.php b/src/Routing/ChainResourcePathResolver.php index d618ae25..f2782488 100644 --- a/src/Routing/ChainResourcePathResolver.php +++ b/src/Routing/ChainResourcePathResolver.php @@ -16,19 +16,17 @@ final class ChainResourcePathResolver implements PathResolverInterface public function addPathResolver(PathResolverInterface $pathResolver): ChainResourcePathResolver { $this->pathResolvers[get_class($pathResolver)] = $pathResolver; + return $this; } - /** - * @inheritDoc - */ public function resolvePath( string $path, array $supportedFormatExtensions = ['html'], bool $allowRootPaths = false, - bool $allowNonReachableNodes = true + bool $allowNonReachableNodes = true, ): ResourceInfo { - if (count($this->pathResolvers) === 0) { + if (0 === count($this->pathResolvers)) { throw new ResourceNotFoundException('No PathResolverInterface was registered to resolve path'); } foreach ($this->pathResolvers as $pathResolver) { diff --git a/src/Routing/DocumentUrlGenerator.php b/src/Routing/DocumentUrlGenerator.php index 005a7cb5..f45a5882 100644 --- a/src/Routing/DocumentUrlGenerator.php +++ b/src/Routing/DocumentUrlGenerator.php @@ -16,14 +16,11 @@ public function __construct( FilesystemOperator $documentsStorage, UrlHelper $urlHelper, private readonly UrlGeneratorInterface $urlGenerator, - CacheItemPoolInterface $optionsCacheAdapter + CacheItemPoolInterface $optionsCacheAdapter, ) { parent::__construct($documentsStorage, $urlHelper, $optionsCacheAdapter); } - /** - * @return string - */ protected function getRouteName(): string { return 'interventionRequestProcess'; diff --git a/src/Routing/DynamicUrlMatcher.php b/src/Routing/DynamicUrlMatcher.php index 51d0b61a..e33b7b43 100644 --- a/src/Routing/DynamicUrlMatcher.php +++ b/src/Routing/DynamicUrlMatcher.php @@ -21,7 +21,7 @@ public function __construct( RequestContext $context, protected readonly PreviewResolverInterface $previewResolver, protected readonly Stopwatch $stopwatch, - protected readonly LoggerInterface $logger + protected readonly LoggerInterface $logger, ) { parent::__construct(new RouteCollection(), $context); } diff --git a/src/Routing/NodePathInfo.php b/src/Routing/NodePathInfo.php index 30e8710b..7b2e2b6e 100644 --- a/src/Routing/NodePathInfo.php +++ b/src/Routing/NodePathInfo.php @@ -11,19 +11,11 @@ class NodePathInfo protected bool $isComplete = false; protected bool $containsScheme = false; - /** - * @return string|null - */ public function getPath(): ?string { return $this->path; } - /** - * @param string $path - * - * @return NodePathInfo - */ public function setPath(string $path): NodePathInfo { $this->path = $path; @@ -31,19 +23,11 @@ public function setPath(string $path): NodePathInfo return $this; } - /** - * @return array - */ public function getParameters(): array { return $this->parameters; } - /** - * @param array $parameters - * - * @return NodePathInfo - */ public function setParameters(array $parameters): NodePathInfo { $this->parameters = $parameters; @@ -51,19 +35,11 @@ public function setParameters(array $parameters): NodePathInfo return $this; } - /** - * @return bool - */ public function isComplete(): bool { return $this->isComplete; } - /** - * @param bool $isComplete - * - * @return NodePathInfo - */ public function setComplete(bool $isComplete): NodePathInfo { $this->isComplete = $isComplete; @@ -71,19 +47,11 @@ public function setComplete(bool $isComplete): NodePathInfo return $this; } - /** - * @return bool - */ public function containsScheme(): bool { return $this->containsScheme; } - /** - * @param bool $containsScheme - * - * @return NodePathInfo - */ public function setContainsScheme(bool $containsScheme): NodePathInfo { $this->containsScheme = $containsScheme; @@ -100,11 +68,12 @@ public function serialize(): string 'path' => $this->getPath(), 'parameters' => $this->getParameters(), 'is_complete' => $this->isComplete(), - 'contains_scheme' => $this->containsScheme() + 'contains_scheme' => $this->containsScheme(), ]); if (false === $json) { throw new \RuntimeException('Unable to serialize NodePathInfo'); } + return $json; } @@ -114,7 +83,7 @@ public function __serialize(): array 'path' => $this->getPath(), 'parameters' => $this->getParameters(), 'is_complete' => $this->isComplete(), - 'contains_scheme' => $this->containsScheme() + 'contains_scheme' => $this->containsScheme(), ]; } diff --git a/src/Routing/NodeRouteHelper.php b/src/Routing/NodeRouteHelper.php index d9bb2723..7d0e949a 100644 --- a/src/Routing/NodeRouteHelper.php +++ b/src/Routing/NodeRouteHelper.php @@ -5,7 +5,7 @@ namespace RZ\Roadiz\CoreBundle\Routing; use Psr\Log\LoggerInterface; -use RZ\Roadiz\CoreBundle\Entity\Node; +use RZ\Roadiz\Core\AbstractEntities\NodeInterface; use RZ\Roadiz\CoreBundle\Entity\Theme; use RZ\Roadiz\CoreBundle\Preview\PreviewResolverInterface; use RZ\Roadiz\Utils\StringHandler; @@ -19,20 +19,15 @@ final class NodeRouteHelper private ?string $controller = null; /** - * @param Node $node - * @param Theme|null $theme - * @param PreviewResolverInterface $previewResolver - * @param LoggerInterface $logger * @param class-string $defaultControllerClass - * @param string $defaultControllerNamespace */ public function __construct( - private readonly Node $node, + private readonly NodeInterface $node, private readonly ?Theme $theme, private readonly PreviewResolverInterface $previewResolver, private readonly LoggerInterface $logger, private readonly string $defaultControllerClass, - private readonly string $defaultControllerNamespace = '\\App\\Controller' + private readonly string $defaultControllerNamespace = '\\App\\Controller', ) { } @@ -47,16 +42,14 @@ public function getController(): ?string if (!$this->node->getNodeType()->isReachable()) { return null; } - $controllerClassName = $this->getControllerNamespace() . '\\' . - StringHandler::classify($this->node->getNodeType()->getName()) . + $controllerClassName = $this->getControllerNamespace().'\\'. + StringHandler::classify($this->node->getNodeType()->getName()). 'Controller'; if (\class_exists($controllerClassName)) { $reflection = new \ReflectionClass($controllerClassName); if (!$reflection->isSubclassOf(AbstractController::class)) { - throw new \InvalidArgumentException( - 'Controller class ' . $controllerClassName . ' must extends ' . AbstractController::class - ); + throw new \InvalidArgumentException('Controller class '.$controllerClassName.' must extends '.AbstractController::class); } // @phpstan-ignore-next-line $this->controller = $controllerClassName; @@ -67,6 +60,7 @@ public function getController(): ?string $this->controller = $this->defaultControllerClass; } } + // @phpstan-ignore-next-line return $this->controller; } @@ -76,8 +70,9 @@ protected function getControllerNamespace(): string $namespace = $this->defaultControllerNamespace; if (null !== $this->theme) { $reflection = new \ReflectionClass($this->theme->getClassName()); - $namespace = $reflection->getNamespaceName() . '\\Controllers'; + $namespace = $reflection->getNamespaceName().'\\Controllers'; } + return $namespace; } @@ -88,20 +83,20 @@ public function getMethod(): string /** * Return FALSE or TRUE if node is viewable. - * - * @return bool */ public function isViewable(): bool { if (!class_exists($this->getController())) { - $this->logger->debug($this->getController() . ' controller does not exist.'); + $this->logger->debug($this->getController().' controller does not exist.'); + return false; } if (!method_exists($this->getController(), $this->getMethod())) { $this->logger->debug( - $this->getController() . ':' . - $this->getMethod() . ' controller method does not exist.' + $this->getController().':'. + $this->getMethod().' controller method does not exist.' ); + return false; } diff --git a/src/Routing/NodeRouter.php b/src/Routing/NodeRouter.php index 4d839b48..3b5528ac 100644 --- a/src/Routing/NodeRouter.php +++ b/src/Routing/NodeRouter.php @@ -36,7 +36,7 @@ public function __construct( protected readonly CacheItemPoolInterface $nodeSourceUrlCacheAdapter, RequestContext $context, LoggerInterface $logger, - array $options = [] + array $options = [], ) { parent::__construct( new NullLoader(), @@ -48,9 +48,6 @@ public function __construct( $this->matcher = $matcher; } - /** - * {@inheritdoc} - */ public function getRouteCollection(): RouteCollection { return new RouteCollection(); @@ -58,54 +55,44 @@ public function getRouteCollection(): RouteCollection /** * Gets the UrlMatcher instance associated with this Router. - * - * @return UrlMatcherInterface */ public function getMatcher(): UrlMatcherInterface { return $this->matcher; } - /** - * @return Theme|null - */ public function getTheme(): ?Theme { return $this->theme; } - /** - * @param Theme|null $theme - * @return NodeRouter - */ public function setTheme(?Theme $theme): NodeRouter { $this->theme = $theme; + return $this; } - /** - * @inheritDoc - */ public function getRouteDebugMessage(string $name, array $parameters = []): string { if (RouteObjectInterface::OBJECT_BASED_ROUTE_NAME === $name) { if ( - array_key_exists(RouteObjectInterface::ROUTE_OBJECT, $parameters) && - $parameters[RouteObjectInterface::ROUTE_OBJECT] instanceof NodesSources + array_key_exists(RouteObjectInterface::ROUTE_OBJECT, $parameters) + && $parameters[RouteObjectInterface::ROUTE_OBJECT] instanceof NodesSources ) { $route = $parameters[RouteObjectInterface::ROUTE_OBJECT]; - return '[' . $route->getTranslation()->getLocale() . ']' . - $route->getTitle() . ' - ' . - $route->getNode()->getNodeName() . - '[' . $route->getNode()->getId() . ']'; + + return '['.$route->getTranslation()->getLocale().']'. + $route->getTitle().' - '. + $route->getNode()->getNodeName(). + '['.$route->getNode()->getId().']'; } } + return (string) $name; } /** - * {@inheritdoc} * @throws InvalidArgumentException */ public function generate(string $name, array $parameters = [], int $referenceType = self::ABSOLUTE_PATH): string @@ -115,8 +102,8 @@ public function generate(string $name, array $parameters = [], int $referenceTyp } if ( - array_key_exists(RouteObjectInterface::ROUTE_OBJECT, $parameters) && - $parameters[RouteObjectInterface::ROUTE_OBJECT] instanceof NodesSources + array_key_exists(RouteObjectInterface::ROUTE_OBJECT, $parameters) + && $parameters[RouteObjectInterface::ROUTE_OBJECT] instanceof NodesSources ) { $route = $parameters[RouteObjectInterface::ROUTE_OBJECT]; unset($parameters[RouteObjectInterface::ROUTE_OBJECT]); @@ -132,12 +119,12 @@ public function generate(string $name, array $parameters = [], int $referenceTyp $schemeAuthority = trim($parameters['canonicalScheme']); unset($parameters['canonicalScheme']); } else { - $schemeAuthority = $this->getContext()->getScheme() . '://' . $this->getHttpHost(); + $schemeAuthority = $this->getContext()->getScheme().'://'.$this->getHttpHost(); } $noCache = false; if (!empty($parameters[static::NO_CACHE_PARAMETER])) { - $noCache = (bool)($parameters[static::NO_CACHE_PARAMETER]); + $noCache = (bool) $parameters[static::NO_CACHE_PARAMETER]; } $nodePathInfo = $this->getResourcePath($route, $parameters, $noCache); @@ -146,9 +133,10 @@ public function generate(string $name, array $parameters = [], int $referenceTyp * If node path is complete, do not alter path anymore. */ if (true === $nodePathInfo->isComplete()) { - if ($referenceType == self::ABSOLUTE_URL && !$nodePathInfo->containsScheme()) { - return $schemeAuthority . $nodePathInfo->getPath(); + if (self::ABSOLUTE_URL == $referenceType && !$nodePathInfo->containsScheme()) { + return $schemeAuthority.$nodePathInfo->getPath(); } + return $nodePathInfo->getPath(); } @@ -157,9 +145,9 @@ public function generate(string $name, array $parameters = [], int $referenceTyp $matcher = $this->getMatcher(); if ( - isset($parameters['_format']) && - $matcher instanceof NodeUrlMatcher && - in_array($parameters['_format'], $matcher->getSupportedFormatExtensions()) + isset($parameters['_format']) + && $matcher instanceof NodeUrlMatcher + && in_array($parameters['_format'], $matcher->getSupportedFormatExtensions()) ) { unset($parameters['_format']); } @@ -167,51 +155,41 @@ public function generate(string $name, array $parameters = [], int $referenceTyp unset($parameters[static::NO_CACHE_PARAMETER]); } if (count($parameters) > 0) { - $queryString = '?' . http_build_query($parameters); + $queryString = '?'.http_build_query($parameters); } - if ($referenceType == self::ABSOLUTE_URL) { + if (self::ABSOLUTE_URL == $referenceType) { // Absolute path - return $schemeAuthority . $this->getContext()->getBaseUrl() . '/' . $nodePathInfo->getPath() . $queryString; + return $schemeAuthority.$this->getContext()->getBaseUrl().'/'.$nodePathInfo->getPath().$queryString; } // ABSOLUTE_PATH - return $this->getContext()->getBaseUrl() . '/' . $nodePathInfo->getPath() . $queryString; + return $this->getContext()->getBaseUrl().'/'.$nodePathInfo->getPath().$queryString; } /** - * @param NodesSources $source - * @param array $parameters - * @param bool $noCache - * - * @return NodePathInfo - * @throws \Psr\Cache\InvalidArgumentException + * @throws InvalidArgumentException */ protected function getResourcePath( NodesSources $source, array $parameters = [], - bool $noCache = false + bool $noCache = false, ): NodePathInfo { if ($noCache) { $parametersHash = sha1(serialize($parameters)); - $cacheKey = 'ns_url_' . $source->getId() . '_' . $this->getContext()->getHost() . '_' . $parametersHash; + $cacheKey = 'ns_url_'.$source->getId().'_'.$this->getContext()->getHost().'_'.$parametersHash; $cacheItem = $this->nodeSourceUrlCacheAdapter->getItem($cacheKey); if (!$cacheItem->isHit()) { $cacheItem->set($this->getNodesSourcesPath($source, $parameters)); $this->nodeSourceUrlCacheAdapter->save($cacheItem); } + return $cacheItem->get(); } return $this->getNodesSourcesPath($source, $parameters); } - /** - * @param NodesSources $source - * @param array $parameters - * - * @return NodePathInfo - */ protected function getNodesSourcesPath(NodesSources $source, array $parameters = []): NodePathInfo { $event = new NodesSourcesPathGeneratingEvent( @@ -238,6 +216,7 @@ protected function getNodesSourcesPath(NodesSources $source, array $parameters = if (null === $nodePathInfo->getPath()) { throw new InvalidParameterException('NodeSource generated path is null.'); } + return $nodePathInfo; } @@ -245,8 +224,6 @@ protected function getNodesSourcesPath(NodesSources $source, array $parameters = * Returns the HTTP host being requested. * * The port name will be appended to the host if it's non-standard. - * - * @return string */ private function getHttpHost(): string { @@ -254,11 +231,11 @@ private function getHttpHost(): string $port = ''; if ('http' === $scheme && 80 != $this->context->getHttpPort()) { - $port = ':' . $this->context->getHttpPort(); + $port = ':'.$this->context->getHttpPort(); } elseif ('https' === $scheme && 443 != $this->context->getHttpsPort()) { - $port = ':' . $this->context->getHttpsPort(); + $port = ':'.$this->context->getHttpsPort(); } - return $this->getContext()->getHost() . $port; + return $this->getContext()->getHost().$port; } } diff --git a/src/Routing/NodeUrlMatcher.php b/src/Routing/NodeUrlMatcher.php index 743e405f..96cee535 100644 --- a/src/Routing/NodeUrlMatcher.php +++ b/src/Routing/NodeUrlMatcher.php @@ -20,11 +20,6 @@ final class NodeUrlMatcher extends DynamicUrlMatcher implements NodeUrlMatcherInterface { /** - * @param PathResolverInterface $pathResolver - * @param RequestContext $context - * @param PreviewResolverInterface $previewResolver - * @param Stopwatch $stopwatch - * @param LoggerInterface $logger * @param class-string $defaultControllerClass */ public function __construct( @@ -33,33 +28,25 @@ public function __construct( PreviewResolverInterface $previewResolver, Stopwatch $stopwatch, LoggerInterface $logger, - private readonly string $defaultControllerClass + private readonly string $defaultControllerClass, ) { parent::__construct($context, $previewResolver, $stopwatch, $logger); } - /** - * @return array - */ public function getSupportedFormatExtensions(): array { return ['xml', 'json', 'pdf', 'html']; } - /** - * @return string - */ public function getDefaultSupportedFormatExtension(): string { return 'html'; } - /** - * @inheritDoc - */ public function match(string $pathinfo): array { $decodedUrl = rawurldecode($pathinfo); + /* * Try nodes routes */ @@ -77,11 +64,6 @@ protected function getNodeRouteHelper(NodesSources $nodeSource, ?Theme $theme): ); } - /** - * @param string $decodedUrl - * @param Theme|null $theme - * @return array - */ public function matchNode(string $decodedUrl, ?Theme $theme): array { $resourceInfo = $this->pathResolver->resolvePath( @@ -103,7 +85,7 @@ public function matchNode(string $decodedUrl, ?Theme $theme): array } return [ - '_controller' => $nodeRouteHelper->getController() . '::' . $nodeRouteHelper->getMethod(), + '_controller' => $nodeRouteHelper->getController().'::'.$nodeRouteHelper->getMethod(), '_locale' => $resourceInfo->getLocale(), '_route' => RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, '_format' => $resourceInfo->getFormat(), diff --git a/src/Routing/NodesSourcesPathResolver.php b/src/Routing/NodesSourcesPathResolver.php index 2e8167c1..ba517195 100644 --- a/src/Routing/NodesSourcesPathResolver.php +++ b/src/Routing/NodesSourcesPathResolver.php @@ -12,8 +12,8 @@ use RZ\Roadiz\CoreBundle\Entity\NodesSources; use RZ\Roadiz\CoreBundle\Entity\NodeType; use RZ\Roadiz\CoreBundle\Entity\Translation; -use RZ\Roadiz\CoreBundle\Repository\TranslationRepository; use RZ\Roadiz\CoreBundle\Preview\PreviewResolverInterface; +use RZ\Roadiz\CoreBundle\Repository\TranslationRepository; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\Stopwatch\Stopwatch; @@ -28,28 +28,25 @@ public function __construct( private readonly Stopwatch $stopwatch, private readonly Settings $settingsBag, private readonly RequestStack $requestStack, - private readonly bool $useAcceptLanguageHeader + private readonly bool $useAcceptLanguageHeader, ) { } - /** - * @inheritDoc - */ public function resolvePath( string $path, array $supportedFormatExtensions = ['html'], bool $allowRootPaths = false, - bool $allowNonReachableNodes = true + bool $allowNonReachableNodes = true, ): ResourceInfo { $resourceInfo = new ResourceInfo(); $tokens = $this->tokenizePath($path); $_format = 'html'; - if (count($tokens) === 0 && !$allowRootPaths) { + if (0 === count($tokens) && !$allowRootPaths) { throw new ResourceNotFoundException(); } - if ($path === '/') { + if ('/' === $path) { $this->stopwatch->start('parseRootPath', 'routing'); $translation = $this->parseTranslation(); $nodeSource = $this->getHome($translation); @@ -60,11 +57,11 @@ public function resolvePath( $identifier = strip_tags($tokens[(int) (count($tokens) - 1)]); } - if ($identifier !== '') { + if ('' !== $identifier) { /* * Prevent searching nodes with special characters. */ - if (0 === preg_match('#' . static::$nodeNamePattern . '#', $identifier)) { + if (0 === preg_match('#'.static::$nodeNamePattern.'#', $identifier)) { throw new ResourceNotFoundException(); } @@ -73,7 +70,7 @@ public function resolvePath( */ if ( 0 !== preg_match( - '#^(' . static::$nodeNamePattern . ')\.(' . implode('|', $supportedFormatExtensions) . ')$#', + '#^('.static::$nodeNamePattern.')\.('.implode('|', $supportedFormatExtensions).')$#', $identifier, $matches ) @@ -104,14 +101,12 @@ public function resolvePath( $resourceInfo->setTranslation($nodeSource->getTranslation()); $resourceInfo->setFormat($_format); $resourceInfo->setLocale($nodeSource->getTranslation()->getPreferredLocale()); + return $resourceInfo; } /** * Split path into meaningful tokens. - * - * @param string $path - * @return array */ private function tokenizePath(string $path): array { @@ -121,13 +116,9 @@ private function tokenizePath(string $path): array return $tokens; } - /** - * @param TranslationInterface $translation - * @return NodesSources|null - */ private function getHome(TranslationInterface $translation): ?NodesSources { - /** + /* * Resolve home page * @phpstan-ignore-next-line */ @@ -135,7 +126,7 @@ private function getHome(TranslationInterface $translation): ?NodesSources ->getRepository(NodesSources::class) ->findOneBy([ 'node.home' => true, - 'translation' => $translation + 'translation' => $translation, ]); } @@ -144,7 +135,6 @@ private function getHome(TranslationInterface $translation): ?NodesSources * * @param array $tokens * - * @return TranslationInterface|null * @throws NonUniqueResultException */ private function parseTranslation(array &$tokens = []): ?TranslationInterface @@ -159,7 +149,7 @@ private function parseTranslation(array &$tokens = []): ?TranslationInterface $firstToken = $tokens[0]; $locale = \mb_strtolower(strip_tags((string) $firstToken)); // First token is for language and should not exceed 11 chars, i.e. tzm-Latn-DZ - if ($locale !== null && $locale != '' && \mb_strlen($locale) <= 11) { + if (null !== $locale && '' != $locale && \mb_strlen($locale) <= 11) { $translation = $repository->$findOneByMethod($locale); if (null !== $translation) { return $translation; @@ -170,8 +160,8 @@ private function parseTranslation(array &$tokens = []): ?TranslationInterface } if ( - $this->useAcceptLanguageHeader && - $this->settingsBag->get('force_locale', false) === true + $this->useAcceptLanguageHeader + && true === $this->settingsBag->get('force_locale', false) ) { /* * When no information to find locale is found and "force_locale" is ON, @@ -181,8 +171,8 @@ private function parseTranslation(array &$tokens = []): ?TranslationInterface */ $request = $this->requestStack->getMainRequest(); if ( - null !== $request && - null !== $preferredLocale = $request->getPreferredLanguage($repository->getAvailableLocales()) + null !== $request + && null !== $preferredLocale = $request->getPreferredLanguage($repository->getAvailableLocales()) ) { $translation = $repository->$findOneByMethod($preferredLocale); if (null !== $translation) { @@ -196,14 +186,11 @@ private function parseTranslation(array &$tokens = []): ?TranslationInterface /** * @param array $tokens - * @param TranslationInterface|null $translation - * @param bool $allowNonReachableNodes - * @return NodesSources|null */ private function parseFromIdentifier( array &$tokens, ?TranslationInterface $translation = null, - bool $allowNonReachableNodes = true + bool $allowNonReachableNodes = true, ): ?NodesSources { if (!empty($tokens[0])) { /* @@ -211,7 +198,7 @@ private function parseFromIdentifier( */ if (count($tokens) > 1 || !in_array($tokens[0], Translation::getAvailableLocales())) { $identifier = \mb_strtolower(strip_tags($tokens[(int) (count($tokens) - 1)])); - if ($identifier !== null && $identifier != '') { + if (null !== $identifier && '' != $identifier) { $array = $this->managerRegistry ->getRepository(Node::class) ->findNodeTypeNameAndSourceIdByIdentifier( @@ -225,8 +212,9 @@ private function parseFromIdentifier( $nodeSource = $this->managerRegistry ->getRepository($this->getNodeTypeClassname($array['name'])) ->findOneBy([ - 'id' => $array['id'] + 'id' => $array['id'], ]); + return $nodeSource; } else { $this->stopwatch->stop('parseFromIdentifier'); @@ -243,15 +231,15 @@ private function parseFromIdentifier( } /** - * @param string $name * @return class-string */ private function getNodeTypeClassname(string $name): string { - $fqcn = NodeType::getGeneratedEntitiesNamespace() . '\\NS' . ucwords($name); + $fqcn = NodeType::getGeneratedEntitiesNamespace().'\\NS'.ucwords($name); if (!class_exists($fqcn)) { - throw new ResourceNotFoundException($fqcn . ' entity does not exist.'); + throw new ResourceNotFoundException($fqcn.' entity does not exist.'); } + return $fqcn; } } diff --git a/src/Routing/NodesSourcesUrlGenerator.php b/src/Routing/NodesSourcesUrlGenerator.php index 1b3b8fc2..5441fbd4 100644 --- a/src/Routing/NodesSourcesUrlGenerator.php +++ b/src/Routing/NodesSourcesUrlGenerator.php @@ -10,20 +10,16 @@ /** * Do not extend this class, use NodesSourcesPathGeneratingEvent::class event. */ -final class NodesSourcesUrlGenerator +final readonly class NodesSourcesUrlGenerator { public function __construct( - private readonly NodesSourcesPathAggregator $pathAggregator, - private readonly ?NodesSources $nodeSource = null, - private readonly bool $forceLocale = false, - private readonly bool $forceLocaleWithUrlAlias = false + private NodesSourcesPathAggregator $pathAggregator, + private ?NodesSources $nodeSource = null, + private bool $forceLocale = false, + private bool $forceLocaleWithUrlAlias = false, ) { } - /** - * @param NodesSources $nodeSource - * @return bool - */ protected function isNodeSourceHome(NodesSources $nodeSource): bool { if ($nodeSource->getNode()->isHome()) { @@ -38,19 +34,14 @@ protected function isNodeSourceHome(NodesSources $nodeSource): bool * root folder. * * It returns a relative url to Roadiz, not relative to your server root. - * - * @param Theme|null $theme - * @param array $parameters - * - * @return string */ public function getNonContextualUrl(?Theme $theme = null, array $parameters = []): string { if (null !== $this->nodeSource) { if ($this->isNodeSourceHome($this->nodeSource)) { if ( - $this->nodeSource->getTranslation()->isDefaultTranslation() && - false === $this->forceLocale + $this->nodeSource->getTranslation()->isDefaultTranslation() + && false === $this->forceLocale ) { return ''; } else { @@ -65,30 +56,25 @@ public function getNonContextualUrl(?Theme $theme = null, array $parameters = [] * translation is not the default one. */ if ($this->urlNeedsLocalePrefix($this->nodeSource)) { - $path = $this->nodeSource->getTranslation()->getPreferredLocale() . '/' . $path; + $path = $this->nodeSource->getTranslation()->getPreferredLocale().'/'.$path; } - if (null !== $theme && $theme->getRoutePrefix() != '') { - $path = $theme->getRoutePrefix() . '/' . $path; + if (null !== $theme && '' != $theme->getRoutePrefix()) { + $path = $theme->getRoutePrefix().'/'.$path; } /* * Add non default format at the path end. */ if (isset($parameters['_format']) && in_array($parameters['_format'], ['xml', 'json', 'pdf'])) { - $path .= '.' . $parameters['_format']; + $path .= '.'.$parameters['_format']; } return $path; } else { - throw new \RuntimeException("Cannot generate Url for a NULL NodesSources", 1); + throw new \RuntimeException('Cannot generate Url for a NULL NodesSources', 1); } } - /** - * @param NodesSources $nodesSources - * - * @return bool - */ protected function useUrlAlias(NodesSources $nodesSources): bool { if ($nodesSources->getIdentifier() !== $nodesSources->getNode()->getNodeName()) { @@ -98,11 +84,6 @@ protected function useUrlAlias(NodesSources $nodesSources): bool return false; } - /** - * @param NodesSources $nodesSources - * - * @return bool - */ protected function urlNeedsLocalePrefix(NodesSources $nodesSources): bool { /* @@ -113,15 +94,15 @@ protected function urlNeedsLocalePrefix(NodesSources $nodesSources): bool */ if ( ( - !$this->useUrlAlias($nodesSources) && - !$nodesSources->getTranslation()->isDefaultTranslation() - ) || - ( - $this->useUrlAlias($nodesSources) && - !$nodesSources->getTranslation()->isDefaultTranslation() && - true === $this->forceLocaleWithUrlAlias - ) || - true === $this->forceLocale + !$this->useUrlAlias($nodesSources) + && !$nodesSources->getTranslation()->isDefaultTranslation() + ) + || ( + $this->useUrlAlias($nodesSources) + && !$nodesSources->getTranslation()->isDefaultTranslation() + && true === $this->forceLocaleWithUrlAlias + ) + || true === $this->forceLocale ) { return true; } diff --git a/src/Routing/NullLoader.php b/src/Routing/NullLoader.php index 673b621d..981a2959 100644 --- a/src/Routing/NullLoader.php +++ b/src/Routing/NullLoader.php @@ -9,33 +9,21 @@ final class NullLoader implements LoaderInterface { - /** - * @inheritDoc - */ - public function load(mixed $resource, string $type = null): mixed + public function load(mixed $resource, ?string $type = null): mixed { return null; } - /** - * @inheritDoc - */ - public function supports(mixed $resource, string $type = null): bool + public function supports(mixed $resource, ?string $type = null): bool { return true; } - /** - * @inheritDoc - */ public function getResolver(): ?LoaderResolverInterface { return null; } - /** - * @inheritDoc - */ public function setResolver(LoaderResolverInterface $resolver): self { return $this; diff --git a/src/Routing/OptimizedNodesSourcesGraphPathAggregator.php b/src/Routing/OptimizedNodesSourcesGraphPathAggregator.php index 0d171edf..058afb40 100644 --- a/src/Routing/OptimizedNodesSourcesGraphPathAggregator.php +++ b/src/Routing/OptimizedNodesSourcesGraphPathAggregator.php @@ -11,32 +11,30 @@ use RZ\Roadiz\CoreBundle\Entity\Node; use RZ\Roadiz\CoreBundle\Entity\NodesSources; -final class OptimizedNodesSourcesGraphPathAggregator implements NodesSourcesPathAggregator +final readonly class OptimizedNodesSourcesGraphPathAggregator implements NodesSourcesPathAggregator { public function __construct( - private readonly ManagerRegistry $managerRegistry, - private readonly CacheItemPoolInterface $cacheAdapter + private ManagerRegistry $managerRegistry, + private CacheItemPoolInterface $cacheAdapter, ) { } private function getCacheKey(NodesSources $nodesSources): string { - return 'ns_url_' . $nodesSources->getId(); + return 'ns_url_'.$nodesSources->getId(); } /** - * @param NodesSources $nodesSources - * @param array $parameters - * @return string * @throws InvalidArgumentException */ public function aggregatePath(NodesSources $nodesSources, array $parameters = []): string { if ( - isset($parameters[NodeRouter::NO_CACHE_PARAMETER]) && - $parameters[NodeRouter::NO_CACHE_PARAMETER] === true + isset($parameters[NodeRouter::NO_CACHE_PARAMETER]) + && true === $parameters[NodeRouter::NO_CACHE_PARAMETER] ) { $urlTokens = array_reverse($this->getIdentifiers($nodesSources)); + return implode('/', $urlTokens); } @@ -46,18 +44,17 @@ public function aggregatePath(NodesSources $nodesSources, array $parameters = [] $cacheItem->set(implode('/', $urlTokens)); $this->cacheAdapter->save($cacheItem); } + return $cacheItem->get(); } /** - * @param Node $parent - * * @return array */ private function getParentsIds(Node $parent): array { $parentIds = []; - while ($parent !== null && !$parent->isHome()) { + while (null !== $parent && !$parent->isHome()) { $parentIds[] = $parent->getId(); $parent = $parent->getParent(); } @@ -68,10 +65,6 @@ private function getParentsIds(Node $parent): array /** * Get every nodeSource parents identifier from current to * farthest ancestor. - * - * @param NodesSources $source - * - * @return array */ private function getIdentifiers(NodesSources $source): array { @@ -84,8 +77,7 @@ private function getIdentifiers(NodesSources $source): array $parentIds = $this->getParentsIds($parentNode); if (count($parentIds) > 0) { /** - * - * Do a partial query to optimize SQL time + * Do a partial query to optimize SQL time. */ $qb = $this->managerRegistry ->getRepository(NodesSources::class) @@ -99,7 +91,7 @@ private function getIdentifiers(NodesSources $source): array ->setParameters([ 'parentIds' => $parentIds, 'visible' => true, - 'translation' => $source->getTranslation() + 'translation' => $source->getTranslation(), ]) ->getQuery() ->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true) diff --git a/src/Routing/PathResolverInterface.php b/src/Routing/PathResolverInterface.php index 45b3429c..ad934d74 100644 --- a/src/Routing/PathResolverInterface.php +++ b/src/Routing/PathResolverInterface.php @@ -9,16 +9,14 @@ interface PathResolverInterface /** * Resolve a ResourceInfo containing AbstractEntity, format and translation using a unique path. * - * @param string $path * @param array $supportedFormatExtensions - * @param bool $allowRootPaths Allow resolving / and /en, /fr paths to home pages - * @param bool $allowNonReachableNodes Allow resolving non-reachable nodes - * @return ResourceInfo + * @param bool $allowRootPaths Allow resolving / and /en, /fr paths to home pages + * @param bool $allowNonReachableNodes Allow resolving non-reachable nodes */ public function resolvePath( string $path, array $supportedFormatExtensions = ['html'], bool $allowRootPaths = false, - bool $allowNonReachableNodes = true + bool $allowNonReachableNodes = true, ): ResourceInfo; } diff --git a/src/Routing/RedirectableUrlMatcher.php b/src/Routing/RedirectableUrlMatcher.php index b6f3c486..bca8a00b 100644 --- a/src/Routing/RedirectableUrlMatcher.php +++ b/src/Routing/RedirectableUrlMatcher.php @@ -12,8 +12,8 @@ final class RedirectableUrlMatcher extends BaseMatcher /** * Redirects the user to another URL. * - * @param string $path The path info to redirect to - * @param string $route The route that matched + * @param string $path The path info to redirect to + * @param string $route The route that matched * @param string|null $scheme The URL scheme (null to keep the current one) * * @return array An array of parameters @@ -21,7 +21,7 @@ final class RedirectableUrlMatcher extends BaseMatcher public function redirect(string $path, string $route, ?string $scheme = null): array { return [ - '_controller' => RedirectionController::class . '::redirectToRouteAction', + '_controller' => RedirectionController::class.'::redirectToRouteAction', 'path' => $path, 'permanent' => true, 'scheme' => $scheme, diff --git a/src/Routing/RedirectionMatcher.php b/src/Routing/RedirectionMatcher.php index 81001bee..6258a3dd 100644 --- a/src/Routing/RedirectionMatcher.php +++ b/src/Routing/RedirectionMatcher.php @@ -21,14 +21,11 @@ final class RedirectionMatcher extends UrlMatcher public function __construct( RequestContext $context, private readonly RedirectionPathResolver $pathResolver, - private readonly LoggerInterface $logger + private readonly LoggerInterface $logger, ) { parent::__construct(new RouteCollection(), $context); } - /** - * {@inheritdoc} - */ public function match(string $pathinfo): array { $decodedUrl = rawurldecode($pathinfo); @@ -38,8 +35,9 @@ public function match(string $pathinfo): array */ if (null !== $redirection = $this->matchRedirection($decodedUrl)) { $this->logger->debug('Matched redirection.', ['query' => $redirection->getQuery()]); + return [ - '_controller' => RedirectionController::class . '::redirectAction', + '_controller' => RedirectionController::class.'::redirectAction', 'redirection' => $redirection, '_route' => null, ]; @@ -48,13 +46,10 @@ public function match(string $pathinfo): array throw new ResourceNotFoundException(sprintf('%s did not match any Doctrine Redirection', $pathinfo)); } - /** - * @param string $decodedUrl - * @return Redirection|null - */ protected function matchRedirection(string $decodedUrl): ?Redirection { $resource = $this->pathResolver->resolvePath($decodedUrl)->getResource(); + return $resource instanceof Redirection ? $resource : null; } } diff --git a/src/Routing/RedirectionPathResolver.php b/src/Routing/RedirectionPathResolver.php index d6947849..78a8f8b8 100644 --- a/src/Routing/RedirectionPathResolver.php +++ b/src/Routing/RedirectionPathResolver.php @@ -25,7 +25,7 @@ public function resolvePath( string $path, array $supportedFormatExtensions = ['html'], bool $allowRootPaths = false, - bool $allowNonReachableNodes = true + bool $allowNonReachableNodes = true, ): ResourceInfo { $this->stopwatch->start('lookForRedirection', 'routing'); $cacheItem = $this->cacheAdapter->getItem(self::CACHE_KEY); diff --git a/src/Routing/RedirectionRouter.php b/src/Routing/RedirectionRouter.php index 1ec14a2e..0cb3adc0 100644 --- a/src/Routing/RedirectionRouter.php +++ b/src/Routing/RedirectionRouter.php @@ -21,8 +21,8 @@ public function __construct( protected readonly ManagerRegistry $managerRegistry, protected readonly Stopwatch $stopwatch, array $options = [], - RequestContext $context = null, - LoggerInterface $logger = null, + ?RequestContext $context = null, + ?LoggerInterface $logger = null, ) { parent::__construct( new NullLoader(), @@ -34,20 +34,14 @@ public function __construct( $this->matcher = $matcher; } - /** - * {@inheritdoc} - */ public function getRouteCollection(): RouteCollection { return new RouteCollection(); } - /** - * {@inheritdoc} - */ public function generate(string $name, array $parameters = [], int $referenceType = self::ABSOLUTE_PATH): string { - throw new RouteNotFoundException(get_class($this) . ' does not support path generation.'); + throw new RouteNotFoundException(get_class($this).' does not support path generation.'); } /** @@ -55,7 +49,7 @@ public function generate(string $name, array $parameters = [], int $referenceTyp */ public function getGenerator(): UrlGeneratorInterface { - throw new \BadMethodCallException(get_class($this) . ' does not support path generation.'); + throw new \BadMethodCallException(get_class($this).' does not support path generation.'); } public function getRouteDebugMessage(mixed $name, array $parameters = []): string diff --git a/src/Routing/ResourceInfo.php b/src/Routing/ResourceInfo.php index d25db2f5..47b128d7 100644 --- a/src/Routing/ResourceInfo.php +++ b/src/Routing/ResourceInfo.php @@ -14,75 +14,51 @@ final class ResourceInfo protected ?string $format = null; protected ?string $locale = null; - /** - * @return PersistableInterface|null - */ public function getResource(): ?PersistableInterface { return $this->resource; } - /** - * @param PersistableInterface|null $resource - * @return ResourceInfo - */ public function setResource(?PersistableInterface $resource): ResourceInfo { $this->resource = $resource; + return $this; } - /** - * @return TranslationInterface|null - */ public function getTranslation(): ?TranslationInterface { return $this->translation; } - /** - * @param TranslationInterface|null $translation - * @return ResourceInfo - */ public function setTranslation(?TranslationInterface $translation): ResourceInfo { $this->translation = $translation; + return $this; } - /** - * @return string|null - */ public function getFormat(): ?string { return $this->format; } - /** - * @param string|null $format - * @return ResourceInfo - */ public function setFormat(?string $format): ResourceInfo { $this->format = $format; + return $this; } - /** - * @return string|null - */ public function getLocale(): ?string { return $this->locale; } - /** - * @param string|null $locale - * @return ResourceInfo - */ public function setLocale(?string $locale): ResourceInfo { $this->locale = $locale; + return $this; } } diff --git a/src/Routing/RouteHandler.php b/src/Routing/RouteHandler.php index 01146723..d5d515be 100644 --- a/src/Routing/RouteHandler.php +++ b/src/Routing/RouteHandler.php @@ -7,16 +7,14 @@ use RZ\Roadiz\Utils\StringHandler; use Symfony\Component\String\UnicodeString; -/** - * Route handling methods. - */ -class RouteHandler +final class RouteHandler { public static function getBaseRoute(string $path): string { if ((new UnicodeString($path))->endsWith('Locale')) { - $path = StringHandler::replaceLast("Locale", "", $path); + $path = StringHandler::replaceLast('Locale', '', $path); } + return $path; } } diff --git a/src/SearchEngine/AbstractSearchHandler.php b/src/SearchEngine/AbstractSearchHandler.php index 133f3691..660ab06a 100644 --- a/src/SearchEngine/AbstractSearchHandler.php +++ b/src/SearchEngine/AbstractSearchHandler.php @@ -15,22 +15,16 @@ abstract class AbstractSearchHandler implements SearchHandlerInterface { - protected ClientRegistry $clientRegistry; - protected ObjectManager $em; protected LoggerInterface $logger; - protected EventDispatcherInterface $eventDispatcher; protected int $highlightingFragmentSize = 150; public function __construct( - ClientRegistry $clientRegistry, - ObjectManager $em, - LoggerInterface $searchEngineLogger, - EventDispatcherInterface $eventDispatcher + protected readonly ClientRegistry $clientRegistry, + protected readonly ObjectManager $em, + readonly LoggerInterface $searchEngineLogger, + protected readonly EventDispatcherInterface $eventDispatcher, ) { - $this->clientRegistry = $clientRegistry; - $this->em = $em; $this->logger = $searchEngineLogger; - $this->eventDispatcher = $eventDispatcher; } public function getSolr(): Client @@ -39,37 +33,35 @@ public function getSolr(): Client if (null === $solr) { throw new SolrServerNotAvailableException(); } + return $solr; } /** - * Search on Solr with pre-filled argument for highlighting + * Search on Solr with pre-filled argument for highlighting. * * * $q is the search criteria. * * $args is an array with solr query argument. * The common argument can be found [here](https://cwiki.apache.org/confluence/display/solr/Common+Query+Parameters) * and for highlighting argument is [here](https://cwiki.apache.org/confluence/display/solr/Standard+Highlighter). * - * @param string $q - * @param array $args - * @param int $rows * @param bool $searchTags Search in tags/folders too, even if a node don’t match - * @param int $page * - * @return SearchResultsInterface Return a SearchResultsInterface iterable object. + * @return SearchResultsInterface return a SearchResultsInterface iterable object */ public function searchWithHighlight( string $q, array $args = [], int $rows = 20, bool $searchTags = false, - int $page = 1 + int $page = 1, ): SearchResultsInterface { $args = $this->argFqProcess($args); - $args["fq"][] = "document_type_s:" . $this->getDocumentType(); - $args["hl.q"] = $this->buildHighlightingQuery($q); + $args['fq'][] = 'document_type_s:'.$this->getDocumentType(); + $args['hl.q'] = $this->buildHighlightingQuery($q); $args = array_merge($this->getHighlightingOptions($args), $args); $response = $this->nativeSearch($q, $args, $rows, $searchTags, $page); + return $this->createSearchResultsFromResponse($response); } @@ -78,38 +70,22 @@ protected function createSearchResultsFromResponse(?array $response): SolrSearch return new SolrSearchResults(null !== $response ? $response : [], $this->em); } - /** - * @param array $args - * @return array - */ abstract protected function argFqProcess(array &$args): array; - /** - * @return string - */ abstract protected function getDocumentType(): string; - /** - * @param array $args - * @return array - */ protected function getHighlightingOptions(array &$args = []): array { $tmp = []; - $tmp["hl"] = true; - $tmp["hl.fl"] = $this->getTitleField($args) . ' ' . $this->getCollectionField($args); - $tmp["hl.fragsize"] = $this->getHighlightingFragmentSize(); - $tmp["hl.simple.pre"] = ''; - $tmp["hl.simple.post"] = ''; + $tmp['hl'] = true; + $tmp['hl.fl'] = $this->getTitleField($args).' '.$this->getCollectionField($args); + $tmp['hl.fragsize'] = $this->getHighlightingFragmentSize(); + $tmp['hl.simple.pre'] = ''; + $tmp['hl.simple.post'] = ''; return $tmp; } - /** - * @param array $args - * - * @return string - */ protected function getCollectionField(array &$args): string { /* @@ -117,27 +93,20 @@ protected function getCollectionField(array &$args): string * is filtered by translation. */ if (isset($args['locale']) && is_string($args['locale'])) { - return 'collection_txt_' . \Locale::getPrimaryLanguage($args['locale']); + return 'collection_txt_'.\Locale::getPrimaryLanguage($args['locale']); } if (isset($args['translation']) && $args['translation'] instanceof Translation) { - return 'collection_txt_' . \Locale::getPrimaryLanguage($args['translation']->getLocale()); + return 'collection_txt_'.\Locale::getPrimaryLanguage($args['translation']->getLocale()); } + return 'collection_txt'; } - /** - * @return int - */ public function getHighlightingFragmentSize(): int { return $this->highlightingFragmentSize; } - /** - * @param int $highlightingFragmentSize - * - * @return AbstractSearchHandler - */ public function setHighlightingFragmentSize(int $highlightingFragmentSize): AbstractSearchHandler { $this->highlightingFragmentSize = $highlightingFragmentSize; @@ -145,21 +114,12 @@ public function setHighlightingFragmentSize(int $highlightingFragmentSize): Abst return $this; } - /** - * @param string $q - * @param array $args - * @param int $rows - * @param bool $searchTags - * @param int $page - * - * @return array|null - */ abstract protected function nativeSearch( string $q, array $args = [], int $rows = 20, bool $searchTags = false, - int $page = 1 + int $page = 1, ): ?array; /** @@ -186,12 +146,9 @@ abstract protected function nativeSearch( * * this explicitly filter by title. * - * - * @param string $q - * @param array $args - * @param int $rows Results per page + * @param int $rows Results per page * @param bool $searchTags Search in tags/folders too, even if a node don’t match - * @param int $page Retrieve a specific page + * @param int $page Retrieve a specific page * * @return SearchResultsInterface Return an array of doctrine Entities (Document, NodesSources) */ @@ -200,21 +157,18 @@ public function search( array $args = [], int $rows = 20, bool $searchTags = false, - int $page = 1 + int $page = 1, ): SearchResultsInterface { $args = $this->argFqProcess($args); - $args["fq"][] = "document_type_s:" . $this->getDocumentType(); + $args['fq'][] = 'document_type_s:'.$this->getDocumentType(); $tmp = []; $args = array_merge($tmp, $args); $response = $this->nativeSearch($q, $args, $rows, $searchTags, $page); + return $this->createSearchResultsFromResponse($response); } - /** - * @param string $input - * @return string - */ public function escapeQuery(string $input): string { $qHelper = new Helper(); @@ -222,20 +176,20 @@ public function escapeQuery(string $input): string $input = $qHelper->escapeTerm($input); // Solarium does not escape Lucene reserved words // https://stackoverflow.com/questions/10337908/how-to-properly-escape-or-and-and-in-lucene-query - $input = preg_replace("#\\b(AND|OR|NOT)\\b#", "\\\\\\\\$1", $input); + $input = preg_replace('#\\b(AND|OR|NOT)\\b#', '\\\\\\\$1', $input); return $input; } /** - * @param string $q * @return array [$exactQuery, $fuzzyQuery, $wildcardQuery] */ protected function getFormattedQuery(string $q): array { $q = trim($q); /** - * Generate a fuzzy query by appending proximity to each word + * Generate a fuzzy query by appending proximity to each word. + * * @see https://lucene.apache.org/solr/guide/6_6/the-standard-query-parser.html#TheStandardQueryParser-FuzzySearches */ $words = preg_split('#[\s,]+#', $q, -1, PREG_SPLIT_NO_EMPTY); @@ -248,8 +202,9 @@ protected function getFormattedQuery(string $q): array * Proximity is set to 1 by default for single-words */ if (\mb_strlen($word) > 3) { - return $this->escapeQuery($word) . '~2'; + return $this->escapeQuery($word).'~2'; } + return $this->escapeQuery($word); }, $words)); /* @@ -259,7 +214,7 @@ protected function getFormattedQuery(string $q): array /* * Wildcard search for allowing autocomplete */ - $wildcardQuery = $this->escapeQuery($q) . '*~2'; + $wildcardQuery = $this->escapeQuery($q).'*~2'; return [$exactQuery, $fuzzyiedQuery, $wildcardQuery]; } @@ -268,11 +223,6 @@ protected function getFormattedQuery(string $q): array * Default Solr query builder. * * Extends this method to customize your Solr queries. Eg. to boost custom fields. - * - * @param string $q - * @param array $args - * @param bool $searchTags - * @return string */ protected function buildQuery(string $q, array &$args, bool $searchTags = false): string { @@ -287,7 +237,7 @@ protected function buildQuery(string $q, array &$args, bool $searchTags = false) if ($searchTags) { // Need to use Fuzzy search AND Exact search return sprintf( - '(' . $titleField . ':%s)^10 (' . $titleField . ':%s) (' . $titleField . ':%s) (' . $collectionField . ':%s)^2 (' . $collectionField . ':%s) (' . $tagsField . ':%s) (' . $tagsField . ':%s)', + '('.$titleField.':%s)^10 ('.$titleField.':%s) ('.$titleField.':%s) ('.$collectionField.':%s)^2 ('.$collectionField.':%s) ('.$tagsField.':%s) ('.$tagsField.':%s)', $exactQuery, $fuzzyiedQuery, $wildcardQuery, @@ -298,7 +248,7 @@ protected function buildQuery(string $q, array &$args, bool $searchTags = false) ); } else { return sprintf( - '(' . $titleField . ':%s)^10 (' . $titleField . ':%s) (' . $titleField . ':%s) (' . $collectionField . ':%s)^2 (' . $collectionField . ':%s)', + '('.$titleField.':%s)^10 ('.$titleField.':%s) ('.$titleField.':%s) ('.$collectionField.':%s)^2 ('.$collectionField.':%s)', $exactQuery, $fuzzyiedQuery, $wildcardQuery, @@ -317,14 +267,10 @@ protected function buildHighlightingQuery(string $q): string } $q = $this->escapeQuery($q); + return sprintf('%s~2', $q); } - /** - * @param array $args - * @param bool $searchTags - * @return string - */ protected function buildQueryFields(array &$args, bool $searchTags = true): string { $titleField = $this->getTitleField($args); @@ -332,19 +278,15 @@ protected function buildQueryFields(array &$args, bool $searchTags = true): stri $tagsField = $this->getTagsField($args); if ($searchTags) { - return $titleField . '^10 ' . $collectionField . '^2 ' . $tagsField . ' slug_s'; + return $titleField.'^10 '.$collectionField.'^2 '.$tagsField.' slug_s'; } - return $titleField . ' ' . $collectionField . ' slug_s'; + + return $titleField.' '.$collectionField.' slug_s'; } - /** - * @param string $q - * - * @return bool - */ protected function isQuerySingleWord(string $q): bool { - return preg_match('#[\s\-\'\"\–\—\’\”\‘\“\/\+\.\,]#', $q) !== 1; + return 1 !== preg_match('#[\s\-\'\"\–\—\’\”\‘\“\/\+\.\,]#', $q); } protected function formatDateTimeToUTC(\DateTimeInterface $dateTime): string @@ -352,11 +294,6 @@ protected function formatDateTimeToUTC(\DateTimeInterface $dateTime): string return gmdate('Y-m-d\TH:i:s\Z', $dateTime->getTimestamp()); } - /** - * @param array $args - * - * @return string - */ protected function getTitleField(array &$args): string { /* @@ -364,19 +301,15 @@ protected function getTitleField(array &$args): string * is filtered by translation. */ if (isset($args['locale']) && is_string($args['locale'])) { - return 'title_txt_' . \Locale::getPrimaryLanguage($args['locale']); + return 'title_txt_'.\Locale::getPrimaryLanguage($args['locale']); } if (isset($args['translation']) && $args['translation'] instanceof Translation) { - return 'title_txt_' . \Locale::getPrimaryLanguage($args['translation']->getLocale()); + return 'title_txt_'.\Locale::getPrimaryLanguage($args['translation']->getLocale()); } + return 'title'; } - /** - * @param array $args - * - * @return string - */ protected function getTagsField(array &$args): string { /* @@ -384,21 +317,17 @@ protected function getTagsField(array &$args): string * is filtered by translation. */ if (isset($args['locale']) && is_string($args['locale'])) { - return 'tags_txt_' . \Locale::getPrimaryLanguage($args['locale']); + return 'tags_txt_'.\Locale::getPrimaryLanguage($args['locale']); } if (isset($args['translation']) && $args['translation'] instanceof Translation) { - return 'tags_txt_' . \Locale::getPrimaryLanguage($args['translation']->getLocale()); + return 'tags_txt_'.\Locale::getPrimaryLanguage($args['translation']->getLocale()); } + return 'tags_txt'; } /** * Create Solr Select query. Override it to add DisMax fields and rules. - * - * @param array $args - * @param int $rows - * @param int $page - * @return Query */ protected function createSolrQuery(array &$args = [], int $rows = 20, int $page = 1): Query { @@ -408,15 +337,15 @@ protected function createSolrQuery(array &$args = [], int $rows = 20, int $page if (is_array($value)) { foreach ($value as $k => $v) { $query->addFilterQuery([ - "key" => "fq" . $k, - "query" => $v, + 'key' => 'fq'.$k, + 'query' => $v, ]); } } elseif (is_scalar($value)) { $query->addParam($key, $value); } } - /** + /* * Add start if not first page. */ if ($page > 1) { diff --git a/src/SearchEngine/AbstractSolarium.php b/src/SearchEngine/AbstractSolarium.php index d4ac841a..7ef06842 100644 --- a/src/SearchEngine/AbstractSolarium.php +++ b/src/SearchEngine/AbstractSolarium.php @@ -13,9 +13,6 @@ use Solarium\QueryType\Update\Query\Document; use Solarium\QueryType\Update\Query\Query; -/** - * @package RZ\Roadiz\CoreBundle\SearchEngine - */ abstract class AbstractSolarium { public const DOCUMENT_TYPE = 'AbstractDocument'; @@ -55,20 +52,16 @@ abstract class AbstractSolarium 'tr', ]; - protected ClientRegistry $clientRegistry; protected bool $indexed = false; protected ?DocumentInterface $document = null; protected LoggerInterface $logger; - protected MarkdownInterface $markdown; public function __construct( - ClientRegistry $clientRegistry, - LoggerInterface $searchEngineLogger, - MarkdownInterface $markdown + protected readonly ClientRegistry $clientRegistry, + readonly LoggerInterface $searchEngineLogger, + protected readonly MarkdownInterface $markdown, ) { $this->logger = $searchEngineLogger; - $this->markdown = $markdown; - $this->clientRegistry = $clientRegistry; } public function getSolr(): Client @@ -77,6 +70,7 @@ public function getSolr(): Client if (null === $solr) { throw new SolrServerNotAvailableException(); } + return $solr; } @@ -85,7 +79,6 @@ public function getSolr(): Client * * Use this method only when you need to index single NodeSources. * - * @return ResultInterface|null * @throws \Exception */ public function indexAndCommit(): ?ResultInterface @@ -109,7 +102,6 @@ public function indexAndCommit(): ?ResultInterface * * Use this method **only** when you need to re-index a single NodeSources. * - * @return ResultInterface|null * @throws \Exception */ public function updateAndCommit(): ?ResultInterface @@ -119,6 +111,7 @@ public function updateAndCommit(): ?ResultInterface $update->addCommit(true, true, false); $this->logger->debug('[Solr] Document updated.'); + return $this->getSolr()->update($update); } @@ -127,8 +120,6 @@ public function updateAndCommit(): ?ResultInterface * * Use this method only when you need to re-index bulk NodeSources. * - * @param Query $update - * * @throws \Exception */ public function update(Query $update): void @@ -143,9 +134,7 @@ public function update(Query $update): void /** * Remove current document from SearchEngine index. * - * @param Query $update - * @return bool - * @throws \RuntimeException If no document is available. + * @throws \RuntimeException if no document is available */ public function remove(Query $update): bool { @@ -172,6 +161,7 @@ public function removeAndCommit(): void $this->getSolr()->update($update); } } + /** * Remove any document linked to current node-source and commit after. * @@ -190,7 +180,6 @@ public function cleanAndCommit(): void /** * Index current document with entity data. * - * @return bool * @throws \Exception */ public function index(): bool @@ -204,61 +193,56 @@ public function index(): bool $this->document->setField($key, $value); } } + return true; } catch (\RuntimeException $e) { return false; } } - throw new \RuntimeException("No Solr item available for current entity", 1); + throw new \RuntimeException('No Solr item available for current entity', 1); } - /** - * @return DocumentInterface|null - */ public function getDocument(): ?DocumentInterface { return $this->document; } /** - * @param DocumentInterface $document * @return $this - * @deprecated Use createEmptyDocument instead of set an empty Solr document. + * + * @deprecated use createEmptyDocument instead of set an empty Solr document */ public function setDocument(DocumentInterface $document): self { $this->document = $document; + return $this; } /** - * @param Query $update * @return $this */ public function createEmptyDocument(Query $update): self { $this->document = $update->createDocument(); + return $this; } abstract public function clean(Query $update): bool; - - /** - * @return int|string - */ abstract public function getDocumentId(): int|string; /** * Get document from Solr index. * - * @return bool *FALSE* if no document found linked to current node-source. + * @return bool *FALSE* if no document found linked to current node-source */ public function getDocumentFromIndex(): bool { $query = $this->getSolr()->createSelect(); - $query->setQuery(static::IDENTIFIER_KEY . ':' . $this->getDocumentId()); - $query->createFilterQuery('type')->setQuery(static::TYPE_DISCRIMINATOR . ':' . static::DOCUMENT_TYPE); + $query->setQuery(static::IDENTIFIER_KEY.':'.$this->getDocumentId()); + $query->createFilterQuery('type')->setQuery(static::TYPE_DISCRIMINATOR.':'.static::DOCUMENT_TYPE); // this executes the query and returns the result $resultset = $this->getSolr()->select($query); @@ -268,26 +252,21 @@ public function getDocumentFromIndex(): bool } else { foreach ($resultset as $document) { $this->document = $document; + return true; } } + return false; } /** * Get a key/value array representation of current indexed object. * - * @return array * @throws \Exception */ abstract protected function getFieldsAssoc(): array; - /** - * @param string|null $content - * @param bool $stripMarkdown - * - * @return string|null - */ public function cleanTextContent(?string $content, bool $stripMarkdown = true): ?string { if (!is_string($content)) { @@ -305,16 +284,15 @@ public function cleanTextContent(?string $content, bool $stripMarkdown = true): /* * Remove ctrl characters */ - $content = preg_replace("[:cntrl:]", "", $content); + $content = preg_replace('[:cntrl:]', '', $content); $content = preg_replace('/[\x00-\x1F]/', '', $content); + return $content; } /** * You MUST override this method to provide an idempotent identifier. * This identifier MUST be the same for the same entity. - * - * @return string */ protected function getIdempotentIdentifier(): string { diff --git a/src/SearchEngine/ClientRegistry.php b/src/SearchEngine/ClientRegistry.php index 85ef24f8..5d87d45f 100644 --- a/src/SearchEngine/ClientRegistry.php +++ b/src/SearchEngine/ClientRegistry.php @@ -7,9 +7,9 @@ use Solarium\Core\Client\Client; use Symfony\Component\DependencyInjection\ContainerInterface; -final class ClientRegistry +final readonly class ClientRegistry { - public function __construct(private readonly ContainerInterface $container) + public function __construct(private ContainerInterface $container) { } @@ -23,8 +23,9 @@ public function getClient(): ?Client return null; } if (!($client instanceof Client)) { - throw new \RuntimeException('Solr client must be an instance of ' . Client::class); + throw new \RuntimeException('Solr client must be an instance of '.Client::class); } + return $client; } @@ -36,6 +37,7 @@ public function isClientReady(?Client $client): bool $ping = $client->createPing(); try { $client->ping($ping); + return true; } catch (\Exception $e) { return false; diff --git a/src/SearchEngine/DocumentSearchHandler.php b/src/SearchEngine/DocumentSearchHandler.php index eb83052a..7ccdb773 100644 --- a/src/SearchEngine/DocumentSearchHandler.php +++ b/src/SearchEngine/DocumentSearchHandler.php @@ -8,26 +8,14 @@ use RZ\Roadiz\CoreBundle\Entity\Translation; use RZ\Roadiz\CoreBundle\SearchEngine\Event\DocumentSearchQueryEvent; -/** - * @package RZ\Roadiz\CoreBundle\SearchEngine - */ class DocumentSearchHandler extends AbstractSearchHandler { - /** - * @param string $q - * @param array $args - * @param integer $rows - * @param bool $searchTags - * @param integer $page - * - * @return array|null - */ protected function nativeSearch( string $q, array $args = [], int $rows = 20, bool $searchTags = false, - int $page = 1 + int $page = 1, ): ?array { if (empty($q)) { return null; @@ -51,7 +39,7 @@ protected function nativeSearch( $this->logger->debug('[Solr] Request document search…', [ 'query' => $queryTxt, - 'fq' => $args["fq"] ?? [], + 'fq' => $args['fq'] ?? [], 'params' => $query->getParams(), ]); @@ -62,17 +50,14 @@ protected function nativeSearch( $query = $event->getQuery(); $solrRequest = $this->getSolr()->execute($query); + return $solrRequest->getData(); } - /** - * @param array $args - * @return array - */ protected function argFqProcess(array &$args): array { - if (!isset($args["fq"])) { - $args["fq"] = []; + if (!isset($args['fq'])) { + $args['fq'] = []; } /* @@ -80,11 +65,11 @@ protected function argFqProcess(array &$args): array */ if (!empty($args['folders'])) { if ($args['folders'] instanceof Folder) { - $args["fq"][] = sprintf('all_tags_slugs_ss:"%s"', $args['folders']->getFolderName()); + $args['fq'][] = sprintf('all_tags_slugs_ss:"%s"', $args['folders']->getFolderName()); } elseif (is_array($args['folders'])) { foreach ($args['folders'] as $folder) { if ($folder instanceof Folder) { - $args["fq"][] = sprintf('all_tags_slugs_ss:"%s"', $folder->getFolderName()); + $args['fq'][] = sprintf('all_tags_slugs_ss:"%s"', $folder->getFolderName()); } } } @@ -92,48 +77,45 @@ protected function argFqProcess(array &$args): array } if (isset($args['mimeType'])) { - $tmp = "mime_type_s:"; + $tmp = 'mime_type_s:'; if (!is_array($args['mimeType'])) { $tmp .= (string) $args['mimeType']; } else { $value = implode(' AND ', $args['mimeType']); - $tmp .= '(' . $value . ')'; + $tmp .= '('.$value.')'; } unset($args['mimeType']); - $args["fq"][] = $tmp; + $args['fq'][] = $tmp; } /* * Filter by translation or locale */ if (isset($args['translation']) && $args['translation'] instanceof Translation) { - $args["fq"][] = "locale_s:" . $args['translation']->getLocale(); + $args['fq'][] = 'locale_s:'.$args['translation']->getLocale(); } if (isset($args['locale']) && is_string($args['locale'])) { - $args["fq"][] = "locale_s:" . $args['locale']; + $args['fq'][] = 'locale_s:'.$args['locale']; } /* * Filter by filename */ if (isset($args['filename'])) { - $args["fq"][] = sprintf('filename_s:"%s"', trim($args['filename'])); + $args['fq'][] = sprintf('filename_s:"%s"', trim($args['filename'])); } /* * Filter out non-valid copyright documents */ if (isset($args['copyrightValid'])) { - $args["fq"][] = '(copyright_valid_since_dt:[* TO NOW] AND copyright_valid_until_dt:[NOW TO *])'; + $args['fq'][] = '(copyright_valid_since_dt:[* TO NOW] AND copyright_valid_until_dt:[NOW TO *])'; unset($args['copyrightValid']); } return $args; } - /** - * @return string - */ protected function getDocumentType(): string { return 'DocumentTranslation'; diff --git a/src/SearchEngine/Event/AbstractSearchQueryEvent.php b/src/SearchEngine/Event/AbstractSearchQueryEvent.php index 0b65abda..0507d533 100644 --- a/src/SearchEngine/Event/AbstractSearchQueryEvent.php +++ b/src/SearchEngine/Event/AbstractSearchQueryEvent.php @@ -18,17 +18,11 @@ public function __construct(Query $query, array $args) $this->args = $args; } - /** - * @return Query - */ public function getQuery(): Query { return $this->query; } - /** - * @return array - */ public function getArgs(): array { return $this->args; diff --git a/src/SearchEngine/GlobalNodeSourceSearchHandler.php b/src/SearchEngine/GlobalNodeSourceSearchHandler.php index 761a221d..081669d0 100644 --- a/src/SearchEngine/GlobalNodeSourceSearchHandler.php +++ b/src/SearchEngine/GlobalNodeSourceSearchHandler.php @@ -10,16 +10,10 @@ use RZ\Roadiz\CoreBundle\Entity\NodesSources; use RZ\Roadiz\CoreBundle\Entity\Translation; -/** - * @package RZ\Roadiz\CoreBundle\SearchEngine - */ -class GlobalNodeSourceSearchHandler +readonly class GlobalNodeSourceSearchHandler { - private ObjectManager $em; - - public function __construct(ObjectManager $em) + public function __construct(private ObjectManager $em) { - $this->em = $em; } /** @@ -31,26 +25,22 @@ protected function getRepository(): EntityRepository } /** - * @param bool $displayNonPublishedNodes - * * @return $this */ public function setDisplayNonPublishedNodes(bool $displayNonPublishedNodes): self { $this->getRepository()->setDisplayingNotPublishedNodes($displayNonPublishedNodes); + return $this; } /** - * @param string $searchTerm - * @param int $resultCount - * @param Translation|null $translation * @return NodesSources[] */ public function getNodeSourcesBySearchTerm( string $searchTerm, int $resultCount, - ?Translation $translation = null + ?Translation $translation = null, ): array { $safeSearchTerms = strip_tags($searchTerm); @@ -80,7 +70,7 @@ public function getNodeSourcesBySearchTerm( $resultCount ); - if (count($nodesSources) === 0) { + if (0 === count($nodesSources)) { /* * Then try with node name. */ @@ -93,7 +83,7 @@ public function getNodeSourcesBySearchTerm( $qb->expr()->like('ns.title', ':nodeName') )) ->setMaxResults($resultCount) - ->setParameter('nodeName', '%' . $safeSearchTerms . '%'); + ->setParameter('nodeName', '%'.$safeSearchTerms.'%'); if (null !== $translation) { $qb->andWhere($qb->expr()->eq('ns.translation', ':translation')) diff --git a/src/SearchEngine/Indexer/AbstractIndexer.php b/src/SearchEngine/Indexer/AbstractIndexer.php index 94e9716c..3bfded51 100644 --- a/src/SearchEngine/Indexer/AbstractIndexer.php +++ b/src/SearchEngine/Indexer/AbstractIndexer.php @@ -21,37 +21,30 @@ public function __construct( protected readonly ClientRegistry $clientRegistry, protected readonly ManagerRegistry $managerRegistry, protected readonly SolariumFactoryInterface $solariumFactory, - readonly LoggerInterface $searchEngineLogger + readonly LoggerInterface $searchEngineLogger, ) { $this->logger = $searchEngineLogger; } - /** - * @return Client - */ public function getSolr(): Client { $solr = $this->clientRegistry->getClient(); if (null === $solr) { throw new SolrServerNotAvailableException(); } + return $solr; } - /** - * @param SymfonyStyle|null $io - * @return AbstractIndexer - */ public function setIo(?SymfonyStyle $io): self { $this->io = $io; + return $this; } /** * Empty Solr index. - * - * @param string|null $documentType */ public function emptySolr(?string $documentType = null): void { diff --git a/src/SearchEngine/Indexer/Indexer.php b/src/SearchEngine/Indexer/Indexer.php index 2030841b..020c8da1 100644 --- a/src/SearchEngine/Indexer/Indexer.php +++ b/src/SearchEngine/Indexer/Indexer.php @@ -7,8 +7,12 @@ interface Indexer { public function reindexAll(): void; + public function index(mixed $id): void; + public function delete(mixed $id): void; + public function emptySolr(?string $documentType = null): void; + public function optimizeSolr(): void; } diff --git a/src/SearchEngine/Indexer/IndexerFactory.php b/src/SearchEngine/Indexer/IndexerFactory.php index 22ad1cba..3241853a 100644 --- a/src/SearchEngine/Indexer/IndexerFactory.php +++ b/src/SearchEngine/Indexer/IndexerFactory.php @@ -4,7 +4,6 @@ namespace RZ\Roadiz\CoreBundle\SearchEngine\Indexer; -use LogicException; use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; use Psr\Container\NotFoundExceptionInterface; @@ -25,7 +24,7 @@ public function __construct(ContainerInterface $serviceLocator) /** * @param class-string $classname - * @return Indexer + * * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ @@ -37,7 +36,7 @@ public function getIndexerFor(string $classname): Indexer Document::class => $this->serviceLocator->get(DocumentIndexer::class), Tag::class => $this->serviceLocator->get(TagIndexer::class), Folder::class => $this->serviceLocator->get(FolderIndexer::class), - default => throw new LogicException(sprintf('No indexer found for "%s"', $classname)), + default => throw new \LogicException(sprintf('No indexer found for "%s"', $classname)), }; } } diff --git a/src/SearchEngine/Indexer/IndexerFactoryInterface.php b/src/SearchEngine/Indexer/IndexerFactoryInterface.php index 03952dff..ac2b946c 100644 --- a/src/SearchEngine/Indexer/IndexerFactoryInterface.php +++ b/src/SearchEngine/Indexer/IndexerFactoryInterface.php @@ -8,7 +8,6 @@ interface IndexerFactoryInterface { /** * @param class-string $classname - * @return Indexer */ public function getIndexerFor(string $classname): Indexer; } diff --git a/src/SearchEngine/Indexer/NodesSourcesIndexer.php b/src/SearchEngine/Indexer/NodesSourcesIndexer.php index 65279dd0..eae097a8 100644 --- a/src/SearchEngine/Indexer/NodesSourcesIndexer.php +++ b/src/SearchEngine/Indexer/NodesSourcesIndexer.php @@ -56,9 +56,7 @@ protected function deleteNodeSource(?NodesSources $nodeSource): void } /** - * Overridable - * - * @return QueryBuilder + * Overridable. */ protected function getAllQueryBuilder(): QueryBuilder { @@ -71,8 +69,9 @@ protected function getAllQueryBuilder(): QueryBuilder /** * Loop over every NodesSources to index them again. * - * @param int $batchCount Split reindex span to several batches. - * @param int $batchNumber Execute reindex on a specific batch. + * @param int $batchCount split reindex span to several batches + * @param int $batchNumber execute reindex on a specific batch + * * @throws \Doctrine\ORM\NoResultException * @throws \Doctrine\ORM\NonUniqueResultException */ diff --git a/src/SearchEngine/Message/AbstractSolrMessage.php b/src/SearchEngine/Message/AbstractSolrMessage.php index 9ce292a4..3633ad68 100644 --- a/src/SearchEngine/Message/AbstractSolrMessage.php +++ b/src/SearchEngine/Message/AbstractSolrMessage.php @@ -9,36 +9,22 @@ abstract class AbstractSolrMessage implements AsyncMessage { /** - * Cannot typehint with class-string: breaks Symfony Serializer 5.4 - * @var string + * Cannot typehint with class-string: breaks Symfony Serializer 5.4. */ protected string $classname; - /** - * @var mixed - */ protected mixed $identifier; - /** - * @param string $classname - * @param mixed $identifier - */ public function __construct(string $classname, mixed $identifier) { $this->classname = $classname; $this->identifier = $identifier; } - /** - * @return string - */ public function getClassname(): string { return $this->classname; } - /** - * @return mixed - */ public function getIdentifier(): mixed { return $this->identifier; diff --git a/src/SearchEngine/Message/Handler/SolrDeleteMessageHandler.php b/src/SearchEngine/Message/Handler/SolrDeleteMessageHandler.php index 3ee62b78..7d330c82 100644 --- a/src/SearchEngine/Message/Handler/SolrDeleteMessageHandler.php +++ b/src/SearchEngine/Message/Handler/SolrDeleteMessageHandler.php @@ -8,13 +8,14 @@ use RZ\Roadiz\CoreBundle\Exception\SolrServerNotAvailableException; use RZ\Roadiz\CoreBundle\SearchEngine\Indexer\IndexerFactoryInterface; use RZ\Roadiz\CoreBundle\SearchEngine\Message\SolrDeleteMessage; -use Symfony\Component\Messenger\Handler\MessageHandlerInterface; +use Symfony\Component\Messenger\Attribute\AsMessageHandler; -final class SolrDeleteMessageHandler implements MessageHandlerInterface +#[AsMessageHandler] +final class SolrDeleteMessageHandler { public function __construct( private readonly IndexerFactoryInterface $indexerFactory, - private readonly LoggerInterface $searchEngineLogger + private readonly LoggerInterface $searchEngineLogger, ) { } diff --git a/src/SearchEngine/Message/Handler/SolrReindexMessageHandler.php b/src/SearchEngine/Message/Handler/SolrReindexMessageHandler.php index 6087ce7a..55442258 100644 --- a/src/SearchEngine/Message/Handler/SolrReindexMessageHandler.php +++ b/src/SearchEngine/Message/Handler/SolrReindexMessageHandler.php @@ -8,13 +8,14 @@ use RZ\Roadiz\CoreBundle\Exception\SolrServerNotAvailableException; use RZ\Roadiz\CoreBundle\SearchEngine\Indexer\IndexerFactoryInterface; use RZ\Roadiz\CoreBundle\SearchEngine\Message\SolrReindexMessage; -use Symfony\Component\Messenger\Handler\MessageHandlerInterface; +use Symfony\Component\Messenger\Attribute\AsMessageHandler; -final class SolrReindexMessageHandler implements MessageHandlerInterface +#[AsMessageHandler] +final class SolrReindexMessageHandler { public function __construct( private readonly IndexerFactoryInterface $indexerFactory, - private readonly LoggerInterface $searchEngineLogger + private readonly LoggerInterface $searchEngineLogger, ) { } diff --git a/src/SearchEngine/NodeSourceSearchHandler.php b/src/SearchEngine/NodeSourceSearchHandler.php index 56c6a166..49cbf129 100644 --- a/src/SearchEngine/NodeSourceSearchHandler.php +++ b/src/SearchEngine/NodeSourceSearchHandler.php @@ -9,32 +9,21 @@ use RZ\Roadiz\Core\AbstractEntities\TranslationInterface; use RZ\Roadiz\CoreBundle\Entity\Node; use RZ\Roadiz\CoreBundle\Entity\Tag; +use RZ\Roadiz\CoreBundle\Enum\NodeStatus; use RZ\Roadiz\CoreBundle\SearchEngine\Event\NodeSourceSearchQueryEvent; -/** - * @package RZ\Roadiz\CoreBundle\SearchEngine - */ class NodeSourceSearchHandler extends AbstractSearchHandler implements NodeSourceSearchHandlerInterface { protected bool $boostByPublicationDate = false; protected bool $boostByUpdateDate = false; protected bool $boostByCreationDate = false; - /** - * @param string $q - * @param array $args - * @param integer $rows - * @param bool $searchTags - * @param int $page - * - * @return array|null - */ protected function nativeSearch( string $q, array $args = [], int $rows = 20, bool $searchTags = false, - int $page = 1 + int $page = 1, ): ?array { if (empty($q)) { return null; @@ -44,15 +33,15 @@ protected function nativeSearch( if ($this->boostByPublicationDate) { $boost = '{!boost b=recip(ms(NOW,published_at_dt),3.16e-11,1,1)}'; - $queryTxt = $boost . $queryTxt; + $queryTxt = $boost.$queryTxt; } if ($this->boostByUpdateDate) { $boost = '{!boost b=recip(ms(NOW,updated_at_dt),3.16e-11,1,1)}'; - $queryTxt = $boost . $queryTxt; + $queryTxt = $boost.$queryTxt; } if ($this->boostByCreationDate) { $boost = '{!boost b=recip(ms(NOW,created_at_dt),3.16e-11,1,1)}'; - $queryTxt = $boost . $queryTxt; + $queryTxt = $boost.$queryTxt; } $query->setQuery($queryTxt); @@ -72,7 +61,7 @@ protected function nativeSearch( $this->logger->debug('[Solr] Request node-sources search…', [ 'query' => $queryTxt, - 'fq' => $args["fq"] ?? [], + 'fq' => $args['fq'] ?? [], 'params' => $query->getParams(), ]); @@ -83,25 +72,22 @@ protected function nativeSearch( $query = $event->getQuery(); $solrRequest = $this->getSolr()->execute($query); + return $solrRequest->getData(); } - /** - * @param array $args - * @return array - */ protected function argFqProcess(array &$args): array { - if (!isset($args["fq"])) { - $args["fq"] = []; + if (!isset($args['fq'])) { + $args['fq'] = []; } $visible = $args['visible'] ?? $args['node.visible'] ?? null; if (isset($visible)) { - $tmp = "node_visible_b:" . (($visible) ? 'true' : 'false'); + $tmp = 'node_visible_b:'.(($visible) ? 'true' : 'false'); unset($args['visible']); unset($args['node.visible']); - $args["fq"][] = $tmp; + $args['fq'][] = $tmp; } /* @@ -110,11 +96,11 @@ protected function argFqProcess(array &$args): array */ if (!empty($args['tags'])) { if ($args['tags'] instanceof Tag) { - $args["fq"][] = sprintf('all_tags_slugs_ss:"%s"', $args['tags']->getTagName()); + $args['fq'][] = sprintf('all_tags_slugs_ss:"%s"', $args['tags']->getTagName()); } elseif (is_array($args['tags'])) { foreach ($args['tags'] as $tag) { if ($tag instanceof Tag) { - $args["fq"][] = sprintf('all_tags_slugs_ss:"%s"', $tag->getTagName()); + $args['fq'][] = sprintf('all_tags_slugs_ss:"%s"', $tag->getTagName()); } } } @@ -135,11 +121,11 @@ protected function argFqProcess(array &$args): array $orQuery[] = $singleNodeType; } } - $args["fq"][] = "node_type_s:(" . implode(' OR ', $orQuery) . ')'; + $args['fq'][] = 'node_type_s:('.implode(' OR ', $orQuery).')'; } elseif ($nodeType instanceof NodeTypeInterface) { - $args["fq"][] = "node_type_s:" . $nodeType->getName(); + $args['fq'][] = 'node_type_s:'.$nodeType->getName(); } else { - $args["fq"][] = "node_type_s:" . $nodeType; + $args['fq'][] = 'node_type_s:'.$nodeType; } unset($args['nodeType']); unset($args['node.nodeType']); @@ -151,11 +137,11 @@ protected function argFqProcess(array &$args): array $parent = $args['parent'] ?? $args['node.parent'] ?? null; if (!empty($parent)) { if ($parent instanceof Node) { - $args["fq"][] = "node_parent_i:" . $parent->getId(); + $args['fq'][] = 'node_parent_i:'.$parent->getId(); } elseif (is_string($parent)) { - $args["fq"][] = "node_parent_s:" . trim($parent); + $args['fq'][] = 'node_parent_s:'.trim($parent); } elseif (is_numeric($parent)) { - $args["fq"][] = "node_parent_i:" . (int) $parent; + $args['fq'][] = 'node_parent_i:'.(int) $parent; } unset($args['parent']); unset($args['node.parent']); @@ -165,81 +151,77 @@ protected function argFqProcess(array &$args): array * Handle publication date-time filtering */ if (isset($args['publishedAt'])) { - $tmp = "published_at_dt:"; + $tmp = 'published_at_dt:'; if (!is_array($args['publishedAt']) && $args['publishedAt'] instanceof \DateTimeInterface) { $tmp .= $this->formatDateTimeToUTC($args['publishedAt']); } elseif ( - isset($args['publishedAt'][0]) && - $args['publishedAt'][0] === "BETWEEN" && - isset($args['publishedAt'][1]) && - $args['publishedAt'][1] instanceof \DateTimeInterface && - isset($args['publishedAt'][2]) && - $args['publishedAt'][2] instanceof \DateTimeInterface + isset($args['publishedAt'][0]) + && 'BETWEEN' === $args['publishedAt'][0] + && isset($args['publishedAt'][1]) + && $args['publishedAt'][1] instanceof \DateTimeInterface + && isset($args['publishedAt'][2]) + && $args['publishedAt'][2] instanceof \DateTimeInterface ) { - $tmp .= "[" . - $this->formatDateTimeToUTC($args['publishedAt'][1]) . - " TO " . - $this->formatDateTimeToUTC($args['publishedAt'][2]) . "]"; + $tmp .= '['. + $this->formatDateTimeToUTC($args['publishedAt'][1]). + ' TO '. + $this->formatDateTimeToUTC($args['publishedAt'][2]).']'; } elseif ( - isset($args['publishedAt'][0]) && - $args['publishedAt'][0] === "<=" && - isset($args['publishedAt'][1]) && - $args['publishedAt'][1] instanceof \DateTimeInterface + isset($args['publishedAt'][0]) + && '<=' === $args['publishedAt'][0] + && isset($args['publishedAt'][1]) + && $args['publishedAt'][1] instanceof \DateTimeInterface ) { - $tmp .= "[* TO " . $this->formatDateTimeToUTC($args['publishedAt'][1]) . "]"; + $tmp .= '[* TO '.$this->formatDateTimeToUTC($args['publishedAt'][1]).']'; } elseif ( - isset($args['publishedAt'][0]) && - $args['publishedAt'][0] === ">=" && - isset($args['publishedAt'][1]) && - $args['publishedAt'][1] instanceof \DateTimeInterface + isset($args['publishedAt'][0]) + && '>=' === $args['publishedAt'][0] + && isset($args['publishedAt'][1]) + && $args['publishedAt'][1] instanceof \DateTimeInterface ) { - $tmp .= "[" . $this->formatDateTimeToUTC($args['publishedAt'][1]) . " TO *]"; + $tmp .= '['.$this->formatDateTimeToUTC($args['publishedAt'][1]).' TO *]'; } unset($args['publishedAt']); - $args["fq"][] = $tmp; + $args['fq'][] = $tmp; } $status = $args['status'] ?? $args['node.status'] ?? null; if (isset($status)) { - $tmp = "node_status_i:"; - if (!is_array($status)) { + $tmp = 'node_status_i:'; + if ($status instanceof NodeStatus) { + $tmp .= (string) $status->value; + } elseif (is_numeric($status)) { $tmp .= (string) $status; - } elseif ($status[0] == "<=") { - $tmp .= "[* TO " . (string) $status[1] . "]"; - } elseif ($status[0] == ">=") { - $tmp .= "[" . (string) $status[1] . " TO *]"; + } elseif (is_array($status) && '<=' == $status[0] && $status[1] instanceof NodeStatus) { + $tmp .= '[* TO '.(string) $status[1]->value.']'; + } elseif (is_array($status) && '>=' == $status[0]->value && $status[1] instanceof NodeStatus) { + $tmp .= '['.(string) $status[1]->value.' TO *]'; } unset($args['status']); unset($args['node.status']); - $args["fq"][] = $tmp; + $args['fq'][] = $tmp; } else { - $args["fq"][] = "node_status_i:" . (string) (Node::PUBLISHED); + $args['fq'][] = 'node_status_i:'.(string) NodeStatus::PUBLISHED->value; } /* * Filter by translation or locale */ if (isset($args['translation']) && $args['translation'] instanceof TranslationInterface) { - $args["fq"][] = "locale_s:" . $args['translation']->getLocale(); + $args['fq'][] = 'locale_s:'.$args['translation']->getLocale(); } if (isset($args['locale']) && is_string($args['locale'])) { - $args["fq"][] = "locale_s:" . $args['locale']; + $args['fq'][] = 'locale_s:'.$args['locale']; } return $args; } - /** - * @return string - */ protected function getDocumentType(): string { return 'NodesSources'; } - /** - * @return NodeSourceSearchHandler - */ public function boostByPublicationDate(): NodeSourceSearchHandler { $this->boostByPublicationDate = true; @@ -249,9 +231,6 @@ public function boostByPublicationDate(): NodeSourceSearchHandler return $this; } - /** - * @return NodeSourceSearchHandler - */ public function boostByUpdateDate(): NodeSourceSearchHandler { $this->boostByPublicationDate = false; @@ -261,9 +240,6 @@ public function boostByUpdateDate(): NodeSourceSearchHandler return $this; } - /** - * @return NodeSourceSearchHandler - */ public function boostByCreationDate(): NodeSourceSearchHandler { $this->boostByPublicationDate = false; diff --git a/src/SearchEngine/NodeSourceSearchHandlerInterface.php b/src/SearchEngine/NodeSourceSearchHandlerInterface.php index e14e4faa..c451a9cf 100644 --- a/src/SearchEngine/NodeSourceSearchHandlerInterface.php +++ b/src/SearchEngine/NodeSourceSearchHandlerInterface.php @@ -7,6 +7,8 @@ interface NodeSourceSearchHandlerInterface extends SearchHandlerInterface { public function boostByPublicationDate(): NodeSourceSearchHandlerInterface; + public function boostByUpdateDate(): NodeSourceSearchHandlerInterface; + public function boostByCreationDate(): NodeSourceSearchHandlerInterface; } diff --git a/src/SearchEngine/SearchHandlerInterface.php b/src/SearchEngine/SearchHandlerInterface.php index 9612829c..c1bf2a94 100644 --- a/src/SearchEngine/SearchHandlerInterface.php +++ b/src/SearchEngine/SearchHandlerInterface.php @@ -7,11 +7,9 @@ interface SearchHandlerInterface { /** - * @param string $q - * @param array $args - * @param int $rows Results per page + * @param int $rows Results per page * @param bool $searchTags Search in tags/folders too, even if a node don’t match - * @param int $page Retrieve a specific page + * @param int $page Retrieve a specific page * * @return SearchResultsInterface Return an array of doctrine Entities (Document, NodesSources) */ @@ -20,31 +18,23 @@ public function search( array $args = [], int $rows = 20, bool $searchTags = false, - int $page = 1 + int $page = 1, ): SearchResultsInterface; /** * Search with pre-filled argument for highlighting. * - * @param string $q - * @param array $args - * @param int $rows - * @param boolean $searchTags Search in tags/folders too, even if a node don’t match - * @param int $page + * @param bool $searchTags Search in tags/folders too, even if a node don’t match * - * @return SearchResultsInterface Return a SearchResultsInterface iterable object. + * @return SearchResultsInterface return a SearchResultsInterface iterable object */ public function searchWithHighlight( string $q, array $args = [], int $rows = 20, bool $searchTags = false, - int $page = 1 + int $page = 1, ): SearchResultsInterface; - /** - * @param int $highlightingFragmentSize - * @return SearchHandlerInterface - */ public function setHighlightingFragmentSize(int $highlightingFragmentSize): SearchHandlerInterface; } diff --git a/src/SearchEngine/SearchResultsInterface.php b/src/SearchEngine/SearchResultsInterface.php index 8705097a..de5c4011 100644 --- a/src/SearchEngine/SearchResultsInterface.php +++ b/src/SearchEngine/SearchResultsInterface.php @@ -10,9 +10,11 @@ interface SearchResultsInterface extends \Iterator { public function getResultCount(): int; + /** * @return array */ public function getResultItems(): array; + public function map(callable $callable): array; } diff --git a/src/SearchEngine/SolariumDocument.php b/src/SearchEngine/SolariumDocument.php index 666606c2..f0fa0f84 100644 --- a/src/SearchEngine/SolariumDocument.php +++ b/src/SearchEngine/SolariumDocument.php @@ -5,36 +5,25 @@ namespace RZ\Roadiz\CoreBundle\SearchEngine; use Psr\Log\LoggerInterface; -use RZ\Roadiz\Core\AbstractEntities\PersistableInterface; use RZ\Roadiz\CoreBundle\Entity\Document; use RZ\Roadiz\Markdown\MarkdownInterface; use Solarium\Core\Query\DocumentInterface; use Solarium\Core\Query\Result\ResultInterface; use Solarium\QueryType\Update\Query\Query; -use Symfony\Component\String\Slugger\AsciiSlugger; /** - * Wrap a Solarium and a Document’ translations together to ease indexing. - * - * @package RZ\Roadiz\CoreBundle\SearchEngine + * Wrap a Solarium and a document translations together to ease indexing. */ class SolariumDocument extends AbstractSolarium { protected array $documentTranslationItems; - /** - * @param Document $rzDocument - * @param SolariumFactoryInterface $solariumFactory - * @param ClientRegistry $clientRegistry - * @param LoggerInterface $searchEngineLogger - * @param MarkdownInterface $markdown - */ public function __construct( - Document $rzDocument, + readonly Document $rzDocument, SolariumFactoryInterface $solariumFactory, ClientRegistry $clientRegistry, LoggerInterface $searchEngineLogger, - MarkdownInterface $markdown + MarkdownInterface $markdown, ) { parent::__construct($clientRegistry, $searchEngineLogger, $markdown); $this->documentTranslationItems = []; @@ -55,7 +44,7 @@ public function getDocument(): ?DocumentInterface /** * @return array<\Solarium\QueryType\Update\Query\Document|DocumentInterface> Each document translation Solr document */ - public function getDocuments() + public function getDocuments(): array { $documents = []; /** @var SolariumDocumentTranslation $documentTranslationItem */ @@ -74,7 +63,7 @@ public function getDocumentId(): string|int /** * Get document from Solr index. * - * @return bool *FALSE* if no document found linked to current Roadiz document. + * @return bool *FALSE* if no document found linked to current Roadiz document */ public function getDocumentFromIndex(): bool { @@ -87,7 +76,6 @@ public function getDocumentFromIndex(): bool } /** - * @param Query $update * @return $this */ public function createEmptyDocument(Query $update): self @@ -96,6 +84,7 @@ public function createEmptyDocument(Query $update): self foreach ($this->documentTranslationItems as $documentTranslationItem) { $documentTranslationItem->createEmptyDocument($update); } + return $this; } @@ -104,11 +93,6 @@ protected function getFieldsAssoc(): array return []; } - /** - * @param Query $update - * - * @return bool - */ public function clean(Query $update): bool { /** @var SolariumDocumentTranslation $documentTranslationItem */ @@ -126,11 +110,11 @@ public function indexAndCommit(): ?ResultInterface foreach ($this->documentTranslationItems as $documentTranslationItem) { $lastResult = $documentTranslationItem->indexAndCommit(); } + return $lastResult; } /** - * @return ResultInterface|null * @throws \Exception */ public function updateAndCommit(): ?ResultInterface @@ -145,8 +129,6 @@ public function updateAndCommit(): ?ResultInterface } /** - * @param Query $update - * * @throws \Exception */ public function update(Query $update): void @@ -157,23 +139,16 @@ public function update(Query $update): void } } - /** - * @param Query $update - * - * @return bool - */ public function remove(Query $update): bool { /** @var SolariumDocumentTranslation $documentTranslationItem */ foreach ($this->documentTranslationItems as $documentTranslationItem) { $documentTranslationItem->remove($update); } + return true; } - /** - * @inheritdoc - */ public function removeAndCommit(): void { /** @var SolariumDocumentTranslation $documentTranslationItem */ @@ -182,9 +157,6 @@ public function removeAndCommit(): void } } - /** - * @inheritdoc - */ public function cleanAndCommit(): void { /** @var SolariumDocumentTranslation $documentTranslationItem */ @@ -193,9 +165,6 @@ public function cleanAndCommit(): void } } - /** - * @inheritdoc - */ public function index(): bool { /** @var SolariumDocumentTranslation $documentTranslationItem */ diff --git a/src/SearchEngine/SolariumDocumentTranslation.php b/src/SearchEngine/SolariumDocumentTranslation.php index 8ea8b2fa..47dbdd4e 100644 --- a/src/SearchEngine/SolariumDocumentTranslation.php +++ b/src/SearchEngine/SolariumDocumentTranslation.php @@ -14,28 +14,20 @@ /** * Wrap a Solarium and a DocumentTranslation together to ease indexing. - * - * @package RZ\Roadiz\CoreBundle\SearchEngine */ class SolariumDocumentTranslation extends AbstractSolarium { public const DOCUMENT_TYPE = 'DocumentTranslation'; public const IDENTIFIER_KEY = 'document_translation_id_i'; - protected DocumentTranslation $documentTranslation; - protected EventDispatcherInterface $dispatcher; - public function __construct( - DocumentTranslation $documentTranslation, + protected readonly DocumentTranslation $documentTranslation, ClientRegistry $clientRegistry, - EventDispatcherInterface $dispatcher, + protected readonly EventDispatcherInterface $dispatcher, LoggerInterface $searchEngineLogger, - MarkdownInterface $markdown + MarkdownInterface $markdown, ) { parent::__construct($clientRegistry, $searchEngineLogger, $markdown); - - $this->documentTranslation = $documentTranslation; - $this->dispatcher = $dispatcher; } public function getDocumentId(): int|string @@ -48,21 +40,19 @@ public function getFieldsAssoc(bool $subResource = false): array $event = new DocumentTranslationIndexingEvent($this->documentTranslation, [], $this); /** @var DocumentTranslationIndexingEvent $event */ $event = $this->dispatcher->dispatch($event); + return $event->getAssociations(); } /** * Remove any document linked to current node-source. - * - * @param Query $update - * @return bool */ public function clean(Query $update): bool { $update->addDeleteQuery( - static::IDENTIFIER_KEY . ':"' . $this->documentTranslation->getId() . '"' . - '&' . static::TYPE_DISCRIMINATOR . ':"' . static::DOCUMENT_TYPE . '"' . - '&locale_s:"' . $this->documentTranslation->getTranslation()->getLocale() . '"' + static::IDENTIFIER_KEY.':"'.$this->documentTranslation->getId().'"'. + '&'.static::TYPE_DISCRIMINATOR.':"'.static::DOCUMENT_TYPE.'"'. + '&locale_s:"'.$this->documentTranslation->getTranslation()->getLocale().'"' ); return true; @@ -73,6 +63,7 @@ protected function getIdempotentIdentifier(): string $namespace = explode('\\', get_class($this->documentTranslation)); // get last 3 parts of namespace $namespace = array_slice($namespace, -3); - return (new AsciiSlugger())->slug(implode(' ', $namespace))->lower()->snake() . '.' . $this->documentTranslation->getId(); + + return (new AsciiSlugger())->slug(implode(' ', $namespace))->lower()->snake().'.'.$this->documentTranslation->getId(); } } diff --git a/src/SearchEngine/SolariumFactory.php b/src/SearchEngine/SolariumFactory.php index 34fa3d51..99f4fa0f 100644 --- a/src/SearchEngine/SolariumFactory.php +++ b/src/SearchEngine/SolariumFactory.php @@ -14,24 +14,16 @@ class SolariumFactory implements SolariumFactoryInterface { - protected ClientRegistry $clientRegistry; protected LoggerInterface $logger; - protected MarkdownInterface $markdown; - protected EventDispatcherInterface $dispatcher; - protected HandlerFactoryInterface $handlerFactory; public function __construct( - ClientRegistry $clientRegistry, - LoggerInterface $searchEngineLogger, - MarkdownInterface $markdown, - EventDispatcherInterface $dispatcher, - HandlerFactoryInterface $handlerFactory + protected readonly ClientRegistry $clientRegistry, + readonly LoggerInterface $searchEngineLogger, + protected readonly MarkdownInterface $markdown, + protected readonly EventDispatcherInterface $dispatcher, + protected readonly HandlerFactoryInterface $handlerFactory, ) { - $this->clientRegistry = $clientRegistry; $this->logger = $searchEngineLogger; - $this->markdown = $markdown; - $this->dispatcher = $dispatcher; - $this->handlerFactory = $handlerFactory; } public function createWithDocument(Document $document): SolariumDocument diff --git a/src/SearchEngine/SolariumFactoryInterface.php b/src/SearchEngine/SolariumFactoryInterface.php index ab59410c..4a140cc3 100644 --- a/src/SearchEngine/SolariumFactoryInterface.php +++ b/src/SearchEngine/SolariumFactoryInterface.php @@ -11,6 +11,8 @@ interface SolariumFactoryInterface { public function createWithDocument(Document $document): SolariumDocument; + public function createWithDocumentTranslation(DocumentTranslation $documentTranslation): SolariumDocumentTranslation; + public function createWithNodesSources(NodesSources $nodeSource): SolariumNodeSource; } diff --git a/src/SearchEngine/SolariumNodeSource.php b/src/SearchEngine/SolariumNodeSource.php index 0c9ecf23..dd3742b0 100644 --- a/src/SearchEngine/SolariumNodeSource.php +++ b/src/SearchEngine/SolariumNodeSource.php @@ -20,19 +20,14 @@ class SolariumNodeSource extends AbstractSolarium public const DOCUMENT_TYPE = 'NodesSources'; public const IDENTIFIER_KEY = 'node_source_id_i'; - protected NodesSources $nodeSource; - protected EventDispatcherInterface $dispatcher; - public function __construct( - NodesSources $nodeSource, + protected readonly NodesSources $nodeSource, ClientRegistry $clientRegistry, - EventDispatcherInterface $dispatcher, + protected readonly EventDispatcherInterface $dispatcher, LoggerInterface $searchEngineLogger, - MarkdownInterface $markdown + MarkdownInterface $markdown, ) { parent::__construct($clientRegistry, $searchEngineLogger, $markdown); - $this->nodeSource = $nodeSource; - $this->dispatcher = $dispatcher; } public function getDocumentId(): int|string @@ -45,7 +40,6 @@ public function getDocumentId(): int|string * * @param bool $subResource Tell when this field gathering is for a main resource indexation or a sub-resource * - * @return array * @throws \Exception */ public function getFieldsAssoc(bool $subResource = false): array @@ -53,21 +47,19 @@ public function getFieldsAssoc(bool $subResource = false): array $event = new NodesSourcesIndexingEvent($this->nodeSource, [], $this); /** @var NodesSourcesIndexingEvent $event */ $event = $this->dispatcher->dispatch($event); + return $event->getAssociations(); } /** * Remove any document linked to current node-source. - * - * @param Query $update - * @return bool */ public function clean(Query $update): bool { $update->addDeleteQuery( - static::IDENTIFIER_KEY . ':"' . $this->nodeSource->getId() . '"' . - '&' . static::TYPE_DISCRIMINATOR . ':"' . static::DOCUMENT_TYPE . '"' . - '&locale_s:"' . $this->nodeSource->getTranslation()->getLocale() . '"' + static::IDENTIFIER_KEY.':"'.$this->nodeSource->getId().'"'. + '&'.static::TYPE_DISCRIMINATOR.':"'.static::DOCUMENT_TYPE.'"'. + '&locale_s:"'.$this->nodeSource->getTranslation()->getLocale().'"' ); return true; @@ -78,6 +70,7 @@ protected function getIdempotentIdentifier(): string $namespace = explode('\\', get_class($this->nodeSource)); // get last 3 parts of namespace $namespace = array_slice($namespace, -3); - return (new AsciiSlugger())->slug(implode(' ', $namespace))->lower()->snake() . '.' . $this->nodeSource->getId(); + + return (new AsciiSlugger())->slug(implode(' ', $namespace))->lower()->snake().'.'.$this->nodeSource->getId(); } } diff --git a/src/SearchEngine/SolrSearchResultItem.php b/src/SearchEngine/SolrSearchResultItem.php index ac474955..a25feab0 100644 --- a/src/SearchEngine/SolrSearchResultItem.php +++ b/src/SearchEngine/SolrSearchResultItem.php @@ -14,15 +14,15 @@ #[ApiResource( stateless: true, )] -final class SolrSearchResultItem +final readonly class SolrSearchResultItem { /** - * @param T $item + * @param T $item * @param array> $highlighting */ public function __construct( - private readonly object $item, - private readonly array $highlighting = [] + private object $item, + private array $highlighting = [], ) { } diff --git a/src/SearchEngine/SolrSearchResults.php b/src/SearchEngine/SolrSearchResults.php index 50d7bc52..b08e049a 100644 --- a/src/SearchEngine/SolrSearchResults.php +++ b/src/SearchEngine/SolrSearchResults.php @@ -32,16 +32,13 @@ public function __construct( protected readonly array $response, #[JMS\Exclude] #[Ignore] - protected readonly ObjectManager $entityManager + protected readonly ObjectManager $entityManager, ) { $this->position = 0; $this->resultItems = null; } - /** - * @return int - */ - #[JMS\Groups(["search_results"])] + #[JMS\Groups(['search_results'])] #[JMS\VirtualProperty()] public function getResultCount(): int { @@ -50,13 +47,14 @@ public function getResultCount(): int ) { return (int) $this->response['response']['numFound']; } + return 0; } /** * @return array */ - #[JMS\Groups(["search_results"])] + #[JMS\Groups(['search_results'])] #[JMS\VirtualProperty()] public function getResultItems(): array { @@ -72,6 +70,7 @@ function (array $item) { return null; } $highlighting = $this->getHighlighting($item['id']); + return new SolrSearchResultItem( $object, $highlighting @@ -89,7 +88,6 @@ function (array $item) { * Get highlighting for one field. * This does not merge highlighting for all fields anymore. * - * @param string $id * @return array */ protected function getHighlighting(string $id): array @@ -97,22 +95,16 @@ protected function getHighlighting(string $id): array if (isset($this->response['highlighting'][$id]) && \is_array($this->response['highlighting'][$id])) { return $this->response['highlighting'][$id]; } + return []; } - /** - * @param callable $callable - * - * @return array - */ public function map(callable $callable): array { return array_map($callable, $this->getResultItems()); } /** - * @param array $item - * * @return array|object|null */ protected function getHydratedItem(array $item): mixed @@ -129,6 +121,7 @@ protected function getHydratedItem(array $item): mixed DocumentTranslation::class, $item[SolariumDocumentTranslation::IDENTIFIER_KEY] ); + return $documentTranslation?->getDocument(); } } @@ -137,10 +130,9 @@ protected function getHydratedItem(array $item): mixed } /** - * Return the current element + * Return the current element. * - * @link https://php.net/manual/en/iterator.current.php - * @return SolrSearchResultItem + * @see https://php.net/manual/en/iterator.current.php * @since 5.0 */ #[\ReturnTypeWillChange] @@ -150,10 +142,12 @@ public function current(): SolrSearchResultItem } /** - * Move forward to next element + * Move forward to next element. + * + * @see https://php.net/manual/en/iterator.next.php + * + * @return void any returned value is ignored * - * @link https://php.net/manual/en/iterator.next.php - * @return void Any returned value is ignored. * @since 5.0 */ public function next(): void @@ -162,10 +156,9 @@ public function next(): void } /** - * Return the key of the current element + * Return the key of the current element. * - * @link https://php.net/manual/en/iterator.key.php - * @return int + * @see https://php.net/manual/en/iterator.key.php * @since 5.0 */ #[\ReturnTypeWillChange] @@ -175,11 +168,13 @@ public function key(): int } /** - * Checks if current position is valid + * Checks if current position is valid. + * + * @see https://php.net/manual/en/iterator.valid.php * - * @link https://php.net/manual/en/iterator.valid.php * @return bool The return value will be casted to boolean and then evaluated. - * Returns true on success or false on failure. + * Returns true on success or false on failure. + * * @since 5.0 */ public function valid(): bool @@ -188,10 +183,12 @@ public function valid(): bool } /** - * Rewind the Iterator to the first element + * Rewind the Iterator to the first element. + * + * @see https://php.net/manual/en/iterator.rewind.php + * + * @return void any returned value is ignored * - * @link https://php.net/manual/en/iterator.rewind.php - * @return void Any returned value is ignored. * @since 5.0 */ public function rewind(): void diff --git a/src/SearchEngine/Subscriber/AbstractIndexingSubscriber.php b/src/SearchEngine/Subscriber/AbstractIndexingSubscriber.php index 3bb5c452..008ee936 100644 --- a/src/SearchEngine/Subscriber/AbstractIndexingSubscriber.php +++ b/src/SearchEngine/Subscriber/AbstractIndexingSubscriber.php @@ -31,12 +31,13 @@ protected function formatGeoJsonFeature(mixed $geoJson): ?string } if ( - isset($geoJson['type']) && - $geoJson['type'] === 'Feature' && - isset($geoJson['geometry']['coordinates']) + isset($geoJson['type']) + && 'Feature' === $geoJson['type'] + && isset($geoJson['geometry']['coordinates']) ) { - return $geoJson['geometry']['coordinates'][1] . ',' . $geoJson['geometry']['coordinates'][0]; + return $geoJson['geometry']['coordinates'][1].','.$geoJson['geometry']['coordinates'][0]; } + return null; } @@ -52,15 +53,16 @@ protected function formatGeoJsonFeatureCollection(mixed $geoJson): ?array return null; } if ( - isset($geoJson['type']) && - $geoJson['type'] === 'FeatureCollection' && - isset($geoJson['features']) && - \count($geoJson['features']) > 0 + isset($geoJson['type']) + && 'FeatureCollection' === $geoJson['type'] + && isset($geoJson['features']) + && \count($geoJson['features']) > 0 ) { return array_filter(array_map(function ($feature) { return $this->formatGeoJsonFeature($feature); }, $geoJson['features'])); } + return null; } } diff --git a/src/SearchEngine/Subscriber/AttributeValueIndexingSubscriber.php b/src/SearchEngine/Subscriber/AttributeValueIndexingSubscriber.php index 929a85e9..bb11e791 100644 --- a/src/SearchEngine/Subscriber/AttributeValueIndexingSubscriber.php +++ b/src/SearchEngine/Subscriber/AttributeValueIndexingSubscriber.php @@ -12,9 +12,6 @@ final class AttributeValueIndexingSubscriber extends AbstractIndexingSubscriber { - /** - * {@inheritdoc} - */ public static function getSubscribedEvents(): array { return [ @@ -33,7 +30,7 @@ public function onIndexing(NodesSourcesIndexingEvent $event): void ->getNode() ->getAttributesValuesForTranslation($event->getNodeSource()->getTranslation()); - if ($attributeValues->count() === 0) { + if (0 === $attributeValues->count()) { return; } @@ -80,7 +77,7 @@ public function onIndexing(NodesSourcesIndexingEvent $event): void $associations['collection_txt'][] = $content; if (null !== $lang) { // Compile all text content into a single localized text field. - $associations['collection_txt_' . $lang] = $this->flattenTextCollection($associations['collection_txt']); + $associations['collection_txt_'.$lang] = $this->flattenTextCollection($associations['collection_txt']); } break; case AttributeInterface::DATETIME_T: @@ -96,7 +93,7 @@ public function onIndexing(NodesSourcesIndexingEvent $event): void * with right language */ if (null !== $lang) { - $fieldName .= '_txt_' . $lang; + $fieldName .= '_txt_'.$lang; } else { $lang = null; $fieldName .= '_t'; @@ -111,7 +108,7 @@ public function onIndexing(NodesSourcesIndexingEvent $event): void $associations['collection_txt'][] = $content; if (null !== $lang) { // Compile all text content into a single localized text field. - $associations['collection_txt_' . $lang] = $this->flattenTextCollection($associations['collection_txt']); + $associations['collection_txt_'.$lang] = $this->flattenTextCollection($associations['collection_txt']); } } break; diff --git a/src/SearchEngine/Subscriber/DefaultDocumentTranslationIndexingSubscriber.php b/src/SearchEngine/Subscriber/DefaultDocumentTranslationIndexingSubscriber.php index a4da9db0..3b6ce386 100644 --- a/src/SearchEngine/Subscriber/DefaultDocumentTranslationIndexingSubscriber.php +++ b/src/SearchEngine/Subscriber/DefaultDocumentTranslationIndexingSubscriber.php @@ -13,9 +13,6 @@ final class DefaultDocumentTranslationIndexingSubscriber extends AbstractIndexingSubscriber { - /** - * @inheritDoc - */ public static function getSubscribedEvents(): array { return [ @@ -56,23 +53,23 @@ public function onIndexing(DocumentTranslationIndexingEvent $event): void */ $suffix = '_t'; if (in_array($lang, SolariumDocumentTranslation::$availableLocalizedTextFields)) { - $suffix = '_txt_' . $lang; + $suffix = '_txt_'.$lang; } $assoc['title'] = $documentTranslation->getName(); - $assoc['title' . $suffix] = $documentTranslation->getName(); + $assoc['title'.$suffix] = $documentTranslation->getName(); /* * Remove ctrl characters */ $description = $event->getSolariumDocument()->cleanTextContent($documentTranslation->getDescription()); - $assoc['description' . $suffix] = $description; + $assoc['description'.$suffix] = $description; - $assoc['copyright' . $suffix] = $documentTranslation->getCopyright(); + $assoc['copyright'.$suffix] = $documentTranslation->getCopyright(); $collection[] = $assoc['title']; - $collection[] = $assoc['description' . $suffix]; - $collection[] = $assoc['copyright' . $suffix]; + $collection[] = $assoc['description'.$suffix]; + $collection[] = $assoc['copyright'.$suffix]; /* * `tags_txt` Must store only public, visible and user-searchable content. @@ -92,7 +89,7 @@ public function onIndexing(DocumentTranslationIndexingEvent $event): void // Use tags_txt to be compatible with other data types $assoc['tags_txt'] = $visibleFolderNames; // Compile all tags names into a single localized text field. - $assoc['tags_txt_' . $lang] = implode(' ', $visibleFolderNames); + $assoc['tags_txt_'.$lang] = implode(' ', $visibleFolderNames); /* * `all_tags_slugs_ss` can store all folders, even technical one, this fields should not user searchable. @@ -112,7 +109,7 @@ public function onIndexing(DocumentTranslationIndexingEvent $event): void */ $assoc['collection_txt'] = $collection; // Compile all text content into a single localized text field. - $assoc['collection_txt_' . $lang] = $this->flattenTextCollection($collection); + $assoc['collection_txt_'.$lang] = $this->flattenTextCollection($collection); $event->setAssociations($assoc); } } diff --git a/src/SearchEngine/Subscriber/DefaultNodesSourcesIndexingSubscriber.php b/src/SearchEngine/Subscriber/DefaultNodesSourcesIndexingSubscriber.php index f86bb8e1..e68de05d 100644 --- a/src/SearchEngine/Subscriber/DefaultNodesSourcesIndexingSubscriber.php +++ b/src/SearchEngine/Subscriber/DefaultNodesSourcesIndexingSubscriber.php @@ -13,9 +13,6 @@ final class DefaultNodesSourcesIndexingSubscriber extends AbstractIndexingSubscriber { - /** - * @inheritDoc - */ public static function getSubscribedEvents(): array { return [ @@ -46,7 +43,7 @@ public function onIndexing(NodesSourcesIndexingEvent $event): void */ $title = $event->getSolariumDocument()->cleanTextContent($nodeSource->getTitle(), false); $assoc['title'] = $title; - $assoc['title_txt_' . $lang] = $title; + $assoc['title_txt_'.$lang] = $title; /* * Do not index locale and tags if this is a sub-resource @@ -55,14 +52,14 @@ public function onIndexing(NodesSourcesIndexingEvent $event): void $assoc['node_type_s'] = $nodeSource->getNodeTypeName(); $assoc['node_name_s'] = $node->getNodeName(); $assoc['slug_s'] = $node->getNodeName(); - $assoc['node_status_i'] = $node->getStatus(); + $assoc['node_status_i'] = $node->getStatus()->value; $assoc['node_visible_b'] = $node->isVisible(); $assoc['node_reachable_b'] = $nodeSource->isReachable(); $assoc['created_at_dt'] = $this->formatDateTimeToUTC($node->getCreatedAt()); $assoc['updated_at_dt'] = $this->formatDateTimeToUTC($node->getUpdatedAt()); if (null !== $nodeSource->getPublishedAt()) { - $assoc['published_at_dt'] = $this->formatDateTimeToUTC($nodeSource->getPublishedAt()); + $assoc['published_at_dt'] = $this->formatDateTimeToUTC($nodeSource->getPublishedAt()); } if ($this->canIndexTitleInCollection($nodeSource)) { @@ -86,6 +83,7 @@ function (Tag $tag) use ($event, $nodeSource) { $tagName = $translatedTag ? $translatedTag->getName() : $tag->getTagName(); + return $event->getSolariumDocument()->cleanTextContent($tagName, false); }, $nodeSource->getNode()->getTags()->filter(function (Tag $tag) { @@ -96,7 +94,7 @@ function (Tag $tag) use ($event, $nodeSource) { // Use tags_txt to be compatible with other data types $assoc['tags_txt'] = $out; // Compile all tags names into a single localized text field. - $assoc['tags_txt_' . $lang] = implode(' ', $out); + $assoc['tags_txt_'.$lang] = implode(' ', $out); /* * `all_tags_slugs_ss` can store all tags, even technical one, this fields should not user searchable. @@ -182,7 +180,7 @@ function (Tag $tag) { * with right language */ if (in_array($lang, SolariumNodeSource::$availableLocalizedTextFields)) { - $name .= '_txt_' . $lang; + $name .= '_txt_'.$lang; } else { $name .= '_t'; } @@ -196,16 +194,12 @@ function (Tag $tag) { */ $assoc['collection_txt'] = $collection; // Compile all text content into a single localized text field. - $assoc['collection_txt_' . $lang] = $this->flattenTextCollection($collection); + $assoc['collection_txt_'.$lang] = $this->flattenTextCollection($collection); $event->setAssociations($assoc); } /** * @param iterable $fields - * @param string $suffix - * @param NodesSources $nodeSource - * @param array $assoc - * @return void */ protected function indexSuffixedFields(iterable $fields, string $suffix, NodesSources $nodeSource, array &$assoc): void { @@ -222,17 +216,13 @@ protected function indexSuffixedFields(iterable $fields, string $suffix, NodesSo } } - /** - * @param NodesSources $source - * @return bool - */ protected function canIndexTitleInCollection(NodesSources $source): bool { if (method_exists($source, 'getHideTitle')) { return !((bool) $source->getHideTitle()); } if (method_exists($source, 'getShowTitle')) { - return ((bool) $source->getShowTitle()); + return (bool) $source->getShowTitle(); } return $source->getNode()->getNodeType()->isSearchable(); diff --git a/src/SearchEngine/Subscriber/SolariumSubscriber.php b/src/SearchEngine/Subscriber/SolariumSubscriber.php index 397b1455..500eddb1 100644 --- a/src/SearchEngine/Subscriber/SolariumSubscriber.php +++ b/src/SearchEngine/Subscriber/SolariumSubscriber.php @@ -63,9 +63,6 @@ public static function getSubscribedEvents(): array ]; } - /** - * @param Event $event - */ public function onSolariumNodeWorkflowComplete(Event $event): void { $node = $event->getSubject(); @@ -77,8 +74,6 @@ public function onSolariumNodeWorkflowComplete(Event $event): void /** * Update or create Solr document for current Node-source. * - * @param NodesSourcesUpdatedEvent $event - * * @throws \Exception */ public function onSolariumSingleUpdate(NodesSourcesUpdatedEvent $event): void @@ -88,8 +83,6 @@ public function onSolariumSingleUpdate(NodesSourcesUpdatedEvent $event): void /** * Delete solr document for current Node-source. - * - * @param NodesSourcesDeletedEvent $event */ public function onSolariumSingleDelete(NodesSourcesDeletedEvent $event): void { @@ -98,8 +91,6 @@ public function onSolariumSingleDelete(NodesSourcesDeletedEvent $event): void /** * Delete solr documents for each Node sources. - * - * @param NodeDeletedEvent $event */ public function onSolariumNodeDelete(NodeDeletedEvent $event): void { @@ -109,8 +100,6 @@ public function onSolariumNodeDelete(NodeDeletedEvent $event): void /** * Update or create solr documents for each Node sources. * - * @param FilterNodeEvent $event - * * @throws \Exception */ public function onSolariumNodeUpdate(FilterNodeEvent $event): void @@ -118,11 +107,8 @@ public function onSolariumNodeUpdate(FilterNodeEvent $event): void $this->messageBus->dispatch(new Envelope(new SolrReindexMessage(Node::class, $event->getNode()->getId()))); } - /** * Delete solr documents for each Document translation. - * - * @param FilterDocumentEvent $event */ public function onSolariumDocumentDelete(FilterDocumentEvent $event): void { @@ -135,8 +121,6 @@ public function onSolariumDocumentDelete(FilterDocumentEvent $event): void /** * Update or create solr documents for each Document translation. * - * @param FilterDocumentEvent $event - * * @throws \Exception */ public function onSolariumDocumentUpdate(FilterDocumentEvent $event): void @@ -150,9 +134,8 @@ public function onSolariumDocumentUpdate(FilterDocumentEvent $event): void /** * Update solr documents linked to current event Tag. * - * @param TagUpdatedEvent $event - * * @throws \Exception + * * @deprecated This can lead to a timeout if more than 500 nodes use that tag! */ public function onSolariumTagUpdate(TagUpdatedEvent $event): void @@ -163,9 +146,8 @@ public function onSolariumTagUpdate(TagUpdatedEvent $event): void /** * Update solr documents linked to current event Folder. * - * @param FolderUpdatedEvent $event - * * @throws \Exception + * * @deprecated This can lead to a timeout if more than 500 documents use that folder! */ public function onSolariumFolderUpdate(FolderUpdatedEvent $event): void diff --git a/src/SearchEngine/Subscriber/TreeWalkerIndexingEventSubscriber.php b/src/SearchEngine/Subscriber/TreeWalkerIndexingEventSubscriber.php index cc104e46..310d437b 100644 --- a/src/SearchEngine/Subscriber/TreeWalkerIndexingEventSubscriber.php +++ b/src/SearchEngine/Subscriber/TreeWalkerIndexingEventSubscriber.php @@ -20,13 +20,10 @@ public function __construct( private readonly WalkerContextInterface $walkerContext, private readonly SolariumFactoryInterface $solariumFactory, private readonly int $maxLevel = 5, - private readonly string $defaultLocale = 'en' + private readonly string $defaultLocale = 'en', ) { } - /** - * @inheritDoc - */ public static function getSubscribedEvents(): array { return [ @@ -64,9 +61,6 @@ public function onIndexing(NodesSourcesIndexingEvent $event): void } /** - * @param WalkerInterface $walker - * @param array $assoc - * @param string $locale * @throws \Exception */ protected function walkAndIndex(WalkerInterface $walker, array &$assoc, string $locale): void @@ -80,7 +74,7 @@ protected function walkAndIndex(WalkerInterface $walker, array &$assoc, string $ $assoc['collection_txt'], $childAssoc['collection_txt'] )); - $assoc['collection_txt_' . $locale] = $this->flattenTextCollection($assoc['collection_txt']); + $assoc['collection_txt_'.$locale] = $this->flattenTextCollection($assoc['collection_txt']); } if ($walker->count() > 0) { foreach ($walker->getChildren() as $subWalker) { diff --git a/src/Security/Authentication/JwtAuthenticationSuccessHandler.php b/src/Security/Authentication/BackofficeAuthenticationSuccessHandler.php similarity index 50% rename from src/Security/Authentication/JwtAuthenticationSuccessHandler.php rename to src/Security/Authentication/BackofficeAuthenticationSuccessHandler.php index d21a2a3d..b43c7153 100644 --- a/src/Security/Authentication/JwtAuthenticationSuccessHandler.php +++ b/src/Security/Authentication/BackofficeAuthenticationSuccessHandler.php @@ -5,30 +5,32 @@ namespace RZ\Roadiz\CoreBundle\Security\Authentication; use Doctrine\Persistence\ManagerRegistry; -use Lexik\Bundle\JWTAuthenticationBundle\Security\Http\Authentication\AuthenticationSuccessHandler; use RZ\Roadiz\CoreBundle\Entity\User; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; -final class JwtAuthenticationSuccessHandler implements AuthenticationSuccessHandlerInterface +final readonly class BackofficeAuthenticationSuccessHandler implements AuthenticationSuccessHandlerInterface { public function __construct( - private readonly AuthenticationSuccessHandler $decorated, - private readonly ManagerRegistry $managerRegistry + private UrlGeneratorInterface $urlGenerator, + private ManagerRegistry $managerRegistry, ) { } - public function onAuthenticationSuccess(Request $request, TokenInterface $token): Response + public function onAuthenticationSuccess(Request $request, TokenInterface $token): ?Response { - $response = $this->decorated->onAuthenticationSuccess($request, $token); $user = $token->getUser(); if ($user instanceof User) { - $user->setLastLogin(new \DateTime()); - $this->managerRegistry->getManager()->flush(); + $user->setLastLogin(new \DateTime('now')); + $manager = $this->managerRegistry->getManagerForClass(User::class); + $manager?->flush(); } - return $response; + + return new RedirectResponse($this->urlGenerator->generate('adminHomePage')); } } diff --git a/src/Security/Authentication/RoadizAuthenticator.php b/src/Security/Authentication/RoadizAuthenticator.php index 6c22dc08..fe3ba208 100644 --- a/src/Security/Authentication/RoadizAuthenticator.php +++ b/src/Security/Authentication/RoadizAuthenticator.php @@ -16,45 +16,32 @@ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\BadCredentialsException; -use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials; use Symfony\Component\Security\Http\Authenticator\Passport\Passport; +use Symfony\Component\Security\Http\SecurityRequestAttributes; use Symfony\Component\Security\Http\Util\TargetPathTrait; abstract class RoadizAuthenticator extends AbstractLoginFormAuthenticator { use TargetPathTrait; - public const LOGIN_ROUTE = 'loginPage'; - - private UrlGeneratorInterface $urlGenerator; - private ManagerRegistry $managerRegistry; - private LoggerInterface $logger; - private string $usernamePath; - private string $passwordPath; - public function __construct( - UrlGeneratorInterface $urlGenerator, - ManagerRegistry $managerRegistry, - LoggerInterface $logger, - string $usernamePath = 'username', - string $passwordPath = 'password' + protected readonly UrlGeneratorInterface $urlGenerator, + private readonly ManagerRegistry $managerRegistry, + private readonly LoggerInterface $logger, + private readonly string $usernamePath = 'username', + private readonly string $passwordPath = 'password', ) { - $this->urlGenerator = $urlGenerator; - $this->managerRegistry = $managerRegistry; - $this->logger = $logger; - $this->usernamePath = $usernamePath; - $this->passwordPath = $passwordPath; } public function authenticate(Request $request): Passport { $credentials = $this->getCredentials($request); - $request->getSession()->set(Security::LAST_USERNAME, $credentials['username']); + $request->getSession()->set(SecurityRequestAttributes::LAST_USERNAME, $credentials['username']); return new Passport( new UserBadge($credentials['username']), @@ -73,16 +60,14 @@ public function onAuthenticationSuccess(Request $request, TokenInterface $token, if ($user instanceof User) { $user->setLastLogin(new \DateTime('now')); $manager = $this->managerRegistry->getManagerForClass(User::class); - if (null !== $manager) { - $manager->flush(); - } + $manager?->flush(); } if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) { return new RedirectResponse($targetPath); } - return new RedirectResponse($this->urlGenerator->generate('adminHomePage')); + return new RedirectResponse($this->getDefaultSuccessPath($request)); } public function onAuthenticationFailure(Request $request, AuthenticationException $exception): Response @@ -91,21 +76,18 @@ public function onAuthenticationFailure(Request $request, AuthenticationExceptio $ipAddress = $request->getClientIp(); $this->logger->error($exception->getMessage(), [ 'username' => $credentials['username'], - 'ipAddress' => $ipAddress + 'ipAddress' => $ipAddress, ]); return parent::onAuthenticationFailure($request, $exception); } + abstract protected function getLoginUrl(Request $request): string; - protected function getLoginUrl(Request $request): string - { - return $this->urlGenerator->generate(self::LOGIN_ROUTE); - } + abstract protected function getDefaultSuccessPath(Request $request): string; /** - * @param Request $request - * @return array + * @return array<'username'|'password', string> */ private function getCredentials(Request $request): array { @@ -117,7 +99,7 @@ private function getCredentials(Request $request): array throw new BadRequestHttpException(sprintf('The key "%s" must be a string.', $this->usernamePath)); } - if (\mb_strlen($credentials['username']) > Security::MAX_USERNAME_LENGTH) { + if (\mb_strlen($credentials['username']) > 4096) { throw new BadCredentialsException('Invalid username.'); } } catch (AccessException $e) { diff --git a/src/Security/Authorization/AccessDeniedHandler.php b/src/Security/Authorization/AccessDeniedHandler.php index ff05c9e3..2899141b 100644 --- a/src/Security/Authorization/AccessDeniedHandler.php +++ b/src/Security/Authorization/AccessDeniedHandler.php @@ -5,7 +5,6 @@ namespace RZ\Roadiz\CoreBundle\Security\Authorization; use Psr\Log\LoggerInterface; -use Psr\Log\NullLogger; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; @@ -18,50 +17,32 @@ * This is used by the ExceptionListener to translate an AccessDeniedException * to a Response object. */ -class AccessDeniedHandler implements AccessDeniedHandlerInterface +final readonly class AccessDeniedHandler implements AccessDeniedHandlerInterface { - protected LoggerInterface $logger; - protected UrlGeneratorInterface $urlGenerator; - protected string $redirectRoute; - protected array $redirectParameters; - - /** - * @param UrlGeneratorInterface $urlGenerator - * @param LoggerInterface|null $logger - * @param string $redirectRoute Route to redirect if access denied is thrown - * @param array $redirectParameters - */ public function __construct( - UrlGeneratorInterface $urlGenerator, - ?LoggerInterface $logger = null, - string $redirectRoute = '', - array $redirectParameters = [] + private UrlGeneratorInterface $urlGenerator, + private ?LoggerInterface $logger, + private string $redirectRoute = '', + private array $redirectParameters = [], ) { - $this->logger = $logger ?? new NullLogger(); - $this->urlGenerator = $urlGenerator; - $this->redirectRoute = $redirectRoute; - $this->redirectParameters = $redirectParameters; } /** - * Handles access denied failure redirecting to home page - * - * @param Request $request - * @param AccessDeniedException $accessDeniedException + * Handles access denied failure redirecting to home page. * * @return Response|null may return null */ public function handle(Request $request, AccessDeniedException $accessDeniedException): ?Response { - $this->logger->error('User tried to access: ' . $request->getUri()); + $this->logger->error('User tried to access: '.$request->getUri()); - $returnJson = $request->isXmlHttpRequest() || - $request->getRequestFormat() === 'json' || - ( - count($request->getAcceptableContentTypes()) === 1 && - $request->getAcceptableContentTypes()[0] === 'application/json' - ) || - ($request->attributes->has('_format') && $request->attributes->get('_format') === 'json'); + $returnJson = $request->isXmlHttpRequest() + || 'json' === $request->getRequestFormat() + || ( + 1 === count($request->getAcceptableContentTypes()) + && 'application/json' === $request->getAcceptableContentTypes()[0] + ) + || ($request->attributes->has('_format') && 'json' === $request->attributes->get('_format')); if ($returnJson) { return new JsonResponse( @@ -78,6 +59,7 @@ public function handle(Request $request, AccessDeniedException $accessDeniedExce } else { $redirectUrl = $request->getBaseUrl(); } + // Forbidden code should be set on final response, not the redirection! return new RedirectResponse($redirectUrl, Response::HTTP_FOUND); } diff --git a/src/Security/Authorization/Chroot/NodeChrootChainResolver.php b/src/Security/Authorization/Chroot/NodeChrootChainResolver.php index 2e836a50..6c21dcc8 100644 --- a/src/Security/Authorization/Chroot/NodeChrootChainResolver.php +++ b/src/Security/Authorization/Chroot/NodeChrootChainResolver.php @@ -11,35 +11,22 @@ /** * Loops over NodeChrootResolver implementations to find the right one supporting * a given UserInterface or string User representation (from a Token for example). - * - * @package RZ\Roadiz\CoreBundle\Security\Authorization\Chroot */ -class NodeChrootChainResolver implements NodeChrootResolver +final readonly class NodeChrootChainResolver implements NodeChrootResolver { - /** - * @var array - */ - private array $resolvers; - - /** - * @param array $resolvers - */ - public function __construct(array $resolvers) + public function __construct(private array $resolvers) { - $this->resolvers = $resolvers; foreach ($this->resolvers as $resolver) { if (!($resolver instanceof NodeChrootResolver)) { - throw new \InvalidArgumentException('Resolver must implements ' . NodeChrootResolver::class); + throw new \InvalidArgumentException('Resolver must implements '.NodeChrootResolver::class); } } } /** * @param User|UserInterface|string|null $user - * - * @return Node|null */ - public function getChroot($user = null): ?Node + public function getChroot(mixed $user): ?Node { /** @var NodeChrootResolver $resolver */ foreach ($this->resolvers as $resolver) { @@ -47,15 +34,14 @@ public function getChroot($user = null): ?Node return $resolver->getChroot($user); } } + return null; } /** * @param User|UserInterface|string|null $user - * - * @return bool */ - public function supports($user): bool + public function supports(mixed $user): bool { /** @var NodeChrootResolver $resolver */ foreach ($this->resolvers as $resolver) { @@ -63,6 +49,7 @@ public function supports($user): bool return true; } } + return false; } } diff --git a/src/Security/Authorization/Chroot/NodeChrootResolver.php b/src/Security/Authorization/Chroot/NodeChrootResolver.php index 5a0a4476..4f9d4a75 100644 --- a/src/Security/Authorization/Chroot/NodeChrootResolver.php +++ b/src/Security/Authorization/Chroot/NodeChrootResolver.php @@ -12,22 +12,10 @@ * * This enables third-party User from OAuth2 or SSO to be locked using their * own business logic, without need of a Roadiz User. - * - * @package RZ\Roadiz\CoreBundle\Security\Authorization\Chroot */ interface NodeChrootResolver { - /** - * @param mixed $user - * - * @return bool - */ - public function supports($user): bool; + public function supports(mixed $user): bool; - /** - * @param mixed $user - * - * @return Node|null - */ - public function getChroot($user): ?Node; + public function getChroot(mixed $user): ?Node; } diff --git a/src/Security/Authorization/Chroot/RoadizUserNodeChrootResolver.php b/src/Security/Authorization/Chroot/RoadizUserNodeChrootResolver.php index 8b6717f0..17023eba 100644 --- a/src/Security/Authorization/Chroot/RoadizUserNodeChrootResolver.php +++ b/src/Security/Authorization/Chroot/RoadizUserNodeChrootResolver.php @@ -9,22 +9,18 @@ /** * Classic Roadiz User chroot from Doctrine relation. - * - * @package RZ\Roadiz\CoreBundle\Security\Authorization\Chroot */ -class RoadizUserNodeChrootResolver implements NodeChrootResolver +final class RoadizUserNodeChrootResolver implements NodeChrootResolver { - public function supports($user): bool + public function supports(mixed $user): bool { return $user instanceof User; } /** * @param User $user - * - * @return Node|null */ - public function getChroot($user): ?Node + public function getChroot(mixed $user): ?Node { return $user->getChroot(); } diff --git a/src/Security/Authorization/Voter/GroupVoter.php b/src/Security/Authorization/Voter/GroupVoter.php index a6d8a341..8bfda235 100644 --- a/src/Security/Authorization/Voter/GroupVoter.php +++ b/src/Security/Authorization/Voter/GroupVoter.php @@ -28,9 +28,6 @@ protected function extractRoles(TokenInterface $token): array return $this->roleHierarchy->getReachableRoleNames($token->getRoleNames()); } - /** - * @inheritDoc - */ public function vote(TokenInterface $token, $subject, array $attributes): int { $result = VoterInterface::ACCESS_ABSTAIN; @@ -54,8 +51,8 @@ public function vote(TokenInterface $token, $subject, array $attributes): int * If user is part of current tested group, grant it. */ if ( - $user instanceof User && - $user->getGroups()->exists(function ($key, Group $group) use ($attribute) { + $user instanceof User + && $user->getGroups()->exists(function ($key, Group $group) use ($attribute) { return $attribute->getId() === $group->getId(); }) ) { @@ -76,8 +73,6 @@ public function vote(TokenInterface $token, $subject, array $attributes): int } /** - * @param Group $group - * * @return string[] */ protected function extractGroupRoles(Group $group): array @@ -86,10 +81,7 @@ protected function extractGroupRoles(Group $group): array } /** - * @param string $role * @param string[] $roles - * - * @return bool */ protected function isRoleContained(string $role, array $roles): bool { diff --git a/src/Security/Authorization/Voter/NodeTypeFieldVoter.php b/src/Security/Authorization/Voter/NodeTypeFieldVoter.php index eb55732c..a0b35cbf 100644 --- a/src/Security/Authorization/Voter/NodeTypeFieldVoter.php +++ b/src/Security/Authorization/Voter/NodeTypeFieldVoter.php @@ -15,7 +15,7 @@ final class NodeTypeFieldVoter extends Voter public const VIEW = 'VIEW'; public function __construct( - private readonly Security $security + private readonly Security $security, ) { } @@ -24,6 +24,7 @@ protected function supports(string $attribute, mixed $subject): bool if (!\in_array($attribute, [self::VIEW])) { return false; } + return $subject instanceof NodeTypeField; } @@ -38,7 +39,7 @@ protected function voteOnAttribute(string $attribute, mixed $subject, TokenInter return match ($attribute) { self::VIEW => $this->canView($subject, $user), - default => throw new \LogicException('This code should not be reached!') + default => throw new \LogicException('This code should not be reached!'), }; } diff --git a/src/Security/Authorization/Voter/NodeVoter.php b/src/Security/Authorization/Voter/NodeVoter.php index 4cfbe0aa..0cc9115f 100644 --- a/src/Security/Authorization/Voter/NodeVoter.php +++ b/src/Security/Authorization/Voter/NodeVoter.php @@ -4,6 +4,7 @@ namespace RZ\Roadiz\CoreBundle\Security\Authorization\Voter; +use RZ\Roadiz\Core\AbstractEntities\NodeInterface; use RZ\Roadiz\CoreBundle\Entity\Node; use RZ\Roadiz\CoreBundle\Entity\NodesSources; use RZ\Roadiz\CoreBundle\Node\NodeOffspringResolverInterface; @@ -45,10 +46,10 @@ protected function supports(string $attribute, mixed $subject): bool { if ( \in_array($attribute, [ - self::CREATE_AT_ROOT, - self::READ_AT_ROOT, - self::SEARCH, - self::EMPTY_TRASH, + self::CREATE_AT_ROOT, + self::READ_AT_ROOT, + self::SEARCH, + self::EMPTY_TRASH, ]) ) { return true; @@ -56,23 +57,23 @@ protected function supports(string $attribute, mixed $subject): bool if ( !\in_array($attribute, [ - self::CREATE, - self::DUPLICATE, - self::READ, - self::READ_LOGS, - self::EDIT_CONTENT, - self::EDIT_SETTING, - self::EDIT_TAGS, - self::EDIT_REALMS, - self::EDIT_STATUS, - self::EDIT_ATTRIBUTE, - self::DELETE + self::CREATE, + self::DUPLICATE, + self::READ, + self::READ_LOGS, + self::EDIT_CONTENT, + self::EDIT_SETTING, + self::EDIT_TAGS, + self::EDIT_REALMS, + self::EDIT_STATUS, + self::EDIT_ATTRIBUTE, + self::DELETE, ]) ) { return false; } - if ($subject instanceof Node || $subject instanceof NodesSources) { + if ($subject instanceof NodeInterface || $subject instanceof NodesSources) { return true; } @@ -108,11 +109,11 @@ protected function voteOnAttribute(string $attribute, mixed $subject, TokenInter self::EDIT_ATTRIBUTE => $this->canEditAttribute($subject, $user), self::DELETE => $this->canDelete($subject, $user), self::EMPTY_TRASH => $this->canEmptyTrash($user), - default => throw new \LogicException('This code should not be reached!') + default => throw new \LogicException('This code should not be reached!'), }; } - private function isNodeInsideUserChroot(Node $node, Node $chroot, bool $includeChroot = false): bool + private function isNodeInsideUserChroot(NodeInterface $node, NodeInterface $chroot, bool $includeChroot = false): bool { if (!$includeChroot && $chroot->getId() === $node->getId()) { return false; @@ -125,26 +126,28 @@ private function isNodeInsideUserChroot(Node $node, Node $chroot, bool $includeC return \in_array($node->getId(), $this->nodeOffspringResolver->getAllOffspringIds($chroot), true); } - private function isGrantedWithUserChroot(Node $node, UserInterface $user, array|string $roles, bool $includeChroot): bool + private function isGrantedWithUserChroot(NodeInterface $node, UserInterface $user, array|string $roles, bool $includeChroot): bool { $chroot = $this->chrootResolver->getChroot($user); if (null === $chroot) { return $this->security->isGranted($roles); } - return $this->security->isGranted($roles) && - $this->isNodeInsideUserChroot($node, $chroot, $includeChroot); + return $this->security->isGranted($roles) + && $this->isNodeInsideUserChroot($node, $chroot, $includeChroot); } private function canCreateAtRoot(UserInterface $user): bool { $chroot = $this->chrootResolver->getChroot($user); + return null === $chroot && $this->security->isGranted('ROLE_ACCESS_NODES'); } private function canReadAtRoot(UserInterface $user): bool { $chroot = $this->chrootResolver->getChroot($user); + return null === $chroot && $this->security->isGranted('ROLE_ACCESS_NODES'); } @@ -159,11 +162,11 @@ private function canSearch(UserInterface $user): bool private function canEmptyTrash(UserInterface $user): bool { $chroot = $this->chrootResolver->getChroot($user); + return null === $chroot && $this->security->isGranted('ROLE_ACCESS_NODES_DELETE'); } - - private function canCreate(Node $node, UserInterface $user): bool + private function canCreate(NodeInterface $node, UserInterface $user): bool { /* * Creation is allowed only if node is inside user chroot, @@ -172,7 +175,7 @@ private function canCreate(Node $node, UserInterface $user): bool return $this->isGrantedWithUserChroot($node, $user, 'ROLE_ACCESS_NODES', true); } - private function canRead(Node $node, UserInterface $user): bool + private function canRead(NodeInterface $node, UserInterface $user): bool { /* * Read is allowed only if node is inside user chroot, @@ -181,12 +184,12 @@ private function canRead(Node $node, UserInterface $user): bool return $this->isGrantedWithUserChroot($node, $user, 'ROLE_ACCESS_NODES', true); } - private function canReadLogs(Node $node, UserInterface $user): bool + private function canReadLogs(NodeInterface $node, UserInterface $user): bool { return $this->isGrantedWithUserChroot($node, $user, ['ROLE_ACCESS_NODES', 'ROLE_ACCESS_LOGS'], false); } - private function canEditContent(Node $node, UserInterface $user): bool + private function canEditContent(NodeInterface $node, UserInterface $user): bool { /* * Edition is allowed only if node is inside user chroot, @@ -195,17 +198,17 @@ private function canEditContent(Node $node, UserInterface $user): bool return $this->isGrantedWithUserChroot($node, $user, 'ROLE_ACCESS_NODES', false); } - private function canEditTags(Node $node, UserInterface $user): bool + private function canEditTags(NodeInterface $node, UserInterface $user): bool { return $this->isGrantedWithUserChroot($node, $user, ['ROLE_ACCESS_NODES', 'ROLE_ACCESS_TAGS'], false); } - private function canEditRealms(Node $node, UserInterface $user): bool + private function canEditRealms(NodeInterface $node, UserInterface $user): bool { return $this->isGrantedWithUserChroot($node, $user, ['ROLE_ACCESS_NODES', 'ROLE_ACCESS_REALM_NODES'], false); } - private function canDuplicate(Node $node, UserInterface $user): bool + private function canDuplicate(NodeInterface $node, UserInterface $user): bool { /* * Duplication is allowed only if node is inside user chroot, @@ -214,22 +217,22 @@ private function canDuplicate(Node $node, UserInterface $user): bool return $this->isGrantedWithUserChroot($node, $user, 'ROLE_ACCESS_NODES', false); } - private function canEditSetting(Node $node, UserInterface $user): bool + private function canEditSetting(NodeInterface $node, UserInterface $user): bool { return $this->isGrantedWithUserChroot($node, $user, 'ROLE_ACCESS_NODES_SETTING', false); } - private function canEditStatus(Node $node, UserInterface $user): bool + private function canEditStatus(NodeInterface $node, UserInterface $user): bool { return $this->isGrantedWithUserChroot($node, $user, 'ROLE_ACCESS_NODES_STATUS', false); } - private function canDelete(Node $node, UserInterface $user): bool + private function canDelete(NodeInterface $node, UserInterface $user): bool { return $this->isGrantedWithUserChroot($node, $user, 'ROLE_ACCESS_NODES_DELETE', false); } - private function canEditAttribute(Node $node, UserInterface $user): bool + private function canEditAttribute(NodeInterface $node, UserInterface $user): bool { return $this->isGrantedWithUserChroot($node, $user, 'ROLE_ACCESS_NODE_ATTRIBUTES', false); } diff --git a/src/Security/Authorization/Voter/RealmVoter.php b/src/Security/Authorization/Voter/RealmVoter.php index 204508da..7e3c2bdd 100644 --- a/src/Security/Authorization/Voter/RealmVoter.php +++ b/src/Security/Authorization/Voter/RealmVoter.php @@ -21,13 +21,13 @@ final class RealmVoter extends Voter public function __construct( private readonly Security $security, - private readonly RequestStack $requestStack + private readonly RequestStack $requestStack, ) { } public function supportsAttribute(string $attribute): bool { - return $attribute === self::READ; + return self::READ === $attribute; } protected function supports(string $attribute, mixed $subject): bool @@ -36,10 +36,7 @@ protected function supports(string $attribute, mixed $subject): bool } /** - * @param string $attribute * @param RealmInterface $subject - * @param TokenInterface $token - * @return bool */ public function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool { @@ -51,49 +48,34 @@ public function voteOnAttribute(string $attribute, mixed $subject, TokenInterfac }; } - /** - * @param string $attribute - * @param RealmInterface $subject - * @param TokenInterface $token - * @return bool - */ private function voteForRole(string $attribute, RealmInterface $subject, TokenInterface $token): bool { if (null === $role = $subject->getRole()) { return false; } + return $this->security->isGranted($role); } - /** - * @param string $attribute - * @param RealmInterface $subject - * @param TokenInterface $token - * @return bool - */ private function voteForUser(string $attribute, RealmInterface $subject, TokenInterface $token): bool { - if ($subject->getUsers()->count() === 0 || null === $token->getUser()) { + if (0 === $subject->getUsers()->count() || null === $token->getUser()) { return false; } + return $subject->getUsers()->exists(function ($key, UserInterface $user) use ($token) { return $user->getUserIdentifier() === $token->getUserIdentifier(); }); } - /** - * @param string $attribute - * @param RealmInterface $subject - * @param TokenInterface $token - * @return bool - */ private function voteForPassword(string $attribute, RealmInterface $subject, TokenInterface $token): bool { $request = $this->requestStack->getCurrentRequest(); if (null === $request || empty($subject->getPlainPassword())) { return false; } - return $request->query->has(self::PASSWORD_QUERY_PARAMETER) && - $request->query->get(self::PASSWORD_QUERY_PARAMETER) === $subject->getPlainPassword(); + + return $request->query->has(self::PASSWORD_QUERY_PARAMETER) + && $request->query->get(self::PASSWORD_QUERY_PARAMETER) === $subject->getPlainPassword(); } } diff --git a/src/Security/Authorization/Voter/RoleArrayVoter.php b/src/Security/Authorization/Voter/RoleArrayVoter.php index b373a3c2..27015f63 100644 --- a/src/Security/Authorization/Voter/RoleArrayVoter.php +++ b/src/Security/Authorization/Voter/RoleArrayVoter.php @@ -13,9 +13,6 @@ */ class RoleArrayVoter extends RoleVoter { - /** - * {@inheritdoc} - */ public function vote(TokenInterface $token, $subject, array $attributes): int { if (isset($attributes[0]) && !\is_array($attributes[0])) { diff --git a/src/Security/Authorization/Voter/SuperAdminRoleHierarchyVoter.php b/src/Security/Authorization/Voter/SuperAdminRoleHierarchyVoter.php index 23ccd845..e1b45baf 100644 --- a/src/Security/Authorization/Voter/SuperAdminRoleHierarchyVoter.php +++ b/src/Security/Authorization/Voter/SuperAdminRoleHierarchyVoter.php @@ -24,18 +24,17 @@ protected function extractRoles(TokenInterface $token): array $this->managerRegistry->getRepository(Role::class)->getAllBasicRoleName() ); } + return $roleNames; } private function isSuperAdmin(TokenInterface $token): bool { $roleNames = parent::extractRoles($token); - if ( - \in_array('ROLE_SUPER_ADMIN', $roleNames) || - \in_array('ROLE_SUPERADMIN', $roleNames) - ) { - return true; - } - return false; + + return + \in_array('ROLE_SUPER_ADMIN', $roleNames) + || \in_array('ROLE_SUPERADMIN', $roleNames) + ; } } diff --git a/src/Security/Blacklist/Top500Provider.php b/src/Security/Blacklist/Top500Provider.php deleted file mode 100644 index 34404252..00000000 --- a/src/Security/Blacklist/Top500Provider.php +++ /dev/null @@ -1,522 +0,0 @@ -publishMessage($request, $msg, 'confirm', $source); + } + + /** + * Publish an error message in Session flash bag and + * logger interface. + */ + public function publishErrorMessage(Request $request, string $msg, ?object $source = null): void + { + $this->publishMessage($request, $msg, 'error', $source); + } + + /** + * Publish a message in Session flash bag and + * logger interface. + */ + protected function publishMessage( + Request $request, + string $msg, + string $level = 'confirm', + ?object $source = null, + ): void { + $session = $this->getSession($request); + if ($session instanceof Session) { + $session->getFlashBag()->add($level, $msg); + } + + switch ($level) { + case 'error': + case 'danger': + case 'fail': + $this->logger->error($msg, ['entity' => $source]); + break; + default: + $this->logger->info($msg, ['entity' => $source]); + break; + } + } + + /** + * Returns the current session. + */ + public function getSession(?Request $request): ?SessionInterface + { + return !$request?->hasPreviousSession() ? null : $request->getSession(); + } +} diff --git a/src/Security/LoginLink/EmailLoginLinkSender.php b/src/Security/LoginLink/EmailLoginLinkSender.php new file mode 100644 index 00000000..b0b8abdc --- /dev/null +++ b/src/Security/LoginLink/EmailLoginLinkSender.php @@ -0,0 +1,68 @@ +isEnabled()) { + throw new \InvalidArgumentException('User must be enabled to send a login link.'); + } + + if (!\method_exists($user, 'getEmail')) { + throw new \InvalidArgumentException('User implementation must have getEmail method.'); + } + + if (null === $user->getEmail()) { + throw new \InvalidArgumentException('User must have an email to send a login link.'); + } + + $emailManager = $this->emailManagerFactory->create(); + $emailContact = $this->settingsBag->get('email_sender', null); + if (!\is_string($emailContact)) { + throw new \InvalidArgumentException('Email sender must be a string.'); + } + $siteName = $this->settingsBag->get('site_name', null); + if (!\is_string($siteName)) { + throw new \InvalidArgumentException('Site name must be a string.'); + } + + $emailManager->setAssignation([ + 'loginLink' => $loginLinkDetails->getUrl(), + 'expiresAt' => $loginLinkDetails->getExpiresAt(), + 'user' => $user, + 'site' => $siteName, + 'mailContact' => $emailContact, + ]); + $emailManager->setEmailTemplate($this->htmlTemplate); + $emailManager->setEmailPlainTextTemplate($this->txtTemplate); + $emailManager->setSubject($this->translator->trans( + 'login_link.request' + )); + + $emailManager->setReceiver($user->getEmail()); + $emailManager->setSender([$emailContact => $siteName]); + + // Send the message + $emailManager->send(); + } +} diff --git a/src/Security/LoginLink/LoginLinkSenderInterface.php b/src/Security/LoginLink/LoginLinkSenderInterface.php new file mode 100644 index 00000000..894eeda1 --- /dev/null +++ b/src/Security/LoginLink/LoginLinkSenderInterface.php @@ -0,0 +1,16 @@ +managerRegistry = $managerRegistry; } /** - * @param string $username - * @return UserInterface * @deprecated since Symfony 5.3, use loadUserByIdentifier() instead */ public function loadUserByUsername(string $username): UserInterface @@ -43,14 +32,14 @@ protected function loadUserByUsernameOrEmail(string $identifier): UserInterface ->getRepository(User::class) ->findOneBy(['username' => $identifier]); - if ($user === null) { + if (null === $user) { /** @var User|null $user */ $user = $this->managerRegistry ->getRepository(User::class) ->findOneBy(['email' => $identifier]); } - if ($user !== null) { + if (null !== $user) { return $user; } else { throw new UserNotFoundException(); @@ -70,8 +59,8 @@ public function loadUserByIdentifier(string $identifier): UserInterface * object can just be merged into some internal array of users / identity * map. * - * @param UserInterface $user * @return User + * * @throws UnsupportedUserException */ public function refreshUser(UserInterface $user): UserInterface @@ -81,10 +70,10 @@ public function refreshUser(UserInterface $user): UserInterface /** @var User|null $refreshUser */ $refreshUser = $manager->find(User::class, (int) $user->getId()); if ( - $refreshUser !== null && - $refreshUser->isEnabled() && - $refreshUser->isAccountNonExpired() && - $refreshUser->isAccountNonLocked() + null !== $refreshUser + && $refreshUser->isEnabled() + && $refreshUser->isAccountNonExpired() + && $refreshUser->isAccountNonLocked() ) { // Always refresh User from database: too much related entities to rely only on token. return $refreshUser; @@ -96,13 +85,12 @@ public function refreshUser(UserInterface $user): UserInterface } /** - * Whether this provider supports the given user class + * Whether this provider supports the given user class. * * @param class-string $class - * @return bool */ public function supportsClass($class): bool { - return $class === User::class; + return User::class === $class; } } diff --git a/src/Security/User/UserViewer.php b/src/Security/User/UserViewer.php index 8c2741da..03582759 100644 --- a/src/Security/User/UserViewer.php +++ b/src/Security/User/UserViewer.php @@ -8,49 +8,36 @@ use RZ\Roadiz\CoreBundle\Bag\Settings; use RZ\Roadiz\CoreBundle\Entity\User; use RZ\Roadiz\CoreBundle\Mailer\EmailManagerFactory; +use RZ\Roadiz\CoreBundle\Security\LoginLink\LoginLinkSenderInterface; use Symfony\Cmf\Component\Routing\RouteObjectInterface; use Symfony\Component\Mailer\Exception\TransportExceptionInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; +use Symfony\Component\Security\Core\User\UserInterface; +use Symfony\Component\Security\Http\LoginLink\LoginLinkDetails; use Symfony\Contracts\Translation\TranslatorInterface; -class UserViewer +final readonly class UserViewer { - protected Settings $settingsBag; - protected UrlGeneratorInterface $urlGenerator; - protected TranslatorInterface $translator; - protected EmailManagerFactory $emailManagerFactory; - protected LoggerInterface $logger; - public function __construct( - Settings $settingsBag, - UrlGeneratorInterface $urlGenerator, - TranslatorInterface $translator, - EmailManagerFactory $emailManagerFactory, - LoggerInterface $logger + private Settings $settingsBag, + private UrlGeneratorInterface $urlGenerator, + private TranslatorInterface $translator, + private EmailManagerFactory $emailManagerFactory, + private LoggerInterface $logger, + private LoginLinkSenderInterface $loginLinkSender, ) { - $this->settingsBag = $settingsBag; - $this->translator = $translator; - $this->emailManagerFactory = $emailManagerFactory; - $this->logger = $logger; - $this->urlGenerator = $urlGenerator; } /** * Send email to reset user password. * - * @param User $user - * @param object|string $route - * @param string $htmlTemplate - * @param string $txtTemplate - * - * @return bool * @throws TransportExceptionInterface */ public function sendPasswordResetLink( User $user, object|string $route = 'loginResetPage', string $htmlTemplate = '@RoadizCore/email/users/reset_password_email.html.twig', - string $txtTemplate = '@RoadizCore/email/users/reset_password_email.txt.twig' + string $txtTemplate = '@RoadizCore/email/users/reset_password_email.txt.twig', ): bool { $emailManager = $this->emailManagerFactory->create(); $emailContact = $this->getContactEmail(); @@ -92,6 +79,7 @@ public function sendPasswordResetLink( // Send the message $emailManager->send(); + return true; } catch (\Exception $e) { // Silent error not to prevent user creation if mailer is not configured @@ -100,31 +88,38 @@ public function sendPasswordResetLink( 'message' => $e->getMessage(), 'entity' => $user, ]); + return false; } } /** - * @return string + * @deprecated Use LoginLinkSenderInterface::sendLoginLink instead */ + public function sendLoginLink( + UserInterface $user, + LoginLinkDetails $loginLinkDetails, + string $htmlTemplate = '@RoadizCore/email/users/login_link_email.html.twig', + string $txtTemplate = '@RoadizCore/email/users/login_link_email.txt.twig', + ): void { + $this->loginLinkSender->sendLoginLink($user, $loginLinkDetails); + } + protected function getContactEmail(): string { $emailContact = $this->settingsBag->get('email_sender') ?? ''; if (empty($emailContact)) { - $emailContact = "noreply@roadiz.io"; + $emailContact = 'noreply@roadiz.io'; } return $emailContact; } - /** - * @return string - */ protected function getSiteName(): string { $siteName = $this->settingsBag->get('site_name') ?? ''; if (empty($siteName)) { - $siteName = "Unnamed site"; + $siteName = 'Unnamed site'; } return $siteName; diff --git a/src/Serializer/CircularReferenceHandler.php b/src/Serializer/CircularReferenceHandler.php index 8b5055d7..2948673c 100644 --- a/src/Serializer/CircularReferenceHandler.php +++ b/src/Serializer/CircularReferenceHandler.php @@ -4,12 +4,12 @@ namespace RZ\Roadiz\CoreBundle\Serializer; -use ApiPlatform\Api\IriConverterInterface; -use ApiPlatform\Api\UrlGeneratorInterface; +use ApiPlatform\Metadata\IriConverterInterface; +use ApiPlatform\Metadata\UrlGeneratorInterface; -final class CircularReferenceHandler +final readonly class CircularReferenceHandler { - public function __construct(private readonly IriConverterInterface $iriConverter) + public function __construct(private IriConverterInterface $iriConverter) { } @@ -26,6 +26,7 @@ public function __invoke(mixed $object, string $format, array $context): ?string if (is_object($object) && method_exists($object, 'getId')) { return (string) $object->getId(); } + return ''; } } diff --git a/src/Serializer/Normalizer/AbstractPathNormalizer.php b/src/Serializer/Normalizer/AbstractPathNormalizer.php index 729e3ae5..c4a3b320 100644 --- a/src/Serializer/Normalizer/AbstractPathNormalizer.php +++ b/src/Serializer/Normalizer/AbstractPathNormalizer.php @@ -9,44 +9,41 @@ use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\SerializerAwareInterface; use Symfony\Component\Serializer\SerializerInterface; +use Symfony\Component\Stopwatch\Stopwatch; abstract class AbstractPathNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface { - protected UrlGeneratorInterface $urlGenerator; /** * @var DenormalizerInterface&NormalizerInterface */ protected $decorated; - public function __construct(NormalizerInterface $decorated, UrlGeneratorInterface $urlGenerator) - { + public function __construct( + NormalizerInterface $decorated, + protected readonly UrlGeneratorInterface $urlGenerator, + protected readonly Stopwatch $stopwatch, + ) { if (!$decorated instanceof DenormalizerInterface) { throw new \InvalidArgumentException(sprintf('The decorated normalizer must implement the %s.', DenormalizerInterface::class)); } $this->decorated = $decorated; - $this->urlGenerator = $urlGenerator; } - public function supportsNormalization(mixed $data, string $format = null, array $context = []): bool + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool { - return $this->decorated->supportsNormalization($data, $format/*, $context*/); + return $this->decorated->supportsNormalization($data, $format/* , $context */); } - public function supportsDenormalization(mixed $data, string $type, string $format = null, array $context = []): bool + public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool { - return $this->decorated->supportsDenormalization($data, $type, $format/*, $context*/); + return $this->decorated->supportsDenormalization($data, $type, $format/* , $context */); } /** - * @param mixed $data - * @param string $type - * @param string|null $format - * @param array $context - * @return mixed * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface */ - public function denormalize(mixed $data, string $type, string $format = null, array $context = []): mixed + public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): mixed { return $this->decorated->denormalize($data, $type, $format, $context); } diff --git a/src/Serializer/Normalizer/AttributeValueNormalizer.php b/src/Serializer/Normalizer/AttributeValueNormalizer.php index b125a1a3..5e89ef2d 100644 --- a/src/Serializer/Normalizer/AttributeValueNormalizer.php +++ b/src/Serializer/Normalizer/AttributeValueNormalizer.php @@ -15,16 +15,15 @@ final class AttributeValueNormalizer extends AbstractPathNormalizer { /** - * @param mixed $object - * @param string|null $format - * @param array $context * @return array|\ArrayObject|bool|float|int|mixed|string|null + * * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface */ public function normalize(mixed $object, ?string $format = null, array $context = []): mixed { $data = $this->decorated->normalize($object, $format, $context); if ($object instanceof AttributeValue && is_array($data)) { + $this->stopwatch->start('normalizeAttributeValue', 'serializer'); /** @var array $serializationGroups */ $serializationGroups = isset($context['groups']) && is_array($context['groups']) ? $context['groups'] : []; @@ -37,8 +36,8 @@ public function normalize(mixed $object, ?string $format = null, array $context $translatedData = $object->getAttributeValueTranslation($context['translation']); $data['label'] = $object->getAttribute()->getLabelOrCode($context['translation']); if ( - $translatedData instanceof AttributeValueTranslationInterface && - $translatedData->getValue() !== null + $translatedData instanceof AttributeValueTranslationInterface + && null !== $translatedData->getValue() ) { $data['value'] = $translatedData->getValue(); } else { @@ -57,7 +56,9 @@ public function normalize(mixed $object, ?string $format = null, array $context return $this->decorated->normalize($document, $format, $documentsContext); }, $object->getAttribute()->getDocuments()->toArray()); } + $this->stopwatch->stop('normalizeAttributeValue'); } + return $data; } } diff --git a/src/Serializer/Normalizer/CustomFormNormalizer.php b/src/Serializer/Normalizer/CustomFormNormalizer.php index 6faf3844..41f60cdd 100644 --- a/src/Serializer/Normalizer/CustomFormNormalizer.php +++ b/src/Serializer/Normalizer/CustomFormNormalizer.php @@ -12,11 +12,9 @@ */ final class CustomFormNormalizer extends AbstractPathNormalizer { - /** - * @param mixed $object - * @param string|null $format - * @param array $context + /** * @return array|\ArrayObject|bool|float|int|mixed|string|null + * * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface */ public function normalize(mixed $object, ?string $format = null, array $context = []): mixed @@ -30,17 +28,18 @@ public function normalize(mixed $object, ?string $format = null, array $context $data['open'] = $object->isFormStillOpen(); if ( - isset($context['groups']) && - \in_array('urls', $context['groups'], true) + isset($context['groups']) + && \in_array('urls', $context['groups'], true) ) { $data['definitionUrl'] = $this->urlGenerator->generate('api_custom_forms_item_definition', [ - 'id' => $object->getId() + 'id' => $object->getId(), ]); $data['postUrl'] = $this->urlGenerator->generate('api_custom_forms_item_post', [ - 'id' => $object->getId() + 'id' => $object->getId(), ]); } } + return $data; } } diff --git a/src/Serializer/Normalizer/DocumentNormalizer.php b/src/Serializer/Normalizer/DocumentNormalizer.php index 7ec0ce91..87bf4b95 100644 --- a/src/Serializer/Normalizer/DocumentNormalizer.php +++ b/src/Serializer/Normalizer/DocumentNormalizer.php @@ -10,8 +10,10 @@ use RZ\Roadiz\CoreBundle\Entity\DocumentTranslation; use RZ\Roadiz\Documents\MediaFinders\EmbedFinderFactory; use RZ\Roadiz\Documents\Models\FolderInterface; +use RZ\Roadiz\Documents\UrlGenerators\DocumentUrlGeneratorInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use Symfony\Component\Stopwatch\Stopwatch; /** * Override Document default normalization. @@ -21,33 +23,34 @@ final class DocumentNormalizer extends AbstractPathNormalizer public function __construct( NormalizerInterface $decorated, UrlGeneratorInterface $urlGenerator, + Stopwatch $stopwatch, private readonly FilesystemOperator $documentsStorage, - private readonly EmbedFinderFactory $embedFinderFactory + private readonly EmbedFinderFactory $embedFinderFactory, + private readonly DocumentUrlGeneratorInterface $documentUrlGenerator, ) { - parent::__construct($decorated, $urlGenerator); + parent::__construct($decorated, $urlGenerator, $stopwatch); } /** - * @param mixed $object - * @param string|null $format - * @param array $context * @return array|\ArrayObject|bool|float|int|string|null + * * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface */ public function normalize(mixed $object, ?string $format = null, array $context = []): mixed { $data = $this->decorated->normalize($object, $format, $context); if ( - $object instanceof Document && - is_array($data) + $object instanceof Document + && is_array($data) ) { + $this->stopwatch->start('normalizeDocument', 'serializer'); /** @var array $serializationGroups */ $serializationGroups = isset($context['groups']) && is_array($context['groups']) ? $context['groups'] : []; $data['type'] = $object->getShortType(); if ( - !$object->isPrivate() && - !$object->isProcessable() + !$object->isPrivate() + && !$object->isProcessable() ) { $mountPath = $object->getMountPath(); if (null !== $mountPath) { @@ -56,9 +59,9 @@ public function normalize(mixed $object, ?string $format = null, array $context } if ( - !$object->isPrivate() && - $object->isProcessable() && - null !== $alignment = $object->getImageCropAlignment() + !$object->isPrivate() + && $object->isProcessable() + && null !== $alignment = $object->getImageCropAlignment() ) { $data['imageCropAlignment'] = $alignment; } @@ -83,8 +86,8 @@ public function normalize(mixed $object, ?string $format = null, array $context } if ( - $object->getEmbedPlatform() && - $object->getEmbedId() + $object->getEmbedPlatform() + && $object->getEmbedId() ) { $embedFinder = $this->embedFinderFactory->createForPlatform( $object->getEmbedPlatform(), @@ -109,7 +112,23 @@ public function normalize(mixed $object, ?string $format = null, array $context $data['externalUrl'] = $translatedData->getExternalUrl(); } } + + if ( + !$object->isPrivate() + && \in_array('explorer_thumbnail', $serializationGroups, true) + ) { + $data['url'] = $this->documentUrlGenerator + ->setDocument($object) + ->setOptions([ + 'fit' => '250x200', + 'quality' => 60, + ]) + ->getUrl(); + } + + $this->stopwatch->stop('normalizeDocument'); } + return $data; } } diff --git a/src/Serializer/Normalizer/DocumentSourcesNormalizer.php b/src/Serializer/Normalizer/DocumentSourcesNormalizer.php index e52f4004..238d9ac7 100644 --- a/src/Serializer/Normalizer/DocumentSourcesNormalizer.php +++ b/src/Serializer/Normalizer/DocumentSourcesNormalizer.php @@ -8,22 +8,22 @@ use RZ\Roadiz\Documents\DocumentFinderInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use Symfony\Component\Stopwatch\Stopwatch; final class DocumentSourcesNormalizer extends AbstractPathNormalizer { public function __construct( NormalizerInterface $decorated, UrlGeneratorInterface $urlGenerator, - private readonly DocumentFinderInterface $documentFinder + Stopwatch $stopwatch, + private readonly DocumentFinderInterface $documentFinder, ) { - parent::__construct($decorated, $urlGenerator); + parent::__construct($decorated, $urlGenerator, $stopwatch); } /** - * @param mixed $object - * @param string|null $format - * @param array $context * @return array|\ArrayObject|bool|float|int|mixed|string|null + * * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface */ public function normalize(mixed $object, ?string $format = null, array $context = []): mixed @@ -57,6 +57,7 @@ public function normalize(mixed $object, ?string $format = null, array $context } } } + return $data; } } diff --git a/src/Serializer/Normalizer/FolderNormalizer.php b/src/Serializer/Normalizer/FolderNormalizer.php index c9573a21..3290cb72 100644 --- a/src/Serializer/Normalizer/FolderNormalizer.php +++ b/src/Serializer/Normalizer/FolderNormalizer.php @@ -13,11 +13,9 @@ */ final class FolderNormalizer extends AbstractPathNormalizer { - /** - * @param mixed $object - * @param string|null $format - * @param array $context + /** * @return array|\ArrayObject|bool|float|int|mixed|string|null + * * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface */ public function normalize(mixed $object, ?string $format = null, array $context = []): mixed @@ -35,6 +33,7 @@ public function normalize(mixed $object, ?string $format = null, array $context } } } + return $data; } } diff --git a/src/Serializer/Normalizer/NodesSourcesPathNormalizer.php b/src/Serializer/Normalizer/NodesSourcesPathNormalizer.php index 650ff2e0..53b98c3c 100644 --- a/src/Serializer/Normalizer/NodesSourcesPathNormalizer.php +++ b/src/Serializer/Normalizer/NodesSourcesPathNormalizer.php @@ -6,36 +6,35 @@ use RZ\Roadiz\CoreBundle\Entity\NodesSources; use Symfony\Cmf\Component\Routing\RouteObjectInterface; -use Symfony\Component\Routing\Generator\UrlGeneratorInterface; final class NodesSourcesPathNormalizer extends AbstractPathNormalizer { - /** - * @param mixed $object - * @param string|null $format - * @param array $context + /** * @return array|\ArrayObject|bool|float|int|mixed|string|null + * * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface */ public function normalize(mixed $object, ?string $format = null, array $context = []): mixed { $data = $this->decorated->normalize($object, $format, $context); if ( - $object instanceof NodesSources && - $object->isReachable() && - \is_array($data) && - !isset($data['url']) && - isset($context['groups']) && - \in_array('urls', $context['groups'], true) + $object instanceof NodesSources + && $object->isReachable() + && \is_array($data) + && !isset($data['url']) + && isset($context['groups']) + && \in_array('urls', $context['groups'], true) ) { + $this->stopwatch->start('normalizeNodesSourcesUrl', 'serializer'); $data['url'] = $this->urlGenerator->generate( RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, [ - RouteObjectInterface::ROUTE_OBJECT => $object - ], - UrlGeneratorInterface::ABSOLUTE_PATH + RouteObjectInterface::ROUTE_OBJECT => $object, + ] ); + $this->stopwatch->stop('normalizeNodesSourcesUrl'); } + return $data; } } diff --git a/src/Serializer/Normalizer/RealmSerializationGroupNormalizer.php b/src/Serializer/Normalizer/RealmSerializationGroupNormalizer.php index a470c7eb..06713d95 100644 --- a/src/Serializer/Normalizer/RealmSerializationGroupNormalizer.php +++ b/src/Serializer/Normalizer/RealmSerializationGroupNormalizer.php @@ -23,14 +23,11 @@ final class RealmSerializationGroupNormalizer implements NormalizerInterface, No public function __construct( private readonly Security $security, private readonly RealmResolver $realmResolver, - private readonly Stopwatch $stopwatch + private readonly Stopwatch $stopwatch, ) { } - /** - * @inheritDoc - */ - public function supportsNormalization(mixed $data, string $format = null, array $context = []): bool + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool { if (!($data instanceof NodesSources)) { return false; @@ -51,7 +48,6 @@ public function getSupportedTypes(?string $format): array } /** - * @inheritDoc * @return array|string|int|float|bool|\ArrayObject|null */ public function normalize(mixed $object, ?string $format = null, array $context = []): mixed diff --git a/src/Serializer/Normalizer/TagNormalizer.php b/src/Serializer/Normalizer/TagNormalizer.php index 0970525f..4f690bb6 100644 --- a/src/Serializer/Normalizer/TagNormalizer.php +++ b/src/Serializer/Normalizer/TagNormalizer.php @@ -14,22 +14,21 @@ */ final class TagNormalizer extends AbstractPathNormalizer { - /** - * @param mixed $object - * @param string|null $format - * @param array $context + /** * @return array|\ArrayObject|bool|float|int|mixed|string|null + * * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface */ public function normalize(mixed $object, ?string $format = null, array $context = []): mixed { $data = $this->decorated->normalize($object, $format, $context); if ( - $object instanceof Tag && - is_array($data) && - isset($context['translation']) && - $context['translation'] instanceof TranslationInterface + $object instanceof Tag + && is_array($data) + && isset($context['translation']) + && $context['translation'] instanceof TranslationInterface ) { + $this->stopwatch->start('normalizeTag', 'serializer'); /** @var array $serializationGroups */ $serializationGroups = isset($context['groups']) && is_array($context['groups']) ? $context['groups'] : []; /* @@ -49,7 +48,9 @@ public function normalize(mixed $object, ?string $format = null, array $context }, $translatedData->getDocuments()); } } + $this->stopwatch->stop('normalizeTag'); } + return $data; } } diff --git a/src/Serializer/Normalizer/TranslationAwareNormalizer.php b/src/Serializer/Normalizer/TranslationAwareNormalizer.php index eb1c3df2..3f840279 100644 --- a/src/Serializer/Normalizer/TranslationAwareNormalizer.php +++ b/src/Serializer/Normalizer/TranslationAwareNormalizer.php @@ -12,9 +12,9 @@ use RZ\Roadiz\CoreBundle\Preview\PreviewResolverInterface; use RZ\Roadiz\CoreBundle\Repository\TranslationRepository; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; final class TranslationAwareNormalizer implements NormalizerInterface, NormalizerAwareInterface { @@ -25,15 +25,13 @@ final class TranslationAwareNormalizer implements NormalizerInterface, Normalize public function __construct( private readonly RequestStack $requestStack, private readonly ManagerRegistry $managerRegistry, - private readonly PreviewResolverInterface $previewResolver + private readonly PreviewResolverInterface $previewResolver, ) { } /** - * @param mixed $object - * @param string|null $format - * @param array $context * @return array|\ArrayObject|bool|float|int|string|null + * * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface */ public function normalize(mixed $object, ?string $format = null, array $context = []): mixed @@ -92,8 +90,8 @@ private function getTranslationFromRequest(): ?TranslationInterface $locale = $request->query->get('_locale', $request->getLocale()); if ( - \is_string($locale) && - null !== $translation = $this->getTranslationFromLocale($locale) + \is_string($locale) + && null !== $translation = $this->getTranslationFromLocale($locale) ) { return $translation; } @@ -101,7 +99,7 @@ private function getTranslationFromRequest(): ?TranslationInterface return null; } - public function supportsNormalization(mixed $data, string $format = null, array $context = []): bool + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool { // Make sure we're not called twice if (isset($context[self::ALREADY_CALLED])) { diff --git a/src/Serializer/ObjectConstructor/AbstractTypedObjectConstructor.php b/src/Serializer/ObjectConstructor/AbstractTypedObjectConstructor.php index 476a75dd..39569646 100644 --- a/src/Serializer/ObjectConstructor/AbstractTypedObjectConstructor.php +++ b/src/Serializer/ObjectConstructor/AbstractTypedObjectConstructor.php @@ -15,48 +15,33 @@ abstract class AbstractTypedObjectConstructor implements TypedObjectConstructorI { public function __construct( protected readonly ObjectManager $entityManager, - protected readonly ObjectConstructorInterface $fallbackConstructor + protected readonly ObjectConstructorInterface $fallbackConstructor, ) { } - /** - * @param mixed $data - * @param DeserializationContext $context - * - * @return object|null - */ abstract protected function findObject(mixed $data, DeserializationContext $context): ?object; - /** - * @param object $object - * @param array $data - */ abstract protected function fillIdentifier(object $object, array $data): void; - /** - * @return bool - */ protected function canBeFlushed(): bool { return true; } - /** - * @inheritDoc - */ + public function construct( DeserializationVisitorInterface $visitor, ClassMetadata $metadata, $data, array $type, - DeserializationContext $context + DeserializationContext $context, ): ?object { // Entity update, load it from database $object = $this->findObject($data, $context); if ( - null !== $object && - $context->hasAttribute(static::EXCEPTION_ON_EXISTING) && - true === $context->getAttribute(static::EXCEPTION_ON_EXISTING) + null !== $object + && $context->hasAttribute(static::EXCEPTION_ON_EXISTING) + && true === $context->getAttribute(static::EXCEPTION_ON_EXISTING) ) { throw new EntityAlreadyExistsException('Object already exists in database.'); } @@ -64,8 +49,8 @@ public function construct( if (null === $object) { $object = $this->fallbackConstructor->construct($visitor, $metadata, $data, $type, $context); if ( - $context->hasAttribute(static::PERSIST_NEW_OBJECTS) && - true === $context->getAttribute(static::PERSIST_NEW_OBJECTS) + $context->hasAttribute(static::PERSIST_NEW_OBJECTS) + && true === $context->getAttribute(static::PERSIST_NEW_OBJECTS) ) { $this->entityManager->persist($object); } @@ -78,8 +63,8 @@ public function construct( $this->fillIdentifier($object, $data); if ( - $context->hasAttribute(static::FLUSH_NEW_OBJECTS) && - true === $context->getAttribute(static::FLUSH_NEW_OBJECTS) + $context->hasAttribute(static::FLUSH_NEW_OBJECTS) + && true === $context->getAttribute(static::FLUSH_NEW_OBJECTS) ) { $this->entityManager->flush(); } diff --git a/src/Serializer/ObjectConstructor/AttributeObjectConstructor.php b/src/Serializer/ObjectConstructor/AttributeObjectConstructor.php index ba437452..70d66028 100644 --- a/src/Serializer/ObjectConstructor/AttributeObjectConstructor.php +++ b/src/Serializer/ObjectConstructor/AttributeObjectConstructor.php @@ -13,19 +13,13 @@ final class AttributeObjectConstructor extends AbstractTypedObjectConstructor { public const EXCEPTION_ON_EXISTING = 'exception_on_existing_attribute'; - /** - * @inheritDoc - */ public function supports(string $className, array $data): bool { - return ( + return \is_subclass_of($className, AttributeInterface::class) - ) && \array_key_exists('code', $data); + && \array_key_exists('code', $data); } - /** - * @inheritDoc - */ protected function findObject(mixed $data, DeserializationContext $context): ?object { if (empty($data['code'])) { @@ -36,9 +30,9 @@ protected function findObject(mixed $data, DeserializationContext $context): ?ob ->findOneByCode($data['code']); if ( - null !== $tag && - $context->hasAttribute(self::EXCEPTION_ON_EXISTING) && - true === $context->hasAttribute(self::EXCEPTION_ON_EXISTING) + null !== $tag + && $context->hasAttribute(self::EXCEPTION_ON_EXISTING) + && true === $context->hasAttribute(self::EXCEPTION_ON_EXISTING) ) { throw new EntityAlreadyExistsException('Attribute already exists in database.'); } diff --git a/src/Serializer/ObjectConstructor/ChainDoctrineObjectConstructor.php b/src/Serializer/ObjectConstructor/ChainDoctrineObjectConstructor.php index eeff57cc..bd61f5e0 100644 --- a/src/Serializer/ObjectConstructor/ChainDoctrineObjectConstructor.php +++ b/src/Serializer/ObjectConstructor/ChainDoctrineObjectConstructor.php @@ -16,24 +16,19 @@ final class ChainDoctrineObjectConstructor implements ObjectConstructorInterface public function __construct( private readonly ?ObjectManager $entityManager, private readonly ObjectConstructorInterface $fallbackConstructor, - private readonly array $typedObjectConstructors + private readonly array $typedObjectConstructors, ) { } /** - * @param DeserializationVisitorInterface $visitor - * @param ClassMetadata $metadata * @param PersistableInterface|array $data - * @param array $type - * @param DeserializationContext $context - * @return object|null */ public function construct( DeserializationVisitorInterface $visitor, ClassMetadata $metadata, $data, array $type, - DeserializationContext $context + DeserializationContext $context, ): ?object { if (null === $this->entityManager) { // No ObjectManager found, proceed with normal deserialization diff --git a/src/Serializer/ObjectConstructor/GroupObjectConstructor.php b/src/Serializer/ObjectConstructor/GroupObjectConstructor.php index 9cd71848..6fdcb934 100644 --- a/src/Serializer/ObjectConstructor/GroupObjectConstructor.php +++ b/src/Serializer/ObjectConstructor/GroupObjectConstructor.php @@ -10,22 +10,17 @@ final class GroupObjectConstructor extends AbstractTypedObjectConstructor { - /** - * @inheritDoc - */ public function supports(string $className, array $data): bool { - return $className === Group::class && array_key_exists('name', $data); + return Group::class === $className && array_key_exists('name', $data); } - /** - * @inheritDoc - */ protected function findObject(mixed $data, DeserializationContext $context): ?object { - if (null === $data['name'] || $data['name'] === '') { + if (null === $data['name'] || '' === $data['name']) { throw new ObjectConstructionException('Group name can not be empty'); } + return $this->entityManager->getRepository(Group::class)->findOneByName($data['name']); } @@ -34,9 +29,6 @@ protected function fillIdentifier(object $object, array $data): void trigger_error('Cannot call fillIdentifier on Group', E_USER_WARNING); } - /** - * @return bool - */ protected function canBeFlushed(): bool { return false; diff --git a/src/Serializer/ObjectConstructor/NodeObjectConstructor.php b/src/Serializer/ObjectConstructor/NodeObjectConstructor.php index ec0cc75c..9919cae3 100644 --- a/src/Serializer/ObjectConstructor/NodeObjectConstructor.php +++ b/src/Serializer/ObjectConstructor/NodeObjectConstructor.php @@ -11,17 +11,11 @@ final class NodeObjectConstructor extends AbstractTypedObjectConstructor { - /** - * @inheritDoc - */ public function supports(string $className, array $data): bool { - return $className === Node::class && array_key_exists('nodeName', $data); + return Node::class === $className && array_key_exists('nodeName', $data); } - /** - * @inheritDoc - */ protected function findObject(mixed $data, DeserializationContext $context): ?object { if (empty($data['nodeName']) && empty($data['node_name'])) { @@ -31,6 +25,7 @@ protected function findObject(mixed $data, DeserializationContext $context): ?ob $nodeRepository = $this->entityManager ->getRepository(Node::class) ->setDisplayingAllNodesStatuses(true); + return $nodeRepository->findOneByNodeName($data['nodeName'] ?? $data['node_name']); } diff --git a/src/Serializer/ObjectConstructor/NodeTypeObjectConstructor.php b/src/Serializer/ObjectConstructor/NodeTypeObjectConstructor.php index 4d51fccd..18a4a37d 100644 --- a/src/Serializer/ObjectConstructor/NodeTypeObjectConstructor.php +++ b/src/Serializer/ObjectConstructor/NodeTypeObjectConstructor.php @@ -11,23 +11,18 @@ final class NodeTypeObjectConstructor extends AbstractTypedObjectConstructor { - /** - * @inheritDoc - */ public function supports(string $className, array $data): bool { - return \is_subclass_of($className, NodeTypeInterface::class) && - array_key_exists('name', $data); + return \is_subclass_of($className, NodeTypeInterface::class) + && array_key_exists('name', $data); } - /** - * @inheritDoc - */ protected function findObject(mixed $data, DeserializationContext $context): ?object { - if (null === $data['name'] || $data['name'] === '') { + if (null === $data['name'] || '' === $data['name']) { throw new ObjectConstructionException('NodeType name can not be empty'); } + return $this->entityManager ->getRepository(NodeType::class) ->findOneByName($data['name']); diff --git a/src/Serializer/ObjectConstructor/ObjectConstructor.php b/src/Serializer/ObjectConstructor/ObjectConstructor.php index b56536c5..5a8077b3 100644 --- a/src/Serializer/ObjectConstructor/ObjectConstructor.php +++ b/src/Serializer/ObjectConstructor/ObjectConstructor.php @@ -16,9 +16,10 @@ public function construct( ClassMetadata $metadata, $data, array $type, - DeserializationContext $context + DeserializationContext $context, ): ?object { $className = $metadata->name; + return new $className(); } } diff --git a/src/Serializer/ObjectConstructor/RoleObjectConstructor.php b/src/Serializer/ObjectConstructor/RoleObjectConstructor.php index 00698c86..0e5d88f9 100644 --- a/src/Serializer/ObjectConstructor/RoleObjectConstructor.php +++ b/src/Serializer/ObjectConstructor/RoleObjectConstructor.php @@ -10,22 +10,17 @@ final class RoleObjectConstructor extends AbstractTypedObjectConstructor { - /** - * @inheritDoc - */ public function supports(string $className, array $data): bool { - return $className === Role::class && array_key_exists('name', $data); + return Role::class === $className && array_key_exists('name', $data); } - /** - * @inheritDoc - */ protected function findObject(mixed $data, DeserializationContext $context): ?object { - if (null === $data['name'] || $data['name'] === '') { + if (null === $data['name'] || '' === $data['name']) { throw new ObjectConstructionException('Role name can not be empty'); } + return $this->entityManager ->getRepository(Role::class) ->findOneByName($data['name']); diff --git a/src/Serializer/ObjectConstructor/SettingGroupObjectConstructor.php b/src/Serializer/ObjectConstructor/SettingGroupObjectConstructor.php index 19834d39..e202a606 100644 --- a/src/Serializer/ObjectConstructor/SettingGroupObjectConstructor.php +++ b/src/Serializer/ObjectConstructor/SettingGroupObjectConstructor.php @@ -10,22 +10,17 @@ final class SettingGroupObjectConstructor extends AbstractTypedObjectConstructor { - /** - * @inheritDoc - */ public function supports(string $className, array $data): bool { - return $className === SettingGroup::class && array_key_exists('name', $data); + return SettingGroup::class === $className && array_key_exists('name', $data); } - /** - * @inheritDoc - */ protected function findObject(mixed $data, DeserializationContext $context): ?object { - if (null === $data['name'] || $data['name'] === '') { + if (null === $data['name'] || '' === $data['name']) { throw new ObjectConstructionException('SettingGroup name can not be empty'); } + return $this->entityManager ->getRepository(SettingGroup::class) ->findOneByName($data['name']); diff --git a/src/Serializer/ObjectConstructor/SettingObjectConstructor.php b/src/Serializer/ObjectConstructor/SettingObjectConstructor.php index c43a7384..77523e80 100644 --- a/src/Serializer/ObjectConstructor/SettingObjectConstructor.php +++ b/src/Serializer/ObjectConstructor/SettingObjectConstructor.php @@ -10,22 +10,17 @@ final class SettingObjectConstructor extends AbstractTypedObjectConstructor { - /** - * @inheritDoc - */ public function supports(string $className, array $data): bool { - return $className === Setting::class && array_key_exists('name', $data); + return Setting::class === $className && array_key_exists('name', $data); } - /** - * @inheritDoc - */ protected function findObject(mixed $data, DeserializationContext $context): ?object { - if (null === $data['name'] || $data['name'] === '') { + if (null === $data['name'] || '' === $data['name']) { throw new ObjectConstructionException('Setting name can not be empty'); } + return $this->entityManager->getRepository(Setting::class)->findOneByName($data['name']); } diff --git a/src/Serializer/ObjectConstructor/TagObjectConstructor.php b/src/Serializer/ObjectConstructor/TagObjectConstructor.php index cc984c9a..726601b8 100644 --- a/src/Serializer/ObjectConstructor/TagObjectConstructor.php +++ b/src/Serializer/ObjectConstructor/TagObjectConstructor.php @@ -13,20 +13,14 @@ final class TagObjectConstructor extends AbstractTypedObjectConstructor { public const EXCEPTION_ON_EXISTING_TAG = 'exception_on_existing_tag'; - /** - * @inheritDoc - */ public function supports(string $className, array $data): bool { - return $className === Tag::class && ( - \array_key_exists('tagName', $data) || - \array_key_exists('tag_name', $data) + return Tag::class === $className && ( + \array_key_exists('tagName', $data) + || \array_key_exists('tag_name', $data) ); } - /** - * @inheritDoc - */ protected function findObject(mixed $data, DeserializationContext $context): ?object { if (empty($data['tagName']) && empty($data['tag_name'])) { @@ -37,9 +31,9 @@ protected function findObject(mixed $data, DeserializationContext $context): ?ob ->findOneByTagName($data['tagName'] ?? $data['tag_name']); if ( - null !== $tag && - $context->hasAttribute(static::EXCEPTION_ON_EXISTING_TAG) && - true === $context->hasAttribute(static::EXCEPTION_ON_EXISTING_TAG) + null !== $tag + && $context->hasAttribute(static::EXCEPTION_ON_EXISTING_TAG) + && true === $context->hasAttribute(static::EXCEPTION_ON_EXISTING_TAG) ) { throw new EntityAlreadyExistsException('Tag already exists in database.'); } diff --git a/src/Serializer/ObjectConstructor/TranslationObjectConstructor.php b/src/Serializer/ObjectConstructor/TranslationObjectConstructor.php index 4bc72788..059b9fb7 100644 --- a/src/Serializer/ObjectConstructor/TranslationObjectConstructor.php +++ b/src/Serializer/ObjectConstructor/TranslationObjectConstructor.php @@ -10,21 +10,15 @@ final class TranslationObjectConstructor extends AbstractTypedObjectConstructor { - /** - * @inheritDoc - */ public function supports(string $className, array $data): bool { - return \is_subclass_of($className, TranslationInterface::class) && - array_key_exists('locale', $data); + return \is_subclass_of($className, TranslationInterface::class) + && array_key_exists('locale', $data); } - /** - * @inheritDoc - */ - protected function findObject($data, DeserializationContext $context): ?object + protected function findObject(mixed $data, DeserializationContext $context): ?object { - if (null === $data['locale'] || $data['locale'] === '') { + if (null === $data['locale'] || '' === $data['locale']) { throw new ObjectConstructionException('Translation locale can not be empty'); } diff --git a/src/Serializer/ObjectConstructor/TypedObjectConstructorInterface.php b/src/Serializer/ObjectConstructor/TypedObjectConstructorInterface.php index 6e8460b3..2576fa22 100644 --- a/src/Serializer/ObjectConstructor/TypedObjectConstructorInterface.php +++ b/src/Serializer/ObjectConstructor/TypedObjectConstructorInterface.php @@ -12,11 +12,5 @@ interface TypedObjectConstructorInterface extends ObjectConstructorInterface public const FLUSH_NEW_OBJECTS = 'flush_on_deserialize'; public const EXCEPTION_ON_EXISTING = 'exception_on_existing'; - /** - * @param string $className - * @param array $data - * - * @return bool - */ public function supports(string $className, array $data): bool; } diff --git a/src/Serializer/TranslationAwareContextBuilder.php b/src/Serializer/TranslationAwareContextBuilder.php index 66867a64..69b0e628 100644 --- a/src/Serializer/TranslationAwareContextBuilder.php +++ b/src/Serializer/TranslationAwareContextBuilder.php @@ -11,22 +11,21 @@ use RZ\Roadiz\CoreBundle\Repository\TranslationRepository; use Symfony\Component\HttpFoundation\Request; -final class TranslationAwareContextBuilder implements SerializerContextBuilderInterface +final readonly class TranslationAwareContextBuilder implements SerializerContextBuilderInterface { public function __construct( - private readonly SerializerContextBuilderInterface $decorated, - private readonly ManagerRegistry $managerRegistry, - private readonly PreviewResolverInterface $previewResolver + private SerializerContextBuilderInterface $decorated, + private ManagerRegistry $managerRegistry, + private PreviewResolverInterface $previewResolver, ) { } - /** - * @inheritDoc - */ - public function createFromRequest(Request $request, bool $normalization, array $extractedAttributes = null): array + + public function createFromRequest(Request $request, bool $normalization, ?array $extractedAttributes = null): array { $context = $this->decorated->createFromRequest($request, $normalization, $extractedAttributes); if (isset($context['translation']) && $context['translation'] instanceof TranslationInterface) { + // @phpstan-ignore-next-line return $context; } @@ -36,6 +35,7 @@ public function createFromRequest(Request $request, bool $normalization, array $ $requestTranslation = $request->attributes->get('_translation'); if ($requestTranslation instanceof TranslationInterface) { $context['translation'] = $requestTranslation; + return $context; } diff --git a/src/Tag/TagFactory.php b/src/Tag/TagFactory.php index 9a7c79fa..6d31b414 100644 --- a/src/Tag/TagFactory.php +++ b/src/Tag/TagFactory.php @@ -11,21 +11,13 @@ use RZ\Roadiz\CoreBundle\Repository\TagRepository; use RZ\Roadiz\Utils\StringHandler; -final class TagFactory +final readonly class TagFactory { - public function __construct(private readonly ManagerRegistry $managerRegistry) + public function __construct(private ManagerRegistry $managerRegistry) { } - /** - * @param string $name - * @param TranslationInterface|null $translation - * @param Tag|null $parent - * @param int|float $latestPosition - * - * @return Tag - */ - public function create(string $name, ?TranslationInterface $translation = null, ?Tag $parent = null, $latestPosition = 0): Tag + public function create(string $name, ?TranslationInterface $translation = null, ?Tag $parent = null, int|float $latestPosition = 0): Tag { $name = strip_tags(trim($name)); $tagName = StringHandler::slugify($name); @@ -43,7 +35,7 @@ public function create(string $name, ?TranslationInterface $translation = null, return $tag; } - if ($translation === null) { + if (null === $translation) { $translation = $this->managerRegistry->getRepository(TranslationInterface::class)->findDefault(); } diff --git a/src/Traits/LoginRequestTrait.php b/src/Traits/LoginRequestTrait.php index 19ea1b16..a5dba0ae 100644 --- a/src/Traits/LoginRequestTrait.php +++ b/src/Traits/LoginRequestTrait.php @@ -23,13 +23,8 @@ trait LoginRequestTrait abstract protected function getUserViewer(): UserViewer; /** - * @param FormInterface $form - * @param ObjectManager $entityManager - * @param LoggerInterface $logger - * @param UrlGeneratorInterface $urlGenerator - * @param string $resetRoute - * * @return bool TRUE if confirmation has been sent. FALSE if errors + * * @throws \Doctrine\ORM\ORMException * @throws \Doctrine\ORM\OptimisticLockException */ @@ -38,7 +33,7 @@ public function sendConfirmationEmail( ObjectManager $entityManager, LoggerInterface $logger, UrlGeneratorInterface $urlGenerator, - string $resetRoute = 'loginResetPage' + string $resetRoute = 'loginResetPage', ): bool { $email = $form->get('email')->getData(); /** @var User $user */ @@ -53,6 +48,7 @@ public function sendConfirmationEmail( $entityManager->flush(); $userViewer = $this->getUserViewer(); $userViewer->sendPasswordResetLink($user, $resetRoute); + return true; } catch (\Throwable $e) { $user->setPasswordRequestedAt(null); diff --git a/src/Traits/LoginResetTrait.php b/src/Traits/LoginResetTrait.php index 08a3e7e3..d8e2c684 100644 --- a/src/Traits/LoginResetTrait.php +++ b/src/Traits/LoginResetTrait.php @@ -10,24 +10,12 @@ trait LoginResetTrait { - /** - * @param ObjectManager $entityManager - * @param string $token - * @return null|User - */ public function getUserByToken(ObjectManager $entityManager, string $token): ?User { return $entityManager->getRepository(User::class)->findOneByConfirmationToken($token); } - /** - * @param FormInterface $form - * @param User $user - * @param ObjectManager $entityManager - * - * @return bool - */ - public function updateUserPassword(FormInterface $form, User $user, ObjectManager $entityManager) + public function updateUserPassword(FormInterface $form, User $user, ObjectManager $entityManager): bool { $user->setConfirmationToken(null); $user->setPasswordRequestedAt(null); diff --git a/src/Translation/TranslationViewer.php b/src/Translation/TranslationViewer.php index 450d746b..5011143c 100644 --- a/src/Translation/TranslationViewer.php +++ b/src/Translation/TranslationViewer.php @@ -27,13 +27,10 @@ public function __construct( private readonly ManagerRegistry $managerRegistry, private readonly Settings $settingsBag, private readonly RouterInterface $router, - private readonly PreviewResolverInterface $previewResolver + private readonly PreviewResolverInterface $previewResolver, ) { } - /** - * @return TranslationRepository - */ public function getRepository(): TranslationRepository { return $this->managerRegistry->getRepository(Translation::class); @@ -71,10 +68,8 @@ public function getRepository(): TranslationRepository * 'active' => boolean false * 'translation' => string 'Spanish' * - * @param Request $request * @param bool $absolute Generate absolute url or relative paths * - * @return array * @throws ORMException */ public function getTranslationMenuAssignation(Request $request, bool $absolute = false): array @@ -83,9 +78,9 @@ public function getTranslationMenuAssignation(Request $request, bool $absolute = $query = $request->query->all(); $name = ''; $forceLocale = (bool) $this->settingsBag->get('force_locale'); - $useStaticRouting = !empty($attr['_route']) && - is_string($attr['_route']) && - $attr['_route'] !== RouteObjectInterface::OBJECT_BASED_ROUTE_NAME; + $useStaticRouting = !empty($attr['_route']) + && is_string($attr['_route']) + && RouteObjectInterface::OBJECT_BASED_ROUTE_NAME !== $attr['_route']; /* * Fix absolute boolean to Int constant. @@ -93,7 +88,7 @@ public function getTranslationMenuAssignation(Request $request, bool $absolute = $absolute = $absolute ? UrlGeneratorInterface::ABSOLUTE_URL : UrlGeneratorInterface::ABSOLUTE_PATH; if (key_exists('node', $attr) && $attr['node'] instanceof Node) { - $node = $attr["node"]; + $node = $attr['node']; $this->managerRegistry->getManagerForClass(Node::class)->refresh($node); } else { $node = null; @@ -106,9 +101,9 @@ public function getTranslationMenuAssignation(Request $request, bool $absolute = /* * Search for a route without Locale suffix */ - $baseRoute = RouteHandler::getBaseRoute($attr["_route"]); + $baseRoute = RouteHandler::getBaseRoute($attr['_route']); if (null !== $this->router->getRouteCollection()->get($baseRoute)) { - $attr["_route"] = $baseRoute; + $attr['_route'] = $baseRoute; } } elseif (null !== $node) { /* @@ -119,7 +114,7 @@ public function getTranslationMenuAssignation(Request $request, bool $absolute = } else { $translations = $this->getRepository()->findStrictlyAvailableTranslationsForNode($node); } - $name = "node"; + $name = 'node'; } else { return []; } @@ -132,7 +127,7 @@ public function getTranslationMenuAssignation(Request $request, bool $absolute = * Remove existing _locale in query string */ if (key_exists('_locale', $query)) { - unset($query["_locale"]); + unset($query['_locale']); } /* * Remove existing page parameter in query string @@ -154,8 +149,8 @@ public function getTranslationMenuAssignation(Request $request, bool $absolute = /* * Search for a Locale suffixed route */ - if (null !== $this->router->getRouteCollection()->get($attr['_route'] . "Locale")) { - $name = $attr['_route'] . 'Locale'; + if (null !== $this->router->getRouteCollection()->get($attr['_route'].'Locale')) { + $name = $attr['_route'].'Locale'; } $attr['_route_params']['_locale'] = $translation->getPreferredLocale(); @@ -185,7 +180,7 @@ public function getTranslationMenuAssignation(Request $request, bool $absolute = $url = $this->router->generate( RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, array_merge($attr['_route_params'], $query, [ - RouteObjectInterface::ROUTE_OBJECT => $name + RouteObjectInterface::ROUTE_OBJECT => $name, ]), $absolute ); @@ -196,7 +191,7 @@ public function getTranslationMenuAssignation(Request $request, bool $absolute = $url = $this->router->generate( RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, array_merge($query, [ - RouteObjectInterface::ROUTE_OBJECT => $nodesSources + RouteObjectInterface::ROUTE_OBJECT => $nodesSources, ]), $absolute ); @@ -213,24 +208,22 @@ public function getTranslationMenuAssignation(Request $request, bool $absolute = ]; } } + return $return; } - /** - * @return TranslationInterface|null - */ public function getTranslation(): ?TranslationInterface { return $this->translation; } /** - * @param TranslationInterface|null $translation * @return TranslationViewer */ public function setTranslation(?TranslationInterface $translation) { $this->translation = $translation; + return $this; } } diff --git a/src/TwigExtension/AttributesExtension.php b/src/TwigExtension/AttributesExtension.php index 92755704..588e0193 100644 --- a/src/TwigExtension/AttributesExtension.php +++ b/src/TwigExtension/AttributesExtension.php @@ -90,23 +90,17 @@ public function isPercent(AttributeValueTranslationInterface $attributeValueTran public function isNumber(AttributeValueTranslationInterface $attributeValueTranslation): bool { - return $attributeValueTranslation->getAttributeValue()->getAttribute()->isInteger() || - $attributeValueTranslation->getAttributeValue()->getAttribute()->isDecimal(); + return $attributeValueTranslation->getAttributeValue()->getAttribute()->isInteger() + || $attributeValueTranslation->getAttributeValue()->getAttribute()->isDecimal(); } - /** - * @param AttributableInterface|null $attributable - * @param TranslationInterface $translation - * @param bool $hideNotTranslated - * - * @return array * @throws SyntaxError */ public function getAttributeValues( ?AttributableInterface $attributable, TranslationInterface $translation, - bool $hideNotTranslated = false + bool $hideNotTranslated = false, ): array { if (null === $attributable) { throw new SyntaxError('Cannot call get_attributes on NULL'); @@ -150,10 +144,6 @@ public function getAttributeValues( } /** - * @param NodesSources|null $nodesSources - * @param bool $hideNotTranslated - * - * @return array * @throws SyntaxError */ public function getNodeSourceAttributeValues(?NodesSources $nodesSources, bool $hideNotTranslated = false): array @@ -161,14 +151,11 @@ public function getNodeSourceAttributeValues(?NodesSources $nodesSources, bool $ if (null === $nodesSources) { throw new SyntaxError('Cannot call node_source_attributes on NULL'); } + return $this->getAttributeValues($nodesSources->getNode(), $nodesSources->getTranslation(), $hideNotTranslated); } /** - * @param NodesSources|null $nodesSources - * @param bool $hideNotTranslated - * - * @return array * @throws SyntaxError */ public function getNodeSourceGroupedAttributeValues(?NodesSources $nodesSources, bool $hideNotTranslated = false): array @@ -176,10 +163,10 @@ public function getNodeSourceGroupedAttributeValues(?NodesSources $nodesSources, $groups = [ INF => [ 'group' => null, - 'attributeValues' => [] - ] + 'attributeValues' => [], + ], ]; - $attributeValueTranslations = $this->getNodeSourceAttributeValues($nodesSources, $hideNotTranslated); + $attributeValueTranslations = $this->getNodeSourceAttributeValues($nodesSources, $hideNotTranslated); /** @var AttributeValueTranslationInterface $attributeValueTranslation */ foreach ($attributeValueTranslations as $attributeValueTranslation) { $group = $attributeValueTranslation->getAttributeValue()->getAttribute()->getGroup(); @@ -187,7 +174,7 @@ public function getNodeSourceGroupedAttributeValues(?NodesSources $nodesSources, if (!isset($groups[$group->getCanonicalName()])) { $groups[$group->getCanonicalName()] = [ 'group' => $group, - 'attributeValues' => [] + 'attributeValues' => [], ]; } $groups[$group->getCanonicalName()]['attributeValues'][] = $attributeValueTranslation; @@ -201,13 +188,7 @@ public function getNodeSourceGroupedAttributeValues(?NodesSources $nodesSources, }); } - /** - * @param mixed $mixed - * @param TranslationInterface|null $translation - * - * @return string|null - */ - public function getAttributeLabelOrCode(mixed $mixed, TranslationInterface $translation = null): ?string + public function getAttributeLabelOrCode(mixed $mixed, ?TranslationInterface $translation = null): ?string { if (null === $mixed) { return null; @@ -223,18 +204,14 @@ public function getAttributeLabelOrCode(mixed $mixed, TranslationInterface $tran if (null === $translation) { $translation = $mixed->getTranslation(); } + return $mixed->getAttributeValue()->getAttribute()->getLabelOrCode($translation); } return null; } - /** - * @param mixed $mixed - * @param TranslationInterface|null $translation - * @return string|null - */ - public function getAttributeGroupLabelOrCode(mixed $mixed, TranslationInterface $translation = null): ?string + public function getAttributeGroupLabelOrCode(mixed $mixed, ?TranslationInterface $translation = null): ?string { if (null === $mixed) { return null; @@ -252,6 +229,7 @@ public function getAttributeGroupLabelOrCode(mixed $mixed, TranslationInterface if (null === $translation) { $translation = $mixed->getTranslation(); } + return $mixed->getAttribute()->getGroup()->getTranslatedName($translation); } diff --git a/src/TwigExtension/BlockRenderExtension.php b/src/TwigExtension/BlockRenderExtension.php index 5e028743..c023d81b 100644 --- a/src/TwigExtension/BlockRenderExtension.php +++ b/src/TwigExtension/BlockRenderExtension.php @@ -29,49 +29,39 @@ public function getFilters(): array } /** - * @param NodesSources|null $nodeSource - * @param string $themeName - * @param array $assignation - * - * @return string * @throws RuntimeError */ - public function blockRender(NodesSources $nodeSource = null, string $themeName = "DefaultTheme", array $assignation = []): string + public function blockRender(?NodesSources $nodeSource = null, string $themeName = 'DefaultTheme', array $assignation = []): string { if (null !== $nodeSource) { if (!empty($themeName)) { $class = $this->getNodeSourceControllerName($nodeSource, $themeName); if (class_exists($class) && method_exists($class, 'blockAction')) { - $controllerReference = new ControllerReference($class . '::blockAction', [ + $controllerReference = new ControllerReference($class.'::blockAction', [ 'source' => $nodeSource, 'assignation' => $assignation, ]); + /* * ignore_errors option MUST BE false in order to catch ForceResponseException * from Master request render method and redirect users. */ return $this->handler->render($controllerReference, 'inline', [ - 'ignore_errors' => false + 'ignore_errors' => false, ]); } else { - throw new RuntimeError($class . "::blockAction() action does not exist."); + throw new RuntimeError($class.'::blockAction() action does not exist.'); } } else { - throw new RuntimeError("Invalid name formatting for your theme."); + throw new RuntimeError('Invalid name formatting for your theme.'); } } - throw new RuntimeError("Invalid NodesSources."); + throw new RuntimeError('Invalid NodesSources.'); } - /** - * @param NodesSources $nodeSource - * @param string $themeName - * - * @return string - */ protected function getNodeSourceControllerName(NodesSources $nodeSource, string $themeName): string { - return '\\Themes\\' . $themeName . '\\Controllers\\Blocks\\' . - $nodeSource->getNodeTypeName() . 'Controller'; + return '\\Themes\\'.$themeName.'\\Controllers\\Blocks\\'. + $nodeSource->getNodeTypeName().'Controller'; } } diff --git a/src/TwigExtension/CentralTruncateExtension.php b/src/TwigExtension/CentralTruncateExtension.php index 077e73e9..1265c2d6 100644 --- a/src/TwigExtension/CentralTruncateExtension.php +++ b/src/TwigExtension/CentralTruncateExtension.php @@ -21,17 +21,10 @@ public function getFilters(): array new TwigFilter( 'central_truncate', [$this, 'centralTruncate'] - ) + ), ]; } - /** - * @param string|null $object - * @param int $length - * @param int $offset - * @param string $ellipsis - * @return string|null - */ public function centralTruncate(?string $object, int $length, int $offset = 0, string $ellipsis = '[…]'): ?string { if (null === $object) { @@ -40,9 +33,10 @@ public function centralTruncate(?string $object, int $length, int $offset = 0, s $unicode = u($object); $unicodeEllipsis = u($ellipsis); if ($unicode->length() > $length + $unicodeEllipsis->length()) { - $str1 = $unicode->slice(0, (int)(floor($length / 2) + floor($offset / 2))); - $str2 = $unicode->slice((int)((floor($length / 2) * -1) + floor($offset / 2))); - return $str1 . $ellipsis . $str2; + $str1 = $unicode->slice(0, (int) (floor($length / 2) + floor($offset / 2))); + $str2 = $unicode->slice((int) ((floor($length / 2) * -1) + floor($offset / 2))); + + return $str1.$ellipsis.$str2; } return $object; diff --git a/src/TwigExtension/DocumentUrlExtension.php b/src/TwigExtension/DocumentUrlExtension.php index af68dd7d..07c5c002 100644 --- a/src/TwigExtension/DocumentUrlExtension.php +++ b/src/TwigExtension/DocumentUrlExtension.php @@ -13,19 +13,16 @@ use Twig\TwigFilter; /** - * Extension that allow render documents Url + * Extension that allow render documents Url. */ final class DocumentUrlExtension extends AbstractExtension { public function __construct( private readonly DocumentUrlGeneratorInterface $documentUrlGenerator, - private readonly bool $throwExceptions = false + private readonly bool $throwExceptions = false, ) { } - /** - * @return array - */ public function getFilters(): array { return [ @@ -40,18 +37,15 @@ public function getFilters(): array * * - Document * - * @param PersistableInterface|null $mixed - * @param array $criteria - * @return string * @throws RuntimeError */ - public function getUrl(PersistableInterface $mixed = null, array $criteria = []): string + public function getUrl(?PersistableInterface $mixed = null, array $criteria = []): string { if (null === $mixed) { if ($this->throwExceptions) { - throw new RuntimeError("Twig “url” filter must be used with a not null object"); + throw new RuntimeError('Twig “url” filter must be used with a not null object'); } else { - return ""; + return ''; } } @@ -64,12 +58,13 @@ public function getUrl(PersistableInterface $mixed = null, array $criteria = []) $this->documentUrlGenerator->setOptions($criteria); $this->documentUrlGenerator->setDocument($mixed); + return $this->documentUrlGenerator->getUrl($absolute); } catch (InvalidArgumentException $e) { throw new RuntimeError($e->getMessage(), -1, null, $e); } } - throw new RuntimeError("Twig “url” filter can be only used with a Document"); + throw new RuntimeError('Twig “url” filter can be only used with a Document'); } } diff --git a/src/TwigExtension/HandlerExtension.php b/src/TwigExtension/HandlerExtension.php index 46bd6cd0..8a432159 100644 --- a/src/TwigExtension/HandlerExtension.php +++ b/src/TwigExtension/HandlerExtension.php @@ -27,8 +27,6 @@ public function getFilters(): array } /** - * @param mixed $mixed - * @return AbstractHandler|null * @throws RuntimeError * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface diff --git a/src/TwigExtension/JwtExtension.php b/src/TwigExtension/JwtExtension.php index 246e20d8..070e0e63 100644 --- a/src/TwigExtension/JwtExtension.php +++ b/src/TwigExtension/JwtExtension.php @@ -17,7 +17,7 @@ final class JwtExtension extends AbstractExtension public function __construct( private readonly JWTTokenManagerInterface $tokenManager, private readonly LoggerInterface $logger, - private readonly PreviewUserProviderInterface $previewUserProvider + private readonly PreviewUserProviderInterface $previewUserProvider, ) { } @@ -34,9 +34,11 @@ public function createPreviewJwt(): ?string return $this->tokenManager->create($this->previewUserProvider->createFromSecurity()); } catch (AccessDeniedException $exception) { $this->logger->warning($exception->getMessage()); + return null; } catch (JWTFailureException $exception) { $this->logger->warning($exception->getMessage()); + return null; } } diff --git a/src/TwigExtension/LogExtension.php b/src/TwigExtension/LogExtension.php index cfaa612e..2e45ebe2 100644 --- a/src/TwigExtension/LogExtension.php +++ b/src/TwigExtension/LogExtension.php @@ -13,8 +13,8 @@ use RZ\Roadiz\CoreBundle\Entity\Translation; use RZ\Roadiz\CoreBundle\Entity\User; use RZ\Roadiz\CoreBundle\Logger\Entity\Log; -use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Bundle\SecurityBundle\Security; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Twig\Extension\AbstractExtension; use Twig\TwigFunction; @@ -22,7 +22,7 @@ final class LogExtension extends AbstractExtension { public function __construct( private readonly Security $security, - private readonly UrlGeneratorInterface $urlGenerator + private readonly UrlGeneratorInterface $urlGenerator, ) { } @@ -43,9 +43,9 @@ public function getEditPath(?object $log): ?string case Node::class: case NodesSources::class: if ( - $this->security->isGranted('ROLE_ACCESS_NODES') && - isset($log->getAdditionalData()['node_id']) && - isset($log->getAdditionalData()['translation_id']) + $this->security->isGranted('ROLE_ACCESS_NODES') + && isset($log->getAdditionalData()['node_id']) + && isset($log->getAdditionalData()['translation_id']) ) { return $this->urlGenerator->generate('nodesEditSourcePage', [ 'nodeId' => $log->getAdditionalData()['node_id'], diff --git a/src/TwigExtension/NodesSourcesExtension.php b/src/TwigExtension/NodesSourcesExtension.php index 55d8fcc8..b4e8506a 100644 --- a/src/TwigExtension/NodesSourcesExtension.php +++ b/src/TwigExtension/NodesSourcesExtension.php @@ -17,14 +17,14 @@ use Twig\TwigTest; /** - * Extension that allow to gather nodes-source from hierarchy + * Extension that allow to gather nodes-source from hierarchy. */ final class NodesSourcesExtension extends AbstractExtension { public function __construct( private readonly ManagerRegistry $managerRegistry, private readonly NodeTypes $nodeTypesBag, - private readonly bool $throwExceptions = false + private readonly bool $throwExceptions = false, ) { } @@ -59,17 +59,15 @@ public function getTests(): array } /** - * @param NodesSources|null $ns - * @param array|null $criteria - * @param array|null $order * @return iterable + * * @throws RuntimeError */ - public function getChildren(NodesSources $ns = null, array $criteria = null, array $order = null): iterable + public function getChildren(?NodesSources $ns = null, ?array $criteria = null, ?array $order = null): iterable { if (null === $ns) { if ($this->throwExceptions) { - throw new RuntimeError("Cannot get children from a NULL node-source."); + throw new RuntimeError('Cannot get children from a NULL node-source.'); } else { return []; } @@ -81,17 +79,13 @@ public function getChildren(NodesSources $ns = null, array $criteria = null, arr } /** - * @param NodesSources|null $ns - * @param array|null $criteria - * @param array|null $order - * @return NodesSources|null * @throws RuntimeError */ - public function getNext(NodesSources $ns = null, array $criteria = null, array $order = null): ?NodesSources + public function getNext(?NodesSources $ns = null, ?array $criteria = null, ?array $order = null): ?NodesSources { if (null === $ns) { if ($this->throwExceptions) { - throw new RuntimeError("Cannot get next sibling from a NULL node-source."); + throw new RuntimeError('Cannot get next sibling from a NULL node-source.'); } else { return null; } @@ -103,17 +97,13 @@ public function getNext(NodesSources $ns = null, array $criteria = null, array $ } /** - * @param NodesSources|null $ns - * @param array|null $criteria - * @param array|null $order - * @return NodesSources|null * @throws RuntimeError */ - public function getPrevious(NodesSources $ns = null, array $criteria = null, array $order = null): ?NodesSources + public function getPrevious(?NodesSources $ns = null, ?array $criteria = null, ?array $order = null): ?NodesSources { if (null === $ns) { if ($this->throwExceptions) { - throw new RuntimeError("Cannot get previous sibling from a NULL node-source."); + throw new RuntimeError('Cannot get previous sibling from a NULL node-source.'); } else { return null; } @@ -125,17 +115,13 @@ public function getPrevious(NodesSources $ns = null, array $criteria = null, arr } /** - * @param NodesSources|null $ns - * @param array|null $criteria - * @param array|null $order - * @return NodesSources|null * @throws RuntimeError */ - public function getLastSibling(NodesSources $ns = null, array $criteria = null, array $order = null): ?NodesSources + public function getLastSibling(?NodesSources $ns = null, ?array $criteria = null, ?array $order = null): ?NodesSources { if (null === $ns) { if ($this->throwExceptions) { - throw new RuntimeError("Cannot get last sibling from a NULL node-source."); + throw new RuntimeError('Cannot get last sibling from a NULL node-source.'); } else { return null; } @@ -147,17 +133,13 @@ public function getLastSibling(NodesSources $ns = null, array $criteria = null, } /** - * @param NodesSources|null $ns - * @param array|null $criteria - * @param array|null $order - * @return NodesSources|null * @throws RuntimeError */ - public function getFirstSibling(NodesSources $ns = null, array $criteria = null, array $order = null): ?NodesSources + public function getFirstSibling(?NodesSources $ns = null, ?array $criteria = null, ?array $order = null): ?NodesSources { if (null === $ns) { if ($this->throwExceptions) { - throw new RuntimeError("Cannot get first sibling from a NULL node-source."); + throw new RuntimeError('Cannot get first sibling from a NULL node-source.'); } else { return null; } @@ -169,15 +151,13 @@ public function getFirstSibling(NodesSources $ns = null, array $criteria = null, } /** - * @param NodesSources|null $ns - * @return NodesSources|null * @throws RuntimeError */ - public function getParent(NodesSources $ns = null): ?NodesSources + public function getParent(?NodesSources $ns = null): ?NodesSources { if (null === $ns) { if ($this->throwExceptions) { - throw new RuntimeError("Cannot get parent from a NULL node-source."); + throw new RuntimeError('Cannot get parent from a NULL node-source.'); } else { return null; } @@ -187,19 +167,16 @@ public function getParent(NodesSources $ns = null): ?NodesSources } /** - * @param NodesSources|null $ns - * @param array|null $criteria - * @return array * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface * @throws RuntimeError * @throws NonUniqueResultException */ - public function getParents(NodesSources $ns = null, array $criteria = null): array + public function getParents(?NodesSources $ns = null, ?array $criteria = null): array { if (null === $ns) { if ($this->throwExceptions) { - throw new RuntimeError("Cannot get parents from a NULL node-source."); + throw new RuntimeError('Cannot get parents from a NULL node-source.'); } else { return []; } @@ -211,17 +188,17 @@ public function getParents(NodesSources $ns = null, array $criteria = null): arr } /** - * @param NodesSources|null $ns * @return iterable + * * @throws RuntimeError * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ - public function getTags(NodesSources $ns = null): iterable + public function getTags(?NodesSources $ns = null): iterable { if (null === $ns) { if ($this->throwExceptions) { - throw new RuntimeError("Cannot get tags from a NULL node-source."); + throw new RuntimeError('Cannot get tags from a NULL node-source.'); } else { return []; } diff --git a/src/TwigExtension/RoadizExtension.php b/src/TwigExtension/RoadizExtension.php index c5d4d333..5b69d609 100644 --- a/src/TwigExtension/RoadizExtension.php +++ b/src/TwigExtension/RoadizExtension.php @@ -21,13 +21,10 @@ public function __construct( private readonly string $cmsVersion, private readonly string $cmsVersionPrefix, private readonly bool $hideRoadizVersion, - private readonly int $maxVersionsShowed + private readonly int $maxVersionsShowed, ) { } - /** - * @return array - */ public function getGlobals(): array { return [ @@ -41,11 +38,13 @@ public function getGlobals(): array 'nodeTypes' => $this->nodeTypesBag, ], 'chroot_resolver' => $this->chrootResolver, + 'main_color' => $this->settingsBag->get('main_color'), 'meta' => [ 'siteName' => $this->settingsBag->get('site_name'), + 'backofficeName' => $this->settingsBag->get('site_name').' backstage', 'siteCopyright' => $this->settingsBag->get('site_copyright'), 'siteDescription' => $this->settingsBag->get('seo_description'), - ] + ], ]; } } diff --git a/src/TwigExtension/RoutingExtension.php b/src/TwigExtension/RoutingExtension.php index adb4d9ac..1b2ccb2e 100644 --- a/src/TwigExtension/RoutingExtension.php +++ b/src/TwigExtension/RoutingExtension.php @@ -19,13 +19,10 @@ final class RoutingExtension extends AbstractExtension { public function __construct( private readonly BaseRoutingExtension $decorated, - private readonly UrlGeneratorInterface $generator + private readonly UrlGeneratorInterface $generator, ) { } - /** - * {@inheritdoc} - */ public function getFunctions(): array { return [ @@ -35,10 +32,6 @@ public function getFunctions(): array } /** - * @param string|object|null $name - * @param array $parameters - * @param bool $relative - * @return string * @throws RuntimeError */ public function getPath(string|object|null $name, array $parameters = [], bool $relative = false): string @@ -61,10 +54,6 @@ public function getPath(string|object|null $name, array $parameters = [], bool $ } /** - * @param string|object|null $name - * @param array $parameters - * @param bool $schemeRelative - * @return string * @throws RuntimeError */ public function getUrl(string|object|null $name, array $parameters = [], bool $schemeRelative = false): string diff --git a/src/TwigExtension/TokenParser/TransChoiceTokenParser.php b/src/TwigExtension/TokenParser/TransChoiceTokenParser.php index bcd01d02..d899ec84 100644 --- a/src/TwigExtension/TokenParser/TransChoiceTokenParser.php +++ b/src/TwigExtension/TokenParser/TransChoiceTokenParser.php @@ -24,11 +24,6 @@ */ class TransChoiceTokenParser extends AbstractTokenParser { - /** - * {@inheritdoc} - * - * @return Node - */ public function parse(Token $token): Node { $lineno = $token->getLine(); @@ -77,11 +72,6 @@ public function decideTransChoiceFork(Token $token): bool return $token->test(['endtranschoice']); } - /** - * {@inheritdoc} - * - * @return string - */ public function getTag(): string { return 'transchoice'; diff --git a/src/TwigExtension/TransChoiceExtension.php b/src/TwigExtension/TransChoiceExtension.php index 96c19b15..d3eb996f 100644 --- a/src/TwigExtension/TransChoiceExtension.php +++ b/src/TwigExtension/TransChoiceExtension.php @@ -49,7 +49,7 @@ public function transchoice( int $count, array $arguments = [], ?string $domain = null, - ?string $locale = null + ?string $locale = null, ): string { return $this->translator->trans($message, array_merge(['%count%' => $count], $arguments), $domain, $locale); } diff --git a/src/TwigExtension/TranslationExtension.php b/src/TwigExtension/TranslationExtension.php index cd248352..ec52773d 100644 --- a/src/TwigExtension/TranslationExtension.php +++ b/src/TwigExtension/TranslationExtension.php @@ -25,15 +25,10 @@ public function getFilters(): array public function getTests(): array { return [ - new TwigTest('rtl', [$this, 'isLocaleRtl']) + new TwigTest('rtl', [$this, 'isLocaleRtl']), ]; } - /** - * @param mixed $mixed - * - * @return bool - */ public function isLocaleRtl(mixed $mixed): bool { if ($mixed instanceof TranslationInterface) { @@ -47,22 +42,11 @@ public function isLocaleRtl(mixed $mixed): bool return false; } - /** - * @param string $iso - * @param string|null $locale - * @return string - */ public function getCountryName(string $iso, ?string $locale = null): string { return Countries::getName($iso, $locale); } - /** - * @param string $iso - * @param string|null $locale - * - * @return string - */ public function getLocaleName(string $iso, ?string $locale = null): string { return Locales::getName($iso, $locale); diff --git a/src/TwigExtension/TranslationMenuExtension.php b/src/TwigExtension/TranslationMenuExtension.php deleted file mode 100644 index 2c0bccd8..00000000 --- a/src/TwigExtension/TranslationMenuExtension.php +++ /dev/null @@ -1,45 +0,0 @@ -translationViewer->setTranslation($translation); - return $this->translationViewer->getTranslationMenuAssignation($this->requestStack->getCurrentRequest(), $absolute); - } else { - return []; - } - } -} diff --git a/src/Webhook/Exception/TooManyWebhookTriggeredException.php b/src/Webhook/Exception/TooManyWebhookTriggeredException.php index c53c4b58..662e0197 100644 --- a/src/Webhook/Exception/TooManyWebhookTriggeredException.php +++ b/src/Webhook/Exception/TooManyWebhookTriggeredException.php @@ -4,22 +4,17 @@ namespace RZ\Roadiz\CoreBundle\Webhook\Exception; -use Throwable; - final class TooManyWebhookTriggeredException extends \RuntimeException { public function __construct( private readonly ?\DateTimeImmutable $doNotTriggerBefore = null, - string $message = "", + string $message = '', int $code = 0, - Throwable $previous = null + ?\Throwable $previous = null, ) { parent::__construct($message, $code, $previous); } - /** - * @return \DateTimeImmutable - */ public function getDoNotTriggerBefore(): \DateTimeImmutable { return $this->doNotTriggerBefore ?? \DateTimeImmutable::createFromMutable((new \DateTime())->add(new \DateInterval('PT30S'))); diff --git a/src/Webhook/Message/GenericJsonPostMessage.php b/src/Webhook/Message/GenericJsonPostMessage.php deleted file mode 100644 index cd8d9c4b..00000000 --- a/src/Webhook/Message/GenericJsonPostMessage.php +++ /dev/null @@ -1,54 +0,0 @@ -uri, - [ - 'Content-Type' => 'application/json', - 'Accept' => 'application/json' - ], - json_encode($this->payload ?? [], JSON_NUMERIC_CHECK | JSON_THROW_ON_ERROR) - ); - } - - /** - * @return array - */ - public function getOptions(): array - { - return [ - 'debug' => false, - 'timeout' => 3 - ]; - } - - /** - * @param Webhook $webhook - * @return static - */ - public static function fromWebhook(WebhookInterface $webhook): self - { - return new self($webhook->getUri(), $webhook->getPayload()); - } -} diff --git a/src/Webhook/Message/GenericJsonPostMessageInterface.php b/src/Webhook/Message/GenericJsonPostMessageInterface.php new file mode 100644 index 00000000..cd4d3007 --- /dev/null +++ b/src/Webhook/Message/GenericJsonPostMessageInterface.php @@ -0,0 +1,49 @@ + 3, + 'body' => \json_encode($this->payload ?? [], JSON_NUMERIC_CHECK | JSON_THROW_ON_ERROR), + 'headers' => [ + 'Content-Type' => 'application/json', + 'Accept' => 'application/json', + ], + ]; + } + + /** + * @param Webhook $webhook + */ + public static function fromWebhook(WebhookInterface $webhook): self + { + return new self($webhook->getUri(), $webhook->getPayload()); + } + + public function getMethod(): string + { + return 'POST'; + } + + public function getUri(): string + { + return $this->uri; + } +} diff --git a/src/Webhook/Message/GitlabPipelineTriggerMessage.php b/src/Webhook/Message/GitlabPipelineTriggerMessageInterface.php similarity index 55% rename from src/Webhook/Message/GitlabPipelineTriggerMessage.php rename to src/Webhook/Message/GitlabPipelineTriggerMessageInterface.php index 8783c286..e16429fd 100644 --- a/src/Webhook/Message/GitlabPipelineTriggerMessage.php +++ b/src/Webhook/Message/GitlabPipelineTriggerMessageInterface.php @@ -4,23 +4,21 @@ namespace RZ\Roadiz\CoreBundle\Webhook\Message; -use GuzzleHttp\Psr7\Request; -use Psr\Http\Message\RequestInterface; use RZ\Roadiz\CoreBundle\Message\AsyncMessage; -use RZ\Roadiz\CoreBundle\Message\HttpRequestMessage; +use RZ\Roadiz\CoreBundle\Message\HttpRequestMessageInterface; use RZ\Roadiz\CoreBundle\Webhook\WebhookInterface; -final class GitlabPipelineTriggerMessage implements AsyncMessage, HttpRequestMessage, WebhookMessage +final readonly class GitlabPipelineTriggerMessageInterface implements AsyncMessage, HttpRequestMessageInterface, WebhookMessage { public function __construct( - private readonly string $uri, - private readonly string $token, - private readonly string $ref = 'main', - private readonly ?array $variables = null + private string $uri, + private string $token, + private string $ref = 'main', + private ?array $variables = null, ) { } - public function getRequest(): RequestInterface + public function getOptions(): array { $postBody = [ 'token' => $this->token, @@ -30,35 +28,23 @@ public function getRequest(): RequestInterface $postBody['variables'] = $this->variables; } - return new Request( - 'POST', - $this->uri, - [ + return [ + 'timeout' => 3, + 'headers' => [ 'Content-Type' => 'application/x-www-form-urlencoded', - 'Accept' => 'application/json' + 'Accept' => 'application/json', ], - http_build_query($postBody) - ); - } - - /** - * @return array - */ - public function getOptions(): array - { - return [ - 'debug' => false, - 'timeout' => 3 + 'body' => http_build_query($postBody), ]; } /** - * @param WebhookInterface $webhook * @return static */ public static function fromWebhook(WebhookInterface $webhook): self { $payload = $webhook->getPayload(); + return new self( $webhook->getUri(), $payload['token'] ?? '', @@ -66,4 +52,14 @@ public static function fromWebhook(WebhookInterface $webhook): self $payload['variables'] ?? [] ); } + + public function getMethod(): string + { + return 'POST'; + } + + public function getUri(): string + { + return $this->uri; + } } diff --git a/src/Webhook/Message/NetlifyBuildHookMessage.php b/src/Webhook/Message/NetlifyBuildHookMessage.php deleted file mode 100644 index dc0ee797..00000000 --- a/src/Webhook/Message/NetlifyBuildHookMessage.php +++ /dev/null @@ -1,56 +0,0 @@ -payload) { - return new Request( - 'POST', - $this->uri, - [ - 'Content-Type' => 'application/x-www-form-urlencoded', - 'Accept' => 'application/json' - ], - http_build_query($this->payload) - ); - } - return new Request('POST', $this->uri); - } - - /** - * @return array - */ - public function getOptions(): array - { - return [ - 'debug' => false, - 'timeout' => 3 - ]; - } - - /** - * @param WebhookInterface $webhook - * @return static - */ - public static function fromWebhook(WebhookInterface $webhook): self - { - return new self($webhook->getUri(), $webhook->getPayload()); - } -} diff --git a/src/Webhook/Message/NetlifyBuildHookMessageInterface.php b/src/Webhook/Message/NetlifyBuildHookMessageInterface.php new file mode 100644 index 00000000..02b8a1fc --- /dev/null +++ b/src/Webhook/Message/NetlifyBuildHookMessageInterface.php @@ -0,0 +1,57 @@ +payload) { + return [ + 'timeout' => 3, + 'headers' => [ + 'Accept' => 'application/json', + ], + ]; + } + + return [ + 'timeout' => 3, + 'headers' => [ + 'Content-Type' => 'application/x-www-form-urlencoded', + 'Accept' => 'application/json', + ], + 'body' => http_build_query($this->payload), + ]; + } + + /** + * @return static + */ + public static function fromWebhook(WebhookInterface $webhook): self + { + return new self($webhook->getUri(), $webhook->getPayload()); + } + + public function getMethod(): string + { + return 'POST'; + } + + public function getUri(): string + { + return $this->uri; + } +} diff --git a/src/Webhook/Message/WebhookMessage.php b/src/Webhook/Message/WebhookMessage.php index 012c98de..e6f97e06 100644 --- a/src/Webhook/Message/WebhookMessage.php +++ b/src/Webhook/Message/WebhookMessage.php @@ -8,9 +8,5 @@ interface WebhookMessage { - /** - * @param WebhookInterface $webhook - * @return static - */ - public static function fromWebhook(WebhookInterface $webhook); + public static function fromWebhook(WebhookInterface $webhook): self; } diff --git a/src/Webhook/Message/WebhookMessageFactory.php b/src/Webhook/Message/WebhookMessageFactory.php index bd248e0a..89b1d2b0 100644 --- a/src/Webhook/Message/WebhookMessageFactory.php +++ b/src/Webhook/Message/WebhookMessageFactory.php @@ -4,12 +4,12 @@ namespace RZ\Roadiz\CoreBundle\Webhook\Message; -use RZ\Roadiz\CoreBundle\Message\HttpRequestMessage; +use RZ\Roadiz\CoreBundle\Message\HttpRequestMessageInterface; use RZ\Roadiz\CoreBundle\Webhook\WebhookInterface; final class WebhookMessageFactory implements WebhookMessageFactoryInterface { - public function createMessage(WebhookInterface $webhook): HttpRequestMessage + public function createMessage(WebhookInterface $webhook): HttpRequestMessageInterface { if (null === $webhook->getMessageType()) { throw new \LogicException('Webhook message type is null.'); @@ -22,7 +22,7 @@ public function createMessage(WebhookInterface $webhook): HttpRequestMessage throw new \LogicException('Webhook message type does not exist.'); } if (!in_array(WebhookMessage::class, class_implements($messageType))) { - throw new \LogicException('Webhook message type does not implement ' . WebhookMessage::class); + throw new \LogicException('Webhook message type does not implement '.WebhookMessage::class); } return $messageType::fromWebhook($webhook); diff --git a/src/Webhook/Message/WebhookMessageFactoryInterface.php b/src/Webhook/Message/WebhookMessageFactoryInterface.php index e75c6a04..be8062ec 100644 --- a/src/Webhook/Message/WebhookMessageFactoryInterface.php +++ b/src/Webhook/Message/WebhookMessageFactoryInterface.php @@ -4,10 +4,10 @@ namespace RZ\Roadiz\CoreBundle\Webhook\Message; -use RZ\Roadiz\CoreBundle\Message\HttpRequestMessage; +use RZ\Roadiz\CoreBundle\Message\HttpRequestMessageInterface; use RZ\Roadiz\CoreBundle\Webhook\WebhookInterface; interface WebhookMessageFactoryInterface { - public function createMessage(WebhookInterface $webhook): HttpRequestMessage; + public function createMessage(WebhookInterface $webhook): HttpRequestMessageInterface; } diff --git a/src/Webhook/ThrottledWebhookDispatcher.php b/src/Webhook/ThrottledWebhookDispatcher.php index 82e08d8d..56c22e90 100644 --- a/src/Webhook/ThrottledWebhookDispatcher.php +++ b/src/Webhook/ThrottledWebhookDispatcher.php @@ -10,25 +10,24 @@ use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\RateLimiter\RateLimiterFactory; -final class ThrottledWebhookDispatcher implements WebhookDispatcher +final readonly class ThrottledWebhookDispatcher implements WebhookDispatcher { public function __construct( - private readonly WebhookMessageFactoryInterface $messageFactory, - private readonly MessageBusInterface $messageBus, - private readonly RateLimiterFactory $throttledWebhooksLimiter + private WebhookMessageFactoryInterface $messageFactory, + private MessageBusInterface $messageBus, + private RateLimiterFactory $throttledWebhooksLimiter, ) { } /** - * @param WebhookInterface $webhook * @throws \Exception */ public function dispatch(WebhookInterface $webhook): void { $doNotTriggerBefore = $webhook->doNotTriggerBefore(); if ( - null !== $doNotTriggerBefore && - $doNotTriggerBefore > new \DateTime() + null !== $doNotTriggerBefore + && $doNotTriggerBefore > new \DateTime() ) { throw new TooManyWebhookTriggeredException(\DateTimeImmutable::createFromMutable($doNotTriggerBefore)); } diff --git a/src/Webhook/WebhookInterface.php b/src/Webhook/WebhookInterface.php index 4ad3a08e..3c8821f0 100644 --- a/src/Webhook/WebhookInterface.php +++ b/src/Webhook/WebhookInterface.php @@ -10,16 +10,25 @@ interface WebhookInterface * @return string|null */ public function getId(); + /** * @return string */ public function __toString(); + public function getUri(): ?string; + public function getMessageType(): ?string; + public function getPayload(): ?array; + public function getThrottleSeconds(): int; + public function doNotTriggerBefore(): ?\DateTime; + public function setLastTriggeredAt(?\DateTime $lastTriggeredAt): self; + public function getLastTriggeredAt(): ?\DateTime; + public function isAutomatic(): bool; } diff --git a/src/Workflow/Event/NodeStatusGuardListener.php b/src/Workflow/Event/NodeStatusGuardListener.php index 742fa04c..925f1106 100644 --- a/src/Workflow/Event/NodeStatusGuardListener.php +++ b/src/Workflow/Event/NodeStatusGuardListener.php @@ -6,20 +6,17 @@ use RZ\Roadiz\CoreBundle\Entity\Node; use RZ\Roadiz\CoreBundle\Security\Authorization\Voter\NodeVoter; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Bundle\SecurityBundle\Security; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Workflow\Event\GuardEvent; use Symfony\Component\Workflow\TransitionBlocker; -final class NodeStatusGuardListener implements EventSubscriberInterface +final readonly class NodeStatusGuardListener implements EventSubscriberInterface { - public function __construct(private readonly Security $security) + public function __construct(private Security $security) { } - /** - * @inheritDoc - */ public static function getSubscribedEvents(): array { return [ diff --git a/src/Workflow/NodeWorkflow.php b/src/Workflow/NodeWorkflow.php index e8b51897..e88c50fa 100644 --- a/src/Workflow/NodeWorkflow.php +++ b/src/Workflow/NodeWorkflow.php @@ -4,7 +4,7 @@ namespace RZ\Roadiz\CoreBundle\Workflow; -use RZ\Roadiz\CoreBundle\Entity\Node; +use RZ\Roadiz\CoreBundle\Enum\NodeStatus; use Symfony\Component\Workflow\DefinitionBuilder; use Symfony\Component\Workflow\MarkingStore\MethodMarkingStore; use Symfony\Component\Workflow\Transition; @@ -17,36 +17,31 @@ public function __construct(EventDispatcherInterface $dispatcher) { $definitionBuilder = new DefinitionBuilder(); $definition = $definitionBuilder - ->setInitialPlaces($this->toPlace(Node::DRAFT)) + ->setInitialPlaces(NodeStatus::DRAFT->name) ->addPlaces([ - $this->toPlace(Node::DRAFT), - $this->toPlace(Node::PENDING), - $this->toPlace(Node::PUBLISHED), - $this->toPlace(Node::ARCHIVED), - $this->toPlace(Node::DELETED) + NodeStatus::DRAFT->name, + NodeStatus::PENDING->name, + NodeStatus::PUBLISHED->name, + NodeStatus::ARCHIVED->name, + NodeStatus::DELETED->name, ]) - ->addTransition(new Transition('review', $this->toPlace(Node::DRAFT), $this->toPlace(Node::PENDING))) - ->addTransition(new Transition('review', $this->toPlace(Node::PUBLISHED), $this->toPlace(Node::PENDING))) - ->addTransition(new Transition('reject', $this->toPlace(Node::PENDING), $this->toPlace(Node::DRAFT))) - ->addTransition(new Transition('reject', $this->toPlace(Node::PUBLISHED), $this->toPlace(Node::DRAFT))) - ->addTransition(new Transition('publish', $this->toPlace(Node::DRAFT), $this->toPlace(Node::PUBLISHED))) - ->addTransition(new Transition('publish', $this->toPlace(Node::PENDING), $this->toPlace(Node::PUBLISHED))) - ->addTransition(new Transition('publish', $this->toPlace(Node::PUBLISHED), $this->toPlace(Node::PUBLISHED))) - ->addTransition(new Transition('archive', $this->toPlace(Node::PUBLISHED), $this->toPlace(Node::ARCHIVED))) - ->addTransition(new Transition('unarchive', $this->toPlace(Node::ARCHIVED), $this->toPlace(Node::DRAFT))) - ->addTransition(new Transition('delete', $this->toPlace(Node::DRAFT), $this->toPlace(Node::DELETED))) - ->addTransition(new Transition('delete', $this->toPlace(Node::PENDING), $this->toPlace(Node::DELETED))) - ->addTransition(new Transition('delete', $this->toPlace(Node::PUBLISHED), $this->toPlace(Node::DELETED))) - ->addTransition(new Transition('delete', $this->toPlace(Node::ARCHIVED), $this->toPlace(Node::DELETED))) - ->addTransition(new Transition('undelete', $this->toPlace(Node::DELETED), $this->toPlace(Node::DRAFT))) + ->addTransition(new Transition('review', NodeStatus::DRAFT->name, NodeStatus::PENDING->name)) + ->addTransition(new Transition('review', NodeStatus::PUBLISHED->name, NodeStatus::PENDING->name)) + ->addTransition(new Transition('reject', NodeStatus::PENDING->name, NodeStatus::DRAFT->name)) + ->addTransition(new Transition('reject', NodeStatus::PUBLISHED->name, NodeStatus::DRAFT->name)) + ->addTransition(new Transition('publish', NodeStatus::DRAFT->name, NodeStatus::PUBLISHED->name)) + ->addTransition(new Transition('publish', NodeStatus::PENDING->name, NodeStatus::PUBLISHED->name)) + ->addTransition(new Transition('publish', NodeStatus::PUBLISHED->name, NodeStatus::PUBLISHED->name)) + ->addTransition(new Transition('archive', NodeStatus::PUBLISHED->name, NodeStatus::ARCHIVED->name)) + ->addTransition(new Transition('unarchive', NodeStatus::ARCHIVED->name, NodeStatus::DRAFT->name)) + ->addTransition(new Transition('delete', NodeStatus::DRAFT->name, NodeStatus::DELETED->name)) + ->addTransition(new Transition('delete', NodeStatus::PENDING->name, NodeStatus::DELETED->name)) + ->addTransition(new Transition('delete', NodeStatus::PUBLISHED->name, NodeStatus::DELETED->name)) + ->addTransition(new Transition('delete', NodeStatus::ARCHIVED->name, NodeStatus::DELETED->name)) + ->addTransition(new Transition('undelete', NodeStatus::DELETED->name, NodeStatus::DRAFT->name)) ->build() ; - $markingStore = new MethodMarkingStore(true, 'status'); + $markingStore = new MethodMarkingStore(true, 'statusAsString'); parent::__construct($definition, $markingStore, $dispatcher, 'node'); } - - protected function toPlace(int $legacyPlace): string - { - return (string) $legacyPlace; - } } diff --git a/src/Xlsx/AbstractXlsxSerializer.php b/src/Xlsx/AbstractXlsxSerializer.php index 664457b4..0d10950f 100644 --- a/src/Xlsx/AbstractXlsxSerializer.php +++ b/src/Xlsx/AbstractXlsxSerializer.php @@ -19,13 +19,10 @@ public function __construct(protected readonly TranslatorInterface $translator) /** * Serializes data. * - * @param mixed $obj - * - * @return string * @throws \PhpOffice\PhpSpreadsheet\Exception * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception */ - public function serialize($obj): string + public function serialize(mixed $obj): string { $data = $this->toArray($obj); $exporter = new XlsxExporter($this->translator); @@ -33,9 +30,6 @@ public function serialize($obj): string return $exporter->exportXlsx($data); } - /** - * @return TranslatorInterface - */ public function getTranslator(): TranslatorInterface { return $this->translator; diff --git a/src/Xlsx/NodeSourceXlsxSerializer.php b/src/Xlsx/NodeSourceXlsxSerializer.php index 40747f99..a21ba602 100644 --- a/src/Xlsx/NodeSourceXlsxSerializer.php +++ b/src/Xlsx/NodeSourceXlsxSerializer.php @@ -25,7 +25,7 @@ final class NodeSourceXlsxSerializer extends AbstractXlsxSerializer public function __construct( TranslatorInterface $translator, private readonly ObjectManager $objectManager, - private readonly UrlGeneratorInterface $urlGenerator + private readonly UrlGeneratorInterface $urlGenerator, ) { parent::__construct($translator); } @@ -34,18 +34,17 @@ public function __construct( * Create a simple associative array with a NodeSource. * * @param NodesSources|iterable|null $nodeSource - * @return array */ - public function toArray($nodeSource): array + public function toArray(mixed $nodeSource): array { $data = []; if ($nodeSource instanceof NodesSources) { - if ($this->addUrls === true) { + if (true === $this->addUrls) { $data['_url'] = $this->urlGenerator->generate( RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, [ - RouteObjectInterface::ROUTE_OBJECT => $nodeSource + RouteObjectInterface::ROUTE_OBJECT => $nodeSource, ], UrlGeneratorInterface::ABSOLUTE_URL ); @@ -71,7 +70,6 @@ public function toArray($nodeSource): array } /** - * @param NodesSources $nodeSource * @return array */ protected function getSourceFields(NodesSources $nodeSource): array @@ -91,7 +89,6 @@ protected function getSourceFields(NodesSources $nodeSource): array } /** - * @param NodeTypeInterface $nodeType * @return NodeTypeField[] */ protected function getFields(NodeTypeInterface $nodeType): array @@ -131,32 +128,25 @@ protected function getFields(NodeTypeInterface $nodeType): array ->findBy($criteria, ['position' => 'ASC']); } - /** - * {@inheritDoc} - */ - public function deserialize($string) + public function deserialize(string $string): null { return null; } /** * Serialize only texts. - * - * @param bool $onlyTexts - * @return NodeSourceXlsxSerializer */ public function setOnlyTexts(bool $onlyTexts = true): self { $this->onlyTexts = $onlyTexts; + return $this; } - /** - * @return NodeSourceXlsxSerializer - */ public function addUrls(): self { $this->addUrls = true; + return $this; } } diff --git a/src/Xlsx/SerializerInterface.php b/src/Xlsx/SerializerInterface.php index 7cfde0e3..026cbef3 100644 --- a/src/Xlsx/SerializerInterface.php +++ b/src/Xlsx/SerializerInterface.php @@ -12,29 +12,18 @@ interface SerializerInterface { /** * Serializes data. - * - * @param mixed $obj - * - * @return mixed */ - public function serialize($obj); - + public function serialize(mixed $obj): string; /** * Create a simple associative array with an entity. - * - * @param mixed $obj - * - * @return array */ - public function toArray($obj); + public function toArray(mixed $obj): array; /** - * Deserializes a json file into a readable array of datas. + * Deserializes a json file into a readable array of data. * * @param string $string Input to deserialize - * - * @return mixed */ - public function deserialize($string); + public function deserialize(string $string): mixed; } diff --git a/src/Xlsx/XlsxExporter.php b/src/Xlsx/XlsxExporter.php index e82e931f..7cbdf331 100644 --- a/src/Xlsx/XlsxExporter.php +++ b/src/Xlsx/XlsxExporter.php @@ -12,11 +12,11 @@ use Symfony\Contracts\Translation\TranslatorInterface; /** - * @deprecated XLSX serialization is deprecated and will be removed in next major version. + * @deprecated XLSX serialization is deprecated and will be removed in next major version */ -class XlsxExporter +readonly class XlsxExporter { - public function __construct(protected readonly TranslatorInterface $translator) + public function __construct(protected TranslatorInterface $translator) { } @@ -27,6 +27,7 @@ public function __construct(protected readonly TranslatorInterface $translator) * @param array $keys * * @return string + * * @throws \PhpOffice\PhpSpreadsheet\Exception * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception */ @@ -35,9 +36,9 @@ public function exportXlsx($data, $keys = []) $spreadsheet = new Spreadsheet(); // Set document properties - $spreadsheet->getProperties()->setCreator("Roadiz CMS") - ->setLastModifiedBy("Roadiz CMS") - ->setCategory(""); + $spreadsheet->getProperties()->setCreator('Roadiz CMS') + ->setLastModifiedBy('Roadiz CMS') + ->setCategory(''); $spreadsheet->setActiveSheetIndex(0); $activeSheet = $spreadsheet->getActiveSheet(); @@ -60,10 +61,10 @@ public function exportXlsx($data, $keys = []) if (count($keys) > 0) { foreach ($keys as $key => $value) { $columnAlpha = Coordinate::stringFromColumnIndex($key + 1); - $activeSheet->getStyle($columnAlpha . ($activeRow))->applyFromArray($headerStyles); + $activeSheet->getStyle($columnAlpha.$activeRow)->applyFromArray($headerStyles); $activeSheet->setCellValueByColumnAndRow($key + 1, $activeRow, $this->translator->trans($value)); } - $activeRow++; + ++$activeRow; $hasGlobalHeader = true; } @@ -75,19 +76,19 @@ public function exportXlsx($data, $keys = []) * we print them */ if ( - false === $hasGlobalHeader && - $headerkeys != array_keys($answer) + false === $hasGlobalHeader + && $headerkeys != array_keys($answer) ) { $headerkeys = array_keys($answer); foreach ($headerkeys as $key => $value) { $columnAlpha = Coordinate::stringFromColumnIndex($key + 1); - $activeSheet->getStyle($columnAlpha . $activeRow)->applyFromArray($headerStyles); + $activeSheet->getStyle($columnAlpha.$activeRow)->applyFromArray($headerStyles); if (\is_string($value)) { $value = $this->translator->trans($value); } $activeSheet->setCellValueByColumnAndRow($key + 1, $activeRow, $value); } - $activeRow++; + ++$activeRow; } /* @@ -98,26 +99,26 @@ public function exportXlsx($data, $keys = []) $columnAlpha = Coordinate::stringFromColumnIndex($k + 1); if ( - $value instanceof Collection || - is_array($value) + $value instanceof Collection + || is_array($value) ) { continue; } if ($value instanceof \DateTimeInterface) { $value = Date::PHPToExcel($value); - $activeSheet->getStyle($columnAlpha . ($activeRow)) + $activeSheet->getStyle($columnAlpha.$activeRow) ->getNumberFormat() ->setFormatCode('dd.mm.yyyy hh:MM:ss'); } /* * Set value into cell */ - $activeSheet->getStyle($columnAlpha . $activeRow)->getAlignment()->setWrapText(true); + $activeSheet->getStyle($columnAlpha.$activeRow)->getAlignment()->setWrapText(true); $activeSheet->setCellValueByColumnAndRow($k + 1, $activeRow, $this->translator->trans((string) $value)); } - $activeRow++; + ++$activeRow; } /* @@ -129,7 +130,6 @@ public function exportXlsx($data, $keys = []) ->setWidth(50); } - // Set active sheet index to the first sheet, so Excel opens this as the first sheet $writer = new Xlsx($spreadsheet); ob_start(); @@ -139,6 +139,7 @@ public function exportXlsx($data, $keys = []) if (!\is_string($output)) { throw new \RuntimeException('Output is not a string.'); } + return $output; } } diff --git a/templates/DataCollector/request.html.twig b/templates/DataCollector/request.html.twig index 6207f0e8..cafcfbbc 100644 --- a/templates/DataCollector/request.html.twig +++ b/templates/DataCollector/request.html.twig @@ -8,9 +8,7 @@ {% set text %}
Roadiz CMS - {% if collector.version %} {{ collector.version }} - {% endif %}
{% endset %} diff --git a/templates/customForm/base_custom_form.html.twig b/templates/customForm/base_custom_form.html.twig index e1b14ada..585fb91b 100644 --- a/templates/customForm/base_custom_form.html.twig +++ b/templates/customForm/base_custom_form.html.twig @@ -4,16 +4,16 @@ - {% block title %}{{ head.siteTitle }}{% endblock %} + {% block title %}{{ meta.siteName }}{% endblock %} {% include '@RoadizRozier/admin/meta-icon.html.twig' %} {# CSS scripts inclusions / Using webpack #} {% include '@RoadizRozier/partials/css-inject.html.twig' %} - {% if head.mainColor %} + {% if main_color %}