diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 08e37fdeb4..d7940c9922 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -89,9 +89,10 @@ jobs: TOKEN: ${{ secrets.EZROBOT_PAT }} run: | curl -H "Authorization: token $TOKEN" -L https://github.com/ibexa/vale-styles/archive/refs/heads/main.zip -o vale.zip - unzip vale.zip + unzip vale.zip -d vale rm vale.zip - mv vale-styles-main/* vale-styles-main/.vale.ini . + rm -rf vale/vale-styles-main/tests + mv vale/vale-styles-main/* vale/vale-styles-main/.vale.ini . - name: Run Vale.sh uses: vale-cli/vale-action@v2 diff --git a/.github/workflows/code_samples.yaml b/.github/workflows/code_samples.yaml index 962c8fddec..e1bf702ad3 100644 --- a/.github/workflows/code_samples.yaml +++ b/.github/workflows/code_samples.yaml @@ -60,14 +60,20 @@ jobs: continue-on-error: true run: composer check-rector + - name: Run YAML snippet tests + id: check-yaml + continue-on-error: true + run: composer check-yaml + - name: Fail job if any check failed if: always() run: | - if [[ "${{ steps.phpstan.outcome }}" == "failure" || "${{ steps.deptrac.outcome }}" == "failure" || "${{ steps.rector.outcome }}" == "failure" ]]; then - echo "One or more checks failed: PHPStan=${{ steps.phpstan.outcome }}, Deptrac=${{ steps.deptrac.outcome }}, Rector=${{ steps.rector.outcome }}" + if [[ "${{ steps.phpstan.outcome }}" == "failure" || "${{ steps.deptrac.outcome }}" == "failure" || "${{ steps.rector.outcome }}" == "failure" || "${{ steps.check-yaml.outcome }}" == "failure" ]]; then + echo "One or more checks failed: PHPStan=${{ steps.phpstan.outcome }}, Deptrac=${{ steps.deptrac.outcome }}, Rector=${{ steps.rector.outcome }}, YAML=${{ steps.check-yaml.outcome }}" exit 1 fi + code-samples-inclusion-check: name: Check code samples inclusion runs-on: ubuntu-latest @@ -94,7 +100,7 @@ jobs: - name: Log target branch code_samples usage if: steps.list.outputs.CODE_SAMPLES_CHANGE != '' run: | - git fetch origin + git fetch origin --depth=1 ${{ github.head_ref }} git checkout origin/${{ github.head_ref }} -- tools/code_samples/code_samples_usage.php php tools/code_samples/code_samples_usage.php ${{ steps.list.outputs.CODE_SAMPLES_CHANGE }} > $HOME/code_samples_usage_target.txt diff --git a/.gitignore b/.gitignore index d243a010bd..56f76dfb72 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ auth.json yarn.lock docs/css/*.map .deptrac.cache +.phpunit.result.cache +code_samples/_inline_php/ diff --git a/.php-cs-fixer-factory.php b/.php-cs-fixer-factory.php new file mode 100644 index 0000000000..37d0c0807a --- /dev/null +++ b/.php-cs-fixer-factory.php @@ -0,0 +1,15 @@ + false, +]; + +return [new InternalConfigFactory(), $commonRules]; diff --git a/.php-cs-fixer-inline.php b/.php-cs-fixer-inline.php new file mode 100644 index 0000000000..b30b9978a5 --- /dev/null +++ b/.php-cs-fixer-inline.php @@ -0,0 +1,29 @@ +withRules(array_merge($commonRules, [ + 'psr_autoloading' => false, + 'AdamWojs/phpdoc_force_fqcn_fixer' => false, +])); + +return $configFactory + ->buildConfig() + ->setFinder( + PhpCsFixer\Finder::create() + ->in(__DIR__ . '/code_samples/_inline_php') + ->files()->name('*.php') + ); diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index 38b8df8e41..9796c76101 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -6,12 +6,9 @@ */ declare(strict_types=1); -use Ibexa\CodeStyle\PhpCsFixer\InternalConfigFactory; +[$configFactory, $commonRules] = require __DIR__ . '/.php-cs-fixer-factory.php'; -$configFactory = new InternalConfigFactory(); -$configFactory->withRules([ - 'header_comment' => false, -]); +$configFactory->withRules($commonRules); return $configFactory ->buildConfig() @@ -23,5 +20,6 @@ __DIR__ . '/tests', ], 'is_dir') ) + ->exclude('_inline_php') // handled separately by .php-cs-fixer-inline.php ->files()->name('*.php') ); diff --git a/README.md b/README.md index 81daf33367..7d5e69c80b 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,18 @@ of the command. ## Testing the code samples +### YAML configuration + +To test the YAML configuration, run the following commands: + +``` bash +composer update +composer check-yaml +``` + +To add an error into a baseline, run `composer yaml-update-baseline` and commit the result. +Error added to the baseline are not reported again. + ### markdownlint This repository uses [markdownlint-cli2](https://github.com/DavidAnson/markdownlint-cli2) to check Markdown formatting, including table syntax. diff --git a/code_samples/api/public_php_api/src/Command/SegmentCommand.php b/code_samples/api/public_php_api/src/Command/SegmentCommand.php index 3b3fdd5f0f..64c2c4d95c 100644 --- a/code_samples/api/public_php_api/src/Command/SegmentCommand.php +++ b/code_samples/api/public_php_api/src/Command/SegmentCommand.php @@ -64,6 +64,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int : 'The user is not assigned to the segment.' )); + $this->segmentationService->removeSegmentGroup($segmentGroup); + return self::SUCCESS; } } diff --git a/code_samples/back_office/components/twig_components.yaml b/code_samples/back_office/components/twig_components.yaml index 6e0458f4d0..20d8c3caa2 100644 --- a/code_samples/back_office/components/twig_components.yaml +++ b/code_samples/back_office/components/twig_components.yaml @@ -12,7 +12,6 @@ ibexa_twig_components: priority: 0 arguments: content: 'Hello world!' - admin-ui-user-menu: duplicated_user_menu: type: menu arguments: diff --git a/code_samples/back_office/online_editor/config/packages/custom_plugin.yaml b/code_samples/back_office/online_editor/config/packages/custom_plugin.yaml deleted file mode 100644 index 426b9b75b9..0000000000 --- a/code_samples/back_office/online_editor/config/packages/custom_plugin.yaml +++ /dev/null @@ -1,13 +0,0 @@ -ibexa: - system: - admin_group: - fieldtypes: - ibexa_richtext: - toolbars: - paragraph: - buttons: - date: - priority: 0 -ibexa_fieldtype_richtext: - alloy_editor: - extra_plugins: [date] diff --git a/code_samples/front/shop/order-management/config/packages/ibexa.yaml b/code_samples/front/shop/order-management/config/packages/ibexa.yaml index e17cfbc9e5..310eaca7c3 100644 --- a/code_samples/front/shop/order-management/config/packages/ibexa.yaml +++ b/code_samples/front/shop/order-management/config/packages/ibexa.yaml @@ -65,7 +65,7 @@ framework: to: - dropped -// ... +# ... ibexa: repositories: diff --git a/code_samples/front/shop/payment/src/bundle/Resources/config/services/payment_method.yaml b/code_samples/front/shop/payment/src/bundle/Resources/config/services/payment_method.yaml index b179640c05..ef3b33c817 100644 --- a/code_samples/front/shop/payment/src/bundle/Resources/config/services/payment_method.yaml +++ b/code_samples/front/shop/payment/src/bundle/Resources/config/services/payment_method.yaml @@ -8,7 +8,7 @@ services: $domain: tags: - { name: ibexa.payment.payment_method.type, alias: new_payment_method_type } -services: + App\Payment\PaymentMethod\Voter\NewPaymentMethodTypeVoter: tags: - - { name: ibexa.payment.payment_method.voter, type: new_payment_method_type } \ No newline at end of file + - { name: ibexa.payment.payment_method.voter, type: new_payment_method_type } diff --git a/code_samples/mcp/config/packages/mcp.yaml b/code_samples/mcp/config/packages/mcp.yaml index f71a60e119..a741fd1888 100644 --- a/code_samples/mcp/config/packages/mcp.yaml +++ b/code_samples/mcp/config/packages/mcp.yaml @@ -10,7 +10,7 @@ ibexa: discovery_cache: cache.tagaware.filesystem session: type: psr16 - directory: cache.tagaware.filesystem + service: cache.tagaware.filesystem system: default: mcp: diff --git a/code_samples/recommendations/config/packages/ibexa_connector_raptor.yaml b/code_samples/recommendations/config/packages/ibexa_connector_raptor.yaml index 18ad640c12..192e4073a4 100644 --- a/code_samples/recommendations/config/packages/ibexa_connector_raptor.yaml +++ b/code_samples/recommendations/config/packages/ibexa_connector_raptor.yaml @@ -3,14 +3,14 @@ ibexa: : connector_raptor: enabled: true - customer_id: ~ # Required + customer_id: "12345" # Required tracking_type: client # One of: "client" or "server" # Raptor Recommendations API key - recommendations_api_key: ~ # Required + recommendations_api_key: "your_api_key_here" # Required - # Raptor Recommendations API URL, optional, set by default - recommendations_api_url: '%ibexa.connector.raptor.recommendations.api_url%' + # Raptor Recommendations API URI, optional, set by default + recommendations_api_uri: '%ibexa.connector.raptor.recommendations.api_uri%' # Cookie lifetime in days for server-side tracking identifier # Default: 365 days. Minimum: 1 day. diff --git a/composer.json b/composer.json index d229c7579a..b45d0d85b3 100644 --- a/composer.json +++ b/composer.json @@ -4,6 +4,9 @@ "type": "library", "license": "GNU General Public License v2.0", "autoload-dev": { + "psr-4": { + "Ibexa\\Tests\\Documentation\\": "tests/" + } }, "repositories": [ { @@ -15,6 +18,9 @@ "php": "^8.3" }, "require-dev": { + "phpunit/phpunit": "^11.0", + "symfony/yaml": "^7.0", + "ibexa/connector-gemini": "5.0.x-dev", "ibexa/automated-translation": "5.0.x-dev", "ibexa/code-style": "~2.0.0", "friendsofphp/php-cs-fixer": "^3.30", @@ -52,7 +58,7 @@ "ibexa/page-builder": "5.0.x-dev", "ibexa/order-management": "5.0.x-dev", "ibexa/calendar": "5.0.x-dev", - "ibexa/payment": "5.0.x-dev", + "ibexa/payment": "~5.0.x-dev", "ibexa/shipping": "5.0.x-dev", "ibexa/fieldtype-matrix": "5.0.x-dev", "ibexa/storefront": "5.0.x-dev", @@ -86,21 +92,48 @@ "ibexa/cdp": "~5.0.x-dev", "ibexa/connector-raptor": "~5.0.x-dev", "ibexa/image-editor": "~5.0.x-dev", - "ibexa/integrated-help": "~5.0.x-dev" + "ibexa/integrated-help": "~5.0.x-dev", + "ibexa/site-context": "~5.0.x-dev", + "ibexa/fieldtype-richtext-rte": "~5.0.x-dev", + "ibexa/site-factory": "~5.0.x-dev", + "ibexa/ckeditor-premium": "~5.0.x-dev", + "ibexa/measurement": "~5.0.x-dev", + "ibexa/connector-actito": "~5.0.x-dev", + "ibexa/fastly": "~5.0.x-dev" }, "scripts": { - "fix-cs": "php-cs-fixer fix --config=.php-cs-fixer.php -v --show-progress=dots", - "check-cs": "@fix-cs --dry-run", - "phpstan": "phpstan analyse", - "deptrac": "deptrac analyse", - "check-rector": "rector process --dry-run --ansi" + "fix-cs": [ + "php tools/extract-inline-php.php", + "php-cs-fixer fix --config=.php-cs-fixer.php -v --show-progress=dots", + "php-cs-fixer fix --config=.php-cs-fixer-inline.php -v --show-progress=dots", + "php tools/sync-inline-php-to-markdown.php" + ], + "check-cs": [ + "php tools/extract-inline-php.php", + "php-cs-fixer fix --config=.php-cs-fixer.php -v --show-progress=dots --dry-run", + "php-cs-fixer fix --config=.php-cs-fixer-inline.php -v --show-progress=dots --dry-run" + ], + "phpstan": "php tools/extract-inline-php.php && phpstan analyse", + "deptrac": "php tools/extract-inline-php.php && deptrac analyse", + "fix-rector": [ + "php tools/extract-inline-php.php", + "rector process --ansi", + "php tools/sync-inline-php-to-markdown.php" + ], + "check-rector": "php tools/extract-inline-php.php && rector process --dry-run --ansi", + "check-yaml": "phpunit --group yaml", + "phpunit": "phpunit --exclude-group=yaml", + "yaml-update-baseline": "php tests/generate-yaml-baseline.php" }, "scripts-descriptions": { "fix-cs": "Automatically fixes code style in all files", "check-cs": "Run code style checker for all files", "phpstan": "Run static code analysis", "deptrac": "Run Deptrac architecture testing", - "check-rector": "Check for code refactoring opportunities" + "fix-rector": "Automatically applies Rector refactoring to code samples and syncs back to Markdown", + "check-rector": "Check for code refactoring opportunities", + "check-yaml": "Run PHPUnit tests (YAML validation)", + "yaml-update-baseline": "Regenerate tests/yaml-validation-baseline.yaml from current failures" }, "config": { "allow-plugins": false diff --git a/deptrac.baseline.yaml b/deptrac.baseline.yaml index 9fef31d4bc..48ae699adc 100644 --- a/deptrac.baseline.yaml +++ b/deptrac.baseline.yaml @@ -1,5 +1,7 @@ deptrac: skip_violations: + AcmeFeatureBundle: + - Ibexa\Bundle\Core\DependencyInjection\IbexaCoreExtension App\AutomatedTranslation\ImageFieldEncoder: - Ibexa\Core\FieldType\Image\Value App\Block\Listener\MyBlockListener: @@ -92,6 +94,9 @@ deptrac: - Ibexa\Core\MVC\Symfony\View\View App\Controller\RelationController: - Ibexa\Core\MVC\Symfony\View\View + App\Controller\RideController: + - Ibexa\Bundle\Core\Controller + - Ibexa\Core\MVC\Symfony\View\ContentView App\Controller\SvgController: - Ibexa\Core\Helper\TranslationHelper - Ibexa\Core\IO\IOServiceInterface @@ -130,6 +135,10 @@ deptrac: - Ibexa\FormBuilder\Event\FormEvents App\EventSubscriber\HelpMenuSubscriber: - Ibexa\AdminUi\Menu\Event\ConfigureMenuEvent + App\EventSubscriber\LoginFormViewSubscriber: + - Ibexa\Core\MVC\Symfony\Event\PreContentViewEvent + - Ibexa\Core\MVC\Symfony\MVCEvents + - Ibexa\Core\MVC\Symfony\View\LoginFormView App\EventSubscriber\MyMenuSubscriber: - Ibexa\AdminUi\Menu\Event\ConfigureMenuEvent - Ibexa\AdminUi\Menu\MainMenuBuilder @@ -137,6 +146,8 @@ deptrac: - Ibexa\IntegratedHelp\ProductTour\Block\LinkBlock - Ibexa\IntegratedHelp\ProductTour\Block\TextBlock - Ibexa\IntegratedHelp\ProductTour\ProductTourStep + App\EventSubscriber\ResolveCampaginEventSubscriber: + - Ibexa\ConnectorActito\Campaign\Campaign App\Event\RandomBlockListener: - Ibexa\FieldTypePage\FieldType\Page\Block\Renderer\BlockRenderEvents - Ibexa\FieldTypePage\FieldType\Page\Block\Renderer\Event\PreRenderEvent @@ -194,6 +205,8 @@ deptrac: - Ibexa\Migration\ValueObject\Step\StepInterface App\Migrations\Step\ReplaceNameStepNormalizer: - Ibexa\Migration\ValueObject\Step\StepInterface + App\MyService: + - Ibexa\Core\MVC\Symfony\SiteAccess\SiteAccessServiceInterface App\Notification\ListRenderer: - Ibexa\Core\Notification\Renderer\NotificationRenderer - Ibexa\Core\Notification\Renderer\TypedNotificationRendererInterface @@ -212,6 +225,8 @@ deptrac: App\QueryType\OptionsBasedLatestContentQueryType: - Ibexa\Core\QueryType\OptionsResolverBasedQueryType - Ibexa\Core\QueryType\QueryType + App\QueryType\RideQueryType: + - Ibexa\Core\QueryType\QueryType App\Search\Model\Suggestion\ProductSuggestion: - Ibexa\ProductCatalog\Local\Repository\Values\Product App\Security\FormPolicyProvider: @@ -236,6 +251,8 @@ deptrac: - Ibexa\AdminUi\Limitation\LimitationValueMapperInterface App\Security\MyPolicyProvider: - Ibexa\Bundle\Core\DependencyInjection\Security\PolicyProvider\YamlPolicyProvider + App\Service\MyService: + - Ibexa\User\UserSetting\DateTimeFormat\FormatterInterface App\Setting\Group\MyGroup: - Ibexa\User\UserSetting\Group\AbstractGroup App\Setting\Unit: @@ -254,3 +271,9 @@ deptrac: - Ibexa\Core\MVC\Symfony\View\View AttributeTypeExtension: - Ibexa\PageBuilder\Form\Type\Attribute\AttributeType + CustomRepositoryConfigParser: + - Ibexa\Bundle\Core\DependencyInjection\Configuration\RepositoryConfigParserInterface + JohnDoeCanSelectMore: + - Ibexa\AdminUi\UniversalDiscovery\Event\ConfigResolveEvent + MyMapper: + - Ibexa\ContentForms\Form\Type\FieldType\CheckboxFieldType diff --git a/docs/administration/back_office/back_office_elements/extending_thumbnails.md b/docs/administration/back_office/back_office_elements/extending_thumbnails.md index 707e76abe7..2b6c2cdd47 100644 --- a/docs/administration/back_office/back_office_elements/extending_thumbnails.md +++ b/docs/administration/back_office/back_office_elements/extending_thumbnails.md @@ -41,7 +41,7 @@ This mechanism can be modified to fit your site needs, so you can decide from wh First, create base strategy for returning custom thumbnails from a static file. Create `StaticStrategy.php` in `src/Strategy`. -```php +``` php [[= include_code('code_samples/back_office/thumbnails/src/Strategy/StaticThumbnailStrategy.php') =]] ``` @@ -74,16 +74,16 @@ It enables you to add a thumbnail URL in the text field. Add `FieldValueUrl.php` in `src/Thumbnails`. -```php +``` php shortDateTimeFormatter = $shortDateTimeFormatter; - - // your code } - public function foo() + public function foo(): void { // your code diff --git a/docs/administration/back_office/back_office_menus/back_office_menus.md b/docs/administration/back_office/back_office_menus/back_office_menus.md index 00db6828e7..bb99032430 100644 --- a/docs/administration/back_office/back_office_menus/back_office_menus.md +++ b/docs/administration/back_office/back_office_menus/back_office_menus.md @@ -86,6 +86,7 @@ The following method adds a new menu section under **Content**, and under it, a You can also pass parameters to templates used to render menu items with `template_parameters`: ``` php +/** @var \Knp\Menu\ItemInterface $menu */ $menu->addChild( 'all_content_list', [ @@ -106,6 +107,7 @@ You can then use the variable `custom_parameter` in `templates/themes/admin/list To have translatable labels, use `translation.key` from the `messages` domain: ``` php +/** @var \Knp\Menu\ItemInterface $menu */ $menu->addChild( 'all_content_list', [ diff --git a/docs/administration/back_office/back_office_tabs/back_office_tabs.md b/docs/administration/back_office/back_office_tabs/back_office_tabs.md index d43d8da007..3e633c35a0 100644 --- a/docs/administration/back_office/back_office_tabs/back_office_tabs.md +++ b/docs/administration/back_office/back_office_tabs/back_office_tabs.md @@ -18,7 +18,7 @@ A custom tab can extend one of the following classes: - [`AbstractControllerBasedTab`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-AdminUi-Tab-AbstractControllerBasedTab.html) - embeds the results of a controller action in the tab - [`AbstractRouteBasedTab`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-AdminUi-Tab-AbstractRouteBasedTab.html) - embeds the results of the selected route, passing applicable parameters -``` php +``` php {skip-validation} //... [[= include_file('code_samples/back_office/dashboard/article_tab/src/Tab/Dashboard/Everyone/EveryoneArticleTab.php', 16, 18) =]] //... diff --git a/docs/administration/back_office/browser/browser.md b/docs/administration/back_office/browser/browser.md index 1addc5b3d8..a62807716f 100644 --- a/docs/administration/back_office/browser/browser.md +++ b/docs/administration/back_office/browser/browser.md @@ -146,40 +146,42 @@ If an event listener catches additional parameters passed with context, it uses In the example below, the `johndoe` parameter enables the user to choose multiple items from a **Browser window** by changing `multiple: false` from `my_custom_udw` configuration to `multiple: true`. -```php hl_lines="29 30 31" +``` php hl_lines="31-35" + The event names to listen to */ - public static function getSubscribedEvents() + public static function getSubscribedEvents(): array { return [ ConfigResolveEvent::NAME => 'onUdwConfigResolve', ]; } - /** - * @param \Ibexa\AdminUi\UniversalDiscovery\Event $event - */ - public function onUdwConfigResolve(ConfigResolveEvent $event) + public function onUdwConfigResolve(ConfigResolveEvent $event): void { if ($event->getConfigName() !== self::CONFIGURATION_NAME) { - return; - } + return; + } $config = $event->getConfig(); - $context = $event->getContext(); + $context = $event->getContext(); if (isset($context['some_contextual_parameter'])) { - if ($context['some_contextual_parameter'] === 'johndoe') { - $config['multiple'] = true; - } - } + if ($context['some_contextual_parameter'] === 'johndoe') { + $config['multiple'] = true; + } + } $event->setConfig($config); } diff --git a/docs/administration/back_office/customize_calendar.md b/docs/administration/back_office/customize_calendar.md index fee37e77f1..b73e371334 100644 --- a/docs/administration/back_office/customize_calendar.md +++ b/docs/administration/back_office/customize_calendar.md @@ -47,7 +47,7 @@ Here, you define a new class for your event based on `Ibexa\Contracts\Calendar\E Next, create `src/Calendar/Holidays/EventType.php`: -```php hl_lines="20-23" +``` php hl_lines="20-23" [[= include_code('code_samples/back_office/calendar/src/Calendar/Holidays/EventType.php') =]] ``` @@ -68,7 +68,7 @@ An event source must implement `Ibexa\Contracts\Calendar\EventSource\EventSource One such built-in implementation is `InMemoryEventSource`. To add an in-memory collection as an event source, create `src/Calendar/Holidays/EventSourceFactory.php`: -```php +``` php [[= include_file('code_samples/back_office/calendar/src/Calendar/Holidays/EventSourceFactory.php', 0, 20) =]] [[= include_file('code_samples/back_office/calendar/src/Calendar/Holidays/EventSourceFactory.php', 26, 36) =]] @@ -81,10 +81,15 @@ To add an in-memory collection as an event source, create `src/Calendar/Holidays For example: ``` php + use App\Calendar\Holidays\Event; + use Ibexa\Contracts\Calendar\EventCollection; + + /** @var \App\Calendar\Holidays\EventType $eventType */ $collection = new EventCollection([ - $this->createEvent("Event 1", new DateTime("2024-01-01")), - $this->createEvent("Event 2", new DateTime("2024-01-02")), + new Event('Event 1', new DateTime('2024-01-01'), $eventType), + new Event('Event 2', new DateTime('2024-01-02'), $eventType), // ... + ]); ``` Next, register the event source as a service: diff --git a/docs/administration/back_office/customize_product_tour.md b/docs/administration/back_office/customize_product_tour.md index 288941b683..fd835ed614 100644 --- a/docs/administration/back_office/customize_product_tour.md +++ b/docs/administration/back_office/customize_product_tour.md @@ -40,7 +40,7 @@ ibexa: Then, create a subscriber that modifies the scenario. -```php hl_lines="32-34 36-38 40-42 44-55" +``` php hl_lines="32-34 36-38 40-42 44-55" [[= include_code('code_samples/back_office/product_tour/src/EventSubscriber/NotificationScenarioSubscriber.php') =]] ``` diff --git a/docs/administration/back_office/customize_search_suggestion.md b/docs/administration/back_office/customize_search_suggestion.md index 00e19d9bac..dc185ac40b 100644 --- a/docs/administration/back_office/customize_search_suggestion.md +++ b/docs/administration/back_office/customize_search_suggestion.md @@ -17,8 +17,9 @@ ibexa: system: : search: - min_query_length: 3 - result_limit: 5 + suggestion: + min_query_length: 3 + result_limit: 5 ``` ## Add custom suggestion source diff --git a/docs/administration/back_office/notifications.md b/docs/administration/back_office/notifications.md index 5e8fe93706..f5d9c2b8bd 100644 --- a/docs/administration/back_office/notifications.md +++ b/docs/administration/back_office/notifications.md @@ -26,7 +26,8 @@ There are four types of notifications: `info`, `success`, `warning` and `error`. To send a notification from PHP, inject the `TranslatableNotificationHandlerInterface` into your class. ``` php -$this->notificationHandler->info( +/** @var \Ibexa\Contracts\AdminUi\Notification\TranslatableNotificationHandlerInterface $notificationHandler */ +$notificationHandler->info( /** @Desc("Notification text") */ 'example.notification.text', [], @@ -90,7 +91,7 @@ You can send notifications to users which are displayed in the user menu. To create a new notification you can use the [`NotificationService::createNotification(CreateStruct $createStruct)` method](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Core-Repository-NotificationService.html#method_createNotification) like in the example below: -```php +``` php [[= include_code('code_samples/back_office/notifications/src/EventListener/ContentPublishEventListener.php') =]] ``` @@ -102,7 +103,7 @@ To display a user notification, write a renderer and tag it as a service. The example below presents a renderer that uses Twig to render a view: -```php +``` php [[= include_code('code_samples/back_office/notifications/src/Notification/MyRenderer.php') =]] ``` @@ -126,7 +127,7 @@ To display a list of notifications, expand the above renderer. The example below presents a modified renderer that uses Twig to render a list view: -```php +``` php [[= include_code('code_samples/back_office/notifications/src/Notification/ListRenderer.php') =]] ``` diff --git a/docs/administration/configuration/configuration.md b/docs/administration/configuration/configuration.md index 9928537fe9..5ff421bebb 100644 --- a/docs/administration/configuration/configuration.md +++ b/docs/administration/configuration/configuration.md @@ -74,7 +74,8 @@ parameters: ``` php // Usage inside a controller -$myParameter = $this->container->getParameter( 'myapp.parameter.name' ); +/** @var \Symfony\Component\DependencyInjection\ContainerInterface $container */ +$myParameter = $container->getParameter('myapp.parameter.name'); ``` ## Configuration settings diff --git a/docs/administration/configuration/dynamic_configuration.md b/docs/administration/configuration/dynamic_configuration.md index 09f9cfbf42..60d8516a97 100644 --- a/docs/administration/configuration/dynamic_configuration.md +++ b/docs/administration/configuration/dynamic_configuration.md @@ -18,7 +18,7 @@ parameters: # Internal configuration ibexa.site_access.config.default.content.default_ttl: 60 ibexa.site_access.config.site_group.content.default_ttl: 3600 -  + # Here "myapp" is the namespace, followed by the SiteAccess name as the parameter scope # Parameter "my_param" will have a different value in site_group and admin_group myapp.site_group.my_param: value @@ -27,11 +27,11 @@ parameters: myapp.default.my_param: Default value ``` -Inside a controller, in `site_group` SiteAccess, you can use the parameters in the following way (the same applies for `hasParameter()`): +Inside a controller extending the `Ibexa\Core\MVC\Symfony\Controller\Controller` class, in `site_group` SiteAccess, you can use the parameters in the following way (the same applies for `hasParameter()`): -``` php +``` php {skip-validation} $configResolver = $this->getConfigResolver(); -  + // ibexa.site_access.config is the default namespace, so no need to specify it // The following will resolve ibexa.site_access.config..content.default_ttl // In the case of site_group, it will return 3600. @@ -81,20 +81,14 @@ For more information about dependency injection, see [Service container](php_api namespace App; use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface; -  + class Service { -  /** - * @var \Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface - */ - private $configResolver; -  - public function __construct( ConfigResolverInterface $configResolver ) + public function __construct(private readonly ConfigResolverInterface $configResolver) { - $this->configResolver = $configResolver; } - public function someMethodThatNeedConfig() + public function someMethodThatNeedConfig(): void { $configValue = $this->configResolver->getParameter('my_param', 'myapp'); } diff --git a/docs/administration/configuration/repository_configuration.md b/docs/administration/configuration/repository_configuration.md index 126b39e841..9396455bfd 100644 --- a/docs/administration/configuration/repository_configuration.md +++ b/docs/administration/configuration/repository_configuration.md @@ -327,6 +327,9 @@ final class CustomRepositoryConfigParser implements RepositoryConfigParserInterf You need to register this configuration extension in the following way: ``` php +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\HttpKernel\Bundle\Bundle; + final class AcmeFeatureBundle extends Bundle { public function build(ContainerBuilder $container): void @@ -343,5 +346,6 @@ final class AcmeFeatureBundle extends Bundle To access the configuration settings, use the `Ibexa\Bundle\Core\ApiLoader\RepositoryConfigurationProvider::getRepositoryConfig` method: ``` php +/** @var \Ibexa\Contracts\Core\Container\ApiLoader\RepositoryConfigurationProviderInterface $repositoryConfigProvider */ $acmeConfig = $repositoryConfigProvider->getRepositoryConfig()['acme']; ``` diff --git a/docs/administration/recent_activity/recent_activity.md b/docs/administration/recent_activity/recent_activity.md index 0599a3e4df..faabe5793e 100644 --- a/docs/administration/recent_activity/recent_activity.md +++ b/docs/administration/recent_activity/recent_activity.md @@ -112,7 +112,7 @@ See [Activity Log Search Criteria reference](activity_log_criteria.md) and [Acti In the following example, log groups that contain at least one creation of a Content item are displayed in terminal, with a maximum of 10 groups within the last hour. It uses the default `admin` user that has a [permission](#permission-and-security) to list everyone's entries. -```php hl_lines="34-38" +``` php hl_lines="34-38" [[= include_code('code_samples/recent_activity/src/Command/MonitorRecentContentCreationCommand.php') =]] ``` @@ -173,7 +173,7 @@ First, inject `Ibexa\Contracts\ActivityLog\ActivityLogServiceInterface` into you In the following example, an event subscriber is subscribing to an event dispatched by a custom feature. This event has the information needed by a log entry (see details after the example). -```php +``` php [[= include_code('code_samples/recent_activity/src/EventSubscriber/MyFeatureEventSubscriber.php') =]] ``` diff --git a/docs/ai/ai_actions/configure_ai_actions.md b/docs/ai/ai_actions/configure_ai_actions.md index d0edff8321..3b0627b347 100644 --- a/docs/ai/ai_actions/configure_ai_actions.md +++ b/docs/ai/ai_actions/configure_ai_actions.md @@ -46,7 +46,7 @@ composer require ibexa/connector-anthropic If not using Symfony Flex, enable the bundle in `config/bundles.php`: -``` php +``` php {skip-validation} Ibexa\Bundle\ConnectorAnthropic\IbexaConnectorAnthropicBundle::class => ['all' => true], ``` @@ -106,7 +106,10 @@ composer require ibexa/connector-gemini Then, if not using Symfony Flex, enable the bundle in `config/bundles.php`: ``` php +return [ + // ... Ibexa\Bundle\ConnectorGemini\IbexaConnectorGeminiBundle::class => ['all' => true], +]; ``` This adds the feature code, including basic handlers that let you refine text or generate alternative text for images. diff --git a/docs/api/graphql/graphql_custom_ft.md b/docs/api/graphql/graphql_custom_ft.md index 0e7f56e425..48e2cc601e 100644 --- a/docs/api/graphql/graphql_custom_ft.md +++ b/docs/api/graphql/graphql_custom_ft.md @@ -75,7 +75,7 @@ Only implement methods that you need, the rest is handled by other mappers (conf When a mapper method is decorated, you need to call the decorated service method for unsupported types. To do that, you need to replace `mapXXX` by the method it's in: -```php +``` php [[= include_code('code_samples/api/graphql/src/GraphQL/Schema/MyFieldDefinitionMapper.php', 21, 24, remove_indent=True) =]] ``` @@ -99,7 +99,7 @@ For example, `ibexa_matrix` generates its own input types depending on the confi Example of a `MyFieldDefinitionMapper` mapper for a complex field type: -```php +``` php [[= include_code('code_samples/api/graphql/src/GraphQL/Schema/MyFieldDefinitionMapper.php') =]] ``` diff --git a/docs/api/graphql/graphql_customization.md b/docs/api/graphql/graphql_customization.md index 5ebf97b4f0..be6421d049 100644 --- a/docs/api/graphql/graphql_customization.md +++ b/docs/api/graphql/graphql_customization.md @@ -68,9 +68,9 @@ Mutation: createSomething: builder: Mutation builderConfig: - inputType: CreateSomethingInput - payloadType: SomethingPayload - mutateAndGetPayload: '@=mutation('CreateSomething', [value])' + inputType: CreateSomethingInput + payloadType: SomethingPayload + mutateAndGetPayload: "@=mutation('CreateSomething', [value])" CreateSomethingInput: type: relay-mutation-input diff --git a/docs/api/notification_channels.md b/docs/api/notification_channels.md index 6b3859272c..247082fa8e 100644 --- a/docs/api/notification_channels.md +++ b/docs/api/notification_channels.md @@ -149,7 +149,7 @@ The [`…\Service\NotificationServiceInterface::send()`](/api/php_api/php_api_re For example, to send a notification, you often use a combination like the following: -```php hl_lines="11-14" +``` php hl_lines="11-14" [[= include_code('code_samples/api/notifications/notification_send.php', 2) =]] ``` diff --git a/docs/api/php_api/php_api.md b/docs/api/php_api/php_api.md index f1ef421c99..b6224b71f8 100644 --- a/docs/api/php_api/php_api.md +++ b/docs/api/php_api/php_api.md @@ -109,12 +109,13 @@ For example, to [hide a Location](managing_content.md#hiding-and-revealing-locat ``` php use Ibexa\Contracts\Core\Repository\Repository; +use Ibexa\Contracts\Core\Repository\Values\Content\Location; //... -$hiddenLocation = $repository->sudo(function (Repository $repository) use ($location) { - return $repository->getLocationService()->hideLocation($location); -}); +/** @var Repository $repository */ +/** @var Location $location */ +$hiddenLocation = $repository->sudo(static fn (Repository $repository): Location => $repository->getLocationService()->hideLocation($location)); ``` ### Setting the repository user @@ -149,9 +150,9 @@ Both cases should be covered with error messages: ``` php try { // ... -} catch (\Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException $e) { +} catch (\Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException) { $output->writeln("No content with id $contentId found"); -} catch (\Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException $e) { +} catch (\Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException) { $output->writeln("Permission denied on content with id $contentId"); } ``` diff --git a/docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md b/docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md index 8e820a65f0..e71f602206 100644 --- a/docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md +++ b/docs/api/rest_api/extending_rest_api/creating_new_rest_resource.md @@ -68,10 +68,14 @@ If the returned value was depending on a location, it could have been wrapped in `CachedValue` is used in the following way: -```php +``` php +use Ibexa\Rest\Server\Values\CachedValue; + +$locationId = 12345; + return new CachedValue( - new MyValue($args…), - ['locationId'=> $locationId] + new MyValue($args), + ['locationId' => $locationId] ); ``` diff --git a/docs/api/rest_api/rest_api_authentication.md b/docs/api/rest_api/rest_api_authentication.md index bfe112d350..78d6f9d336 100644 --- a/docs/api/rest_api/rest_api_authentication.md +++ b/docs/api/rest_api/rest_api_authentication.md @@ -337,10 +337,15 @@ For more information, see [HTTP Authentication: Basic and Digest Access Authenti If the installation has a dedicated host for REST, you can enable HTTP basic authentication only on this host by setting a firewall like in the following example before the `ibexa_front` one: ```yaml +security: + firewalls: + # ... ibexa_rest: host: ^api\.example\.com$ http_basic: realm: Ibexa DXP REST API + #ibexa_front: + # ... ``` !!! caution "Back office uses REST API" diff --git a/docs/cdp/cdp_installation.md b/docs/cdp/cdp_installation.md index 30a7162a06..45f98359ae 100644 --- a/docs/cdp/cdp_installation.md +++ b/docs/cdp/cdp_installation.md @@ -27,11 +27,14 @@ Symfony Flex installs and activates the package. After an installation process is finished, go to `config/packages/security.yaml` and uncomment `ibexa_cdp` rule. ```yaml -ibexa_cdp: - pattern: /cdp/webhook - guard: - authenticator: 'Ibexa\Cdp\Security\CdpRequestAuthenticator' - stateless: true +security: + firewalls: + # ... + ibexa_cdp: + request_matcher: Ibexa\Cdp\Security\RequestMatcher + custom_authenticators: + - 'Ibexa\Cdp\Security\CdpRequestAuthenticator' + stateless: true ``` Now, you can configure [[= product_name_cdp =]]. diff --git a/docs/commerce/cart/cart_api.md b/docs/commerce/cart/cart_api.md index 398ae2755e..2cb62ea298 100644 --- a/docs/commerce/cart/cart_api.md +++ b/docs/commerce/cart/cart_api.md @@ -69,6 +69,9 @@ use Ibexa\Contracts\Cart\Value\CartMetadataUpdateStruct; // ... +/** @var \Ibexa\Contracts\Core\Repository\UserService $userService */ +/** @var \Ibexa\Contracts\Cart\CartServiceInterface $cartService */ +/** @var \Ibexa\Contracts\Cart\Value\CartInterface $cart */ $updateMetadataStruct = new CartMetadataUpdateStruct(); $updateMetadataStruct->setOwner($userService->loadUserByLogin('user')); @@ -150,8 +153,14 @@ It can include any relevant information that you want to associate with a partic To add context data to a cart, follow this example: -```php -$createStruct = new CartCreateStruct(...); +``` php +use Ibexa\Contracts\Cart\Value\CartCreateStruct; +use Ibexa\Contracts\Core\Collection\ArrayMap; +use Ibexa\Contracts\ProductCatalog\Values\CurrencyInterface; + +/** @var \Ibexa\Contracts\Cart\CartServiceInterface $cartService */ +/** @var CurrencyInterface $currency */ +$createStruct = new CartCreateStruct('My Cart', $currency); $createStruct->setContext(new ArrayMap([ 'coupon_code' => 'X1MF7699', ])); @@ -166,8 +175,15 @@ You also add "X1MF7699" coupon code as context data to the cart. To attach context data to a cart entry, proceed as follows: -```php -$entryAddStruct = new EntryAddStruct(...); +``` php +use Ibexa\Contracts\Cart\Value\EntryAddStruct; +use Ibexa\Contracts\Core\Collection\ArrayMap; +use Ibexa\ProductCatalog\Local\Repository\Values\Product; + +/** @var \Ibexa\Contracts\Cart\CartServiceInterface $cartService */ +/** @var \Ibexa\Contracts\Cart\Value\CartInterface $cart */ +/** @var Product $product */ +$entryAddStruct = new EntryAddStruct($product); $entryAddStruct->setContext(new ArrayMap([ 'tshirt_text' => 'EqEqEqEq', ])); @@ -184,6 +200,6 @@ In this case, you attach a "tshirt_text" attribute to the cart entry, which migh To combine the contents of multiple shopping carts into a target cart, use the `CartServiceInterface::mergeCarts` method. This operation is helpful when you want to consolidate items from a reorder cart and a current cart into a single order. -```php +``` php [[= include_code('code_samples/api/commerce/src/Command/CartCommand.php', 127, 139, remove_indent=True) =]] ``` diff --git a/docs/commerce/checkout/reorder.md b/docs/commerce/checkout/reorder.md index 4d022782e4..96f83c6bed 100644 --- a/docs/commerce/checkout/reorder.md +++ b/docs/commerce/checkout/reorder.md @@ -54,11 +54,11 @@ framework: places: !php/const Ibexa\OrderManagement\Value\Status::COMPLETED_PLACE: metadata: - ... + # ... can_be_reordered: true !php/const Ibexa\OrderManagement\Value\Status::CANCELLED_PLACE: metadata: - ... + # ... can_be_reordered: true ``` diff --git a/docs/commerce/payment/enable_stripe_payments.md b/docs/commerce/payment/enable_stripe_payments.md index 105ed62402..5d03bd8829 100644 --- a/docs/commerce/payment/enable_stripe_payments.md +++ b/docs/commerce/payment/enable_stripe_payments.md @@ -43,5 +43,4 @@ ibexa: type: strp_checkout: name: "Translated Stripe Checkout name" - ``` diff --git a/docs/commerce/payment/payum_integration.md b/docs/commerce/payment/payum_integration.md index cc991acb71..b665e135c0 100644 --- a/docs/commerce/payment/payum_integration.md +++ b/docs/commerce/payment/payum_integration.md @@ -43,7 +43,7 @@ ibexa_connector_payum: refunded: cancelled captured: pending authorized: authorized -[...] +# ... ``` ## Payment service name translations diff --git a/docs/commerce/shopping_list/install_shopping_list.md b/docs/commerce/shopping_list/install_shopping_list.md index 929d4806fc..1c5d0829ca 100644 --- a/docs/commerce/shopping_list/install_shopping_list.md +++ b/docs/commerce/shopping_list/install_shopping_list.md @@ -18,8 +18,11 @@ The associated Symfony Flex recipe configures the bundle and its routes. Check that the following line has been added by the recipe to `config/bundles.php` file's array: -```php +``` php +return [ + // ... Ibexa\Bundle\ShoppingList\IbexaShoppingListBundle::class => ['all' => true], +]; ``` And that you have a `config/routes/ibexa_shopping_list.yaml` file configuring the following routes: diff --git a/docs/commerce/shopping_list/shopping_list_api.md b/docs/commerce/shopping_list/shopping_list_api.md index b3a7c1befd..3029d347db 100644 --- a/docs/commerce/shopping_list/shopping_list_api.md +++ b/docs/commerce/shopping_list/shopping_list_api.md @@ -40,8 +40,12 @@ and with sort clauses from the [`SortClause` namespace](/api/php_api/php_api_ref To get all shopping lists (of the current user or of the whole repository depending on the current user limitation), use the search method without criterion: -```php -$lists = $this->shoppingListService->findShoppingLists(new ShoppingListQuery()); +``` php +use Ibexa\Contracts\ShoppingList\ShoppingListServiceInterface; +use Ibexa\Contracts\ShoppingList\Value\ShoppingListQuery; + +/** @var ShoppingListServiceInterface $shoppingListService */ +$lists = $shoppingListService->findShoppingLists(new ShoppingListQuery()); ``` For more information about the shopping list search, @@ -56,12 +60,17 @@ If you forgot to retrieve this result in your variable, the local object isn't s In the following example, if some assignments (`$list =`) are removed, the dumped `$list` object doesn't contain the stored shopping list at that time. If only the middle assignment is removed, the last dumped variable contains the up-to-date shopping list. -```php -$list = $this->shoppingListService->getOrCreateDefaultShoppingList(); +``` php +use Ibexa\Contracts\ShoppingList\ShoppingListServiceInterface; +use Ibexa\Contracts\ShoppingList\Value\EntryAddStruct; + +/** @var ShoppingListServiceInterface $shoppingListService */ +/** @var string $productCode */ +$list = $shoppingListService->getOrCreateDefaultShoppingList(); dump($list); -$list = $this->shoppingListService->clearShoppingList($list); +$list = $shoppingListService->clearShoppingList($list); dump($list); -$list = $this->shoppingListService->addEntries($list, [new EntryAddStruct($productCode)]); +$list = $shoppingListService->addEntries($list, [new EntryAddStruct($productCode)]); dump($list); ``` @@ -71,13 +80,13 @@ an exception is thrown if at least product is already in the shopping list and n The following example adds products to a shopping list while avoiding error on duplicated entries. In this example the duplicates are ignored, but you could extend it to, for example, notify the user about each found duplicate. -```php +``` php [[= include_code('code_samples/shopping_list/php_api/src/Command/ShoppingListFilterCommand.php', 40, 50, remove_indent=True) =]] ``` The following example moves products from a source shopping list to a target shopping list after filtering out products already in the target list: -```php +``` php [[= include_code('code_samples/shopping_list/php_api/src/Command/ShoppingListMoveCommand.php', 43, 54, remove_indent=True) =]] ``` @@ -90,7 +99,7 @@ The following example starts with an empty cart and an empty shopping list, then adds a product to the shopping list and copies it twice to the cart. It continues with moving the whole cart to an empty list. -```php +``` php [[= include_code('code_samples/shopping_list/php_api/src/Controller/CartShoppingListTransferController.php', 70, 92, remove_indent=True) =]] ``` diff --git a/docs/commerce/storefront/configure_storefront.md b/docs/commerce/storefront/configure_storefront.md index d014174263..a542100349 100644 --- a/docs/commerce/storefront/configure_storefront.md +++ b/docs/commerce/storefront/configure_storefront.md @@ -63,21 +63,9 @@ The basic configuration of the Storefront can look as follows: ## Retrieve catalog assigned to user -The `\Ibexa\Contracts\Storefront\Repository\CatalogResolverInterface` interface allows retrieving the product catalog available for a specific user. +The [`\Ibexa\Contracts\Storefront\Repository\CatalogResolverInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Storefront-Repository-CatalogResolverInterface.html) interface allows retrieving the product catalog available for a specific user. -```php -namespace Ibexa\Contracts\Storefront\Repository; - -use Ibexa\Contracts\Core\Repository\Values\User\User; -use Ibexa\Contracts\ProductCatalog\Values\CatalogInterface; - -interface CatalogResolverInterface -{ - public function resolveCatalog(?User $user = null): ?CatalogInterface; -} -``` - -`null` stands for the current user. +To retrieve catalog assigned for the current user, pass `null`. ### Configure user account @@ -92,9 +80,10 @@ Settings for a Storefront user are configured under the `ibexa.system..st ibexa: system: site_group: - user_settings_groups: - - location - - custom_group + storefront: + user_settings_groups: + - location + - custom_group ``` By default, only the `location` user settings is provided: diff --git a/docs/commerce/storefront/extend_storefront.md b/docs/commerce/storefront/extend_storefront.md index 1ee79ccdbb..89d6d5c307 100644 --- a/docs/commerce/storefront/extend_storefront.md +++ b/docs/commerce/storefront/extend_storefront.md @@ -100,6 +100,12 @@ Define your own logic in a custom controller. Refer to the code snippet below and create your own file, for example, `CustomProductRenderController.php`: ``` php +use Ibexa\Contracts\ProductCatalog\Values\ProductInterface; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\Response; + +class CustomProductRenderController extends AbstractController +{ public function renderAction(ProductInterface $product): Response { return $this->render('@ibexadesign/storefront/product_card.html.twig', [ @@ -109,4 +115,5 @@ Refer to the code snippet below and create your own file, for example, `CustomPr 'is_relative' => true, ]); } +} ``` diff --git a/docs/commerce/transactional_emails/extend_transactional_emails.md b/docs/commerce/transactional_emails/extend_transactional_emails.md index b231b5e059..679f25621b 100644 --- a/docs/commerce/transactional_emails/extend_transactional_emails.md +++ b/docs/commerce/transactional_emails/extend_transactional_emails.md @@ -30,16 +30,13 @@ framework: [[= product_name =]] comes with a predefined [set of variables](transactional_emails_parameters.md) that you can use when building a template for your transactional email campaign at Actito. If this list isn't sufficient, you can use Events to include additional variables: -```php +``` php getRecipient(); $profile = $event->getProfile(); - $user = $recipient->getUser(); - - // Provide additional data if your profile has more attributes: + $user = $recipient->getUser(); + + // Provide additional data if your profile has more attributes: $attributes = $profile->getAttributes(); $attributes[] = new Attribute('name', $user->getName()); $profile->setAttributes($attributes); @@ -120,8 +117,8 @@ final class TransactionalMailFactoryEventSubscriber implements EventSubscriberIn $profile->setSegmentations($segmentations); // Use the same mechanism to pass other profile data - $profile->setSubscriptions(...); - $profile->setDataCollection(...); + // $profile->setSubscriptions($subscriptions); + // $profile->setDataCollection($dataCollection); } } ``` @@ -134,7 +131,7 @@ You could do it by adding a language suffix to a campaign name. On [[= product_name =]] side, to support this scenario, you must use an Event Subscriber on `Ibexa\Contracts\ConnectorActito\Event\ResolveCampaignEvent`: -```php +``` php contentService->loadVersionInfo($contentInfo, 2); +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo $contentInfo */ +/** @var \Ibexa\Contracts\Core\Repository\ContentService $contentService */ +$versionInfo = $contentService->loadVersionInfo($contentInfo, 2); ``` `loadRelationList` provides an iterable [`RelationList`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Core-Repository-Values-Content-RelationList.html) object @@ -149,7 +151,7 @@ All object state groups can be retrieved through [`loadObjectStateGroups`](/api/ To retrieve the fields of the selected content item, you can use the following command: -```php hl_lines="17-18 20-27" +``` php hl_lines="17-18 20-27" [[= include_file('code_samples/api/public_php_api/src/Command/ViewContentCommand.php', 0, 7) =]] // ... [[= include_file('code_samples/api/public_php_api/src/Command/ViewContentCommand.php', 17, 19) =]] @@ -170,12 +172,18 @@ The repository is SiteAccess-aware, so languages defined by the SiteAccess are a To load a specific language, provide its language code when loading the content item: ``` php -$content = $this->contentService->loadContent($contentId, ['ger-DE']); +/** @var int $contentId */ +/** @var \Ibexa\Contracts\Core\Repository\ContentService $contentService */ +$content = $contentService->loadContent($contentId, ['ger-DE']); ``` To load all languages as a prioritized list, use `Language::ALL`: ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Language; + +/** @var \Ibexa\Contracts\Core\Repository\ContentService $contentService */ +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\Content $content */ $contentService->loadContent($content->id, Language::ALL); ``` @@ -203,8 +211,12 @@ You can do it through the `getMainLocation` method of the ContentInfo object. Next, use the `getParentLocation` method of the location object to access the parent location: ``` php +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo $contentInfo */ $mainLocation = $contentInfo->getMainLocation(); -$output->writeln("Parent Location: " . $mainLocation->getParentLocation()->pathString); +$parentLocation = $mainLocation?->getParentLocation(); +if ($parentLocation !== null) { + $message = 'Parent Location: ' . $parentLocation->pathString; +} ``` ## Getting content from a location @@ -222,11 +234,16 @@ The versions must have the same language. For example, to get the comparison between the `name` field of two versions: -```php -$versionFrom = $this->contentService->loadVersionInfo($contentInfo, $versionFromId); -$versionTo = $this->contentService->loadVersionInfo($contentInfo, $versionToId); - -$nameComparison = $this->comparisonService->compare($versionFrom, $versionTo)->getFieldValueDiffByIdentifier('name')->getComparisonResult(); +``` php +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo $contentInfo */ +/** @var int $versionFromId */ +/** @var int $versionToId */ +/** @var \Ibexa\Contracts\Core\Repository\ContentService $contentService */ +/** @var \Ibexa\Contracts\VersionComparison\Service\VersionComparisonServiceInterface $comparisonService */ +$versionFrom = $contentService->loadVersionInfo($contentInfo, $versionFromId); +$versionTo = $contentService->loadVersionInfo($contentInfo, $versionToId); + +$nameComparison = $comparisonService->compare($versionFrom, $versionTo)->getFieldValueDiffByIdentifier('name')->getComparisonResult(); ``` `getComparisonResult` returns a `ComparisonResult` object, which depends on the field type being compared. diff --git a/docs/content_management/content_api/creating_content.md b/docs/content_management/content_api/creating_content.md index 2c670fafb5..55c3ee89c1 100644 --- a/docs/content_management/content_api/creating_content.md +++ b/docs/content_management/content_api/creating_content.md @@ -104,5 +104,8 @@ You can delete a single translation from a content item's version using [`Conten The method must be provided with a `VersionInfo` object and the code of the language to delete: ``` php -$this->contentService->deleteTranslationFromDraft($versionInfo, $language); +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\VersionInfo $versionInfo */ +$languageCode = 'ger-DE'; +/** @var \Ibexa\Contracts\Core\Repository\ContentService $contentService */ +$contentService->deleteTranslationFromDraft($versionInfo, $languageCode); ``` diff --git a/docs/content_management/content_api/managing_content.md b/docs/content_management/content_api/managing_content.md index d87609fdf4..bce7f49f60 100644 --- a/docs/content_management/content_api/managing_content.md +++ b/docs/content_management/content_api/managing_content.md @@ -117,8 +117,12 @@ The content item is restored under its previous location. You can also provide a different location to restore in as a second argument: ``` php -$newParent = $this->locationService->loadLocation($location); -$this->trashService->recover($trashItem, $newParent); +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\TrashItem $trashItem */ +/** @var \Ibexa\Contracts\Core\Repository\LocationService $locationService */ +/** @var \Ibexa\Contracts\Core\Repository\TrashService $trashService */ +$locationId = 12345; +$newParent = $locationService->loadLocation($locationId); +$trashService->recover($trashItem, $newParent); ``` You can also search through Trash items and sort the results using several public PHP API Search Criteria and Sort Clauses that have been exposed for `TrashService` queries. @@ -179,7 +183,7 @@ This method accepts a `ContentTypeQuery` object that supports filtering and sort The following example shows how you can use the criteria to find content types: -```php hl_lines="28-38" +``` php hl_lines="28-38" [[= include_code('code_samples/api/public_php_api/src/Command/FindContentTypeCommand.php') =]] ``` diff --git a/docs/content_management/data_migration/managing_migrations.md b/docs/content_management/data_migration/managing_migrations.md index 072a7a0e6d..c96e078208 100644 --- a/docs/content_management/data_migration/managing_migrations.md +++ b/docs/content_management/data_migration/managing_migrations.md @@ -50,7 +50,7 @@ You can configure a different folder by using the following settings: ``` yaml ibexa_migrations: - migration_directory: %kernel.project_dir%/src/Migrations/MyMigrations/ + migration_directory: '%kernel.project_dir%/src/Migrations/MyMigrations/' migrations_files_subdir: migration_files ``` @@ -64,7 +64,6 @@ ibexa_migrations: ``` yaml ibexa_migrations: migration_directory: '%kernel.project_dir%/data/' - ... ``` Then, when you run the migration command, you must use the [`--siteaccess` option](exporting_data.md#siteaccess) and provide the name of the SiteAccess that you want to migrate. diff --git a/docs/content_management/field_types/create_custom_generic_field_type.md b/docs/content_management/field_types/create_custom_generic_field_type.md index 9ad512a542..9cd4f1a2d1 100644 --- a/docs/content_management/field_types/create_custom_generic_field_type.md +++ b/docs/content_management/field_types/create_custom_generic_field_type.md @@ -28,7 +28,7 @@ The `HelloWorld` Value class should contain: - public properties that retrieve `name` - an implementation of the `__toString()` method -```php +``` php [[= include_code('code_samples/field_types/generic_ft/src/FieldType/HelloWorld/Value.php') =]] ``` @@ -37,7 +37,7 @@ The `HelloWorld` Value class should contain: Next, implement a definition of a field type extending the Generic field type in the `src/FieldType/HelloWorld/Type.php` class. It provides settings for the field type and an implementation of the `Ibexa\Contracts\Core\FieldType\FieldType` abstract class. -```php +``` php [[= include_file('code_samples/field_types/generic_ft/src/FieldType/HelloWorld/Type.php', 0, 3) =]] [[= include_file('code_samples/field_types/generic_ft/src/FieldType/HelloWorld/Type.php', 6, 8) =]] [[= include_file('code_samples/field_types/generic_ft/src/FieldType/HelloWorld/Type.php', 10, 16) =]][[= include_file('code_samples/field_types/generic_ft/src/FieldType/HelloWorld/Type.php', 26, 27) =]] @@ -56,7 +56,7 @@ Next, register the field type as a service and tag it with `ibexa.field_type`: Create a `src/Form/Type/HelloWorldType.php` form. It enables you to edit the new field type. -```php +``` php [[= include_code('code_samples/field_types/generic_ft/src/Form/Type/HelloWorldType.php') =]] ``` @@ -64,7 +64,7 @@ Now you can map field definitions into Symfony forms with FormMapper. Add the `mapFieldValueForm()` method required by `FieldValueFormMapperInterface` and the required `use` statements to `src/FieldType/HelloWorld/Type.php`: -```php hl_lines="6-7 18-26" +``` php hl_lines="6-7 18-26" [[= include_code('code_samples/field_types/generic_ft/src/FieldType/HelloWorld/Type.php') =]] ``` diff --git a/docs/content_management/field_types/field_type_reference/addressfield.md b/docs/content_management/field_types/field_type_reference/addressfield.md index aee1309c02..d4f01ae0c5 100644 --- a/docs/content_management/field_types/field_type_reference/addressfield.md +++ b/docs/content_management/field_types/field_type_reference/addressfield.md @@ -27,7 +27,9 @@ provided by the `ibexa/fieldtype-address` package. ### Example input -```php +``` php +use Ibexa\FieldTypeAddress\FieldType; + new FieldType\Value( 'My home address', 'PL', @@ -112,7 +114,7 @@ ibexa.address.field.tax_number.billing_address.DE An event listener can also provide validation by using either one of [constraints provided by Symfony]([[= symfony_doc =]]/validation.html#supported-constraints), or a custom constraint. -```php +``` php use Ibexa\Contracts\FieldTypeAddress\Event\MapFieldEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Form\Extension\Core\Type\IntegerType; diff --git a/docs/content_management/field_types/field_type_reference/authorfield.md b/docs/content_management/field_types/field_type_reference/authorfield.md index 87c4de5390..5b19602895 100644 --- a/docs/content_management/field_types/field_type_reference/authorfield.md +++ b/docs/content_management/field_types/field_type_reference/authorfield.md @@ -19,16 +19,18 @@ This field type allows the storage and retrieval of one or more authors. For eac Example: ``` php -$authorList = Author\Value([ +use Ibexa\Core\FieldType\Author; + +$authorList = new Author\Value([ new Author\Author([ 'id' => 1, 'name' => 'Boba Fett', - 'email' => 'boba.fett@example.com' + 'email' => 'boba.fett@example.com', ]), new Author\Author([ 'id' => 2, 'name' => 'Darth Vader', - 'email' => 'darth.vader@example.com' + 'email' => 'darth.vader@example.com', ]), ]); ``` @@ -39,7 +41,7 @@ The hash format mostly matches the value object. It has the following key `autho Example -``` php +``` php {skip-validation} [ [ 'id' => 1, @@ -50,8 +52,8 @@ Example 'id' => 2, 'name' => 'Darth Vader', 'email' => 'darth.vader@example.com' - ] -] + ], +]; ``` #### String representation @@ -85,6 +87,6 @@ Following `defaultAuthor` default value options are available as constants in use Ibexa\Core\FieldType\Author\Type; $settings = [ - "defaultAuthor" => Type::DEFAULT_VALUE_EMPTY + 'defaultAuthor' => Type::DEFAULT_VALUE_EMPTY, ]; ``` diff --git a/docs/content_management/field_types/field_type_reference/binaryfilefield.md b/docs/content_management/field_types/field_type_reference/binaryfilefield.md index 3b7d612234..0d3d48903a 100644 --- a/docs/content_management/field_types/field_type_reference/binaryfilefield.md +++ b/docs/content_management/field_types/field_type_reference/binaryfilefield.md @@ -46,7 +46,8 @@ The hash format mostly matches the value object. It has the following keys: Example: -```php +``` php +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\ContentCreateStruct $fileContentCreateStruct */ $fileContentCreateStruct->setField('file', new Ibexa\Core\FieldType\BinaryFile\Value([ 'fileName' => 'example.pdf', 'inputUri' => '/tmp/example_for_website.pdf', diff --git a/docs/content_management/field_types/field_type_reference/checkboxfield.md b/docs/content_management/field_types/field_type_reference/checkboxfield.md index d3824aca60..31bf3760b9 100644 --- a/docs/content_management/field_types/field_type_reference/checkboxfield.md +++ b/docs/content_management/field_types/field_type_reference/checkboxfield.md @@ -20,16 +20,16 @@ The Value class of this field type contains the following properties: ``` php //Value object content examples -use Ibexa\Core\FieldType\Checkbox\Type; +use Ibexa\Core\FieldType\Checkbox\Value; // Instantiates a checkbox value with a default state (false) -$checkboxValue = new Checkbox\Value(); +$checkboxValue = new Value(); // Checked -$value->bool = true; +$checkboxValue->bool = true; // Unchecked -$value->bool = false; +$checkboxValue->bool = false; ``` ##### Constructor @@ -38,10 +38,10 @@ The `Checkbox\Value` constructor accepts a boolean value: ``` php // Constructor example -use Ibexa\Core\FieldType\Checkbox\Type; +use Ibexa\Core\FieldType\Checkbox\Value; // Instantiates a checkbox value with a checked state -$checkboxValue = new Checkbox\Value( true ); +$checkboxValue = new Value(true); ``` ##### String representation diff --git a/docs/content_management/field_types/field_type_reference/countryfield.md b/docs/content_management/field_types/field_type_reference/countryfield.md index 8940dbd1b5..10f49cfe9d 100644 --- a/docs/content_management/field_types/field_type_reference/countryfield.md +++ b/docs/content_management/field_types/field_type_reference/countryfield.md @@ -12,7 +12,7 @@ This field type represents one or multiple countries. Example array: -``` php +``` php {skip-validation} [ "JP" => [ "Name" => "Japan", @@ -40,7 +40,7 @@ The field definition of this field type can be configured with one option: ``` php // Country FieldType example settings $settings = [ - "isMultiple" => true + 'isMultiple' => true, ]; ``` @@ -51,7 +51,8 @@ It's also available when setting value on the content field, by setting the valu ``` php // Value object content example -$content->fields["countries"] = [ "JP", "NO" ]; +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\Content $content */ +$content->fields['countries'] = ['JP', 'NO']; ``` The format used by the toHash method is the Alpha2 value, however the input is capable of accepting either Name, Alpha2, or Alpha3 value as shown below in the value object section. @@ -68,13 +69,14 @@ The Value class of this field type contains the following properties: ``` php // Value object content example +/** @var \Ibexa\Core\FieldType\Country\Value $value */ $value->countries = [ - "JP" => [ - "Name" => "Japan", - "Alpha2" => "JP", - "Alpha3" => "JPN", - "IDC" => 81 - ] + 'JP' => [ + 'Name' => 'Japan', + 'Alpha2' => 'JP', + 'Alpha3' => 'JPN', + 'IDC' => 81, + ], ]; ``` @@ -85,16 +87,17 @@ It expects an array as input. ``` php // Constructor example +use Ibexa\Core\FieldType\Country as Country; // Instantiates a Country Value object $countryValue = new Country\Value( [ - "JP" => [ - "Name" => "Japan", - "Alpha2" => "JP", - "Alpha3" => "JPN", - "IDC" => 81 - ] + 'JP' => [ + 'Name' => 'Japan', + 'Alpha2' => 'JP', + 'Alpha3' => 'JPN', + 'IDC' => 81, + ], ] ); ``` diff --git a/docs/content_management/field_types/field_type_reference/dateandtimefield.md b/docs/content_management/field_types/field_type_reference/dateandtimefield.md index 35678d5902..32592df213 100644 --- a/docs/content_management/field_types/field_type_reference/dateandtimefield.md +++ b/docs/content_management/field_types/field_type_reference/dateandtimefield.md @@ -61,8 +61,8 @@ Hash value of this field type is an array with two keys: ``` php $hash = [ - "timestamp" => 1400856992, - "rfc850" => "Friday, 23-May-14 14:56:14 GMT+0000" + 'timestamp' => 1400856992, + 'rfc850' => 'Friday, 23-May-14 14:56:14 GMT+0000', ]; ``` @@ -94,9 +94,9 @@ Following `defaultType` default value options are available as constants in the use Ibexa\Core\FieldType\DateAndTime\Type; $settings = [ - "useSeconds" => false, - "defaultType" => Type::DEFAULT_EMPTY, - "dateInterval" => null + 'useSeconds' => false, + 'defaultType' => Type::DEFAULT_EMPTY, + 'dateInterval' => null, ]; ``` @@ -110,6 +110,6 @@ The template called by the [`ibexa_render_field()` Twig function](field_twig_fun Example: -``` php +``` html+twig {{ ibexa_render_field(content, 'datetime') }} ``` diff --git a/docs/content_management/field_types/field_type_reference/datefield.md b/docs/content_management/field_types/field_type_reference/datefield.md index f2b049d675..18633d89be 100644 --- a/docs/content_management/field_types/field_type_reference/datefield.md +++ b/docs/content_management/field_types/field_type_reference/datefield.md @@ -64,8 +64,8 @@ Hash value of this field type is an array with two keys: ``` php // Example of the hash value in PHP $hash = [ - "timestamp" => 1400856992, - "rfc850" => "Friday, 23-May-14 14:56:14 GMT+0000" + 'timestamp' => 1400856992, + 'rfc850' => 'Friday, 23-May-14 14:56:14 GMT+0000', ]; ``` @@ -94,7 +94,7 @@ Following `defaultType` default value options are available as constants in the use Ibexa\Core\FieldType\Date\Type; $settings = [ - "defaultType" => Type::DEFAULT_EMPTY + 'defaultType' => Type::DEFAULT_EMPTY, ]; ``` diff --git a/docs/content_management/field_types/field_type_reference/emailaddressfield.md b/docs/content_management/field_types/field_type_reference/emailaddressfield.md index b7f574f32c..06294cf899 100644 --- a/docs/content_management/field_types/field_type_reference/emailaddressfield.md +++ b/docs/content_management/field_types/field_type_reference/emailaddressfield.md @@ -21,13 +21,13 @@ The `Value` class of this field type contains the following properties: ``` php // Value object content example -use Ibexa\Core\FieldType\EmailAddress\Type; +use Ibexa\Core\FieldType\EmailAddress\Value; // Instantiates an EmailAddress Value object with default value (empty string) -$emailaddressValue = new Type\Value(); +$emailaddressValue = new Value(); // Email definition -$emailaddressValue->email = "someuser@example.com"; +$emailaddressValue->email = 'someuser@example.com'; ``` ##### Constructor @@ -38,10 +38,10 @@ It accepts a string as input. ``` php // Constructor example -use Ibexa\Core\FieldType\EmailAddress\Type; +use Ibexa\Core\FieldType\EmailAddress\Value; // Instantiates an EmailAddress Value object -$emailaddressValue = new Type\Value( "someuser@example.com" ); +$emailaddressValue = new Value('someuser@example.com'); ``` ##### String representation diff --git a/docs/content_management/field_types/field_type_reference/floatfield.md b/docs/content_management/field_types/field_type_reference/floatfield.md index 71e23c7ee4..b8f36d8faa 100644 --- a/docs/content_management/field_types/field_type_reference/floatfield.md +++ b/docs/content_management/field_types/field_type_reference/floatfield.md @@ -30,12 +30,12 @@ The Value class of this field type contains the following properties: ``` php // Value object content example -use Ibexa\Core\FieldType\Float\Type; +use Ibexa\Core\FieldType\Float\Value as FloatValue; // Instantiates a Float Value object -$floatValue = new Type\Value(); +$floatValue = new FloatValue(); -$float->value = 284.773 +$floatValue->value = 284.773; ``` ##### Constructor @@ -46,10 +46,10 @@ It expects a numeric value with or without decimals. ``` php // Constructor example -use Ibexa\Core\FieldType\Float\Type; +use Ibexa\Core\FieldType\Float\Value as FloatValue; // Instantiates a Float Value object -$floatValue = new Type\Value( 284.773 ); +$floatValue = new FloatValue(284.773); ``` ### Validation @@ -64,17 +64,16 @@ This field type supports `FloatValueValidator`, defining maximum and minimum flo ``` php // Validator configuration example in PHP -use Ibexa\Core\FieldType\Float\Type; - +/** @var \Ibexa\Contracts\Core\Repository\Repository $repository */ $contentTypeService = $repository->getContentTypeService(); -$floatFieldCreateStruct = $contentTypeService->newFieldDefinitionCreateStruct( "float", "ibexa_float" ); +$floatFieldCreateStruct = $contentTypeService->newFieldDefinitionCreateStruct('float', 'ibexa_float'); // Accept only numbers between 0.1 and 203.99 $floatFieldCreateStruct->validatorConfiguration = [ - "FileSizeValidator" => [ - "minFloatValue" => 0.1, - "maxFloatValue" => 203.99 - ] + 'FileSizeValidator' => [ + 'minFloatValue' => 0.1, + 'maxFloatValue' => 203.99, + ], ]; ``` diff --git a/docs/content_management/field_types/field_type_reference/imageassetfield.md b/docs/content_management/field_types/field_type_reference/imageassetfield.md index a7d16253a0..ec86c3808c 100644 --- a/docs/content_management/field_types/field_type_reference/imageassetfield.md +++ b/docs/content_management/field_types/field_type_reference/imageassetfield.md @@ -32,8 +32,10 @@ Value object of `ibexa_image_asset` contains the following properties: ``` php // Value object content example +/** @var \Ibexa\Core\FieldType\ImageAsset\Value $imageAssetValue */ +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo $contentInfo */ $imageAssetValue->destinationContentId = $contentInfo->id; -$imageAssetValue->alternativeText = "Picture of an apple."; +$imageAssetValue->alternativeText = 'Picture of an apple.'; ``` #### Constructor @@ -44,8 +46,11 @@ It expects an ID of a content item representing asset and the alternative text. ``` php // Constructor example +use Ibexa\Core\FieldType\ImageAsset as ImageAsset; + +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo $contentInfo */ // Instantiates a ImageAsset Value object -$imageAssetValue = new ImageAsset\Value($contentInfo->id, "Picture of an apple."); +$imageAssetValue = new ImageAsset\Value($contentInfo->id, 'Picture of an apple.'); ``` ### Validation diff --git a/docs/content_management/field_types/field_type_reference/imagefield.md b/docs/content_management/field_types/field_type_reference/imagefield.md index 0b0b36284c..f94c8ae396 100644 --- a/docs/content_management/field_types/field_type_reference/imagefield.md +++ b/docs/content_management/field_types/field_type_reference/imagefield.md @@ -150,8 +150,13 @@ The variation service, `ibexa.field_type.ibexa_image.variation_service`, can be It expects a VersionInfo, the Image field, and the variation name as a string (`large`, `medium`, and more.): ``` php +/** @var \Ibexa\Contracts\Core\Variation\VariationHandler $imageVariationHandler */ +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\Field $imageField */ +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\VersionInfo $versionInfo */ $variation = $imageVariationHandler->getVariation( - $imageField, $versionInfo, 'large' + $imageField, + $versionInfo, + 'large' ); echo $variation->uri; @@ -165,41 +170,46 @@ As for any field type, there are several ways to input content to a field. For an Image, the quickest is to call `setField()` on the ContentStruct: ``` php +/** @var \Ibexa\Contracts\Core\Repository\ContentService $contentService */ +/** @var \Ibexa\Contracts\Core\Repository\ContentTypeService $contentTypeService */ $createStruct = $contentService->newContentCreateStruct( - $contentTypeService->loadContentType( 'image' ), + $contentTypeService->loadContentTypeByIdentifier('image'), 'eng-GB' ); -$createStruct->setField( 'image', '/tmp/image.png' ); +$createStruct->setField('image', '/tmp/image.png'); ``` To customize the Image's alternative texts, you must first get an `Image\Value` object, and set this property. For that, you can use the `Image\Value::fromString()` method that accepts the path to a local file: ``` php +/** @var \Ibexa\Contracts\Core\Repository\ContentService $contentService */ +/** @var \Ibexa\Contracts\Core\Repository\ContentTypeService $contentTypeService */ $createStruct = $contentService->newContentCreateStruct( - $contentTypeService->loadContentType( 'image' ), + $contentTypeService->loadContentTypeByIdentifier('image'), 'eng-GB' ); -$imageField = \Ibexa\Core\FieldType\Image\Value::fromString( '/tmp/image.png' ); +$imageField = \Ibexa\Core\FieldType\Image\Value::fromString('/tmp/image.png'); $imageField->alternativeText = 'My alternative text'; -$createStruct->setField( 'image', $imageField ); +$createStruct->setField('image', $imageField); ``` You can also provide a hash of `Image\Value` properties, either to `setField()`, or to the constructor: ``` php +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\ContentCreateStruct $createStruct */ $imageValue = new \Ibexa\Core\FieldType\Image\Value( [ 'id' => '/tmp/image.png', 'fileSize' => 37931, 'fileName' => 'image.png', - 'alternativeText' => 'My alternative text' + 'alternativeText' => 'My alternative text', ] ); -$createStruct->setField( 'image', $imageValue ); +$createStruct->setField('image', $imageValue); ``` ### From REST diff --git a/docs/content_management/field_types/field_type_reference/integerfield.md b/docs/content_management/field_types/field_type_reference/integerfield.md index 7d6b6f03cf..1315514313 100644 --- a/docs/content_management/field_types/field_type_reference/integerfield.md +++ b/docs/content_management/field_types/field_type_reference/integerfield.md @@ -26,7 +26,8 @@ The Value class of this field type contains the following properties: ``` php // Value object content example -$integer->value = 8 +/** @var \Ibexa\Core\FieldType\Integer\Value $integer */ +$integer->value = 8; ``` #### Constructor @@ -39,7 +40,7 @@ It expects a numeric, integer value. use Ibexa\Core\FieldType\Integer; // Instantiates a Integer Value object -$integerValue = new Integer\Value( 8 ); +$integerValue = new Integer\Value(8); ``` #### Hash format @@ -66,8 +67,8 @@ This field type supports `IntegerValueValidator`, defining maximum and minimum f ``` php // Example of validator configuration in PHP $validatorConfiguration = [ - "minIntegerValue" => 1, - "maxIntegerValue" => 24 + 'minIntegerValue' => 1, + 'maxIntegerValue' => 24, ]; ``` diff --git a/docs/content_management/field_types/field_type_reference/isbnfield.md b/docs/content_management/field_types/field_type_reference/isbnfield.md index 71302aed8d..57cd27dd50 100644 --- a/docs/content_management/field_types/field_type_reference/isbnfield.md +++ b/docs/content_management/field_types/field_type_reference/isbnfield.md @@ -33,8 +33,7 @@ The input passed into this field type is subject of ISBN validation depending on An example of this field setting is shown below and controls if input is validated as ISBN-13 or ISBN-10: ``` php -Array -( - [isISBN13] => true -) +[ + 'isISBN13' => true, +]; ``` diff --git a/docs/content_management/field_types/field_type_reference/keywordfield.md b/docs/content_management/field_types/field_type_reference/keywordfield.md index ddc515b93a..18109a8d44 100644 --- a/docs/content_management/field_types/field_type_reference/keywordfield.md +++ b/docs/content_management/field_types/field_type_reference/keywordfield.md @@ -22,9 +22,9 @@ This field type stores one or several comma-separated keywords as a string or ar The Value class of this field type contains the following properties: -| Property | Type | Description | -|----------|------------|----------------------------------------| -| `$value` | `string[]` | Holds an array of keywords as strings. | +| Property | Type | Description | +|-----------|------------|----------------------------------------| +| `$values` | `string[]` | Holds an array of keywords as strings. | ``` php // Value object content example @@ -34,7 +34,7 @@ use Ibexa\Core\FieldType\Keyword\Value; $keywordValue = new Value(); // Sets an array of keywords as a value -$keyword->value = [ "php", "css3", "html5", "Ibexa Platform" ]; +$keywordValue->values = ['php', 'css3', 'html5', 'Ibexa Platform']; ``` #### Constructor @@ -48,9 +48,9 @@ It expects a list of keywords, either comma-separated in a string or as an array use Ibexa\Core\FieldType\Keyword\Value; // Instantiates a Value object with an array of keywords -$keywordValue = new Value( [ "php5", "css3", "html5" ] ); +$keywordValue = new Value(['php5', 'css3', 'html5']); // Instantiates a Value object with a list of keywords in a string // This is equivalent to the example above -$keywordValue = new Value( "php5,css3,html5" ); +$keywordValue = new Value('php5,css3,html5'); ``` diff --git a/docs/content_management/field_types/field_type_reference/maplocationfield.md b/docs/content_management/field_types/field_type_reference/maplocationfield.md index 6687a22988..7ffebdd103 100644 --- a/docs/content_management/field_types/field_type_reference/maplocationfield.md +++ b/docs/content_management/field_types/field_type_reference/maplocationfield.md @@ -38,13 +38,14 @@ Accepted keys are `latitude` (`float`), `longitude` (`float`), `address` (`strin ``` php // Constructor example +use Ibexa\Core\FieldType\MapLocation as MapLocation; // Instantiates a MapLocation Value object $MapLocationValue = new MapLocation\Value( [ 'latitude' => 59.928732, 'longitude' => 10.777888, - 'address' => "Ibexa Nordics" + 'address' => 'Ibexa Nordics', ] ); ``` diff --git a/docs/content_management/field_types/field_type_reference/matrixfield.md b/docs/content_management/field_types/field_type_reference/matrixfield.md index 1542ceeebd..276ffb5684 100644 --- a/docs/content_management/field_types/field_type_reference/matrixfield.md +++ b/docs/content_management/field_types/field_type_reference/matrixfield.md @@ -18,7 +18,9 @@ The Matrix field type is available via the Matrix Bundle provided by the [ibexa/ Example of input: -```php +``` php +use Ibexa\FieldTypeMatrix\FieldType; + new FieldType\Value([ new FieldType\Value\Row(['col1' => 'Row 1, Col 1', 'col2' => 'Row 1, Col 2']), new FieldType\Value\Row(['col1' => 'Row 2, Col 1', 'col2' => 'Row 2, Col 2']), @@ -46,7 +48,9 @@ If, after removing empty rows, the number of rows doesn't fulfill the configured For example, the following input doesn't validate if `Minimum number of rows` is set to 3, because the second row is empty: -```php +``` php +use Ibexa\FieldTypeMatrix\FieldType; + new FieldType\Value([ new FieldType\Value\Row(['col1' => 'Row 1, Col 1', 'col2' => 'Row 1, Col 2']), new FieldType\Value\Row(['col1' => '', 'col2' => '']), diff --git a/docs/content_management/field_types/field_type_reference/measurementfield.md b/docs/content_management/field_types/field_type_reference/measurementfield.md index c4c82ad185..5a16c7dabd 100644 --- a/docs/content_management/field_types/field_type_reference/measurementfield.md +++ b/docs/content_management/field_types/field_type_reference/measurementfield.md @@ -45,14 +45,16 @@ Depending on the selected input type, the object resembles the following example ``` php // Simple input (single value) example -// @var MeasurementServiceInterface $measurementService +use Ibexa\Measurement\FieldType\MeasurementValue; + +/** @var \Ibexa\Contracts\Measurement\MeasurementServiceInterface $measurementService */ // Instantiates a Measurement Value object -$measurementValue = new Measurement\Value( +$measurementValue = new MeasurementValue( $measurementService->buildSimpleValue( - 'length', - 13.5, - 'centimeter' + 'length', + 13.5, + 'centimeter' ) ); ``` @@ -60,10 +62,12 @@ $measurementValue = new Measurement\Value( ``` php // Range input value example -// @var MeasurementServiceInterface $measurementService +use Ibexa\Measurement\FieldType\MeasurementValue; + +/** @var \Ibexa\Contracts\Measurement\MeasurementServiceInterface $measurementService */ // Instantiates a Measurement Value object -$measurementValue = new Measurement\Value( +$measurementValue = new MeasurementValue( $measurementService->buildRangeValue( 'volume', 0.5, diff --git a/docs/content_management/field_types/field_type_reference/mediafield.md b/docs/content_management/field_types/field_type_reference/mediafield.md index e08378f64d..d29074113e 100644 --- a/docs/content_management/field_types/field_type_reference/mediafield.md +++ b/docs/content_management/field_types/field_type_reference/mediafield.md @@ -76,14 +76,15 @@ The field type supports `FileSizeValidator`, defining maximum size of media file use Ibexa\Core\FieldType\Media\Type; +/** @var \Ibexa\Contracts\Core\Repository\Repository $repository */ $contentTypeService = $repository->getContentTypeService(); -$mediaFieldCreateStruct = $contentTypeService->newFieldDefinitionCreateStruct( "media", "ibexa_media" ); +$mediaFieldCreateStruct = $contentTypeService->newFieldDefinitionCreateStruct('media', 'ibexa_media'); // Setting maximum file size to 5 megabytes $mediaFieldCreateStruct->validatorConfiguration = [ - "FileSizeValidator" => [ - "maxFileSize" => 5 * 1024 * 1024 - ] + 'FileSizeValidator' => [ + 'maxFileSize' => 5 * 1024 * 1024, + ], ]; ``` @@ -112,11 +113,12 @@ List of all available `mediaType` constants is defined in the `Ibexa\Core\FieldT use Ibexa\Core\FieldType\Media\Type; +/** @var \Ibexa\Contracts\Core\Repository\Repository $repository */ $contentTypeService = $repository->getContentTypeService(); -$mediaFieldCreateStruct = $contentTypeService->newFieldDefinitionCreateStruct( "media", "ibexa_media" ); +$mediaFieldCreateStruct = $contentTypeService->newFieldDefinitionCreateStruct('media', 'ibexa_media'); // Setting Adobe Flash as the media type $mediaFieldCreateStruct->fieldSettings = [ - "mediaType" => Type::TYPE_FLASH, + 'mediaType' => Type::TYPE_FLASH, ]; ``` diff --git a/docs/content_management/field_types/field_type_reference/relationfield.md b/docs/content_management/field_types/field_type_reference/relationfield.md index 6a0016cb03..915ca272f7 100644 --- a/docs/content_management/field_types/field_type_reference/relationfield.md +++ b/docs/content_management/field_types/field_type_reference/relationfield.md @@ -28,6 +28,8 @@ The Value class of this field type contains the following properties: ``` php // Value object content example +/** @var \Ibexa\Core\FieldType\Relation\Value $relation */ +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo $contentInfo */ $relation->destinationContentId = $contentInfo->id; ``` @@ -37,9 +39,11 @@ The `Relation\Value` constructor initializes a new value object with the value p ``` php // Constructor example +use Ibexa\Core\FieldType\Relation as Relation; +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo $contentInfo */ // Instantiates a Relation Value object -$relationValue = new Relation\Value( $contentInfo->id ); +$relationValue = new Relation\Value($contentInfo->id); ``` ### Validation @@ -62,8 +66,8 @@ The field definition of this field type can be configured with three options: use Ibexa\Core\FieldType\Relation\Type; $settings = [ - "selectionMethod" => 1, - "selectionRoot" => null, - "selectionContentTypes" => [] + 'selectionMethod' => 1, + 'selectionRoot' => null, + 'selectionContentTypes' => [], ]; ``` diff --git a/docs/content_management/field_types/field_type_reference/relationlistfield.md b/docs/content_management/field_types/field_type_reference/relationlistfield.md index 9bdac070d6..c4b81999d9 100644 --- a/docs/content_management/field_types/field_type_reference/relationlistfield.md +++ b/docs/content_management/field_types/field_type_reference/relationlistfield.md @@ -29,10 +29,13 @@ This field type makes it possible to store and retrieve values of a relation to ``` php // Value object content example -$relationList->destinationContentId = [ +/** @var \Ibexa\Core\FieldType\RelationList\Value $relationList */ +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo $contentInfo1 */ +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo $contentInfo2 */ +$relationList->destinationContentIds = [ $contentInfo1->id, $contentInfo2->id, - 170 + 170, ]; ``` @@ -43,13 +46,16 @@ It expects a mixed array as value. ``` php //Constructor example +use Ibexa\Core\FieldType\RelationList as RelationList; +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo $contentInfo1 */ +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo $contentInfo2 */ // Instantiates a RelationList Value object $relationListValue = new RelationList\Value( [ $contentInfo1->id, $contentInfo2->id, - 170 + 170, ] ); ``` @@ -96,15 +102,15 @@ Following selection methods are available: use Ibexa\Core\FieldType\RelationList\Type; $fieldSettings = [ - "selectionMethod" => Type::SELECTION_BROWSE, - "selectionDefaultLocation" => null, - "selectionContentTypes" => [] + 'selectionMethod' => Type::SELECTION_BROWSE, + 'selectionDefaultLocation' => null, + 'selectionContentTypes' => [], ]; $validators = [ - "RelationListValueValidator" => [ - "selectionLimit" => 0, - ] + 'RelationListValueValidator' => [ + 'selectionLimit' => 0, + ], ]; ``` diff --git a/docs/content_management/field_types/field_type_reference/richtextfield.md b/docs/content_management/field_types/field_type_reference/richtextfield.md index 79acfd9494..a6d46e0eef 100644 --- a/docs/content_management/field_types/field_type_reference/richtextfield.md +++ b/docs/content_management/field_types/field_type_reference/richtextfield.md @@ -71,7 +71,9 @@ You can use the [[= product_name_base =]] flavor of the DocBook format in PHP AP The following example shows how to pass DocBook content to a [create struct](creating_content.md#creating-content-item-draft): ``` php -$contentCreateStruct = $contentService->newContentCreateStruct( $contentType, "eng-GB" ); +/** @var \Ibexa\Contracts\Core\Repository\ContentService $contentService */ +/** @var \Ibexa\Contracts\Core\Repository\Values\ContentType\ContentType $contentType */ +$contentCreateStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB'); $inputString = << @@ -85,7 +87,7 @@ $inputString = << DOCBOOK; -$contentCreateStruct->setField( "description", $inputString ); +$contentCreateStruct->setField('description', $inputString); ``` When creating RichText content with the REST API, use the `xml` key of the `fieldValue` tag: diff --git a/docs/content_management/field_types/field_type_reference/selectionfield.md b/docs/content_management/field_types/field_type_reference/selectionfield.md index e11186d586..8d76e61b6e 100644 --- a/docs/content_management/field_types/field_type_reference/selectionfield.md +++ b/docs/content_management/field_types/field_type_reference/selectionfield.md @@ -27,11 +27,12 @@ The Value class of this field type contains the following properties: ``` php // Value object content examples +/** @var \Ibexa\Core\FieldType\Selection\Value $value */ // Single selection -$value->selection = 1; +$value->selection = [1]; // Multiple selection -$value->selection = [ 1, 4, 5 ]; +$value->selection = [1, 4, 5]; ``` #### Constructor @@ -40,9 +41,10 @@ The `Selection\Value` constructor accepts an array of selected element identifie ``` php // Constructor example +use Ibexa\Core\FieldType\Selection as Selection; // Instanciates a selection value with items #1 and #2 selected -$selectionValue = new Selection\Value( [ 1, 2 ] ); +$selectionValue = new Selection\Value([1, 2]); ``` #### String representation @@ -58,7 +60,7 @@ Hash format of this field type is the same as value object's `selection` propert ``` php // Example of value in hash format -$hash = [ 1, 2 ]; +$hash = [1, 2]; ``` ### Validation @@ -80,7 +82,7 @@ When option validation fails, a list with the invalid options is also presented. use Ibexa\Core\FieldType\Selection\Type; $settings = [ - "isMultiple" => true, - "options" => [1 => 'One', 2 => 'Two', 3 => 'Three'] + 'isMultiple' => true, + 'options' => [1 => 'One', 2 => 'Two', 3 => 'Three'], ]; ``` diff --git a/docs/content_management/field_types/field_type_reference/taxonomyentryassignmentfield.md b/docs/content_management/field_types/field_type_reference/taxonomyentryassignmentfield.md index fb31d95857..517d465d45 100644 --- a/docs/content_management/field_types/field_type_reference/taxonomyentryassignmentfield.md +++ b/docs/content_management/field_types/field_type_reference/taxonomyentryassignmentfield.md @@ -25,8 +25,11 @@ To be able to assign tags to the content, first, you need to add a `TaxonomyEntr Example using an `Ibexa\Taxonomy\FieldType\TaxonomyEntryAssignment\Value` object: ``` php -$taxonomyEntry1 = $this->taxonomyService->loadEntryByIdentifier('example_entry', 'tags'); -$taxonomyEntry2 = $this->taxonomyService->loadEntryByIdentifier('example_entry_2', 'tags'); +use Ibexa\Contracts\Taxonomy\Service\TaxonomyServiceInterface; + +/** @var TaxonomyServiceInterface $taxonomyService */ +$taxonomyEntry1 = $taxonomyService->loadEntryByIdentifier('example_entry', 'tags'); +$taxonomyEntry2 = $taxonomyService->loadEntryByIdentifier('example_entry_2', 'tags'); new \Ibexa\Taxonomy\FieldType\TaxonomyEntryAssignment\Value( [ $taxonomyEntry1, @@ -40,10 +43,14 @@ new \Ibexa\Taxonomy\FieldType\TaxonomyEntryAssignment\Value( Example using array: ``` php -[ +use Ibexa\Contracts\Taxonomy\Value\TaxonomyEntry; + +/** @var TaxonomyEntry $taxonomyEntry */ +/** @var TaxonomyEntry $taxonomyEntry2 */ +return [ 'taxonomy_entries' => [$taxonomyEntry, $taxonomyEntry2], // load entries using TaxonomyService 'taxonomy' => 'tags', -] +]; ``` ### Value object diff --git a/docs/content_management/field_types/field_type_reference/taxonomyentryfield.md b/docs/content_management/field_types/field_type_reference/taxonomyentryfield.md index 89ee705228..046989d5c8 100644 --- a/docs/content_management/field_types/field_type_reference/taxonomyentryfield.md +++ b/docs/content_management/field_types/field_type_reference/taxonomyentryfield.md @@ -19,20 +19,22 @@ A `TaxonomyEntry` field accepts an array with an `Ibexa\Contracts\Taxonomy\Value Example using an `Ibexa\Taxonomy\FieldType\TaxonomyEntry\Value` object: ``` php -$taxonomyEntry = $this->taxonomyService->loadEntryByIdentifier('example_entry', 'tags'); -new \Ibexa\Taxonomy\FieldType\TaxonomyEntry\Value( - new \Ibexa\Contracts\Taxonomy\Value\TaxonomyEntry( - $taxonomyEntry - ) -); +use Ibexa\Contracts\Taxonomy\Service\TaxonomyServiceInterface; + +/** @var TaxonomyServiceInterface $taxonomyService */ +$taxonomyEntry = $taxonomyService->loadEntryByIdentifier('example_entry', 'tags'); +$taxonomyEntryField = new \Ibexa\Taxonomy\FieldType\TaxonomyEntry\Value($taxonomyEntry); ``` Example using array: ``` php -[ +use Ibexa\Contracts\Taxonomy\Value\TaxonomyEntry; + +/** @var TaxonomyEntry $taxonomyEntry */ +return [ 'taxonomy_entry' => $taxonomyEntry, // load Entry using TaxonomyService -] +]; ``` ### Value object @@ -49,12 +51,14 @@ The constructor accepts an `Ibexa\Contracts\Taxonomy\Value\TaxonomyEntry` object ``` php // Constructor example +use Ibexa\Contracts\Taxonomy\Service\TaxonomyServiceInterface; use Ibexa\Taxonomy\FieldType\TaxonomyEntry; // Fetches TaxonomyEntry from TaxonomyService -$taxonomyEntry = $this->taxonomyService->loadEntryByIdentifier('example_entry', 'tags'); -  -// Instantiates a checkbox value with a checked state +/** @var TaxonomyServiceInterface $taxonomyService */ +$taxonomyEntry = $taxonomyService->loadEntryByIdentifier('example_entry', 'tags'); + +// Instantiates a taxonomy entry value $taxonomyEntryFieldTypeValue = new TaxonomyEntry\Value($taxonomyEntry); ``` diff --git a/docs/content_management/field_types/field_type_reference/textlinefield.md b/docs/content_management/field_types/field_type_reference/textlinefield.md index 0b2ed44c99..abb5912f8c 100644 --- a/docs/content_management/field_types/field_type_reference/textlinefield.md +++ b/docs/content_management/field_types/field_type_reference/textlinefield.md @@ -35,11 +35,11 @@ The length of the string provided must be between the minimum length defined in The default value for both properties is 0, which means that the validation is disabled by default. To set the validation properties, the `validateValidatorConfiguration()` method needs to be inspected, which receives an array with `minStringLength` and `maxStringLength` like in the following representation: -```php +``` php [ 'StringLengthValidator' => [ - 'maxStringLength' => 60 - 'minStringLength' => 1 - ] -] + 'maxStringLength' => 60, + 'minStringLength' => 1, + ], +]; ``` diff --git a/docs/content_management/field_types/field_type_reference/timefield.md b/docs/content_management/field_types/field_type_reference/timefield.md index 062270a9af..a7a6b36ed5 100644 --- a/docs/content_management/field_types/field_type_reference/timefield.md +++ b/docs/content_management/field_types/field_type_reference/timefield.md @@ -75,7 +75,7 @@ The Field definition of this field type can be configured with several options: use Ibexa\Core\FieldType\Time\Type; $settings = [ - "defaultType" => DateAndTime::DEFAULT_EMPTY + 'defaultType' => Type::DEFAULT_EMPTY, ]; ``` diff --git a/docs/content_management/field_types/field_type_reference/urlfield.md b/docs/content_management/field_types/field_type_reference/urlfield.md index f3464fed50..b9da287a75 100644 --- a/docs/content_management/field_types/field_type_reference/urlfield.md +++ b/docs/content_management/field_types/field_type_reference/urlfield.md @@ -30,8 +30,9 @@ The Value class of this field type contains the following properties: ``` php // Value object content example -$url->link = "https://www.ibexa.co"; -$url->text = "Ibexa"; +/** @var \Ibexa\Core\FieldType\Url\Value $url */ +$url->link = 'https://www.ibexa.co'; +$url->text = 'Ibexa'; ``` #### Constructor @@ -41,9 +42,10 @@ It expects two comma-separated strings, corresponding to the link and text. ``` php // Constructor example +use Ibexa\Core\FieldType\Url as Url; // Instantiates an Url Value object -$UrlValue = new Url\Value( "https://www.ibexa.co/", "Ibexa" ); +$UrlValue = new Url\Value('https://www.ibexa.co/', 'Ibexa'); ``` ### Hash format @@ -53,11 +55,11 @@ $UrlValue = new Url\Value( "https://www.ibexa.co/", "Ibexa" ); | `link` | `string` | Link content. | "https://www.ibexa.co/" | | `text` | `string` | Text content. | "Ibexa" | -```php +``` php // Example of the hash value in PHP $hash = [ - "link" => "https://www.ibexa.co/", - "text" => "Ibexa" + 'link' => 'https://www.ibexa.co/', + 'text' => 'Ibexa', ]; ``` diff --git a/docs/content_management/field_types/field_type_search.md b/docs/content_management/field_types/field_type_search.md index 807726cb40..4a5bcb9702 100644 --- a/docs/content_management/field_types/field_type_search.md +++ b/docs/content_management/field_types/field_type_search.md @@ -21,11 +21,13 @@ They're described below in further detail. To be able to query data properly an indexable field type also is required to return search specification. You must return an associative array of `Ibexa\Contracts\Core\Search\FieldType` instances from this method, which could look like: -```php -[ - 'url' => new Search\FieldType\StringField(), +``` php +use Ibexa\Contracts\Core\Search; + +return [ + 'url' => new Search\FieldType\StringField(), 'text' => new Search\FieldType\StringField(), -] +]; ``` This example from the `Url` field type shows that the field type always returns two indexable values, both strings. diff --git a/docs/content_management/field_types/field_type_storage.md b/docs/content_management/field_types/field_type_storage.md index 84c05872ec..156081eb01 100644 --- a/docs/content_management/field_types/field_type_storage.md +++ b/docs/content_management/field_types/field_type_storage.md @@ -147,7 +147,7 @@ services: autoconfigure: true public: false - App\FieldType\MyField\Storage\MyFieldStorage: ~ + App\FieldType\MyField\Storage\MyFieldStorage: tags: - {name: ibexa.field_type.storage.external.handler, alias: myfield} ``` diff --git a/docs/content_management/field_types/field_type_validation.md b/docs/content_management/field_types/field_type_validation.md index d2f9a5553a..35229d2e11 100644 --- a/docs/content_management/field_types/field_type_validation.md +++ b/docs/content_management/field_types/field_type_validation.md @@ -21,13 +21,13 @@ For example, for the `ibexa_string` type, the validator schema could be: [ 'stringLength' => [ 'minStringLength' => [ - 'type' => 'int', + 'type' => 'int', 'default' => 0, ], 'maxStringLength' => [ - 'type' => 'int' + 'type' => 'int', 'default' => null, - ] + ], ], ]; ``` diff --git a/docs/content_management/field_types/form_and_template.md b/docs/content_management/field_types/form_and_template.md index 421efa48fc..5c4913a80b 100644 --- a/docs/content_management/field_types/form_and_template.md +++ b/docs/content_management/field_types/form_and_template.md @@ -24,31 +24,36 @@ The `FieldValueFormMapperInterface::mapFieldValueForm` method accepts two argume You have to add your form type to the content editing form. The example shows how `ibexa_boolean` injects the form: ``` php -use Ibexa\Contracts\ContentForms\Data\Content\FieldData; use Ibexa\ContentForms\Form\Type\FieldType\CheckboxFieldType; +use Ibexa\Contracts\ContentForms\Data\Content\FieldData; +use Ibexa\Contracts\ContentForms\FieldType\FieldValueFormMapperInterface; use Symfony\Component\Form\FormInterface; -public function mapFieldValueForm(FormInterface $fieldForm, FieldData $data) +class MyMapper implements FieldValueFormMapperInterface { - $fieldDefinition = $data->fieldDefinition; - $formConfig = $fieldForm->getConfig(); - - $fieldForm - ->add( - $formConfig->getFormFactory()->createBuilder() - ->create( - 'value', - CheckboxFieldType::class, - [ - 'required' => $fieldDefinition->isRequired, - 'label' => $fieldDefinition->getName( - $formConfig->getOption('languageCode') - ), - ] - ) - ->setAutoInitialize(false) - ->getForm() - ); + /** @param FormInterface $fieldForm */ + public function mapFieldValueForm(FormInterface $fieldForm, FieldData $data): void + { + $fieldDefinition = $data->getFieldDefinition(); + $formConfig = $fieldForm->getConfig(); + + $fieldForm + ->add( + $formConfig->getFormFactory()->createBuilder() + ->create( + 'value', + CheckboxFieldType::class, + [ + 'required' => $fieldDefinition->isRequired, + 'label' => $fieldDefinition->getName( + $formConfig->getOption('languageCode') + ), + ] + ) + ->setAutoInitialize(false) + ->getForm() + ); + } } ``` @@ -64,37 +69,44 @@ You can use a [`DataTransformer`]([[= symfony_doc =]]/form/data_transformers.htm Providing definition editing support is almost identical to creating content editing support. The only difference are field names: ``` php +use Ibexa\AdminUi\FieldType\FieldDefinitionFormMapperInterface; use Ibexa\AdminUi\Form\Data\FieldDefinitionData; use Ibexa\ContentForms\Form\Type\FieldType\CountryFieldType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\FormInterface; -public function mapFieldDefinitionForm(FormInterface $fieldDefinitionForm, FieldDefinitionData $data) +class MyMapper implements FieldDefinitionFormMapperInterface { - $fieldDefinitionForm - ->add( - 'isMultiple', - CheckboxType::class, [ - 'required' => false, - 'property_path' => 'fieldSettings[isMultiple]', - 'label' => 'field_definition.ibexa_country.is_multiple', - ] - ) - ->add( - $fieldDefinitionForm->getConfig()->getFormFactory()->createBuilder() - ->create( - 'defaultValue', - CountryFieldType::class, [ - 'choices_as_values' => true, - 'multiple' => true, - 'expanded' => false, - 'required' => false, - 'label' => 'field_definition.ibexa_country.default_value', - ] - ) - // Deactivate auto-initialize as you're not on the root form. - ->setAutoInitialize(false)->getForm() - ); + /** @param FormInterface $fieldDefinitionForm */ + public function mapFieldDefinitionForm(FormInterface $fieldDefinitionForm, FieldDefinitionData $data): void + { + $fieldDefinitionForm + ->add( + 'isMultiple', + CheckboxType::class, + [ + 'required' => false, + 'property_path' => 'fieldSettings[isMultiple]', + 'label' => 'field_definition.ibexa_country.is_multiple', + ] + ) + ->add( + $fieldDefinitionForm->getConfig()->getFormFactory()->createBuilder() + ->create( + 'defaultValue', + CountryFieldType::class, + [ + 'choices_as_values' => true, + 'multiple' => true, + 'expanded' => false, + 'required' => false, + 'label' => 'field_definition.ibexa_country.default_value', + ] + ) + // Deactivate auto-initialize as you're not on the root form. + ->setAutoInitialize(false)->getForm() + ); + } } ``` @@ -189,7 +201,7 @@ If you don't use the design engine, apply the following configuration: ``` yaml ibexa: - systems: + system: admin_group: field_templates: - { template: 'adminui/field/custom_field_view.html.twig', priority: 10 } diff --git a/docs/content_management/field_types/type_and_value.md b/docs/content_management/field_types/type_and_value.md index bc4bddac48..085755f52b 100644 --- a/docs/content_management/field_types/type_and_value.md +++ b/docs/content_management/field_types/type_and_value.md @@ -172,12 +172,12 @@ An example schema could look like this: [ 'backupData' => [ 'type' => 'bool', - 'default' => false + 'default' => false, ], 'defaultValue' => [ 'type' => 'string', - 'default' => 'Default Value' - ] + 'default' => 'Default Value', + ], ]; ``` diff --git a/docs/content_management/file_management/file_management.md b/docs/content_management/file_management/file_management.md index 824c24438b..c9dcc863da 100644 --- a/docs/content_management/file_management/file_management.md +++ b/docs/content_management/file_management/file_management.md @@ -8,9 +8,11 @@ description: Configurations and management of binary files. To access binary files from the PHP API, use the `Ibexa\Core\IO\IOServiceInterface::loadBinaryFile()` method: -```php -$file = $this->ioService->loadBinaryFile($field->value->id); -$fileContent = $this->ioService->getFileContents($file); +``` php +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\Field $field */ +/** @var \Ibexa\Core\IO\IOServiceInterface $ioService */ +$file = $ioService->loadBinaryFile($field->value->id); +$fileContent = $ioService->getFileContents($file); ``` ## Handling binary files diff --git a/docs/content_management/forms/create_form_attribute.md b/docs/content_management/forms/create_form_attribute.md index 1f73910e01..d1bc949653 100644 --- a/docs/content_management/forms/create_form_attribute.md +++ b/docs/content_management/forms/create_form_attribute.md @@ -90,7 +90,7 @@ Now you have to implement the field, and make sure the value from the Rich Text Create a `src/FormBuilder/Form/Type/CheckboxWithRichtextDescriptionType.php` file. -```php +``` php [[= include_code('code_samples/forms/custom_form_attribute/src/FormBuilder/Form/Type/CheckboxWithRichtextDescriptionType.php') =]] ``` @@ -98,7 +98,7 @@ Create a `src/FormBuilder/Form/Type/CheckboxWithRichtextDescriptionType.php` fil To implement a field mapper, create a `src/FormBuilder/FieldType/Field/Mapper/CheckboxWithRichtextDescriptionFieldMapper.php` file. -```php +``` php [[= include_code('code_samples/forms/custom_form_attribute/src/FormBuilder/FieldType/Field/Mapper/CheckboxWithRichtextDescriptionFieldMapper.php') =]] ``` @@ -110,7 +110,7 @@ The new field is based on a checkbox, so to display the submissions of this fiel Create a `src/FormBuilder/FormSubmission/Converter/RichtextDescriptionFieldSubmissionConverter.php` file. -```php +``` php [[= include_code('code_samples/forms/custom_form_attribute/src/FormBuilder/FormSubmission/Converter/RichtextDescriptionFieldSubmissionConverter.php') =]] ``` diff --git a/docs/content_management/images/add_image_asset_from_dam.md b/docs/content_management/images/add_image_asset_from_dam.md index f06a6b74b3..b8a8271fe2 100644 --- a/docs/content_management/images/add_image_asset_from_dam.md +++ b/docs/content_management/images/add_image_asset_from_dam.md @@ -49,15 +49,15 @@ Next, in `config/packages/ibexa.yaml`, set the `dam.html.twig` template for the For more information about displaying content, see [Content rendering](render_content.md). ``` yaml - ibexa: - system: - site: - content_view: - embed: - image_dam: - template: '@ibexadesign/embed/dam.html.twig' - match: - Identifier\ContentType: +ibexa: + system: + site: + content_view: + embed: + image_dam: + template: '@ibexadesign/embed/dam.html.twig' + match: + Identifier\ContentType: ``` In your [configuration file](configuration.md#configuration-files) add the following configuration: @@ -101,7 +101,7 @@ In `src/Connector/Dam/Handler` folder, create the `WikimediaCommonsHandler.php` which implements [`search()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Connector-Dam-Handler-Handler.html#method_search) to query the server and [`fetchAsset()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Connector-Dam-Handler-Handler.html#method_fetchAsset) to return asset objects: -```php +``` php [[= include_code('code_samples/back_office/images/src/Connector/Dam/Handler/WikimediaCommonsHandler.php') =]] ``` @@ -120,7 +120,7 @@ The transformation factory maps [[= product_name =]]'s image variations to corre In `src/Connector/Dam/Transformation` folder, create the `WikimediaCommonsTransformationFactory.php` file that resembles the following example, which implements the [`TransformationFactory` interface](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Connector-Dam-Variation-TransformationFactory.html): -```php +``` php [[= include_code('code_samples/back_office/images/src/Connector/Dam/Transformation/WikimediaCommonsTransformationFactory.php') =]] ``` diff --git a/docs/content_management/images/configure_image_editor.md b/docs/content_management/images/configure_image_editor.md index b8a4f97f2c..ebbca8eed9 100644 --- a/docs/content_management/images/configure_image_editor.md +++ b/docs/content_management/images/configure_image_editor.md @@ -68,7 +68,9 @@ By default, additional information stores the coordinates of the [focal point]([ To modify the value of additional information programmatically, you can set a value of the `Image` field by using the PHP API, for example: ``` php -new FieldValue([ +use Ibexa\Core\FieldType\Image\Value as FieldValue; + +$value = new FieldValue([ 'data' => [ 'width' => '100', 'height' => '200', @@ -82,5 +84,5 @@ new FieldValue([ 'author' => 'John Smith', ], ], - ]), + ]); ``` diff --git a/docs/content_management/images/images.md b/docs/content_management/images/images.md index 73b29e9575..1f066a4adb 100644 --- a/docs/content_management/images/images.md +++ b/docs/content_management/images/images.md @@ -214,13 +214,13 @@ The controller's definition (that you place in the `config/services.yaml` file u [[= include_file('code_samples/back_office/images/config/services.yaml', 0, 8) =]] ``` -```php +``` php [[= include_code('code_samples/back_office/images/src/SvgController.php') =]] ``` To be able to use a proper link in your templates, you also need a dedicated Twig extension: -```php +``` php [[= include_code('code_samples/back_office/images/src/SvgExtension.php') =]] ``` diff --git a/docs/content_management/taxonomy/taxonomy.md b/docs/content_management/taxonomy/taxonomy.md index 227e631150..d395888461 100644 --- a/docs/content_management/taxonomy/taxonomy.md +++ b/docs/content_management/taxonomy/taxonomy.md @@ -192,10 +192,9 @@ By default, the system returns three suggestions. You can change the default number if needed by altering the following setting: ``` yaml hl_lines="4" -ibexa: - taxonomy: +ibexa_taxonomy: text_to_taxonomy: - default_suggested_taxonomies_limit: 5 + default_suggested_taxonomies_limit: 5 ``` You can also override this setting per AI action by editing its configuration. diff --git a/docs/content_management/taxonomy/taxonomy_api.md b/docs/content_management/taxonomy/taxonomy_api.md index e4f1ac7ec7..40498a80ec 100644 --- a/docs/content_management/taxonomy/taxonomy_api.md +++ b/docs/content_management/taxonomy/taxonomy_api.md @@ -21,9 +21,11 @@ and use `TaxonomyServiceInterface::loadEntryByIdentifier()`: A taxonomy entry identifier is unique per taxonomy. If you have [several taxonomies](taxonomy.md#customize-taxonomy-structure), you can increase code readability by always passing the taxonomy identifier even when it's the default one. The default taxonomy is `tags` if it exists, else the first configured taxonomy (see `\Ibexa\Taxonomy\Service\TaxonomyConfiguration::getDefaultTaxonomyName` for details). ``` php - $springs[] = $this->taxonomyService->loadEntryByIdentifier('spring', 'tags'); - $springs[] = $this->taxonomyService->loadEntryByIdentifier('spring', 'events'); - $springs[] = $this->taxonomyService->loadEntryByIdentifier('spring', 'devices'); + /** @var array $springs */ + /** @var \Ibexa\Contracts\Taxonomy\Service\TaxonomyServiceInterface $taxonomyService */ + $springs[] = $taxonomyService->loadEntryByIdentifier('spring', 'tags'); + $springs[] = $taxonomyService->loadEntryByIdentifier('spring', 'events'); + $springs[] = $taxonomyService->loadEntryByIdentifier('spring', 'devices'); ``` You can also get a taxonomy entry from the ID of its underlying content item, by using `TaxonomyServiceInterface::loadEntryByContentId()`. diff --git a/docs/content_management/url_management/url_api.md b/docs/content_management/url_management/url_api.md index 749c2037ed..587cee6d1c 100644 --- a/docs/content_management/url_management/url_api.md +++ b/docs/content_management/url_management/url_api.md @@ -17,7 +17,7 @@ in which you need to specify: - offset for search hits, used for paging the results - query limit. If value is `0`, search query doesn't return any search hits -```php +``` php {skip-validation} // ... [[= include_file('code_samples/api/public_php_api/src/Command/FindUrlCommand.php', 5, 6) =]][[= include_file('code_samples/api/public_php_api/src/Command/FindUrlCommand.php', 7, 10) =]] // ... diff --git a/docs/content_management/url_management/url_management.md b/docs/content_management/url_management/url_management.md index 52431fe5db..d1ff21d755 100644 --- a/docs/content_management/url_management/url_management.md +++ b/docs/content_management/url_management/url_management.md @@ -66,13 +66,13 @@ ibexa: url_checker: handlers: http: - enabled: true - batch_size: 64 + enabled: true + batch_size: 64 https: - enabled: true - ignore_certificate: false + enabled: true + ignore_certificate: false mailto: - enabled: false + enabled: false ``` Available options are protocol-specific. @@ -99,36 +99,13 @@ For more information about [[= product_name_base =]] configuration, see [Configu ### Custom protocol support You can extend the external URL address validation with a custom protocol. -To do this, you must provide a service that implements the `Ibexa\Bundle\Core\URLChecker\URLHandlerInterface` interface: -s - -```php -getURLWildcardService(); -$repository->sudo(function ($repository) use ($urlWildcardService, $source, $destination, $redirect) { +$repository->sudo(static function ($repository) use ($urlWildcardService, $source, $destination, $redirect): void { $urlWildcardService->create($source, $destination, $redirect); }); ``` diff --git a/docs/content_management/user_generated_content.md b/docs/content_management/user_generated_content.md index 4a12ecc3bf..a35612334e 100644 --- a/docs/content_management/user_generated_content.md +++ b/docs/content_management/user_generated_content.md @@ -56,14 +56,17 @@ For example, `/content/edit/draft/1/5/eng-GB` enables you to edit draft 5 of con You can use custom templates for the content editing forms. -Define the templates under the `ibexa.system..content_edit.templates` [configuration key](configuration.md#configuration-files): +Define the templates under the `ibexa.system..content_edit_view` [configuration key](configuration.md#configuration-files): ``` yaml ibexa: system: default: - content_edit: - templates: - edit: content/edit/content_edit.html.twig - create_draft: content/edit/content_create_draft.html.twig + content_edit_view: + full: + : + template: content/edit/content_edit.html.twig + match: true + params: + viewbaseLayout: '@ibexadesign/ui/layout.html.twig' ``` diff --git a/docs/content_management/workflow/add_custom_workflow_action.md b/docs/content_management/workflow/add_custom_workflow_action.md index 4c9967058a..8f70416006 100644 --- a/docs/content_management/workflow/add_custom_workflow_action.md +++ b/docs/content_management/workflow/add_custom_workflow_action.md @@ -81,7 +81,9 @@ You can also modify the context using the `setContext()` method. For example, you can override the message typed by the user: ``` php +/** @var array $context */ +/** @var \Symfony\Component\Workflow\Event\TransitionEvent $event */ $new_context = $context; -$new_context['message'] = "This article went through proofreading"; +$new_context['message'] = 'This article went through proofreading'; $event->setContext($new_context); ``` diff --git a/docs/customer_management/cp_page_builder.md b/docs/customer_management/cp_page_builder.md index 7440f3012e..9e6975b225 100644 --- a/docs/customer_management/cp_page_builder.md +++ b/docs/customer_management/cp_page_builder.md @@ -51,7 +51,7 @@ ibexa: languages: [ eng-GB ] content: tree_root: - location_id: location_id_of_customer_portal + location_id: 12345 # location_id_of_customer_portal excluded_uri_prefixes: [ /media/, /images/ ] ``` @@ -135,7 +135,7 @@ ibexa: languages: [ eng-GB ] content: tree_root: - location_id: location_id_of_customer_portals_root_folder + location_id: 12345 # location_id_of_customer_portals_root_folder excluded_uri_prefixes: [ /media/, /images/ ] ``` @@ -233,7 +233,7 @@ ibexa: page_layout: "@App/my_page_layout.html.twig" content: tree_root: - location_id: location_id_of_customer_portals_root_folder + location_id: 12345 #location_id_of_customer_portals_root_folder excluded_uri_prefixes: [ /media/, /images/ ] ``` diff --git a/docs/infrastructure_and_maintenance/cache/http_cache/content_aware_cache.md b/docs/infrastructure_and_maintenance/cache/http_cache/content_aware_cache.md index 29f645630f..f7954f83a1 100644 --- a/docs/infrastructure_and_maintenance/cache/http_cache/content_aware_cache.md +++ b/docs/infrastructure_and_maintenance/cache/http_cache/content_aware_cache.md @@ -173,6 +173,8 @@ Examples for adding specific content tags using the autowireable `ContentTagInte ``` php /** @var \Ibexa\Contracts\HttpCache\Handler\ContentTagInterface $tagHandler */ +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\Content $content */ +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\Location $location */ // Example for tagging everything needed for Content: $tagHandler->addContentTags([$content->id]); @@ -192,6 +194,8 @@ In PHP, FOSHttpCache exposes the `fos_http_cache.http.symfony_response_tagger` s The following example adds minimal tags when ID 33 and 34 are rendered in ESI, but parent response needs these tags to get refreshed if they're deleted: ``` php +use Ibexa\Contracts\HttpCache\Handler\ContentTagInterface; + /** @var \FOS\HttpCacheBundle\Http\SymfonyResponseTagger $responseTagger */ $responseTagger->addTags([ContentTagInterface::RELATION_PREFIX . '33', ContentTagInterface::RELATION_PREFIX . '34']); ``` @@ -203,9 +207,9 @@ See [Tagging from code](https://foshttpcachebundle.readthedocs.io/en/latest/feat For custom or built-in controllers (for example, REST) that still use `X-Location-Id`, `XLocationIdResponseSubscriber` handles translating this header to tags. It supports singular and comma-separated location ID value(s): -```php +``` php /** @var \Symfony\Component\HttpFoundation\Response $response */ -$response->headers->set('X-Location-Id', 123); +$response->headers->set('X-Location-Id', '123'); // Alternatively using several Location ID values $response->headers->set('X-Location-Id', '123,212,42'); @@ -294,7 +298,7 @@ With the same content structure as above, the `[Child]` location is moved below The new structure is then: -```yaml +```text - [Home] (content-id=52, location-id=2) ez-all c52 ct42 l2 pl1 p1 p2 | @@ -322,8 +326,11 @@ In other words, HTTP Cache for `[Parent1]`, children of `[Parent1]` ( if any ), While the system purges tags whenever API is used to change data, you may need to purge directly from code. For that you can use the built-in purge client: -```php +``` php +use Ibexa\Contracts\HttpCache\Handler\ContentTagInterface; + /** @var \Ibexa\Contracts\HttpCache\PurgeClient\PurgeClientInterface $purgeClient */ +/** @var \Ibexa\Contracts\Core\Repository\Values\Content\Location $location */ // Example for purging by Location ID: $purgeClient->purge([ContentTagInterface::LOCATION_PREFIX . $location->id]); diff --git a/docs/infrastructure_and_maintenance/cache/http_cache/context_aware_cache.md b/docs/infrastructure_and_maintenance/cache/http_cache/context_aware_cache.md index 9d299b4f34..471a46fd4e 100644 --- a/docs/infrastructure_and_maintenance/cache/http_cache/context_aware_cache.md +++ b/docs/infrastructure_and_maintenance/cache/http_cache/context_aware_cache.md @@ -91,9 +91,12 @@ This a low effort solution, and can be enough for one fragment that is reused ac Example: -```php - // Inside a custom controller action, or even a Content View controller - $response->setVary('Cookie'); +``` php +use Symfony\Component\HttpFoundation\Response; + +// Inside a custom controller action, or even a Content View controller +/** @var Response $response */ +$response->setVary('Cookie'); ``` 2\. Ajax/JS lookup to "uncached" custom Symfony controllers: @@ -139,15 +142,28 @@ To avoid overloading any application code, take advantage of Symfony's event sys 1\. Add a [Response event (`kernel.response`)]([[= symfony_doc =]]/reference/events.html#kernel-response) [listener or subscriber]([[= symfony_doc =]]/event_dispatcher.html) to add your own hash to `/_fos_user_context_hash`: -```php -public function addPreferenceHash(FilterResponseEvent $event) +``` php +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpKernel\Event\ResponseEvent; + +final class MyEventSubscriber implements EventSubscriberInterface { - $response = $event->getResponse(); - if ($response->headers->get('Content-Type') !== 'application/vnd.fos.user-context-hash') { - return; + public static function getSubscribedEvents(): array + { + return [ + ResponseEvent::class => 'addPreferenceHash', + ]; } - $response->headers->set('X-User-Preference-Hash', ''); + public function addPreferenceHash(ResponseEvent $event): void + { + $response = $event->getResponse(); + if ($response->headers->get('Content-Type') !== 'application/vnd.fos.user-context-hash') { + return; + } + + $response->headers->set('X-User-Preference-Hash', ''); + } } ``` @@ -186,7 +202,10 @@ public function addPreferenceHash(FilterResponseEvent $event) 3\. Add `Vary` in your custom controller or content view controller: -```php +``` php +use Symfony\Component\HttpFoundation\Response; + +/** @var Response $response */ $response->setVary('X-User-Preference-Hash'); // If you _also_ need to vary on [[= product_name =]] permissions, instead use: diff --git a/docs/infrastructure_and_maintenance/cache/http_cache/reverse_proxy.md b/docs/infrastructure_and_maintenance/cache/http_cache/reverse_proxy.md index d9c3290d48..26a19a121d 100644 --- a/docs/infrastructure_and_maintenance/cache/http_cache/reverse_proxy.md +++ b/docs/infrastructure_and_maintenance/cache/http_cache/reverse_proxy.md @@ -90,8 +90,11 @@ framework: On Upsun, Varnish doesn't have a static IP, like with [AWS LB]([[= symfony_doc =]]/deployment/proxies.html#but-what-if-the-ip-of-my-reverse-proxy-changes-constantly). For this reason, the `TRUSTED_PROXIES` env variable supports being set to value `REMOTE_ADDR`, which is equal to: - ```php - Request::setTrustedProxies([$request->server->get('REMOTE_ADDR')], Request::HEADER_X_FORWARDED_ALL); + ``` php + use Symfony\Component\HttpFoundation\Request; + + /** @var \Symfony\Component\HttpFoundation\Request $request */ + Request::setTrustedProxies([$request->server->get('REMOTE_ADDR')], Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PROTO | Request::HEADER_X_FORWARDED_PORT); ``` When trusting remote IP like this, make sure your application is only accessible through Varnish. @@ -142,6 +145,9 @@ ibexa: If the Varnish server is protected by Basic Auth, specify the Basic Auth credentials within the `purge_servers` setting using the format: ``` yaml +ibexa: + system: + my_siteaccess_group: http_cache: purge_servers: [http://myuser:mypasswd@my.varnish.server:8081] ``` diff --git a/docs/infrastructure_and_maintenance/cache/persistence_cache.md b/docs/infrastructure_and_maintenance/cache/persistence_cache.md index 8f98350b64..d7cd92c27e 100644 --- a/docs/infrastructure_and_maintenance/cache/persistence_cache.md +++ b/docs/infrastructure_and_maintenance/cache/persistence_cache.md @@ -249,10 +249,14 @@ This service is an instance of `Symfony\Component\Cache\Adapter\TagAwareAdapterI Like any other service, you can also get the cache service with the [service container](php_api.md#service-container) like so: ``` php +use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; + // Getting the cache service in PHP -/** @var \Symfony\Component\Cache\Adapter\TagAwareAdapterInterface */ +/** @var ContainerInterface $container */ $pool = $container->get('ibexa.cache_pool'); +/** @var TagAwareAdapterInterface $pool */ ``` ### Using the cache service @@ -260,13 +264,19 @@ $pool = $container->get('ibexa.cache_pool'); Example usage of the cache service: ``` php +use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; + // Example -$cacheItem = $pool->getItem("myApp-object-${id}"); +/** @var TagAwareAdapterInterface $pool */ +/** @var ContainerInterface $container */ +/** @var int $id */ +$cacheItem = $pool->getItem("myApp-object-{$id}"); if ($cacheItem->isHit()) { return $cacheItem->get(); } -$myObject = $container->get('my_app.backend_service')->loadObject($id) +$myObject = $container->get('my_app.backend_service')->loadObject($id); $cacheItem->set($myObject); $cacheItem->tag(['myApp-category-' . $myObject->categoryId]); $pool->save($cacheItem); @@ -295,6 +305,10 @@ For more info on usage, see [Symfony Cache's documentation]([[= symfony_doc =]]/ Persistence cache prefixes it's cache using "ibx-". Clearing persistence cache can thus be done in the following ways: ``` php +use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface; + +/** @var TagAwareAdapterInterface $pool */ +/** @var int $contentId */ // To clear all cache (not recommended without a good reason) $pool->clear(); diff --git a/docs/multisite/languages/automated_translations.md b/docs/multisite/languages/automated_translations.md index 38a6ec1bb2..7e17dec7fa 100644 --- a/docs/multisite/languages/automated_translations.md +++ b/docs/multisite/languages/automated_translations.md @@ -34,7 +34,7 @@ composer require ibexa/automated-translation Symfony Flex installs and activates the package. However, you must modify the `config/bundles.php` file to change the bundle loading order so that `IbexaAutomatedTranslationBundle` is loaded before `IbexaAdminUiBundle`: - ```php + ``` php translator = $translator; -} - -private function getTranslatedDescription(): string +final readonly class MyService { - return $this->translator->trans( - 'custom.extension.description', - [], - 'custom_extension' - ); + public function __construct(private TranslatorInterface $translator) + { + } + + public function getTranslatedDescription(): string + { + return $this->translator->trans( + 'custom.extension.description', + [], + 'custom_extension' + ); + } } ``` diff --git a/docs/multisite/site_factory/site_factory.md b/docs/multisite/site_factory/site_factory.md index 74bed2fefb..3afd0628e9 100644 --- a/docs/multisite/site_factory/site_factory.md +++ b/docs/multisite/site_factory/site_factory.md @@ -204,7 +204,7 @@ Keep in mind that with disabled Site Factory you're unable to add new sites or u doctrine: dbal: connections: - ... + # ... # This connection is dedicated for SiteFactory to avoid known issues site_factory: ``` @@ -214,7 +214,7 @@ doctrine: ``` yaml framework: cache: - ... + # ... pools: # This pool should be used only by SiteFactory bundle site_factory_pool: diff --git a/docs/multisite/siteaccess/injecting_siteaccess.md b/docs/multisite/siteaccess/injecting_siteaccess.md index 87988bd5ae..5ba5aef588 100644 --- a/docs/multisite/siteaccess/injecting_siteaccess.md +++ b/docs/multisite/siteaccess/injecting_siteaccess.md @@ -17,8 +17,10 @@ services: ``` ``` php +siteAccessService = $siteAccessService; - $this->contentService = $contentService; + public function __construct(private readonly SiteAccessServiceInterface $siteAccessService, private readonly ContentService $contentService) + { } } ``` diff --git a/docs/multisite/siteaccess/siteaccess_aware_configuration.md b/docs/multisite/siteaccess/siteaccess_aware_configuration.md index e26575ef82..24cc5f136b 100644 --- a/docs/multisite/siteaccess/siteaccess_aware_configuration.md +++ b/docs/multisite/siteaccess/siteaccess_aware_configuration.md @@ -27,8 +27,11 @@ For more information about the ConfigResolver, namespaces and scopes, see [confi The example below assumes you're using an `Acme\ExampleBundle`. Remember to register the bundle by adding it to `config/bundles.php`: -``` php -Acme\ExampleBundle\AcmeExampleBundle::class => ['all' => true], +``` php {skip-validation} +return [ + // ... + Acme\ExampleBundle\AcmeExampleBundle::class => ['all' => true], +]; ``` ## Parsing semantic configuration diff --git a/docs/permissions/custom_policies.md b/docs/permissions/custom_policies.md index cd85f9211a..67e209f1ed 100644 --- a/docs/permissions/custom_policies.md +++ b/docs/permissions/custom_policies.md @@ -21,16 +21,16 @@ Function value is an array of available limitations, identified by the alias dec If no limitation is provided, value can be `null` or an empty array. ``` php -[ - "content" => [ - "read" => ["Class", "ParentClass", "Node", "Language"], - "edit" => ["Class", "ParentClass", "Language"] +$config = [ + 'content' => [ + 'read' => ['Class', 'ParentClass', 'Node', 'Language'], + 'edit' => ['Class', 'ParentClass', 'Language'], ], - "custom_module" => [ - "custom_function_1" => null, - "custom_function_2" => ["CustomLimitation"] + 'custom_module' => [ + 'custom_function_1' => null, + 'custom_function_2' => ['CustomLimitation'], ], -] +]; ``` Limitations need to be implemented as *Limitation types* and declared as services identified with `ibexa.permissions.limitation_type` tag. @@ -39,7 +39,9 @@ Name provided in the hash for each limitation is the same value set in the `alia For example: ``` php -addConfig([ - "custom_module" => [ - "custom_function_1" => null, - "custom_function_2" => ["CustomLimitation"], + 'custom_module' => [ + 'custom_function_1' => null, + 'custom_function_2' => ['CustomLimitation'], ], ]); } @@ -96,25 +98,30 @@ For example, `translations/forms.en.yaml`: You can also implement `TranslationContainerInterface` to provide those translations in your policy provider class: ``` php -addConfig([ - "custom_module" => [ - "custom_function_1" => null, - "custom_function_2" => ["CustomLimitation"], + 'custom_module' => [ + 'custom_function_1' => null, + 'custom_function_2' => ['CustomLimitation'], ], ]); } + /** @return array<\JMS\TranslationBundle\Model\Message> */ public static function getTranslationMessages(): array { return [ @@ -158,7 +165,7 @@ The type class implements `Ibexa\Contracts\Core\Limitation\Type`. - `accept`, `validate` and `buildValue` implement the value class usage logic. - `evaluate` challenges a limitation value against the current user, the subject object and other context objects to return if the limitation is satisfied or not. `evaluate` is, among others, used by `PermissionResolver::canUser` (to check if a user that has access to a function can use it in its limitations) and `PermissionResolver::lookupLimitations`. -```php +``` php [[= include_code('code_samples/back_office/limitation/src/Security/Limitation/CustomLimitationType.php') =]] ``` @@ -250,7 +257,7 @@ For example, `translations/ibexa_content_forms_policies.en.yaml`: Check if current user has this custom limitation set to true from a custom controller: -```php +``` php [[= include_code('code_samples/back_office/limitation/src/Controller/CustomController.php') =]] ``` @@ -277,7 +284,7 @@ With this setup, users with `content/read` permission can view the form, but can First, create the `FormPolicyProvider.php` policy provider that registers the new `form` module and the `read_submissions` function by injecting the custom permission into the configuration tree: -```php hl_lines="14-18 26" +``` php hl_lines="14-18 26" [[= include_code('code_samples/back_office/limitation/src/Security/FormPolicyProvider.php') =]] ``` @@ -311,7 +318,7 @@ This way, after you clean the cache, the new policy becomes available when you [ To enforce the policy on the PHP API level, decorate the form submission service to enforce permission checks. In `src/Security`, create the `FormSubmissionServiceDecorator.php` file: -```php hl_lines="19 33 40 41 44" +``` php hl_lines="19 33 40 41 44" [[= include_code('code_samples/back_office/limitation/src/Security/Form/FormSubmissionServiceDecorator.php') =]] ``` @@ -335,7 +342,7 @@ This way, users can't access the submission data unless they have the `form/read To enforce the policy in the back office, decorate the **Submissions** tab to hide it when the user lacks permission. In `src/Security`, create the `FormSubmissionsTabDecorator.php` file: -```php hl_lines="19 30 60-61" +``` php hl_lines="19 30 60-61" [[= include_code('code_samples/back_office/limitation/src/Security/Form/FormSubmissionsTabDecorator.php') =]] ``` diff --git a/docs/permissions/permission_overview.md b/docs/permissions/permission_overview.md index 6a8b2f1dbe..5f89078342 100644 --- a/docs/permissions/permission_overview.md +++ b/docs/permissions/permission_overview.md @@ -38,7 +38,7 @@ You can control access to a custom controller by implementing the `performAccess In the following example the user doesn't have access to the controller unless they have the `section/view` policy: -``` php +``` php {skip-validation} use Ibexa\Core\MVC\Symfony\Security\Authorization\Attribute; public function performAccessCheck(): void @@ -63,7 +63,7 @@ public function performAccessCheck(): void To check if a user has access to an operation, use the `isGranted()` method. For example, to check if content can be assigned to a Section: -``` php +``` php {skip-validation} $hasAccess = $this->isGranted( new Attribute('section', 'assign', ['valueObject' => $contentInfo, 'targets' => [$section]]) ); @@ -79,6 +79,6 @@ checks the `content/edit` permission for the provided content item at the provid To block access to a specific action of the controller, add the following to the action's definition: -``` php +``` php {skip-validation} $this->denyAccessUnlessGranted(new Attribute('state', 'administrate')); ``` diff --git a/docs/personalization/enable_personalization.md b/docs/personalization/enable_personalization.md index c5b764a7ef..d5a242bac0 100644 --- a/docs/personalization/enable_personalization.md +++ b/docs/personalization/enable_personalization.md @@ -491,7 +491,7 @@ You can retrieve data returned from the Personalization server and modify it bef To modify recommendation data, subscribe to `RecommendationResponseEvent`. See [`Event/Subscriber/RecommendationEventSubscriber.php`](https://github.com/ibexa/personalization-client/blob/main/src/lib/Event/Subscriber/RecommendationEventSubscriber.php) for an example: -``` php +``` php {skip-validation} public static function getSubscribedEvents(): array { return [ diff --git a/docs/personalization/integrate_recommendation_service.md b/docs/personalization/integrate_recommendation_service.md index a6fab7c00e..740a45ae7b 100644 --- a/docs/personalization/integrate_recommendation_service.md +++ b/docs/personalization/integrate_recommendation_service.md @@ -34,7 +34,7 @@ The following examples show how you can integrate a CLICK event: PHP: -``` php +``` php {skip-validation} $mandator_id = '00000'; $content_type_id = '1'; $product_id = '123'; @@ -57,7 +57,7 @@ ycimg.src=url; A similar tracking image can be placed on a confirmation page that ends the payment process. -``` php +``` php {skip-validation} $server = '//event.perso.ibexa.co'; foreach ($just_bought_products as $product_id) { $tracking = $server.'/api/'.$mandator_id.'/buy/'.urlencode(user_id()).$content_type_id.$product_id; @@ -122,7 +122,7 @@ A response with two recommendations resembles the following object: You can use the following code to make requests and parse results: -``` php +``` php {skip-validation} $mandator_id = '00000'; $license_key = '67890-1234-5678-90123-4567'; $server = "https://reco.perso.ibexa.co"; diff --git a/docs/product_catalog/create_custom_availability_strategy.md b/docs/product_catalog/create_custom_availability_strategy.md index 43f148fe19..1661dd0092 100644 --- a/docs/product_catalog/create_custom_availability_strategy.md +++ b/docs/product_catalog/create_custom_availability_strategy.md @@ -50,6 +50,6 @@ If you're not using [autowiring]([[= symfony_doc =]]/service_container/autowirin To evaluate product availability using a custom strategy, pass the custom context as the second argument to [`ProductAvailabilityServiceInterface::getAvailability()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-ProductAvailabilityServiceInterface.html): -```php +``` php [[= include_code('code_samples/api/product_catalog/src/Command/ProductCommand.php', 122, 127, remove_indent=True) =]] ``` diff --git a/docs/product_catalog/quable/quable_api.md b/docs/product_catalog/quable/quable_api.md index 545788234b..e629e37dc4 100644 --- a/docs/product_catalog/quable/quable_api.md +++ b/docs/product_catalog/quable/quable_api.md @@ -66,7 +66,7 @@ The following sort clauses are supported: For information stored outside of [[= pim_product_name =]], such as [product availability](product_api.md#product-availability) or [pricing](price_api.md), you can use the existing services to manage them: -``` php hl_lines="6 14" +``` php {skip-validation} hl_lines="6 14" // Manage availability [[= include_file('code_samples/api/product_catalog/src/Command/ProductCommand.php', 84, 89, remove_indent=True) =]] // Manage prices diff --git a/docs/recommendations/raptor_integration/connector_installation_configuration.md b/docs/recommendations/raptor_integration/connector_installation_configuration.md index dcb0e9c578..f9c1b42a32 100644 --- a/docs/recommendations/raptor_integration/connector_installation_configuration.md +++ b/docs/recommendations/raptor_integration/connector_installation_configuration.md @@ -35,7 +35,7 @@ To configure the Raptor connector, use the `ibexa.system..connector_rapto - `client` - tracking is executed in the browser using JavaScript snippets generated by the [Twig functions](recommendations_twig_functions.md) and included in the templates. This approach may be blocked by ad blockers. - `server` - tracking is handled on the backend, with events sent directly to the tracking API. It's not affected by ad blockers. - `recommendations_api_key` - an API key used to authenticate requests to the Recommendations API. This key allows the connector to retrieve personalized recommendations from the recommendation engine. You can find this value as ["API key"](connector_installation_configuration.md#recommendations-api-key) in Raptor Control Panel. -- `recommendations_api_url` (optional) - overrides the default Raptor address, do not set it unless a custom endpoint is required. +- `recommendations_api_uri` (optional) - overrides the default Raptor address, do not set it unless a custom endpoint is required. - `cookie_id_lifetime_days` (optional) - the lifetime in days of the server-side tracking identifier cookies. Default value: `365` days. Minimum value: `1` day. By default, `tracking_type` is set to `client` as client-side tracking is the standard Raptor mode. diff --git a/docs/release_notes/ez_platform_v2.4.md b/docs/release_notes/ez_platform_v2.4.md index 90562b8ada..515ee1488c 100644 --- a/docs/release_notes/ez_platform_v2.4.md +++ b/docs/release_notes/ez_platform_v2.4.md @@ -182,7 +182,7 @@ The biggest benefit of this feature is saving load time on complex landing pages 1\. Register `LexikJWTAuthenticationBundle` bundle in `/app/AppKernel.php` - ``` php + ``` php {skip-validation} public function registerBundles() { $bundles = array( @@ -197,18 +197,18 @@ The biggest benefit of this feature is saving load time on complex landing pages 2\. Add the following configuration to `/app/config/config.yml` ``` yaml - lexik_jwt_authentication: - secret_key: '%secret%' - encoder: + lexik_jwt_authentication: + secret_key: '%secret%' + encoder: signature_algorithm: HS256 # Disabled by default, because Page Builder uses custom extractor - token_extractors: - authorization_header: - enabled: false - cookie: - enabled: false - query_parameter: - enabled: false + token_extractors: + authorization_header: + enabled: false + cookie: + enabled: false + query_parameter: + enabled: false ``` By default `HS256` is used as signature algorithm for generated token but we strongly recommend switching to SSH keys. @@ -218,23 +218,23 @@ The biggest benefit of this feature is saving load time on complex landing pages 3\. Add `EzSystems\EzPlatformPageBuilder\Security\EditorialMode\TokenAuthenticator` authentication provider to `ezpublish_front` firewall before `form_login` in `app/config/security.yml`: ``` yaml - security: + security: # ... - firewalls: - ezpublish_front: - # ... - simple_preauth: - authenticator: 'EzSystems\EzPlatformPageBuilder\Security\EditorialMode\TokenAuthenticator' - form_login: - require_previous_session: false - # ... + firewalls: + ezpublish_front: + # ... + simple_preauth: + authenticator: 'EzSystems\EzPlatformPageBuilder\Security\EditorialMode\TokenAuthenticator' + form_login: + require_previous_session: false + # ... ``` 4\. Make sure that parameter `page_builder.token_authenticator.enabled` has value `true`. If the parameter isn't present, add it to `/app/config/config.yml`: ``` yaml - # ... - parameters: + # ... + parameters: # ... page_builder.token_authenticator.enabled: true ``` diff --git a/docs/release_notes/ez_platform_v3.0_deprecations.md b/docs/release_notes/ez_platform_v3.0_deprecations.md index 233511207a..3f7a960a2a 100644 --- a/docs/release_notes/ez_platform_v3.0_deprecations.md +++ b/docs/release_notes/ez_platform_v3.0_deprecations.md @@ -772,7 +772,7 @@ All classes and interfaces from `eZ\Publish\Core\Persistence\Database` and `eZ\P The signature of the `\eZ\Publish\Core\Persistence\Legacy\URL\Query\CriterionHandler::handle` contract now accepts `\Doctrine\DBAL\Query\QueryBuilder` instead of `\eZ\Publish\Core\Persistence\Database\SelectQuery` and has the following form: -``` php +``` php {skip-validation} use \Doctrine\DBAL\Query\QueryBuilder; use \eZ\Publish\Core\Persistence\Legacy\URL\Query\CriteriaConverter; use \eZ\Publish\API\Repository\Values\URL\Query\Criterion; diff --git a/docs/release_notes/ibexa_dxp_v4.6.md b/docs/release_notes/ibexa_dxp_v4.6.md index 0a30c84294..3f9b6b2eaf 100644 --- a/docs/release_notes/ibexa_dxp_v4.6.md +++ b/docs/release_notes/ibexa_dxp_v4.6.md @@ -1696,7 +1696,7 @@ Endpoints that allow you to manage prices in your platform with REST API: A signature for the `\Ibexa\Contracts\Rest\Output\Generator::startValueElement` method has been updated to the following: -```php +``` php {skip-validation} /** * @phpstan-param scalar $value * @phpstan-param array $attributes diff --git a/docs/resources/contributing/package_structure.md b/docs/resources/contributing/package_structure.md index 3d3ade8962..97302ca1a7 100644 --- a/docs/resources/contributing/package_structure.md +++ b/docs/resources/contributing/package_structure.md @@ -17,17 +17,17 @@ The following conventions apply to contributions to [[= product_name_base =]] co Define [[= product_name =]] core PHP code in a namespace with the following prefix: -```php +``` php {skip-validation} namespace Ibexa; ``` A package which groups some DXP features can use an additional prefix, for example: -```php +``` php {skip-validation} namespace Ibexa\Commerce; ``` -```php +``` php {skip-validation} namespace Ibexa\Personalization; ``` @@ -55,11 +55,11 @@ The `src/lib` directory and its corresponding `Ibexa\` namespace ar Examples: -```php +``` php {skip-validation} namespace Ibexa\Search; ``` -```php +``` php {skip-validation} namespace Ibexa\Commerce\Shop; ``` @@ -67,7 +67,7 @@ namespace Ibexa\Commerce\Shop; The bundle class definition in the `src/bundle` directory must be: -```php +``` php {skip-validation} namespace Ibexa\Bundle\; class Ibexa[ProductGroup]Bundle // ... @@ -75,13 +75,13 @@ class Ibexa[ProductGroup]Bundle // ... Examples: -```php +``` php {skip-validation} namespace Ibexa\Bundle\Search; class IbexaSearchBundle // ... ``` -```php +``` php {skip-validation} namespace Ibexa\Bundle\Commerce\Shop; class IbexaCommerceShopBundle // ... @@ -91,21 +91,21 @@ class IbexaCommerceShopBundle // ... A package may introduce a namespace for contracts, to be consumed by first and third party packages and projects, which must be prefixed as: -```php +``` php {skip-validation} namespace Ibexa\Contracts; ``` Examples: -```php +``` php {skip-validation} namespace Ibexa\Contracts\Kernel; ``` -```php +``` php {skip-validation} namespace Ibexa\Contracts\SiteFactory; ``` -```php +``` php {skip-validation} namespace Ibexa\Contracts\Commerce\Shop; ``` diff --git a/docs/search/activity_log_search_reference/action_criterion.md b/docs/search/activity_log_search_reference/action_criterion.md index b89e51d6eb..71b9c14cd5 100644 --- a/docs/search/activity_log_search_reference/action_criterion.md +++ b/docs/search/activity_log_search_reference/action_criterion.md @@ -10,11 +10,14 @@ A set of built-in names is available as `ActivityLogServiceInterface`'s `ACTION_ ## Example -```php +``` php +use Ibexa\Contracts\ActivityLog\ActivityLogServiceInterface; +use Ibexa\Contracts\ActivityLog\Values\ActivityLog as ActivityLog; + $query = new ActivityLog\Query([ new ActivityLog\Criterion\ActionCriterion([ - ActivityLog\ActivityLogServiceInterface::ACTION_DELETE, - ActivityLog\ActivityLogServiceInterface::ACTION_TRASH, + ActivityLogServiceInterface::ACTION_DELETE, + ActivityLogServiceInterface::ACTION_TRASH, ]), ]); ``` diff --git a/docs/search/activity_log_search_reference/logged_at_criterion.md b/docs/search/activity_log_search_reference/logged_at_criterion.md index b48457b347..c39b486fa3 100644 --- a/docs/search/activity_log_search_reference/logged_at_criterion.md +++ b/docs/search/activity_log_search_reference/logged_at_criterion.md @@ -20,7 +20,9 @@ The `LoggedAtCriterion` Activity Log Criterion matches activity log group that h The following example is to match all activity log groups that aren't older than a day: -```php +``` php +use Ibexa\Contracts\ActivityLog\Values\ActivityLog as ActivityLog; + $query = new ActivityLog\Query([ new ActivityLog\Criterion\LoggedAtCriterion(new \DateTime('- 1 day'), ActivityLog\Criterion\LoggedAtCriterion::GTE), ]); diff --git a/docs/search/activity_log_search_reference/object_criterion.md b/docs/search/activity_log_search_reference/object_criterion.md index 7be18ad3c5..55e7b06931 100644 --- a/docs/search/activity_log_search_reference/object_criterion.md +++ b/docs/search/activity_log_search_reference/object_criterion.md @@ -9,14 +9,18 @@ The `ObjectCriterion` Activity Log Criterion matches log group with a log entry ## Examples -```php +``` php +use Ibexa\Contracts\ActivityLog\Values\ActivityLog as ActivityLog; + $query = new ActivityLog\Query([ new ActivityLog\Criterion\ObjectCriterion(Ibexa\Contracts\Core\Repository\Values\Content\Content::class), ]); ``` -```php +``` php +use Ibexa\Contracts\ActivityLog\Values\ActivityLog as ActivityLog; + $query = new ActivityLog\Query([ - new ActivityLog\Criterion\ObjectCriterion(Ibexa\Contracts\ProductCatalog\Values\ProductVariantInterface::class, [123, 234, 345]), + new ActivityLog\Criterion\ObjectCriterion(Ibexa\Contracts\ProductCatalog\Values\ProductVariantInterface::class, ['123', '234', '345']), ]); ``` diff --git a/docs/search/activity_log_search_reference/object_name_criterion.md b/docs/search/activity_log_search_reference/object_name_criterion.md index 48ad0b1248..1eea5139c3 100644 --- a/docs/search/activity_log_search_reference/object_name_criterion.md +++ b/docs/search/activity_log_search_reference/object_name_criterion.md @@ -13,7 +13,9 @@ The `ObjectNameCriterion` Activity Log Criterion matches log groups that have a ## Example -```php +``` php +use Ibexa\Contracts\ActivityLog\Values\ActivityLog as ActivityLog; + $query = new ActivityLog\Query([ new ActivityLog\Criterion\ObjectNameCriterion('Ibexa', ActivityLog\Criterion\ObjectNameCriterion::OPERATOR_CONTAINS), ]); diff --git a/docs/search/activity_log_search_reference/user_criterion.md b/docs/search/activity_log_search_reference/user_criterion.md index def4663f95..871f6e6113 100644 --- a/docs/search/activity_log_search_reference/user_criterion.md +++ b/docs/search/activity_log_search_reference/user_criterion.md @@ -8,7 +8,9 @@ The `UserCriterion` Activity Log Criterion matches log groups that have an activ ## Example -```php +``` php +use Ibexa\Contracts\ActivityLog\Values\ActivityLog as ActivityLog; + $query = new ActivityLog\Query([ new ActivityLog\Criterion\UserCriterion([10, 14]), ]); diff --git a/docs/search/aggregation_reference/authorterm_aggregation.md b/docs/search/aggregation_reference/authorterm_aggregation.md index 80d155c488..d170997b61 100644 --- a/docs/search/aggregation_reference/authorterm_aggregation.md +++ b/docs/search/aggregation_reference/authorterm_aggregation.md @@ -13,6 +13,9 @@ The field-based [AuthorTermAggregation](/api/php_api/php_api_reference/classes/I ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; + $query = new Query(); $query->aggregations[] = new Aggregation\Field\AuthorTermAggregation('author', 'article', 'authors'); ``` diff --git a/docs/search/aggregation_reference/basepricestats_aggregation.md b/docs/search/aggregation_reference/basepricestats_aggregation.md index 5eb41c1b83..492aad61f0 100644 --- a/docs/search/aggregation_reference/basepricestats_aggregation.md +++ b/docs/search/aggregation_reference/basepricestats_aggregation.md @@ -21,6 +21,11 @@ You can use the provided getters to access the values: ## Example ``` php +use Ibexa\Contracts\ProductCatalog\Values\CurrencyInterface; +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Aggregation\BasePriceStatsAggregation; + +/** @var CurrencyInterface $currency */ $query = new ProductQuery(); $query->setAggregations([ new BasePriceStatsAggregation('base_price_stats_aggregation', $currency), diff --git a/docs/search/aggregation_reference/checkboxterm_aggregation.md b/docs/search/aggregation_reference/checkboxterm_aggregation.md index 7a595366ff..7f503ff832 100644 --- a/docs/search/aggregation_reference/checkboxterm_aggregation.md +++ b/docs/search/aggregation_reference/checkboxterm_aggregation.md @@ -13,6 +13,9 @@ The field-based [CheckboxTermAggregation](/api/php_api/php_api_reference/classes ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; + $query = new Query(); $query->aggregations[] = new Aggregation\Field\CheckboxTermAggregation('checkbox', 'article', 'enable_comments'); ``` diff --git a/docs/search/aggregation_reference/contenttypegroupterm_aggregation.md b/docs/search/aggregation_reference/contenttypegroupterm_aggregation.md index 1d42dced95..0a77afbe98 100644 --- a/docs/search/aggregation_reference/contenttypegroupterm_aggregation.md +++ b/docs/search/aggregation_reference/contenttypegroupterm_aggregation.md @@ -13,6 +13,9 @@ The [ContentTypeGroupTermAggregation](/api/php_api/php_api_reference/classes/Ibe ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; + $query = new Query(); $query->aggregations[] = new Aggregation\ContentTypeGroupTermAggregation('content_type_group'); ``` diff --git a/docs/search/aggregation_reference/contenttypeterm_aggregation.md b/docs/search/aggregation_reference/contenttypeterm_aggregation.md index 1d3d242f26..62d729603c 100644 --- a/docs/search/aggregation_reference/contenttypeterm_aggregation.md +++ b/docs/search/aggregation_reference/contenttypeterm_aggregation.md @@ -13,6 +13,9 @@ The [ContentTypeTermAggregation](/api/php_api/php_api_reference/classes/Ibexa-Co ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; + $query = new Query(); $query->aggregations[] = new Aggregation\ContentTypeTermAggregation('content_type'); ``` diff --git a/docs/search/aggregation_reference/countryterm_aggregation.md b/docs/search/aggregation_reference/countryterm_aggregation.md index 6bc909190e..81e34ddde9 100644 --- a/docs/search/aggregation_reference/countryterm_aggregation.md +++ b/docs/search/aggregation_reference/countryterm_aggregation.md @@ -13,6 +13,9 @@ The field-based [CountryTermAggregation](/api/php_api/php_api_reference/classes/ ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; + $query = new Query(); $query->aggregations[] = new Aggregation\Field\CountryTermAggregation('country', 'article', 'country'); ``` diff --git a/docs/search/aggregation_reference/custompricestats_aggregation.md b/docs/search/aggregation_reference/custompricestats_aggregation.md index 39d98b9ada..b3b0087702 100644 --- a/docs/search/aggregation_reference/custompricestats_aggregation.md +++ b/docs/search/aggregation_reference/custompricestats_aggregation.md @@ -21,6 +21,13 @@ The CustomPriceStatsAggregation aggregates search results by the value of the cu ## Example ``` php +use Ibexa\Contracts\ProductCatalog\Values\CurrencyInterface; +use Ibexa\Contracts\ProductCatalog\Values\CustomerGroupInterface; +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Aggregation\CustomPriceStatsAggregation; + +/** @var CurrencyInterface $currency */ +/** @var CustomerGroupInterface $customerGroup */ $query = new ProductQuery(); $query->setAggregations([ new CustomPriceStatsAggregation('custom_price_stats_aggregation', $currency, $customerGroup), diff --git a/docs/search/aggregation_reference/datemetadatarange_aggregation.md b/docs/search/aggregation_reference/datemetadatarange_aggregation.md index fbd1e431fb..5b766dc53f 100644 --- a/docs/search/aggregation_reference/datemetadatarange_aggregation.md +++ b/docs/search/aggregation_reference/datemetadatarange_aggregation.md @@ -15,11 +15,18 @@ The [DateMetadataRangeAggregation](/api/php_api/php_api_reference/classes/Ibexa- ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range; + $query = new Query(); -$query->aggregations[] = new Aggregation\DateMetadataRangeAggregation('date_metadata', Aggregation\DateMetadataRangeAggregation::PUBLISHED, +$query->aggregations[] = new Aggregation\DateMetadataRangeAggregation( + 'date_metadata', + Aggregation\DateMetadataRangeAggregation::PUBLISHED, [ - new Query\Aggregation\Range(null, new DateTime('2020-06-01')), - new Query\Aggregation\Range(new DateTime('2020-06-01'), new DateTime('2020-12-31')), - new Query\Aggregation\Range(new DateTime('2020-12-31'), null), - ]); + Range::ofDateTime(null, new DateTime('2020-06-01')), + Range::ofDateTime(new DateTime('2020-06-01'), new DateTime('2020-12-31')), + Range::ofDateTime(new DateTime('2020-12-31'), null), + ] +); ``` diff --git a/docs/search/aggregation_reference/daterange_aggregation.md b/docs/search/aggregation_reference/daterange_aggregation.md index 682b745b85..5a4a9b9edd 100644 --- a/docs/search/aggregation_reference/daterange_aggregation.md +++ b/docs/search/aggregation_reference/daterange_aggregation.md @@ -15,11 +15,19 @@ The field-based [DateRangeAggregation](/api/php_api/php_api_reference/classes/Ib ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range; + $query = new Query(); -$query->aggregations[] = new Aggregation\Field\DateRangeAggregation('date', 'event', 'event_date', -[ - new Query\Aggregation\Range(null, new DateTime('2020-06-01')), - new Query\Aggregation\Range(new DateTime('2020-06-01'), new DateTime('2020-12-31')), - new Query\Aggregation\Range(new DateTime('2020-12-31'), null), -]); +$query->aggregations[] = new Aggregation\Field\DateRangeAggregation( + 'date', + 'event', + 'event_date', + [ + Range::ofDateTime(null, new DateTime('2020-06-01')), + Range::ofDateTime(new DateTime('2020-06-01'), new DateTime('2020-12-31')), + Range::ofDateTime(new DateTime('2020-12-31'), null), +] +); ``` diff --git a/docs/search/aggregation_reference/datetimerange_aggregation.md b/docs/search/aggregation_reference/datetimerange_aggregation.md index da6cf0f608..8e4cab9f28 100644 --- a/docs/search/aggregation_reference/datetimerange_aggregation.md +++ b/docs/search/aggregation_reference/datetimerange_aggregation.md @@ -15,11 +15,19 @@ The field-based [DateTimeRangeAggregation](/api/php_api/php_api_reference/classe ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range; + $query = new Query(); -$query->aggregations[] = new Aggregation\Field\DateTimeRangeAggregation('date', 'event', 'event_date', -[ - new Query\Aggregation\Range(null, new DateTime('2020-06-01')), - new Query\Aggregation\Range(new DateTime('2020-06-01'), new DateTime('2020-12-31')), - new Query\Aggregation\Range(new DateTime('2020-12-31'), null), -]); +$query->aggregations[] = new Aggregation\Field\DateTimeRangeAggregation( + 'date', + 'event', + 'event_date', + [ + Range::ofDateTime(null, new DateTime('2020-06-01')), + Range::ofDateTime(new DateTime('2020-06-01'), new DateTime('2020-12-31')), + Range::ofDateTime(new DateTime('2020-12-31'), null), +] +); ``` diff --git a/docs/search/aggregation_reference/floatrange_aggregation.md b/docs/search/aggregation_reference/floatrange_aggregation.md index f1c7b16043..e5451c4979 100644 --- a/docs/search/aggregation_reference/floatrange_aggregation.md +++ b/docs/search/aggregation_reference/floatrange_aggregation.md @@ -15,11 +15,19 @@ The field-based [FloatRangeAggregation](/api/php_api/php_api_reference/classes/I ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range; + $query = new Query(); -$query->aggregations[] = new Aggregation\Field\FloatRangeAggregation('float', 'product', 'weight', -[ - new Query\Aggregation\Range(null, 0.25), - new Query\Aggregation\Range(0.25, 0.75), - new Query\Aggregation\Range(0.75, null), -]); +$query->aggregations[] = new Aggregation\Field\FloatRangeAggregation( + 'float', + 'product', + 'weight', + [ + Range::ofFloat(null, 0.25), + Range::ofFloat(0.25, 0.75), + Range::ofFloat(0.75, null), +] +); ``` diff --git a/docs/search/aggregation_reference/floatstats_aggregation.md b/docs/search/aggregation_reference/floatstats_aggregation.md index 5d2be9bb13..5fc9445378 100644 --- a/docs/search/aggregation_reference/floatstats_aggregation.md +++ b/docs/search/aggregation_reference/floatstats_aggregation.md @@ -20,6 +20,9 @@ You can use the provided getters to access the values: ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; + $query = new Query(); $query->aggregations[] = new Aggregation\Field\FloatStatsAggregation('float', 'product', 'weight'); ``` diff --git a/docs/search/aggregation_reference/integerrange_aggregation.md b/docs/search/aggregation_reference/integerrange_aggregation.md index e2a76f66d0..4080d20521 100644 --- a/docs/search/aggregation_reference/integerrange_aggregation.md +++ b/docs/search/aggregation_reference/integerrange_aggregation.md @@ -15,11 +15,19 @@ The field-based [IntegerRangeAggregation](/api/php_api/php_api_reference/classes ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range; + $query = new Query(); -$query->aggregations[] = new Aggregation\Field\IntegerRangeAggregation('integer', 'product', 'amount', -[ - new Query\Aggregation\Range(null, 12), - new Query\Aggregation\Range(12, 24), - new Query\Aggregation\Range(24, null), -]); +$query->aggregations[] = new Aggregation\Field\IntegerRangeAggregation( + 'integer', + 'product', + 'amount', + [ + Range::ofInt(null, 12), + Range::ofInt(12, 24), + Range::ofInt(24, null), +] +); ``` diff --git a/docs/search/aggregation_reference/integerstats_aggregation.md b/docs/search/aggregation_reference/integerstats_aggregation.md index 13d65dcd3a..ff31603d22 100644 --- a/docs/search/aggregation_reference/integerstats_aggregation.md +++ b/docs/search/aggregation_reference/integerstats_aggregation.md @@ -19,6 +19,9 @@ The field-based [IntegerStatsAggregation](/api/php_api/php_api_reference/classes ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; + $query = new Query(); $query->aggregations[] = new Aggregation\Field\IntegerStatsAggregation('integer', 'product', 'amount'); ``` diff --git a/docs/search/aggregation_reference/keywordterm_aggregation.md b/docs/search/aggregation_reference/keywordterm_aggregation.md index e0eff92f43..4457069e31 100644 --- a/docs/search/aggregation_reference/keywordterm_aggregation.md +++ b/docs/search/aggregation_reference/keywordterm_aggregation.md @@ -13,6 +13,9 @@ The field-based [KeywordTermAggregation](/api/php_api/php_api_reference/classes/ ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; + $query = new Query(); $query->aggregations[] = new Aggregation\Field\KeywordTermAggregation('keyword', 'article', 'tags'); ``` diff --git a/docs/search/aggregation_reference/languageterm_aggregation.md b/docs/search/aggregation_reference/languageterm_aggregation.md index 6f5e6bd09f..41a7f88dbb 100644 --- a/docs/search/aggregation_reference/languageterm_aggregation.md +++ b/docs/search/aggregation_reference/languageterm_aggregation.md @@ -13,6 +13,9 @@ The [LanguageTermAggregation](/api/php_api/php_api_reference/classes/Ibexa-Contr ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; + $query = new Query(); $query->aggregations[] = new Aggregation\LanguageTermAggregation('language'); ``` diff --git a/docs/search/aggregation_reference/locationchildrenterm_aggregation.md b/docs/search/aggregation_reference/locationchildrenterm_aggregation.md index b530e83ab2..077bdaca94 100644 --- a/docs/search/aggregation_reference/locationchildrenterm_aggregation.md +++ b/docs/search/aggregation_reference/locationchildrenterm_aggregation.md @@ -13,6 +13,9 @@ The [LocationChildrenTermAggregation](/api/php_api/php_api_reference/classes/Ibe ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; + $query = new LocationQuery(); $query->aggregations[] = new Aggregation\Location\LocationChildrenTermAggregation('location_children'); ``` diff --git a/docs/search/aggregation_reference/objectstateterm_aggregation.md b/docs/search/aggregation_reference/objectstateterm_aggregation.md index 099df6822c..cd5b1ffa13 100644 --- a/docs/search/aggregation_reference/objectstateterm_aggregation.md +++ b/docs/search/aggregation_reference/objectstateterm_aggregation.md @@ -14,8 +14,11 @@ The [ObjectStateTermAggregation](/api/php_api/php_api_reference/classes/Ibexa-Co ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; + $query = new Query(); -$query->aggregations[] = new Aggregation\Location\ObjectStateTermAggregation('object_state', 'ibexa_lock'); +$query->aggregations[] = new Aggregation\ObjectStateTermAggregation('object_state', 'ibexa_lock'); ``` [[= include_file('docs/snippets/search_term_aggregation_settings.md') =]] diff --git a/docs/search/aggregation_reference/product_attribute_aggregations.md b/docs/search/aggregation_reference/product_attribute_aggregations.md index d6a533713e..845092669d 100644 --- a/docs/search/aggregation_reference/product_attribute_aggregations.md +++ b/docs/search/aggregation_reference/product_attribute_aggregations.md @@ -28,19 +28,26 @@ Range aggregations (`ProductAttributeFloatRangeAggregation` and `ProductAttribut ## Example ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Aggregation\AttributeSelectionTermAggregation; + $query = new ProductQuery(); $query->setAggregations([ - new ProductAttributeSelectionAggregation('skin', 'skin_type'), + new AttributeSelectionTermAggregation('skin', 'skin_type'), ]); ``` ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range; +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Aggregation\AttributeIntegerRangeAggregation; + $query = new ProductQuery(); $query->setAggregations([ - new ProductAttributeIntegerRangeAggregation('buttons', 'number_of_buttons', [ - new \Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range(null, 5), - new \Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range(5, 10), - new \Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range(10, null), + new AttributeIntegerRangeAggregation('buttons', 'number_of_buttons', [ + Range::ofInt(null, 5), + Range::ofInt(5, 10), + Range::ofInt(10, null), ]), ]); ``` diff --git a/docs/search/aggregation_reference/productavailabilityterm_aggregation.md b/docs/search/aggregation_reference/productavailabilityterm_aggregation.md index 45058d73d6..946fb1d611 100644 --- a/docs/search/aggregation_reference/productavailabilityterm_aggregation.md +++ b/docs/search/aggregation_reference/productavailabilityterm_aggregation.md @@ -13,6 +13,9 @@ The ProductAvailabilityTermAggregation aggregates search results by product avai ## Example ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Aggregation\ProductAvailabilityTermAggregation; + $query = new ProductQuery(); $query->setAggregations([ new ProductAvailabilityTermAggregation('product_availability'), diff --git a/docs/search/aggregation_reference/productpricerange_aggregation.md b/docs/search/aggregation_reference/productpricerange_aggregation.md index aa6774888c..ea1455dbc9 100644 --- a/docs/search/aggregation_reference/productpricerange_aggregation.md +++ b/docs/search/aggregation_reference/productpricerange_aggregation.md @@ -15,11 +15,15 @@ The ProductPriceRangeAggregation aggregates search results by the value of the p ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range; +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Aggregation\ProductPriceRangeAggregation; + $query = new ProductQuery(); $query->setAggregations([ new ProductPriceRangeAggregation('price', 'PLN', [ - new \Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range(0, 10000), - new \Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range(10000, null), + Range::ofInt(0, 10000), + Range::ofInt(10000, null), ]), ]); ``` diff --git a/docs/search/aggregation_reference/productstockrange_aggregation.md b/docs/search/aggregation_reference/productstockrange_aggregation.md index 0b29292bc6..d098fe6bca 100644 --- a/docs/search/aggregation_reference/productstockrange_aggregation.md +++ b/docs/search/aggregation_reference/productstockrange_aggregation.md @@ -14,12 +14,16 @@ The ProductStockRangeAggregation aggregates search results by products' numerica ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range; +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Aggregation\ProductStockRangeAggregation; + $productQuery = new ProductQuery(); $productQuery->setAggregations([ new ProductStockRangeAggregation('stock', [ - new Range(null, 10), - new Range(10, 100), - new Range(100, null), + Range::ofInt(null, 10), + Range::ofInt(10, 100), + Range::ofInt(100, null), ]), ]); ``` diff --git a/docs/search/aggregation_reference/producttypeterm_aggregation.md b/docs/search/aggregation_reference/producttypeterm_aggregation.md index aac92ab6d7..d5f5c10c26 100644 --- a/docs/search/aggregation_reference/producttypeterm_aggregation.md +++ b/docs/search/aggregation_reference/producttypeterm_aggregation.md @@ -13,6 +13,9 @@ The ProductTypeTermAggregation aggregates search results by the product type. ## Example ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Aggregation\ProductTypeTermAggregation; + $query = new ProductQuery(); $query->setAggregations([ new ProductTypeTermAggregation('product_type'), diff --git a/docs/search/aggregation_reference/rawrange_aggregation.md b/docs/search/aggregation_reference/rawrange_aggregation.md index 98b7f9c156..1e0d36e81a 100644 --- a/docs/search/aggregation_reference/rawrange_aggregation.md +++ b/docs/search/aggregation_reference/rawrange_aggregation.md @@ -22,9 +22,13 @@ The [RawRangeAggregation](/api/php_api/php_api_reference/classes/Ibexa-Contracts ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range; + $query = new LocationQuery(); $query->aggregations[] = new Aggregation\RawRangeAggregation('priority', 'priority_id', [ - new Query\Aggregation\Range(1, 10), - new Query\Aggregation\Range(10, 100) + Range::ofInt(1, 10), + Range::ofInt(10, 100), ]); ``` diff --git a/docs/search/aggregation_reference/rawstats_aggregation.md b/docs/search/aggregation_reference/rawstats_aggregation.md index fd8b51e0d9..67315492d6 100644 --- a/docs/search/aggregation_reference/rawstats_aggregation.md +++ b/docs/search/aggregation_reference/rawstats_aggregation.md @@ -28,6 +28,9 @@ You can use the provided getters to access the values: ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; + $query = new Query(); $query->aggregations[] = new Aggregation\RawStatsAggregation('location_depth', 'depth_i'); ``` diff --git a/docs/search/aggregation_reference/rawterm_aggregation.md b/docs/search/aggregation_reference/rawterm_aggregation.md index 94d629b520..a1b4aee7eb 100644 --- a/docs/search/aggregation_reference/rawterm_aggregation.md +++ b/docs/search/aggregation_reference/rawterm_aggregation.md @@ -21,6 +21,9 @@ The [RawTermAggregation](/api/php_api/php_api_reference/classes/Ibexa-Contracts- ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; + $query = new Query(); $query->aggregations[] = new Aggregation\RawTermAggregation('content_per_content_type', 'content_type_id_id'); ``` diff --git a/docs/search/aggregation_reference/sectionterm_aggregation.md b/docs/search/aggregation_reference/sectionterm_aggregation.md index 51980b5f76..0dc3a5ae99 100644 --- a/docs/search/aggregation_reference/sectionterm_aggregation.md +++ b/docs/search/aggregation_reference/sectionterm_aggregation.md @@ -13,6 +13,9 @@ The [SectionTermAggregation](/api/php_api/php_api_reference/classes/Ibexa-Contra ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; + $query = new Query(); $query->aggregations[] = new Aggregation\SectionTermAggregation('section'); ``` diff --git a/docs/search/aggregation_reference/selectionterm_aggregation.md b/docs/search/aggregation_reference/selectionterm_aggregation.md index d6b468f228..17164582ba 100644 --- a/docs/search/aggregation_reference/selectionterm_aggregation.md +++ b/docs/search/aggregation_reference/selectionterm_aggregation.md @@ -13,6 +13,9 @@ The field-based [SelectionTermAggregation](/api/php_api/php_api_reference/classe ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; + $query = new Query(); $query->aggregations[] = new Aggregation\Field\SelectionTermAggregation('selection', 'article', 'select'); ``` diff --git a/docs/search/aggregation_reference/subtreeterm_aggregation.md b/docs/search/aggregation_reference/subtreeterm_aggregation.md index 780140492b..902a59f5bd 100644 --- a/docs/search/aggregation_reference/subtreeterm_aggregation.md +++ b/docs/search/aggregation_reference/subtreeterm_aggregation.md @@ -14,6 +14,9 @@ The [SubtreeTermAggregation](/api/php_api/php_api_reference/classes/Ibexa-Contra ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; + $query = new Query(); $query->aggregations[] = new Aggregation\Location\SubtreeTermAggregation('pathstring', '/1/2/'); ``` diff --git a/docs/search/aggregation_reference/taxonomyentryid_aggregation.md b/docs/search/aggregation_reference/taxonomyentryid_aggregation.md index cff1e2b455..ce35d66f94 100644 --- a/docs/search/aggregation_reference/taxonomyentryid_aggregation.md +++ b/docs/search/aggregation_reference/taxonomyentryid_aggregation.md @@ -14,11 +14,17 @@ The `TaxonomyEntryIdAggregation` aggregates search results by the content item's ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Taxonomy\Search\Query\Aggregation as Aggregation; + $query = new Query(); $query->aggregations[] = new Aggregation\TaxonomyEntryIdAggregation('taxonomy', 'tags'); ``` ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\Taxonomy\Search\Query\Aggregation\TaxonomyEntryIdAggregation; + $query = new ProductQuery(); -$query->aggregations[] = new Aggregation\TaxonomyEntryIdAggregation('categories', 'product_categories'); +$query->setAggregations([new TaxonomyEntryIdAggregation('categories', 'product_categories')]); ``` diff --git a/docs/search/aggregation_reference/timerange_aggregation.md b/docs/search/aggregation_reference/timerange_aggregation.md index aadd22c2c3..bd1fc9a1e8 100644 --- a/docs/search/aggregation_reference/timerange_aggregation.md +++ b/docs/search/aggregation_reference/timerange_aggregation.md @@ -15,10 +15,23 @@ The field-based [TimeRangeAggregation](/api/php_api/php_api_reference/classes/Ib ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range; + +$timestamp = mktime(14, 0, 0); +if ($timestamp === false) { + throw new RuntimeException('Failed to create timestamp with mktime.'); +} + $query = new Query(); -$query->aggregations[] = new Aggregation\Field\TimeRangeAggregation('date', 'event', 'event_time', -[ - new Query\Aggregation\Range(null, new DateTime('T14:00')), - new Query\Aggregation\Range(new DateTime('T14:003'), null), -]); +$query->aggregations[] = new Aggregation\Field\TimeRangeAggregation( + 'date', + 'event', + 'event_time', + [ + Range::ofInt(null, $timestamp), + Range::ofInt($timestamp, null), +] +); ``` diff --git a/docs/search/aggregation_reference/usermetadataterm_aggregation.md b/docs/search/aggregation_reference/usermetadataterm_aggregation.md index 275e2742e1..b61f72f109 100644 --- a/docs/search/aggregation_reference/usermetadataterm_aggregation.md +++ b/docs/search/aggregation_reference/usermetadataterm_aggregation.md @@ -13,6 +13,9 @@ The [UserMetadataTermAggregation](/api/php_api/php_api_reference/classes/Ibexa-C ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; + $query = new Query(); $query->aggregations[] = new Aggregation\UserMetadataTermAggregation('user_metadata'); ``` diff --git a/docs/search/aggregation_reference/visibilityterm_aggregation.md b/docs/search/aggregation_reference/visibilityterm_aggregation.md index 780fa57d48..843cb5a36c 100644 --- a/docs/search/aggregation_reference/visibilityterm_aggregation.md +++ b/docs/search/aggregation_reference/visibilityterm_aggregation.md @@ -13,6 +13,9 @@ The [VisibilityTermAggregation](/api/php_api/php_api_reference/classes/Ibexa-Con ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation; + $query = new Query(); $query->aggregations[] = new Aggregation\VisibilityTermAggregation('visibility'); ``` diff --git a/docs/search/collaboration_search_reference/collaboration_criteria.md b/docs/search/collaboration_search_reference/collaboration_criteria.md index 427daa13f7..fae7e90c87 100644 --- a/docs/search/collaboration_search_reference/collaboration_criteria.md +++ b/docs/search/collaboration_search_reference/collaboration_criteria.md @@ -48,7 +48,7 @@ Session Search Criteria are implementing the [CriterionInterface](/api/php_api/p The following example shows how you can use the criteria to find all the currently active sessions: -```php hl_lines="11-15" +``` php hl_lines="11-15" [[= include_code('code_samples/collaboration/src/Query/Search.php') =]] ``` diff --git a/docs/search/collaboration_search_reference/collaboration_sort_clauses.md b/docs/search/collaboration_search_reference/collaboration_sort_clauses.md index 6cab963dd8..8d8882175f 100644 --- a/docs/search/collaboration_search_reference/collaboration_sort_clauses.md +++ b/docs/search/collaboration_search_reference/collaboration_sort_clauses.md @@ -33,7 +33,7 @@ Session Search Sort Clauses are implementing the [SortClauseInterface](/api/php_ The following example shows how to use them to sort the searched sessions: -```php hl_lines="17" +``` php hl_lines="17" [[= include_code('code_samples/collaboration/src/Query/Search.php') =]] ``` diff --git a/docs/search/content_type_search_reference/content_type_criteria.md b/docs/search/content_type_search_reference/content_type_criteria.md index bf20c4ad73..18b6a7d538 100644 --- a/docs/search/content_type_search_reference/content_type_criteria.md +++ b/docs/search/content_type_search_reference/content_type_criteria.md @@ -22,6 +22,6 @@ Content Type Search Criteria are only supported by [Content Type Search (`Conten The following example shows how to use them to search for content types: -```php hl_lines="29-31" +``` php hl_lines="29-31" [[= include_code('code_samples/api/public_php_api/src/Command/FindContentTypeCommand.php') =]] ``` diff --git a/docs/search/content_type_search_reference/content_type_sort_clauses.md b/docs/search/content_type_search_reference/content_type_sort_clauses.md index 0ee8115571..6943d5d9af 100644 --- a/docs/search/content_type_search_reference/content_type_sort_clauses.md +++ b/docs/search/content_type_search_reference/content_type_sort_clauses.md @@ -18,7 +18,7 @@ Sort Clauses are found in the [`Ibexa\Contracts\Core\Repository\Values\ContentTy The following example shows how to use them to sort the searched content types: -```php hl_lines="34-36" +``` php hl_lines="34-36" [[= include_code('code_samples/api/public_php_api/src/Command/FindContentTypeCommand.php') =]] ``` diff --git a/docs/search/criteria_reference/ancestor_criterion.md b/docs/search/criteria_reference/ancestor_criterion.md index d0853413a0..024d8c3c9c 100644 --- a/docs/search/criteria_reference/ancestor_criterion.md +++ b/docs/search/criteria_reference/ancestor_criterion.md @@ -15,7 +15,12 @@ The [`Ancestor` Search Criterion](/api/php_api/php_api_reference/classes/Ibexa-C ### PHP ``` php -$query->query = new Criterion\Ancestor([$this->locationService->loadLocation(62)->pathString]); +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); +/** @var \Ibexa\Contracts\Core\Repository\LocationService $locationService */ +$query->query = new Criterion\Ancestor([$locationService->loadLocation(62)->pathString]); ``` ### REST API @@ -44,11 +49,18 @@ $query->query = new Criterion\Ancestor([$this->locationService->loadLocation(62) You can use the Ancestor Search Criterion to create a list of breadcrumbs leading to the Location: -``` php hl_lines="2" +``` php hl_lines="8" +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$locationId = 12345; + $query = new LocationQuery(); -$query->query = new Criterion\Ancestor([$this->locationService->loadLocation($locationId)->pathString]); +/** @var \Ibexa\Contracts\Core\Repository\LocationService $locationService */ +$query->query = new Criterion\Ancestor([$locationService->loadLocation($locationId)->pathString]); -$results = $this->searchService->findLocations($query); +/** @var \Ibexa\Contracts\Core\Repository\SearchService $searchService */ +$results = $searchService->findLocations($query); $breadcrumbs = []; foreach ($results->searchHits as $searchHit) { $breadcrumbs[] = $searchHit; diff --git a/docs/search/criteria_reference/baseprice_criterion.md b/docs/search/criteria_reference/baseprice_criterion.md index bbc95e06cc..c834d0b416 100644 --- a/docs/search/criteria_reference/baseprice_criterion.md +++ b/docs/search/criteria_reference/baseprice_criterion.md @@ -20,6 +20,9 @@ The `BasePrice` Criterion isn't available in the Legacy Search engine. ### PHP ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + $query = new ProductQuery( null, new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\BasePrice( diff --git a/docs/search/criteria_reference/checkboxattribute_criterion.md b/docs/search/criteria_reference/checkboxattribute_criterion.md index eb72b6a723..64fefc9895 100644 --- a/docs/search/criteria_reference/checkboxattribute_criterion.md +++ b/docs/search/criteria_reference/checkboxattribute_criterion.md @@ -16,6 +16,9 @@ The `CheckboxAttribute` Search Criterion searches for products by the value of t ### PHP ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + $query = new ProductQuery( null, new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\CheckboxAttribute('automatic', true) diff --git a/docs/search/criteria_reference/colorattribute_criterion.md b/docs/search/criteria_reference/colorattribute_criterion.md index 888c36e783..2de0571bbb 100644 --- a/docs/search/criteria_reference/colorattribute_criterion.md +++ b/docs/search/criteria_reference/colorattribute_criterion.md @@ -16,6 +16,9 @@ The `ColorAttribute` Search Criterion searches for products by the value of thei ### PHP ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + $query = new ProductQuery( null, new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\ColorAttribute('color', ['#FF0000']) diff --git a/docs/search/criteria_reference/contentid_criterion.md b/docs/search/criteria_reference/contentid_criterion.md index c468ad0fed..0a547c22ae 100644 --- a/docs/search/criteria_reference/contentid_criterion.md +++ b/docs/search/criteria_reference/contentid_criterion.md @@ -15,6 +15,10 @@ The [`ContentId` Search Criterion](/api/php_api/php_api_reference/classes/Ibexa- ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\ContentId([62, 64]); ``` diff --git a/docs/search/criteria_reference/contentname_criterion.md b/docs/search/criteria_reference/contentname_criterion.md index 0c57bf7023..81f6557267 100644 --- a/docs/search/criteria_reference/contentname_criterion.md +++ b/docs/search/criteria_reference/contentname_criterion.md @@ -15,6 +15,10 @@ The [`ContentName` Search Criterion](https://github.com/ibexa/core/blob/5.0/src/ ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\ContentName('*phone'); ``` diff --git a/docs/search/criteria_reference/contenttypegroupid_criterion.md b/docs/search/criteria_reference/contenttypegroupid_criterion.md index e8395aac51..d901be3cf6 100644 --- a/docs/search/criteria_reference/contenttypegroupid_criterion.md +++ b/docs/search/criteria_reference/contenttypegroupid_criterion.md @@ -15,6 +15,10 @@ The [`ContentTypeGroupId` Search Criterion](/api/php_api/php_api_reference/class ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\ContentTypeGroupId([1, 2]); ``` @@ -45,13 +49,18 @@ $query->query = new Criterion\ContentTypeGroupId([1, 2]); You can use the `ContentTypeGroupId` Criterion to query all Media content items (the default ID for the Media content type group is 3): -``` php hl_lines="1" - $query->query = new Criterion\ContentTypeGroupId([3]); +``` php hl_lines="6" +use Ibexa\Contracts\Core\Repository\SearchService; +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; - $results = $this->searchService->findContent($query); - $media = []; - foreach ($results->searchHits as $searchHit) { - $media[] = $searchHit; - } - } +$query = new Query(); +$query->query = new Criterion\ContentTypeGroupId([3]); + +/** @var SearchService $searchService */ +$results = $searchService->findContent($query); +$media = []; +foreach ($results->searchHits as $searchHit) { + $media[] = $searchHit; +} ``` diff --git a/docs/search/criteria_reference/contenttypeid_criterion.md b/docs/search/criteria_reference/contenttypeid_criterion.md index 2c8301358d..853ba1b908 100644 --- a/docs/search/criteria_reference/contenttypeid_criterion.md +++ b/docs/search/criteria_reference/contenttypeid_criterion.md @@ -15,6 +15,10 @@ The [`ContentTypeId` Search Criterion](/api/php_api/php_api_reference/classes/Ib ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\ContentTypeId([44]); ``` diff --git a/docs/search/criteria_reference/contenttypeidentifier_criterion.md b/docs/search/criteria_reference/contenttypeidentifier_criterion.md index 8cb8995a9e..1d980812ff 100644 --- a/docs/search/criteria_reference/contenttypeidentifier_criterion.md +++ b/docs/search/criteria_reference/contenttypeidentifier_criterion.md @@ -15,6 +15,10 @@ The [`ContentTypeIdentifier` Search Criterion](/api/php_api/php_api_reference/cl ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\ContentTypeIdentifier(['article', 'blog_post']); ``` diff --git a/docs/search/criteria_reference/createdat_criterion.md b/docs/search/criteria_reference/createdat_criterion.md index da799a92fe..1c146535aa 100644 --- a/docs/search/criteria_reference/createdat_criterion.md +++ b/docs/search/criteria_reference/createdat_criterion.md @@ -16,6 +16,9 @@ The `CreatedAt` Search Criterion searches for products based on the date when th ### PHP ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + $criteria = new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\CreatedAt( new DateTime('2023-03-01'), \Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\Operator::GTE, diff --git a/docs/search/criteria_reference/createdatrange_criterion.md b/docs/search/criteria_reference/createdatrange_criterion.md index 3aed62b593..04a1265c20 100644 --- a/docs/search/criteria_reference/createdatrange_criterion.md +++ b/docs/search/criteria_reference/createdatrange_criterion.md @@ -16,6 +16,9 @@ The `CreatedAtRange` Search Criterion searches for products based on the date ra ### PHP ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + $criteria = new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\CreatedAtRange( new \DateTimeImmutable('2020-07-10T00:00:00+00:00'), new \DateTimeImmutable('2023-07-12T00:00:00+00:00') diff --git a/docs/search/criteria_reference/currencycode_criterion.md b/docs/search/criteria_reference/currencycode_criterion.md index c98073e693..7c6b98cbe5 100644 --- a/docs/search/criteria_reference/currencycode_criterion.md +++ b/docs/search/criteria_reference/currencycode_criterion.md @@ -19,5 +19,9 @@ The `CurrencyCodeCriterion` Criterion isn't available in Solr or Elasticsearch e ### PHP ``` php -$query->query = new \Ibexa\Contracts\ProductCatalog\Values\Currency\Query\Criterion\CurrencyCodeCriterion('EUR'); +use Ibexa\Contracts\ProductCatalog\Values\Currency\CurrencyQuery; + +$query = new CurrencyQuery( + new \Ibexa\Contracts\ProductCatalog\Values\Currency\Query\Criterion\CurrencyCodeCriterion('EUR') +); ``` diff --git a/docs/search/criteria_reference/customergroupid_criterion.md b/docs/search/criteria_reference/customergroupid_criterion.md index 4a27b612c6..44c7b31977 100644 --- a/docs/search/criteria_reference/customergroupid_criterion.md +++ b/docs/search/criteria_reference/customergroupid_criterion.md @@ -15,5 +15,9 @@ The `CustomerGroupId` Search Criterion searches for content based on the ID of i ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\ProductCatalog\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\CustomerGroupId(1); ``` diff --git a/docs/search/criteria_reference/customprice_criterion.md b/docs/search/criteria_reference/customprice_criterion.md index b4752cf374..0855e9e596 100644 --- a/docs/search/criteria_reference/customprice_criterion.md +++ b/docs/search/criteria_reference/customprice_criterion.md @@ -22,11 +22,16 @@ The `CustomPrice` Criterion isn't available in the Legacy Search engine. ### PHP ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + +/** @var \Ibexa\Contracts\ProductCatalog\Values\CustomerGroupInterface $customerGroup */ $query = new ProductQuery( null, new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\CustomPrice( \Money\Money::EUR(13800), \Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\Operator::GTE, - $customerGroup) + $customerGroup + ) ); ``` diff --git a/docs/search/criteria_reference/datemetadata_criterion.md b/docs/search/criteria_reference/datemetadata_criterion.md index 3c94a49b8a..200a02d3e2 100644 --- a/docs/search/criteria_reference/datemetadata_criterion.md +++ b/docs/search/criteria_reference/datemetadata_criterion.md @@ -17,6 +17,10 @@ The [`DateMetadata` Search Criterion](/api/php_api/php_api_reference/classes/Ibe ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\DateMetadata( Criterion\DateMetadata::CREATED, Criterion\Operator::BETWEEN, @@ -58,10 +62,14 @@ $query->query = new Criterion\DateMetadata( You can use the `DateMetadata` Criterion to search for blog posts that have been created within the last week: -``` php hl_lines="5" -$query = new LocationQuery; -$date = strtotime("-1 week"); -$query->query = new Criterion\LogicalAnd([ +``` php hl_lines="9" +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new LocationQuery(); +$date = strtotime('-1 week'); +$query->query = new Criterion\LogicalAnd( + [ new Criterion\ContentTypeIdentifier('blog_post'), new Criterion\DateMetadata(Criterion\DateMetadata::CREATED, Criterion\Operator::GTE, $date), ] diff --git a/docs/search/criteria_reference/depth_criterion.md b/docs/search/criteria_reference/depth_criterion.md index 1389da5b42..984ccb6435 100644 --- a/docs/search/criteria_reference/depth_criterion.md +++ b/docs/search/criteria_reference/depth_criterion.md @@ -24,5 +24,9 @@ The `value` argument requires: ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\Location\Depth(Criterion\Operator::LT, 3); ``` diff --git a/docs/search/criteria_reference/field_criterion.md b/docs/search/criteria_reference/field_criterion.md index e07057ebe3..c873d73305 100644 --- a/docs/search/criteria_reference/field_criterion.md +++ b/docs/search/criteria_reference/field_criterion.md @@ -26,6 +26,10 @@ The `Field` Criterion isn't available in [Repository filtering](search_api.md#re ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\Field('name', Criterion\Operator::CONTAINS, 'Platform'); ``` @@ -65,11 +69,15 @@ $query->query = new Criterion\Field('name', Criterion\Operator::CONTAINS, 'Platf You can use the `Field` Criterion to search for articles that contain the word "featured": -``` php hl_lines="4" +``` php hl_lines="8" +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + $query = new LocationQuery(); -$query->query = new Criterion\LogicalAnd([ +$query->query = new Criterion\LogicalAnd( + [ new Criterion\ContentTypeIdentifier('article'), - new Criterion\Field('name', Criterion\Operator::CONTAINS, 'Featured') + new Criterion\Field('name', Criterion\Operator::CONTAINS, 'Featured'), ] ); ``` diff --git a/docs/search/criteria_reference/fieldrelation_criterion.md b/docs/search/criteria_reference/fieldrelation_criterion.md index cf2103597f..9640f43c2c 100644 --- a/docs/search/criteria_reference/fieldrelation_criterion.md +++ b/docs/search/criteria_reference/fieldrelation_criterion.md @@ -23,5 +23,9 @@ The `FieldRelation` Criterion isn't available in [Repository filtering](search_a ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\FieldRelation('relations', Criterion\Operator::CONTAINS, [55, 63]); ``` diff --git a/docs/search/criteria_reference/floatattribute_criterion.md b/docs/search/criteria_reference/floatattribute_criterion.md index 325a0ea33c..928f495b7a 100644 --- a/docs/search/criteria_reference/floatattribute_criterion.md +++ b/docs/search/criteria_reference/floatattribute_criterion.md @@ -16,6 +16,9 @@ The `FloatAttribute` Search Criterion searches for products by the value of thei ### PHP ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + $query = new ProductQuery( null, new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\FloatAttribute( diff --git a/docs/search/criteria_reference/fulltext_criterion.md b/docs/search/criteria_reference/fulltext_criterion.md index 001d62c947..a9ac61cfbe 100644 --- a/docs/search/criteria_reference/fulltext_criterion.md +++ b/docs/search/criteria_reference/fulltext_criterion.md @@ -40,18 +40,30 @@ The `FullText` Criterion isn't available in [Repository filtering](search_api.md ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\FullText('victory'); ``` Using double quotes to indicate a phrase: ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\FullText('"world cup"'); ``` Using the AND operator and parenthesis to search for both words at the same time: ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\FullText('baseball AND cup'); ``` @@ -82,6 +94,10 @@ $query->query = new Criterion\FullText('baseball AND cup'); Assume the following search query: ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\FullText('(cup AND ba*ball) "breaking news"'); ``` diff --git a/docs/search/criteria_reference/image_criterion.md b/docs/search/criteria_reference/image_criterion.md index 2df2a0a3f7..43ad087a37 100644 --- a/docs/search/criteria_reference/image_criterion.md +++ b/docs/search/criteria_reference/image_criterion.md @@ -16,6 +16,9 @@ The `Image` Search Criterion searches for image by specified image attributes. ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + $imageCriteriaData = [ 'mimeTypes' => [ 'image/png', @@ -36,6 +39,8 @@ $imageCriteriaData = [ 'max' => 2, // (default: null, optional) ], ]; + +$query = new Query(); $query->query = new Criterion\Image('image', $imageCriteriaData); ``` diff --git a/docs/search/criteria_reference/imagedimensions_criterion.md b/docs/search/criteria_reference/imagedimensions_criterion.md index 4281fe6fb3..85bad978be 100644 --- a/docs/search/criteria_reference/imagedimensions_criterion.md +++ b/docs/search/criteria_reference/imagedimensions_criterion.md @@ -16,6 +16,10 @@ The `Dimensions` Search Criterion searches for image with specified dimensions. ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $imageCriteriaData = [ 'width' => [ 'min' => 100, // (default: 0, optional) @@ -27,7 +31,7 @@ $imageCriteriaData = [ ], ]; -$query->query = new Criterion\Dimensions('image', $imageCriteriaData); +$query->query = new Criterion\Image\Dimensions('image', $imageCriteriaData); ``` ### REST API diff --git a/docs/search/criteria_reference/imagefilesize_criterion.md b/docs/search/criteria_reference/imagefilesize_criterion.md index 04b85a8024..284d4507d2 100644 --- a/docs/search/criteria_reference/imagefilesize_criterion.md +++ b/docs/search/criteria_reference/imagefilesize_criterion.md @@ -17,7 +17,11 @@ The `FileSize` Search Criterion searches for image with specified size. ### PHP ``` php -$query->query = new Criterion\FileSize('image', 0, 1.5); +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); +$query->query = new Criterion\Image\FileSize('image', 0, 1.5); ``` ### REST API diff --git a/docs/search/criteria_reference/imageheight_criterion.md b/docs/search/criteria_reference/imageheight_criterion.md index 5f1ff96c79..ff8402b4ae 100644 --- a/docs/search/criteria_reference/imageheight_criterion.md +++ b/docs/search/criteria_reference/imageheight_criterion.md @@ -17,5 +17,9 @@ The `Height` Search Criterion searches for image with specified height. ### PHP ``` php -$query->query = new Criterion\Height('image', 0, 1500); +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); +$query->query = new Criterion\Image\Height('image', 0, 1500); ``` diff --git a/docs/search/criteria_reference/imagemimetype_criterion.md b/docs/search/criteria_reference/imagemimetype_criterion.md index f494232d6c..0564efd8da 100644 --- a/docs/search/criteria_reference/imagemimetype_criterion.md +++ b/docs/search/criteria_reference/imagemimetype_criterion.md @@ -16,18 +16,26 @@ The `MimeType` Search Criterion searches for image with specified mime type(s). ### PHP ``` php -$query->query = new Criterion\MimeType('image', 'image/jpeg'); +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); +$query->query = new Criterion\Image\MimeType('image', 'image/jpeg'); ``` or -```php +``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $mimeTypes = [ 'image/jpeg', 'image/png', ]; -$query->query = new Criterion\MimeType('image', $mimeTypes); +$query->query = new Criterion\Image\MimeType('image', $mimeTypes); ``` ### REST API diff --git a/docs/search/criteria_reference/imageorientation_criterion.md b/docs/search/criteria_reference/imageorientation_criterion.md index 1829d957a0..73d54f75b0 100644 --- a/docs/search/criteria_reference/imageorientation_criterion.md +++ b/docs/search/criteria_reference/imageorientation_criterion.md @@ -16,17 +16,30 @@ Supported orientation values: landscape, portrait and square. ### PHP +#### Single orientation value + ``` php -$query->query = new Criterion\Orientation('image', 'landscape'); +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\Image\Orientation; + +$query = new Query(); +$query->query = new Orientation('image', 'landscape'); +``` -OR +#### Multiple orientation values + +``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\Image\Orientation; +$query = new Query(); $orientations = [ 'landscape', 'portrait', ]; -$query->query = new Criterion\Orientation('image', $orientations); +$query->query = new Orientation('image', $orientations); ``` ### REST API diff --git a/docs/search/criteria_reference/imagewidth_criterion.md b/docs/search/criteria_reference/imagewidth_criterion.md index 34ec3293c7..63aa770802 100644 --- a/docs/search/criteria_reference/imagewidth_criterion.md +++ b/docs/search/criteria_reference/imagewidth_criterion.md @@ -17,5 +17,9 @@ The `Width` Search Criterion searches for image with specified width. ### PHP ``` php -$query->query = new Criterion\Width('image', 150, 1000); +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); +$query->query = new Criterion\Image\Width('image', 150, 1000); ``` diff --git a/docs/search/criteria_reference/integerattribute_criterion.md b/docs/search/criteria_reference/integerattribute_criterion.md index a7a0d7ad04..9981cabd3c 100644 --- a/docs/search/criteria_reference/integerattribute_criterion.md +++ b/docs/search/criteria_reference/integerattribute_criterion.md @@ -16,6 +16,9 @@ The `IntegerAttribute` Search Criterion searches for products by the value of th ### PHP ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + $query = new ProductQuery( null, new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\IntegerAttribute( diff --git a/docs/search/criteria_reference/iscontainer_criterion.md b/docs/search/criteria_reference/iscontainer_criterion.md index b30f2d6313..1edc2ba3a4 100644 --- a/docs/search/criteria_reference/iscontainer_criterion.md +++ b/docs/search/criteria_reference/iscontainer_criterion.md @@ -15,7 +15,11 @@ The [`IsContainer` Search Criterion](/api/php_api/php_api_reference/classes/Ibex ### PHP -```php +``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\IsContainer(); // Finds containers $query->query = new Criterion\IsContainer(false); // Finds non-containers ``` diff --git a/docs/search/criteria_reference/iscurrencyenabled_criterion.md b/docs/search/criteria_reference/iscurrencyenabled_criterion.md index 1985d5f8e2..d470584211 100644 --- a/docs/search/criteria_reference/iscurrencyenabled_criterion.md +++ b/docs/search/criteria_reference/iscurrencyenabled_criterion.md @@ -20,5 +20,9 @@ The `IsCurrencyEnabledCriterion` Criterion isn't available in Solr or Elasticsea ### PHP ``` php -$query->query = new \Ibexa\Contracts\ProductCatalog\Values\Currency\Query\Criterion\IsCurrencyEnabledCriterion(); +use Ibexa\Contracts\ProductCatalog\Values\Currency\CurrencyQuery; + +$query = new CurrencyQuery( + new \Ibexa\Contracts\ProductCatalog\Values\Currency\Query\Criterion\IsCurrencyEnabledCriterion() +); ``` diff --git a/docs/search/criteria_reference/isfieldempty_criterion.md b/docs/search/criteria_reference/isfieldempty_criterion.md index f8598b0397..c4ca0506f2 100644 --- a/docs/search/criteria_reference/isfieldempty_criterion.md +++ b/docs/search/criteria_reference/isfieldempty_criterion.md @@ -26,6 +26,10 @@ For this use case, use [`TaxonomyNoEntries`](taxonomy_no_entries.md) instead. ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\IsFieldEmpty('title'); ``` @@ -33,9 +37,13 @@ $query->query = new Criterion\IsFieldEmpty('title'); You can use the `IsFieldEmpty` Criterion to search for articles that don't have an image: -``` php hl_lines="4" -$query = new LocationQuery; -$query->query = new Criterion\LogicalAnd([ +``` php hl_lines="8" +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new LocationQuery(); +$query->query = new Criterion\LogicalAnd( + [ new Criterion\ContentTypeIdentifier('article'), new Criterion\IsFieldEmpty('image'), ] diff --git a/docs/search/criteria_reference/ismainlocation_criterion.md b/docs/search/criteria_reference/ismainlocation_criterion.md index 8b0172d691..d3790a5045 100644 --- a/docs/search/criteria_reference/ismainlocation_criterion.md +++ b/docs/search/criteria_reference/ismainlocation_criterion.md @@ -18,5 +18,10 @@ representing whether to search for a main or not main location ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\Location\IsMainLocation; + +$query = new Query(); $query->query = new Criterion\Location\IsMainLocation(IsMainLocation::MAIN); ``` diff --git a/docs/search/criteria_reference/isproductbased_criterion.md b/docs/search/criteria_reference/isproductbased_criterion.md index 077682c18f..507450e3e3 100644 --- a/docs/search/criteria_reference/isproductbased_criterion.md +++ b/docs/search/criteria_reference/isproductbased_criterion.md @@ -11,5 +11,9 @@ The `IsProductBased` Search Criterion searches for content that plays the role o ### PHP ``` php -$query->query = new Ibexa\Contracts\ProductCatalog\Values\Content\Query\Criterion\IsProductBased(); +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); +$query->query = new \Ibexa\Contracts\ProductCatalog\Values\Content\Query\Criterion\IsProductBased(); ``` diff --git a/docs/search/criteria_reference/isuserbased_criterion.md b/docs/search/criteria_reference/isuserbased_criterion.md index c3302d0db0..b07c5cd58d 100644 --- a/docs/search/criteria_reference/isuserbased_criterion.md +++ b/docs/search/criteria_reference/isuserbased_criterion.md @@ -25,6 +25,10 @@ The `IsUserBased` Criterion isn't available in Solr or Elasticsearch engines. ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\IsUserBased(); ``` diff --git a/docs/search/criteria_reference/isuserenabled_criterion.md b/docs/search/criteria_reference/isuserenabled_criterion.md index d95e3b29ad..bd61b058f5 100644 --- a/docs/search/criteria_reference/isuserenabled_criterion.md +++ b/docs/search/criteria_reference/isuserenabled_criterion.md @@ -16,6 +16,10 @@ The [`IsUserEnabled` Search Criterion](/api/php_api/php_api_reference/classes/Ib ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\IsUserEnabled(); ``` diff --git a/docs/search/criteria_reference/isvirtual_criterion.md b/docs/search/criteria_reference/isvirtual_criterion.md index b8d7700070..5f2bb3aa02 100644 --- a/docs/search/criteria_reference/isvirtual_criterion.md +++ b/docs/search/criteria_reference/isvirtual_criterion.md @@ -15,6 +15,9 @@ The `IsVirtual` Search Criterion searches for virtual or physical products. ### PHP ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + $query = new ProductQuery( null, new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\IsVirtual(true) diff --git a/docs/search/criteria_reference/languagecode_criterion.md b/docs/search/criteria_reference/languagecode_criterion.md index b4a977db2f..7b74156f66 100644 --- a/docs/search/criteria_reference/languagecode_criterion.md +++ b/docs/search/criteria_reference/languagecode_criterion.md @@ -16,6 +16,10 @@ The [`LanguageCode` Search Criterion](/api/php_api/php_api_reference/classes/Ibe ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\LanguageCode('ger-DE', false); ``` @@ -46,23 +50,26 @@ $query->query = new Criterion\LanguageCode('ger-DE', false); You can use the `LanguageCode` Criterion to search for articles that are lacking a translation into a specific language: -``` php hl_lines="5" -$query = new LocationQuery; -$query->query = new Criterion\LogicalAnd([ +``` php hl_lines="9" +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new LocationQuery(); +$query->query = new Criterion\LogicalAnd( + [ new Criterion\ContentTypeIdentifier('article'), new Criterion\LogicalNot( new Criterion\LanguageCode('ger-DE', false) - ) + ), ] ); -$results = $this->searchService->findContent($query); -$articles = []; +/** @var \Ibexa\Contracts\Core\Repository\SearchService $searchService */ +$results = $searchService->findContent($query); +$articlesToTranslate = []; foreach ($results->searchHits as $searchHit) { - $articles[] = $searchHit; + $articlesToTranslate[] = $searchHit; } -return $this->render('list/articles_to_translate.html.twig', [ - 'articles' => $articles, -]); +return $articlesToTranslate; ``` diff --git a/docs/search/criteria_reference/locationid_criterion.md b/docs/search/criteria_reference/locationid_criterion.md index 63169e9c71..7fba54c3f7 100644 --- a/docs/search/criteria_reference/locationid_criterion.md +++ b/docs/search/criteria_reference/locationid_criterion.md @@ -15,6 +15,10 @@ The [`LocationId` Search Criterion](/api/php_api/php_api_reference/classes/Ibexa ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\LocationId(62); ``` diff --git a/docs/search/criteria_reference/locationremoteid_criterion.md b/docs/search/criteria_reference/locationremoteid_criterion.md index d79bfd1aec..e51cadb8c1 100644 --- a/docs/search/criteria_reference/locationremoteid_criterion.md +++ b/docs/search/criteria_reference/locationremoteid_criterion.md @@ -15,6 +15,10 @@ The [`LocationRemoteId` Search Criterion](/api/php_api/php_api_reference/classes ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\LocationRemoteId(['4d1e5f216c0a7aaab7f005ffd4b6a8a8', 'b81ef3e62b514188bfddd2a80d447d34']); ``` diff --git a/docs/search/criteria_reference/logicaland_criterion.md b/docs/search/criteria_reference/logicaland_criterion.md index b4afdf3276..b5eac8a4b3 100644 --- a/docs/search/criteria_reference/logicaland_criterion.md +++ b/docs/search/criteria_reference/logicaland_criterion.md @@ -17,9 +17,14 @@ When querying for [products](product_api.md), use [LogicalAnd](/api/php_api/php_ ### PHP ``` php -$query->query = new Criterion\LogicalAnd([ +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); +$query->query = new Criterion\LogicalAnd( + [ new Criterion\ContentTypeIdentifier('article'), - new Criterion\SectionIdentifier(['sports', 'news']); + new Criterion\SectionIdentifier(['sports', 'news']), ] ); ``` diff --git a/docs/search/criteria_reference/logicalnot_criterion.md b/docs/search/criteria_reference/logicalnot_criterion.md index 444c2702fb..b1796be8d8 100644 --- a/docs/search/criteria_reference/logicalnot_criterion.md +++ b/docs/search/criteria_reference/logicalnot_criterion.md @@ -15,8 +15,14 @@ It takes only one Criterion in the array parameter. ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$contentTypeIdentifier = 'article'; + +$query = new Query(); $query->filter = new Criterion\LogicalNot( - new Criterion\ContentTypeIdentifier($contentTypeId) + new Criterion\ContentTypeIdentifier($contentTypeIdentifier) ); ``` diff --git a/docs/search/criteria_reference/logicalor_criterion.md b/docs/search/criteria_reference/logicalor_criterion.md index 657f9c94ec..0bbc57cd92 100644 --- a/docs/search/criteria_reference/logicalor_criterion.md +++ b/docs/search/criteria_reference/logicalor_criterion.md @@ -17,9 +17,14 @@ When querying for [products](product_api.md), use [LogicalOr](/api/php_api/php_a ### PHP ``` php -$query->filter = new Criterion\LogicalOr([ +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); +$query->filter = new Criterion\LogicalOr( + [ new Criterion\ContentTypeIdentifier('article'), - new Criterion\SectionIdentifier(['sports', 'news']); + new Criterion\SectionIdentifier(['sports', 'news']), ] ); ``` diff --git a/docs/search/criteria_reference/maplocationdistance_criterion.md b/docs/search/criteria_reference/maplocationdistance_criterion.md index 6592008687..c70c375524 100644 --- a/docs/search/criteria_reference/maplocationdistance_criterion.md +++ b/docs/search/criteria_reference/maplocationdistance_criterion.md @@ -28,5 +28,9 @@ The `MapLocationDistance` Criterion isn't available in [Repository filtering](se ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\MapLocationDistance('location', Criterion\Operator::LTE, 5, 51.395973, 22.531696); ``` diff --git a/docs/search/criteria_reference/notification_datecreated_criterion.md b/docs/search/criteria_reference/notification_datecreated_criterion.md index 6af6a8cbf0..a74bf65200 100644 --- a/docs/search/criteria_reference/notification_datecreated_criterion.md +++ b/docs/search/criteria_reference/notification_datecreated_criterion.md @@ -16,6 +16,6 @@ The `DateCreated` Search Criterion searches for notifications based on the date ### PHP -```php hl_lines="14-15 17" +``` php hl_lines="14-15 17" [[= include_code('code_samples/notifications/Src/Query/search.php') =]] ``` diff --git a/docs/search/criteria_reference/notification_status_criterion.md b/docs/search/criteria_reference/notification_status_criterion.md index 9bc3250b34..6dd02a2b04 100644 --- a/docs/search/criteria_reference/notification_status_criterion.md +++ b/docs/search/criteria_reference/notification_status_criterion.md @@ -15,6 +15,6 @@ The `Status` Search Criterion searches for notifications based on notification s ### PHP -```php hl_lines="12" +``` php hl_lines="12" [[= include_code('code_samples/notifications/Src/Query/search.php') =]] ``` diff --git a/docs/search/criteria_reference/notification_type_criterion.md b/docs/search/criteria_reference/notification_type_criterion.md index cd60efe74a..edc395d61c 100644 --- a/docs/search/criteria_reference/notification_type_criterion.md +++ b/docs/search/criteria_reference/notification_type_criterion.md @@ -15,6 +15,6 @@ The `Type` Search Criterion searches for notifications by their types. ### PHP -```php hl_lines="11" +``` php hl_lines="11" [[= include_code('code_samples/notifications/Src/Query/search.php') =]] ``` diff --git a/docs/search/criteria_reference/objectstateid_criterion.md b/docs/search/criteria_reference/objectstateid_criterion.md index f080cbaae9..d4de1e801b 100644 --- a/docs/search/criteria_reference/objectstateid_criterion.md +++ b/docs/search/criteria_reference/objectstateid_criterion.md @@ -15,6 +15,10 @@ The [`ObjectStateId` Search Criterion](/api/php_api/php_api_reference/classes/Ib ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\ObjectStateId([4, 5]); ``` diff --git a/docs/search/criteria_reference/objectstateidentifier_criterion.md b/docs/search/criteria_reference/objectstateidentifier_criterion.md index 75e7153828..90cdbc36d4 100644 --- a/docs/search/criteria_reference/objectstateidentifier_criterion.md +++ b/docs/search/criteria_reference/objectstateidentifier_criterion.md @@ -16,10 +16,18 @@ The [`ObjectStateIdentifier` Search Criterion](/api/php_api/php_api_reference/cl ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\ObjectStateIdentifier(['ready']); ``` ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\ObjectStateIdentifier(['not_locked'], 'ibexa_lock'); ``` diff --git a/docs/search/criteria_reference/order_company_associated_criterion.md b/docs/search/criteria_reference/order_company_associated_criterion.md index ee55c07a30..84e9529614 100644 --- a/docs/search/criteria_reference/order_company_associated_criterion.md +++ b/docs/search/criteria_reference/order_company_associated_criterion.md @@ -16,6 +16,9 @@ The `IsCompanyAssociatedCriterion` Search Criterion searches for orders based on ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\OrderManagement\Value\Order\OrderQuery; + $query = new OrderQuery( new \Ibexa\Contracts\OrderManagement\Value\Order\Query\Criterion\IsCompanyAssociatedCriterion(true) ); diff --git a/docs/search/criteria_reference/order_company_name_criterion.md b/docs/search/criteria_reference/order_company_name_criterion.md index 1f65ad8494..170fd0eaaa 100644 --- a/docs/search/criteria_reference/order_company_name_criterion.md +++ b/docs/search/criteria_reference/order_company_name_criterion.md @@ -16,6 +16,9 @@ The `CompanyNameCriterion` Search Criterion searches for orders based on the nam ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\OrderManagement\Value\Order\OrderQuery; + $query = new OrderQuery( new \Ibexa\Contracts\OrderManagement\Value\Order\Query\Criterion\CompanyNameCriterion('IBM') ); diff --git a/docs/search/criteria_reference/order_created_criterion.md b/docs/search/criteria_reference/order_created_criterion.md index aa59007fff..ac566ca2e6 100644 --- a/docs/search/criteria_reference/order_created_criterion.md +++ b/docs/search/criteria_reference/order_created_criterion.md @@ -17,6 +17,9 @@ The `CreatedAtCriterion` Search Criterion searches for orders based on the date ### PHP ``` php +use Ibexa\Contracts\OrderManagement\Value\Order\OrderQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + $criteria = new \Ibexa\Contracts\OrderManagement\Value\Order\Query\Criterion\CreatedAtCriterion( new DateTime('2023-03-01'), 'GTE' diff --git a/docs/search/criteria_reference/order_currency_code_criterion.md b/docs/search/criteria_reference/order_currency_code_criterion.md index 9348a743a3..9f0b5f639c 100644 --- a/docs/search/criteria_reference/order_currency_code_criterion.md +++ b/docs/search/criteria_reference/order_currency_code_criterion.md @@ -16,6 +16,9 @@ The `CurrencyCodeCriterion` Search Criterion searches for orders based on the cu ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\OrderManagement\Value\Order\OrderQuery; + $query = new OrderQuery( new \Ibexa\Contracts\OrderManagement\Value\Order\Query\Criterion\CurrencyCodeCriterion('USD') ); diff --git a/docs/search/criteria_reference/order_customer_name_criterion.md b/docs/search/criteria_reference/order_customer_name_criterion.md index 80b0fc08d5..6f72425cc1 100644 --- a/docs/search/criteria_reference/order_customer_name_criterion.md +++ b/docs/search/criteria_reference/order_customer_name_criterion.md @@ -16,6 +16,9 @@ The `CustomerNameCriterion` Search Criterion searches for orders based on the na ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\OrderManagement\Value\Order\OrderQuery; + $query = new OrderQuery( new \Ibexa\Contracts\OrderManagement\Value\Order\Query\Criterion\CustomerNameCriterion('john') ); diff --git a/docs/search/criteria_reference/order_identifier_criterion.md b/docs/search/criteria_reference/order_identifier_criterion.md index 4da72e5ab1..107c4fa62d 100644 --- a/docs/search/criteria_reference/order_identifier_criterion.md +++ b/docs/search/criteria_reference/order_identifier_criterion.md @@ -16,6 +16,9 @@ The `IdentifierCriterion` Search Criterion searches for orders based on the orde ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\OrderManagement\Value\Order\OrderQuery; + $query = new OrderQuery( new \Ibexa\Contracts\OrderManagement\Value\Order\Query\Criterion\IdentifierCriterion('f7578972-e7f4-4cae-85dc-a7c74610204e') ); diff --git a/docs/search/criteria_reference/order_owner_criterion.md b/docs/search/criteria_reference/order_owner_criterion.md index 6d037c275a..4b977a1e09 100644 --- a/docs/search/criteria_reference/order_owner_criterion.md +++ b/docs/search/criteria_reference/order_owner_criterion.md @@ -9,14 +9,20 @@ The `OwnerCriterion` Criterion searches for orders based on the user reference. ## Arguments -- `UserReference` object - \Ibexa\Contracts\Core\Repository\Values\User\UserReference(int $userId) +- `UserReference` object - new \Ibexa\Core\Repository\Values\User\UserReference(int $userId) ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\OrderManagement\Value\Order\OrderQuery; + +/** @var \Ibexa\Contracts\Core\Repository\UserService $userService */ +$user = $userService->loadUserByLogin('user'); + $query = new OrderQuery( new \Ibexa\Contracts\OrderManagement\Value\Order\Query\Criterion\OwnerCriterion( - \Ibexa\Contracts\Core\Repository\Values\User\UserReference(14) + $user ) ); ``` @@ -24,11 +30,18 @@ $query = new OrderQuery( `OwnerCriterion` Criterion accepts also multiple values: ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\OrderManagement\Value\Order\OrderQuery; + +/** @var \Ibexa\Contracts\Core\Repository\UserService $userService */ +$user1 = $userService->loadUser(12345); +$user2 = $userService->loadUserByLogin('user'); + $query = new OrderQuery( new \Ibexa\Contracts\OrderManagement\Value\Order\Query\Criterion\OwnerCriterion( [ - \Ibexa\Contracts\Core\Repository\Values\User\UserReference(14), - \Ibexa\Contracts\Core\Repository\Values\User\UserReference(123), + $user1, + $user2, ] ) ); diff --git a/docs/search/criteria_reference/order_price_criterion.md b/docs/search/criteria_reference/order_price_criterion.md index 745ca2a126..e72f32c77b 100644 --- a/docs/search/criteria_reference/order_price_criterion.md +++ b/docs/search/criteria_reference/order_price_criterion.md @@ -17,6 +17,9 @@ The `PriceCriterion` searches for orders by their total net value. ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\OrderManagement\Value\Order\OrderQuery; + $criteria = new \Ibexa\Contracts\OrderManagement\Value\Order\Query\Criterion\PriceCriterion( 12900, 'GTE' diff --git a/docs/search/criteria_reference/order_source_criterion.md b/docs/search/criteria_reference/order_source_criterion.md index 53abd3a519..956fae1ec3 100644 --- a/docs/search/criteria_reference/order_source_criterion.md +++ b/docs/search/criteria_reference/order_source_criterion.md @@ -16,6 +16,9 @@ The `SourceCriterion` Search Criterion searches for orders based on the source o ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\OrderManagement\Value\Order\OrderQuery; + $query = new OrderQuery( new \Ibexa\Contracts\OrderManagement\Value\Order\Query\Criterion\SourceCriterion('local_shop') ); diff --git a/docs/search/criteria_reference/order_status_criterion.md b/docs/search/criteria_reference/order_status_criterion.md index e6f3f5cb48..237b202694 100644 --- a/docs/search/criteria_reference/order_status_criterion.md +++ b/docs/search/criteria_reference/order_status_criterion.md @@ -16,6 +16,9 @@ The `StatusCriterion` Search Criterion searches for orders based on order status ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\OrderManagement\Value\Order\OrderQuery; + $query = new OrderQuery( new \Ibexa\Contracts\OrderManagement\Value\Order\Query\Criterion\StatusCriterion('pending') ); diff --git a/docs/search/criteria_reference/parentlocationid_criterion.md b/docs/search/criteria_reference/parentlocationid_criterion.md index e30307eeb0..eb1514964b 100644 --- a/docs/search/criteria_reference/parentlocationid_criterion.md +++ b/docs/search/criteria_reference/parentlocationid_criterion.md @@ -16,6 +16,10 @@ searches for content based on the Location ID of its parent. ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\ParentLocationId([54, 58]); ``` @@ -45,14 +49,20 @@ $query->query = new Criterion\ParentLocationId([54, 58]); You can use the `ParentLocationId` Search Criterion to list blog posts contained in a blog: -``` php hl_lines="4" +``` php hl_lines="9" +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$locationId = 12345; + $query = new LocationQuery(); $query->query = new Criterion\LogicalAnd([ new Criterion\Visibility(Criterion\Visibility::VISIBLE), new Criterion\ParentLocationId($locationId), ]); -$results = $this->searchService->findLocations($query); +/** @var \Ibexa\Contracts\Core\Repository\SearchService $searchService */ +$results = $searchService->findLocations($query); $posts = []; foreach ($results->searchHits as $searchHit) { $posts[] = $searchHit; diff --git a/docs/search/criteria_reference/payment_createdat_criterion.md b/docs/search/criteria_reference/payment_createdat_criterion.md index d43536e7e1..66c1130db3 100644 --- a/docs/search/criteria_reference/payment_createdat_criterion.md +++ b/docs/search/criteria_reference/payment_createdat_criterion.md @@ -17,6 +17,9 @@ The `CreatedAt` Search Criterion searches for payments based on the date when th ### PHP ``` php +use Ibexa\Contracts\Payment\Payment\PaymentQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + $criteria = new \Ibexa\Contracts\Payment\Payment\Query\Criterion\CreatedAt( new DateTime('2023-03-01') ); diff --git a/docs/search/criteria_reference/payment_currency_criterion.md b/docs/search/criteria_reference/payment_currency_criterion.md index 524561faed..59829269d6 100644 --- a/docs/search/criteria_reference/payment_currency_criterion.md +++ b/docs/search/criteria_reference/payment_currency_criterion.md @@ -16,5 +16,9 @@ The `Currency` Search Criterion searches for payments based on the currency code ### PHP ``` php -$query->query = new \Ibexa\Contracts\Payment\Payment\Query\Criterion\Currency('EUR'); +use Ibexa\Contracts\Payment\Payment\PaymentQuery; + +$query = new PaymentQuery( + new \Ibexa\Contracts\Payment\Payment\Query\Criterion\Currency('EUR') +); ``` diff --git a/docs/search/criteria_reference/payment_id_criterion.md b/docs/search/criteria_reference/payment_id_criterion.md index 3ccd16044d..6c1a9bfeb3 100644 --- a/docs/search/criteria_reference/payment_id_criterion.md +++ b/docs/search/criteria_reference/payment_id_criterion.md @@ -16,5 +16,9 @@ The `Id` Search Criterion searches for payments based on the payment ID. ### PHP ``` php -$query->query = new \Ibexa\Contracts\Payment\Payment\Query\Criterion\Id(2); +use Ibexa\Contracts\Payment\Payment\PaymentQuery; + +$query = new PaymentQuery( + new \Ibexa\Contracts\Payment\Payment\Query\Criterion\Id(2) +); ``` diff --git a/docs/search/criteria_reference/payment_identifier_criterion.md b/docs/search/criteria_reference/payment_identifier_criterion.md index 0f6ca32dfc..7de17744f0 100644 --- a/docs/search/criteria_reference/payment_identifier_criterion.md +++ b/docs/search/criteria_reference/payment_identifier_criterion.md @@ -16,5 +16,9 @@ The `Identifier` Search Criterion searches for payments based on the payment ide ### PHP ``` php -$query->query = new \Ibexa\Contracts\Payment\Payment\Query\Criterion\Identifier('f7578972-e7f4-4cae-85dc-a7c74610204e'); +use Ibexa\Contracts\Payment\Payment\PaymentQuery; + +$query = new PaymentQuery( + new \Ibexa\Contracts\Payment\Payment\Query\Criterion\Identifier('f7578972-e7f4-4cae-85dc-a7c74610204e') +); ``` diff --git a/docs/search/criteria_reference/payment_logicaland_criterion.md b/docs/search/criteria_reference/payment_logicaland_criterion.md index fc51f0ab28..1d947d8c0c 100644 --- a/docs/search/criteria_reference/payment_logicaland_criterion.md +++ b/docs/search/criteria_reference/payment_logicaland_criterion.md @@ -16,10 +16,14 @@ The `LogicalAnd` Search Criterion matches payments if all provided Criteria matc ### PHP ``` php -$query->query = new \Ibexa\Contracts\Payment\Payment\Query\Criterion\LogicalAnd( - [ - new \Ibexa\Contracts\Payment\Payment\Query\Criterion\CreatedAt(new DateTime('2023-03-01')); - new \Ibexa\Contracts\Payment\Payment\Query\Criterion\Currency('USD'); - ] -); +use Ibexa\Contracts\Payment\Payment\PaymentQuery; +use Ibexa\Contracts\Payment\Payment\Query\Criterion\CreatedAt; +use Ibexa\Contracts\Payment\Payment\Query\Criterion\Currency; +use Ibexa\Contracts\Payment\Payment\Query\Criterion\LogicalAnd; + +$query = new PaymentQuery(); +$query->setQuery(new LogicalAnd( + new CreatedAt(new DateTime('2023-03-01')), + new Currency('USD'), +)); ``` diff --git a/docs/search/criteria_reference/payment_logicalor_criterion.md b/docs/search/criteria_reference/payment_logicalor_criterion.md index 0ab036ebc9..e20bc93559 100644 --- a/docs/search/criteria_reference/payment_logicalor_criterion.md +++ b/docs/search/criteria_reference/payment_logicalor_criterion.md @@ -16,10 +16,14 @@ The `LogicalOr` Search Criterion matches payments if at least one of the provide ### PHP ``` php -$query->query = new Criterion\LogicalOr( - [ - new \Ibexa\Contracts\Payment\Payment\Query\Criterion\CreatedAt(new DateTime('2023-03-01')); - new \Ibexa\Contracts\Payment\Payment\Query\Criterion\Currency('USD'); - ] -); +use Ibexa\Contracts\Payment\Payment\PaymentQuery; +use Ibexa\Contracts\Payment\Payment\Query\Criterion\CreatedAt; +use Ibexa\Contracts\Payment\Payment\Query\Criterion\Currency; +use Ibexa\Contracts\Payment\Payment\Query\Criterion\LogicalOr; + +$query = new PaymentQuery(); +$query->setQuery(new LogicalOr( + new CreatedAt(new DateTime('2023-03-01')), + new Currency('USD'), +)); ``` diff --git a/docs/search/criteria_reference/payment_method_createdat_criterion.md b/docs/search/criteria_reference/payment_method_createdat_criterion.md index eac4ce8ab2..fd2280a011 100644 --- a/docs/search/criteria_reference/payment_method_createdat_criterion.md +++ b/docs/search/criteria_reference/payment_method_createdat_criterion.md @@ -17,6 +17,9 @@ The `CreatedAt` Search Criterion searches for payment methods based on the date ### PHP ``` php +use Ibexa\Contracts\Payment\PaymentMethod\PaymentMethodQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + $criteria = new \Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\CreatedAt( new DateTime('2023-03-01') ); diff --git a/docs/search/criteria_reference/payment_method_enabled_criterion.md b/docs/search/criteria_reference/payment_method_enabled_criterion.md index b9671b987d..2447da755f 100644 --- a/docs/search/criteria_reference/payment_method_enabled_criterion.md +++ b/docs/search/criteria_reference/payment_method_enabled_criterion.md @@ -16,5 +16,9 @@ The `Enabled` Search Criterion searches for payment methods based on whether the ### PHP ``` php -$query->query = new \Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\Enabled(true); +use Ibexa\Contracts\Payment\PaymentMethod\PaymentMethodQuery; + +$query = new PaymentMethodQuery( + new \Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\Enabled(true) +); ``` diff --git a/docs/search/criteria_reference/payment_method_id_criterion.md b/docs/search/criteria_reference/payment_method_id_criterion.md index c1ca101653..2a2a7fb661 100644 --- a/docs/search/criteria_reference/payment_method_id_criterion.md +++ b/docs/search/criteria_reference/payment_method_id_criterion.md @@ -16,5 +16,9 @@ The `Id` Search Criterion searches for payment methods based on the payment meth ### PHP ``` php -$query->query = new \Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\Id(2); +use Ibexa\Contracts\Payment\PaymentMethod\PaymentMethodQuery; + +$query = new PaymentMethodQuery( + new \Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\Id(2) +); ``` diff --git a/docs/search/criteria_reference/payment_method_identifier_criterion.md b/docs/search/criteria_reference/payment_method_identifier_criterion.md index 04fdcc21a0..809cf68adc 100644 --- a/docs/search/criteria_reference/payment_method_identifier_criterion.md +++ b/docs/search/criteria_reference/payment_method_identifier_criterion.md @@ -16,5 +16,9 @@ The `Identifier` Search Criterion searches for payment methods based on the paym ### PHP ``` php -$query->query = new \Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\Identifier('f7578972-e7f4-4cae-85dc-a7c74610204e'); +use Ibexa\Contracts\Payment\PaymentMethod\PaymentMethodQuery; + +$query = new PaymentMethodQuery( + new \Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\Identifier('f7578972-e7f4-4cae-85dc-a7c74610204e') +); ``` diff --git a/docs/search/criteria_reference/payment_method_logicaland_criterion.md b/docs/search/criteria_reference/payment_method_logicaland_criterion.md index b903040e18..2ebc5e2ef5 100644 --- a/docs/search/criteria_reference/payment_method_logicaland_criterion.md +++ b/docs/search/criteria_reference/payment_method_logicaland_criterion.md @@ -16,10 +16,14 @@ The `LogicalAnd` Search Criterion matches payment methods if all provided Criter ### PHP ``` php -$query->query = new \Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\LogicalAnd( - [ - new \Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\CreatedAt(new DateTime('2023-03-01')); - new \Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\Enabled(true); - ] -); +use Ibexa\Contracts\Payment\PaymentMethod\PaymentMethodQuery; +use Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\CreatedAt; +use Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\Enabled; +use Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\LogicalAnd; + +$query = new PaymentMethodQuery(); +$query->setQuery(new LogicalAnd( + new CreatedAt(new DateTime('2023-03-01')), + new Enabled(true), +)); ``` diff --git a/docs/search/criteria_reference/payment_method_logicalor_criterion.md b/docs/search/criteria_reference/payment_method_logicalor_criterion.md index 92b0992efe..3798f92745 100644 --- a/docs/search/criteria_reference/payment_method_logicalor_criterion.md +++ b/docs/search/criteria_reference/payment_method_logicalor_criterion.md @@ -16,10 +16,13 @@ The `LogicalOr` Search Criterion matches payment methods if at least one of the ### PHP ``` php -$query->query = new \Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\LogicalOr( - [ - new \Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\CreatedAt(new DateTime('2023-03-01')); - new \Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\CreatedAt(new DateTime('2023-05-01')); - ] -); +use Ibexa\Contracts\Payment\PaymentMethod\PaymentMethodQuery; +use Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\CreatedAt; +use Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\LogicalOr; + +$query = new PaymentMethodQuery(); +$query->setQuery(new LogicalOr( + new CreatedAt(new DateTime('2023-03-01')), + new CreatedAt(new DateTime('2023-05-01')), +)); ``` diff --git a/docs/search/criteria_reference/payment_method_name_criterion.md b/docs/search/criteria_reference/payment_method_name_criterion.md index 0131233c5c..95499b72c6 100644 --- a/docs/search/criteria_reference/payment_method_name_criterion.md +++ b/docs/search/criteria_reference/payment_method_name_criterion.md @@ -16,5 +16,9 @@ The `Name` Search Criterion searches for payment methods based on the existing p ### PHP ``` php -$query->query = new \Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\Name('Credit Card'); +use Ibexa\Contracts\Payment\PaymentMethod\PaymentMethodQuery; + +$query = new PaymentMethodQuery( + new \Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\Name('Credit Card') +); ``` diff --git a/docs/search/criteria_reference/payment_method_type_criterion.md b/docs/search/criteria_reference/payment_method_type_criterion.md index db7e4be3c9..72524ab962 100644 --- a/docs/search/criteria_reference/payment_method_type_criterion.md +++ b/docs/search/criteria_reference/payment_method_type_criterion.md @@ -16,5 +16,12 @@ The `Type` Search Criterion searches for payment methods based on payment method ### PHP ``` php -$query->query = new \Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\Type('offline'); +use Ibexa\Contracts\Payment\PaymentMethod\PaymentMethodQuery; + +/** @var \Ibexa\Contracts\Payment\PaymentMethod\Type\TypeRegistryInterface $paymentMethodTypeRegistry */ +$paymentMethodType = $paymentMethodTypeRegistry->getPaymentMethodType('offline'); + +$query = new PaymentMethodQuery( + new \Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\Type($paymentMethodType) +); ``` diff --git a/docs/search/criteria_reference/payment_method_updatedat_criterion.md b/docs/search/criteria_reference/payment_method_updatedat_criterion.md index be34b4d8d6..13a04438f6 100644 --- a/docs/search/criteria_reference/payment_method_updatedat_criterion.md +++ b/docs/search/criteria_reference/payment_method_updatedat_criterion.md @@ -17,6 +17,9 @@ The `UpdatedAt` Search Criterion searches for payment methods based on the date ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\Payment\PaymentMethod\PaymentMethodQuery; + $criteria = new \Ibexa\Contracts\Payment\PaymentMethod\Query\Criterion\UpdatedAt( new DateTime('2023-03-01') ); diff --git a/docs/search/criteria_reference/payment_order_criterion.md b/docs/search/criteria_reference/payment_order_criterion.md index 05b8eacc1a..3eaf004566 100644 --- a/docs/search/criteria_reference/payment_order_criterion.md +++ b/docs/search/criteria_reference/payment_order_criterion.md @@ -16,5 +16,12 @@ The `Order` Search Criterion searches for payments based on an ID of an associat ### PHP ``` php -$query->query = new \Ibexa\Contracts\Payment\Payment\Query\Criterion\Order(4); +use Ibexa\Contracts\Payment\Payment\PaymentQuery; + +/** @var \Ibexa\Contracts\OrderManagement\OrderServiceInterface $orderService */ +$order = $orderService->getOrder(4); + +$query = new PaymentQuery( + new \Ibexa\Contracts\Payment\Payment\Query\Criterion\Order($order) +); ``` diff --git a/docs/search/criteria_reference/payment_payment_method_criterion.md b/docs/search/criteria_reference/payment_payment_method_criterion.md index 1b9bba10b2..98d7d033c3 100644 --- a/docs/search/criteria_reference/payment_payment_method_criterion.md +++ b/docs/search/criteria_reference/payment_payment_method_criterion.md @@ -16,5 +16,12 @@ The `PaymentMethod` Search Criterion searches for payments based on a payment me ### PHP ``` php -$query->query = new \Ibexa\Contracts\Payment\Payment\Query\Criterion\PaymentMethod(2); +use Ibexa\Contracts\Payment\Payment\PaymentQuery; + +/** @var \Ibexa\Contracts\Payment\PaymentMethodServiceInterface $paymentMethodService */ +$paymentMethod = $paymentMethodService->getPaymentMethod(2); + +$query = new PaymentQuery( + new \Ibexa\Contracts\Payment\Payment\Query\Criterion\PaymentMethod($paymentMethod) +); ``` diff --git a/docs/search/criteria_reference/payment_status_criterion.md b/docs/search/criteria_reference/payment_status_criterion.md index c0a037e994..deb1d6d8f2 100644 --- a/docs/search/criteria_reference/payment_status_criterion.md +++ b/docs/search/criteria_reference/payment_status_criterion.md @@ -16,5 +16,9 @@ The `Status` Search Criterion searches for payments based on payment status. ### PHP ``` php -$query->query = new \Ibexa\Contracts\Payment\Payment\Query\Criterion\Status('failed'); +use Ibexa\Contracts\Payment\Payment\PaymentQuery; + +$query = new PaymentQuery( + new \Ibexa\Contracts\Payment\Payment\Query\Criterion\Status('failed') +); ``` diff --git a/docs/search/criteria_reference/payment_updatedat_criterion.md b/docs/search/criteria_reference/payment_updatedat_criterion.md index ec947465a8..8257b614ac 100644 --- a/docs/search/criteria_reference/payment_updatedat_criterion.md +++ b/docs/search/criteria_reference/payment_updatedat_criterion.md @@ -17,6 +17,9 @@ The `UpdatedAt` Search Criterion searches for payments based on the date when th ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\Payment\Payment\PaymentQuery; + $criteria = new \Ibexa\Contracts\Payment\Payment\Query\Criterion\UpdatedAt( new DateTime('2023-03-01') ); diff --git a/docs/search/criteria_reference/price_currency_criterion.md b/docs/search/criteria_reference/price_currency_criterion.md index 8d3dd0a10b..c96105d174 100644 --- a/docs/search/criteria_reference/price_currency_criterion.md +++ b/docs/search/criteria_reference/price_currency_criterion.md @@ -15,7 +15,11 @@ The `Currency` Search Criterion searches for prices based on the given currency. ### PHP ``` php -$currency = $priceService->getPriceById('EUR'); +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\ProductCatalog\Values\Price\PriceQuery; + +/** @var \Ibexa\Contracts\ProductCatalog\CurrencyServiceInterface $currencyService */ +$currency = $currencyService->getCurrencyByCode('EUR'); $query = new PriceQuery( new \Ibexa\Contracts\ProductCatalog\Values\Price\Query\Criterion\Currency($currency) diff --git a/docs/search/criteria_reference/price_customergroup_criterion.md b/docs/search/criteria_reference/price_customergroup_criterion.md index a23aa07446..2c33e1bd64 100644 --- a/docs/search/criteria_reference/price_customergroup_criterion.md +++ b/docs/search/criteria_reference/price_customergroup_criterion.md @@ -15,6 +15,10 @@ The `CustomerGroup` Search Criterion searches for prices based on the customer g ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\ProductCatalog\Values\Price\PriceQuery; + +/** @var \Ibexa\Contracts\ProductCatalog\CustomerGroupServiceInterface $customerGroupService */ $customerGroup = $customerGroupService->getCustomerGroup(123); $query = new PriceQuery( diff --git a/docs/search/criteria_reference/price_isbaseprice_criterion.md b/docs/search/criteria_reference/price_isbaseprice_criterion.md index 757352702c..56efe39038 100644 --- a/docs/search/criteria_reference/price_isbaseprice_criterion.md +++ b/docs/search/criteria_reference/price_isbaseprice_criterion.md @@ -19,6 +19,9 @@ The `IsBasePrice` Criterion isn't available in Solr or Elasticsearch engines. ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\ProductCatalog\Values\Price\PriceQuery; + $query = new PriceQuery( new \Ibexa\Contracts\ProductCatalog\Values\Price\Query\Criterion\IsBasePrice() ); diff --git a/docs/search/criteria_reference/price_iscustomprice_criterion.md b/docs/search/criteria_reference/price_iscustomprice_criterion.md index 3bf91b360f..0aa2ec2afb 100644 --- a/docs/search/criteria_reference/price_iscustomprice_criterion.md +++ b/docs/search/criteria_reference/price_iscustomprice_criterion.md @@ -19,6 +19,9 @@ The `IsCustomPrice` Criterion isn't available in Solr or Elasticsearch engines. ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\ProductCatalog\Values\Price\PriceQuery; + $query = new PriceQuery( new \Ibexa\Contracts\ProductCatalog\Values\Price\Query\Criterion\IsCustomPrice() ); diff --git a/docs/search/criteria_reference/price_logicaland_criterion.md b/docs/search/criteria_reference/price_logicaland_criterion.md index ee9ab7c48b..7693f7a8e5 100644 --- a/docs/search/criteria_reference/price_logicaland_criterion.md +++ b/docs/search/criteria_reference/price_logicaland_criterion.md @@ -16,10 +16,13 @@ The `LogicalAnd` Search Criterion matches prices if all provided Criteria match. ### PHP ``` php -$query->query = new \Ibexa\Contracts\ProductCatalog\Values\Price\Query\Criterion\LogicalAnd( - [ - new \Ibexa\Contracts\ProductCatalog\Values\Price\Query\Criterion\Currency('USD'), +use Ibexa\Contracts\ProductCatalog\Values\Price\PriceQuery; + +/** @var \Ibexa\Contracts\ProductCatalog\Values\CurrencyInterface $currencyUSD */ +$query = new PriceQuery( + new \Ibexa\Contracts\ProductCatalog\Values\Price\Query\Criterion\LogicalAnd( + new \Ibexa\Contracts\ProductCatalog\Values\Price\Query\Criterion\Currency($currencyUSD), new \Ibexa\Contracts\ProductCatalog\Values\Price\Query\Criterion\IsCustomPrice() - ] + ) ); ``` diff --git a/docs/search/criteria_reference/price_logicalor_criterion.md b/docs/search/criteria_reference/price_logicalor_criterion.md index d3e93a6dc9..5151e271d4 100644 --- a/docs/search/criteria_reference/price_logicalor_criterion.md +++ b/docs/search/criteria_reference/price_logicalor_criterion.md @@ -16,10 +16,14 @@ The `LogicalOr` Search Criterion matches prices if at least one of the provided ### PHP ``` php -$query->query = new \Ibexa\Contracts\ProductCatalog\Values\Price\Query\Criterion\LogicalOr( - [ - new \Ibexa\Contracts\ProductCatalog\Values\Price\Query\Criterion\Currency('USD'), - new \Ibexa\Contracts\ProductCatalog\Values\Price\Query\Criterion\Currency('EUR') - ] +use Ibexa\Contracts\ProductCatalog\Values\Price\PriceQuery; + +/** @var \Ibexa\Contracts\ProductCatalog\Values\CurrencyInterface $currencyUSD */ +/** @var \Ibexa\Contracts\ProductCatalog\Values\CurrencyInterface $currencyEUR */ +$query = new PriceQuery( + new \Ibexa\Contracts\ProductCatalog\Values\Price\Query\Criterion\LogicalOr( + new \Ibexa\Contracts\ProductCatalog\Values\Price\Query\Criterion\Currency($currencyUSD), + new \Ibexa\Contracts\ProductCatalog\Values\Price\Query\Criterion\Currency($currencyEUR) + ) ); ``` diff --git a/docs/search/criteria_reference/price_product_criterion.md b/docs/search/criteria_reference/price_product_criterion.md index 6aaf93a57d..ff213b6a05 100644 --- a/docs/search/criteria_reference/price_product_criterion.md +++ b/docs/search/criteria_reference/price_product_criterion.md @@ -15,6 +15,9 @@ The `Product` Search Criterion searches for prices based on product codes. ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\ProductCatalog\Values\Price\PriceQuery; + $query = new PriceQuery( new \Ibexa\Contracts\ProductCatalog\Values\Price\Query\Criterion\Product('ergo_desk') ); diff --git a/docs/search/criteria_reference/priority_criterion.md b/docs/search/criteria_reference/priority_criterion.md index 34975939d0..feffcf99ac 100644 --- a/docs/search/criteria_reference/priority_criterion.md +++ b/docs/search/criteria_reference/priority_criterion.md @@ -23,5 +23,9 @@ The `value` argument requires: ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\Location\Priority(Criterion\Operator::GTE, 50); ``` diff --git a/docs/search/criteria_reference/productavailability_criterion.md b/docs/search/criteria_reference/productavailability_criterion.md index 3fea37006a..764f9b9a67 100644 --- a/docs/search/criteria_reference/productavailability_criterion.md +++ b/docs/search/criteria_reference/productavailability_criterion.md @@ -21,6 +21,9 @@ For more information, see [Availability and computed availability](products.md#a ### PHP ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + $query = new ProductQuery( null, new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\ProductAvailability(true) diff --git a/docs/search/criteria_reference/productcategory_criterion.md b/docs/search/criteria_reference/productcategory_criterion.md index 76d5fa0002..8ca37ebc9c 100644 --- a/docs/search/criteria_reference/productcategory_criterion.md +++ b/docs/search/criteria_reference/productcategory_criterion.md @@ -15,6 +15,9 @@ The `ProductCategory` Search Criterion searches for products by the category the ### PHP ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + $query = new ProductQuery( null, new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\ProductCategory([2, 3]) diff --git a/docs/search/criteria_reference/productcode_criterion.md b/docs/search/criteria_reference/productcode_criterion.md index 838c623d9f..39d7e1b1af 100644 --- a/docs/search/criteria_reference/productcode_criterion.md +++ b/docs/search/criteria_reference/productcode_criterion.md @@ -15,6 +15,9 @@ The `ProductCode` Search Criterion searches for products by their codes. ### PHP ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + $query = new ProductQuery( null, new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\ProductCode(['ergo_desk', 'alter_desk']) diff --git a/docs/search/criteria_reference/productname_criterion.md b/docs/search/criteria_reference/productname_criterion.md index b19a270ae8..5a3d9a18cf 100644 --- a/docs/search/criteria_reference/productname_criterion.md +++ b/docs/search/criteria_reference/productname_criterion.md @@ -15,6 +15,9 @@ The `ProductName` Search Criterion searches for products by their names. ### PHP ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + $query = new ProductQuery( null, new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\ProductName('sofa*') diff --git a/docs/search/criteria_reference/productstock_criterion.md b/docs/search/criteria_reference/productstock_criterion.md index ed88bc178c..710041b361 100644 --- a/docs/search/criteria_reference/productstock_criterion.md +++ b/docs/search/criteria_reference/productstock_criterion.md @@ -16,6 +16,9 @@ The `ProductStock` Search Criterion searches for products by their numerical sto ### PHP ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + $productQuery = new ProductQuery( null, new Criterion\ProductStock(10) @@ -23,6 +26,9 @@ $productQuery = new ProductQuery( ``` ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + $productQuery = new ProductQuery( null, new Criterion\ProductStock(50, '>=') diff --git a/docs/search/criteria_reference/productstockrange_criterion.md b/docs/search/criteria_reference/productstockrange_criterion.md index f71c7f5adc..b185a705c8 100644 --- a/docs/search/criteria_reference/productstockrange_criterion.md +++ b/docs/search/criteria_reference/productstockrange_criterion.md @@ -16,6 +16,9 @@ The `ProductStockRange` Search Criterion searches for products by their numerica ### PHP ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + $productQuery = new ProductQuery( null, new Criterion\ProductStockRange(10, 120) diff --git a/docs/search/criteria_reference/producttype_criterion.md b/docs/search/criteria_reference/producttype_criterion.md index 06c2c1c452..c98fbcdc09 100644 --- a/docs/search/criteria_reference/producttype_criterion.md +++ b/docs/search/criteria_reference/producttype_criterion.md @@ -15,6 +15,9 @@ The `ProductType` Search Criterion searches for products by their codes. ### PHP ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + $query = new ProductQuery( null, new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\ProductType(['dress']) diff --git a/docs/search/criteria_reference/rangemeasurementattributemaximum_criterion.md b/docs/search/criteria_reference/rangemeasurementattributemaximum_criterion.md index c28be6ffd8..7a5a71edae 100644 --- a/docs/search/criteria_reference/rangemeasurementattributemaximum_criterion.md +++ b/docs/search/criteria_reference/rangemeasurementattributemaximum_criterion.md @@ -16,11 +16,15 @@ The `RangeMeasurementAttributeMaximum` Search Criterion searches for products by ### PHP ``` php -$value = $this->measurementService->buildSimpleValue('length', 150, 'centimeter'); +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + +/** @var \Ibexa\Contracts\Measurement\MeasurementServiceInterface $measurementService */ +$value = $measurementService->buildSimpleValue('length', 150, 'centimeter'); $query = new ProductQuery( null, - new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\RangeMeasurementAttributeMaximum( + new \Ibexa\Contracts\Measurement\Product\Query\Criterion\RangeMeasurementAttributeMaximum( 'length', $value ) diff --git a/docs/search/criteria_reference/rangemeasurementattributeminimum_criterion.md b/docs/search/criteria_reference/rangemeasurementattributeminimum_criterion.md index fb5d54dbad..7f103eee09 100644 --- a/docs/search/criteria_reference/rangemeasurementattributeminimum_criterion.md +++ b/docs/search/criteria_reference/rangemeasurementattributeminimum_criterion.md @@ -16,11 +16,15 @@ The `RangeMeasurementAttributeMinimum` Search Criterion searches for products by ### PHP ``` php -$value = $this->measurementService->buildSimpleValue('length', 100, 'centimeter'); +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + +/** @var \Ibexa\Contracts\Measurement\MeasurementServiceInterface $measurementService */ +$value = $measurementService->buildSimpleValue('length', 100, 'centimeter'); $query = new ProductQuery( null, - new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\RangeMeasurementAttributeMinimum( + new \Ibexa\Contracts\Measurement\Product\Query\Criterion\RangeMeasurementAttributeMinimum( 'length', $value ) diff --git a/docs/search/criteria_reference/remoteid_criterion.md b/docs/search/criteria_reference/remoteid_criterion.md index 6677715cda..948ec2c7e8 100644 --- a/docs/search/criteria_reference/remoteid_criterion.md +++ b/docs/search/criteria_reference/remoteid_criterion.md @@ -16,6 +16,10 @@ searches for content based on its remote content ID. ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\RemoteId('abab615dcf26699a4291657152da4337'); ``` diff --git a/docs/search/criteria_reference/sectionid_criterion.md b/docs/search/criteria_reference/sectionid_criterion.md index cfdc257ccb..b7879fed3b 100644 --- a/docs/search/criteria_reference/sectionid_criterion.md +++ b/docs/search/criteria_reference/sectionid_criterion.md @@ -15,6 +15,10 @@ The [`SectionId` Search Criterion](/api/php_api/php_api_reference/classes/Ibexa- ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\SectionId(3); ``` diff --git a/docs/search/criteria_reference/sectionidentifier_criterion.md b/docs/search/criteria_reference/sectionidentifier_criterion.md index dea856b606..e043a3ac82 100644 --- a/docs/search/criteria_reference/sectionidentifier_criterion.md +++ b/docs/search/criteria_reference/sectionidentifier_criterion.md @@ -15,6 +15,10 @@ The [`SectionIdentifier` Search Criterion](/api/php_api/php_api_reference/classe ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\SectionIdentifier(['sports', 'news']); ``` diff --git a/docs/search/criteria_reference/selectionattribute_criterion.md b/docs/search/criteria_reference/selectionattribute_criterion.md index f3217d090a..cbaf0be364 100644 --- a/docs/search/criteria_reference/selectionattribute_criterion.md +++ b/docs/search/criteria_reference/selectionattribute_criterion.md @@ -16,6 +16,9 @@ The `SelectionAttribute` Search Criterion searches for products by the value of ### PHP ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + $query = new ProductQuery( null, new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\SelectionAttribute( diff --git a/docs/search/criteria_reference/shipment_createdat_criterion.md b/docs/search/criteria_reference/shipment_createdat_criterion.md index be1ed48ff6..e0574ebb9a 100644 --- a/docs/search/criteria_reference/shipment_createdat_criterion.md +++ b/docs/search/criteria_reference/shipment_createdat_criterion.md @@ -17,6 +17,9 @@ The `CreatedAt` Search Criterion searches for shipments based on the date when t ### PHP ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; +use Ibexa\Contracts\Shipping\Shipment\ShipmentQuery; + $criteria = new \Ibexa\Contracts\Shipping\Shipment\Query\Criterion\CreatedAt( new DateTime('2023-03-01 14:07:02'), 'GTE' diff --git a/docs/search/criteria_reference/shipment_currency_criterion.md b/docs/search/criteria_reference/shipment_currency_criterion.md index eeb2e7e9b2..3081565e85 100644 --- a/docs/search/criteria_reference/shipment_currency_criterion.md +++ b/docs/search/criteria_reference/shipment_currency_criterion.md @@ -16,7 +16,10 @@ The `Currency` Search Criterion searches for shipments based on the currency cod ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\Shipping\Shipment\ShipmentQuery; + $query = new ShipmentQuery( - new \Ibexa\Contracts\Shipping\Shipment\Query\Criterion\Currency('USD', 'CZK') + new \Ibexa\Contracts\Shipping\Shipment\Query\Criterion\Currency(['USD', 'CZK']) ); ``` diff --git a/docs/search/criteria_reference/shipment_id_criterion.md b/docs/search/criteria_reference/shipment_id_criterion.md index 782150cccd..36a7fb0479 100644 --- a/docs/search/criteria_reference/shipment_id_criterion.md +++ b/docs/search/criteria_reference/shipment_id_criterion.md @@ -16,6 +16,9 @@ The `Id` Search Criterion searches for shipments based on the shipment ID. ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\Shipping\Shipment\ShipmentQuery; + $query = new ShipmentQuery( new \Ibexa\Contracts\Shipping\Shipment\Query\Criterion\Id(2) ); diff --git a/docs/search/criteria_reference/shipment_identifier_criterion.md b/docs/search/criteria_reference/shipment_identifier_criterion.md index df67826223..db55e3c658 100644 --- a/docs/search/criteria_reference/shipment_identifier_criterion.md +++ b/docs/search/criteria_reference/shipment_identifier_criterion.md @@ -16,6 +16,9 @@ The `Identifier` Search Criterion searches for shipments based on the shipment i ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\Shipping\Shipment\ShipmentQuery; + $query = new ShipmentQuery( new \Ibexa\Contracts\Shipping\Shipment\Query\Criterion\Identifier('f1t7z-3rb3rt') ); diff --git a/docs/search/criteria_reference/shipment_logicaland_criterion.md b/docs/search/criteria_reference/shipment_logicaland_criterion.md index c77c345282..387e4c3bcf 100644 --- a/docs/search/criteria_reference/shipment_logicaland_criterion.md +++ b/docs/search/criteria_reference/shipment_logicaland_criterion.md @@ -16,10 +16,13 @@ The `LogicalAnd` Search Criterion matches shipments if all provided Criteria mat ### PHP ``` php -$query->query = new \Ibexa\Contracts\Shipping\Shipment\Query\Criterion\LogicalAnd( - [ +use Ibexa\Contracts\Shipping\Shipment\ShipmentQuery; + +/** @var \Ibexa\Contracts\Shipping\Value\ShippingMethod\ShippingMethodInterface $shippingMethod */ +$query = new ShipmentQuery( + new \Ibexa\Contracts\Shipping\Shipment\Query\Criterion\LogicalAnd( new \Ibexa\Contracts\Shipping\Shipment\Query\Criterion\CreatedAt(new DateTime('2023-03-01')), new \Ibexa\Contracts\Shipping\Shipment\Query\Criterion\ShippingMethod($shippingMethod) - ] + ) ); ``` diff --git a/docs/search/criteria_reference/shipment_logicalor_criterion.md b/docs/search/criteria_reference/shipment_logicalor_criterion.md index 2903abb758..16a07037ff 100644 --- a/docs/search/criteria_reference/shipment_logicalor_criterion.md +++ b/docs/search/criteria_reference/shipment_logicalor_criterion.md @@ -16,10 +16,13 @@ The `LogicalOr` Search Criterion matches shipments if at least one of the provid ### PHP ``` php -$query->query = new \Ibexa\Contracts\Shipping\Shipment\Query\Criterion\LogicalOr( - [ +use Ibexa\Contracts\Shipping\Shipment\ShipmentQuery; + +/** @var \Ibexa\Contracts\Shipping\Value\ShippingMethod\ShippingMethodInterface $shippingMethod */ +$query = new ShipmentQuery( + new \Ibexa\Contracts\Shipping\Shipment\Query\Criterion\LogicalOr( new \Ibexa\Contracts\Shipping\Shipment\Query\Criterion\CreatedAt(new DateTime('2023-03-01')), new \Ibexa\Contracts\Shipping\Shipment\Query\Criterion\ShippingMethod($shippingMethod) - ] + ) ); ``` diff --git a/docs/search/criteria_reference/shipment_owner_criterion.md b/docs/search/criteria_reference/shipment_owner_criterion.md index c43de34ddf..d836ff406d 100644 --- a/docs/search/criteria_reference/shipment_owner_criterion.md +++ b/docs/search/criteria_reference/shipment_owner_criterion.md @@ -9,14 +9,17 @@ The `Owner` Criterion searches for shipments based on the user reference. ## Arguments -- `UserReference` object - \Ibexa\Contracts\Core\Repository\Values\User\UserReference(int $userId) +- `UserReference` object - new \Ibexa\Core\Repository\Values\User\UserReference(int $userId) ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\Shipping\Shipment\ShipmentQuery; + $query = new ShipmentQuery( new \Ibexa\Contracts\Shipping\Shipment\Query\Criterion\Owner( - \Ibexa\Contracts\Core\Repository\Values\User\UserReference(14) + new \Ibexa\Core\Repository\Values\User\UserReference(14) ) ); ``` @@ -24,11 +27,18 @@ $query = new ShipmentQuery( `Owner` Criterion accepts also multiple values: ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\Shipping\Shipment\ShipmentQuery; + +/** @var \Ibexa\Contracts\Core\Repository\UserService $userService */ +$user1 = $userService->loadUser(12345); +$user2 = $userService->loadUserByLogin('user'); + $query = new ShipmentQuery( new \Ibexa\Contracts\Shipping\Shipment\Query\Criterion\Owner( [ - \Ibexa\Contracts\Core\Repository\Values\User\UserReference(14), - \Ibexa\Contracts\Core\Repository\Values\User\UserReference(123), + $user1, + $user2, ] ) ); diff --git a/docs/search/criteria_reference/shipment_shipping_method_criterion.md b/docs/search/criteria_reference/shipment_shipping_method_criterion.md index 2a503ead43..447b71602b 100644 --- a/docs/search/criteria_reference/shipment_shipping_method_criterion.md +++ b/docs/search/criteria_reference/shipment_shipping_method_criterion.md @@ -16,6 +16,10 @@ The `ShippingMethod` Search Criterion searches for shipments based on a shipping ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\Shipping\Shipment\ShipmentQuery; + +/** @var \Ibexa\Contracts\Shipping\Value\ShippingMethod\ShippingMethodInterface $shippingMethod */ $query = new ShipmentQuery( new \Ibexa\Contracts\Shipping\Shipment\Query\Criterion\ShippingMethod($shippingMethod) ); diff --git a/docs/search/criteria_reference/shipment_status_criterion.md b/docs/search/criteria_reference/shipment_status_criterion.md index 3e2c0d40bc..05b0ec1a51 100644 --- a/docs/search/criteria_reference/shipment_status_criterion.md +++ b/docs/search/criteria_reference/shipment_status_criterion.md @@ -16,6 +16,9 @@ The `Status` Search Criterion searches for shipments based on shipment status. ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\Shipping\Shipment\ShipmentQuery; + $query = new ShipmentQuery( new \Ibexa\Contracts\Shipping\Shipment\Query\Criterion\Status('pending') ); diff --git a/docs/search/criteria_reference/shipment_updatedat_criterion.md b/docs/search/criteria_reference/shipment_updatedat_criterion.md index e7e84e13b7..72763c3c48 100644 --- a/docs/search/criteria_reference/shipment_updatedat_criterion.md +++ b/docs/search/criteria_reference/shipment_updatedat_criterion.md @@ -17,6 +17,9 @@ The `UpdatedAt` Search Criterion searches for shipments based on the date when t ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\Shipping\Shipment\ShipmentQuery; + $criteria = new \Ibexa\Contracts\Shipping\Shipment\Query\Criterion\UpdatedAt( new DateTime('2023-03-01'), 'GTE' diff --git a/docs/search/criteria_reference/sibling_criterion.md b/docs/search/criteria_reference/sibling_criterion.md index 0a3780c3c7..e1504c979c 100644 --- a/docs/search/criteria_reference/sibling_criterion.md +++ b/docs/search/criteria_reference/sibling_criterion.md @@ -16,12 +16,21 @@ The [`Sibling` Search Criterion](/api/php_api/php_api_reference/classes/Ibexa-Co ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\Sibling(59, 2); ``` You can also use the named constructor `Criterion\Sibling::fromLocation` and provide it with the location object: ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); +/** @var \Ibexa\Contracts\Core\Repository\LocationService $locationService */ $location = $locationService->loadLocation(59); $query->query = Criterion\Sibling::fromLocation($location); ``` diff --git a/docs/search/criteria_reference/simplemeasurementattribute_criterion.md b/docs/search/criteria_reference/simplemeasurementattribute_criterion.md index 034a221ed7..7cd56eb2c3 100644 --- a/docs/search/criteria_reference/simplemeasurementattribute_criterion.md +++ b/docs/search/criteria_reference/simplemeasurementattribute_criterion.md @@ -16,11 +16,15 @@ The `SimpleMeasurementAttribute` Search Criterion searches for products by the v ### PHP ``` php -$value = $this->measurementService->buildSimpleValue('length', 120, 'centimeter'); +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; +use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion; + +/** @var \Ibexa\Contracts\Measurement\MeasurementServiceInterface $measurementService */ +$value = $measurementService->buildSimpleValue('length', 120, 'centimeter'); $query = new ProductQuery( null, - new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\SimpleMeasurementAttribute( + new \Ibexa\Contracts\Measurement\Product\Query\Criterion\SimpleMeasurementAttribute( 'width', $value ) diff --git a/docs/search/criteria_reference/subtree_criterion.md b/docs/search/criteria_reference/subtree_criterion.md index a814f314fa..53d5fa7bb2 100644 --- a/docs/search/criteria_reference/subtree_criterion.md +++ b/docs/search/criteria_reference/subtree_criterion.md @@ -16,6 +16,10 @@ It returns the content item and all the content items below it in the subtree. ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\Subtree('/1/2/71/72/'); ``` diff --git a/docs/search/criteria_reference/taxonomy_entry_id.md b/docs/search/criteria_reference/taxonomy_entry_id.md index 1cceaeccc2..968931e2a6 100644 --- a/docs/search/criteria_reference/taxonomy_entry_id.md +++ b/docs/search/criteria_reference/taxonomy_entry_id.md @@ -15,11 +15,19 @@ The [`TaxonomyEntryId` Search Criterion](/api/php_api/php_api_reference/classes/ ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Taxonomy\Search\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\TaxonomyEntryId(1); ``` Add an array of ID's to find Content tagged with at least one of the tags (OR). -```php +``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Taxonomy\Search\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\TaxonomyEntryId([1, 2, 3]); ``` diff --git a/docs/search/criteria_reference/taxonomy_no_entries.md b/docs/search/criteria_reference/taxonomy_no_entries.md index 40522b17b5..3cff3fb566 100644 --- a/docs/search/criteria_reference/taxonomy_no_entries.md +++ b/docs/search/criteria_reference/taxonomy_no_entries.md @@ -19,7 +19,7 @@ It's available for all supported search engines and in [repository filtering](se The following example searches for articles that have no entries assigned in the `tags` taxonomy: -```php hl_lines="11-16" +``` php hl_lines="11-16" [[= include_code('code_samples/search/content/taxonomy_no_entries_criterion.php') =]] ``` diff --git a/docs/search/criteria_reference/taxonomy_subtree.md b/docs/search/criteria_reference/taxonomy_subtree.md index 0afa1638e8..2203a7b08b 100644 --- a/docs/search/criteria_reference/taxonomy_subtree.md +++ b/docs/search/criteria_reference/taxonomy_subtree.md @@ -16,7 +16,7 @@ The [`TaxonomySubtree`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-T The following example searches for articles assigned to taxonomy entry with ID `42` or any of its child entries: -```php hl_lines="11-16" +``` php hl_lines="11-16" [[= include_code('code_samples/search/content/taxonomy_subtree_criterion.php') =]] ``` diff --git a/docs/search/criteria_reference/useremail_criterion.md b/docs/search/criteria_reference/useremail_criterion.md index 7cc730e21f..9402e1c999 100644 --- a/docs/search/criteria_reference/useremail_criterion.md +++ b/docs/search/criteria_reference/useremail_criterion.md @@ -20,10 +20,18 @@ Solr search engine and Elasticsearch support IN and EQ operators only. ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\UserEmail(['johndoe']); ``` ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\UserEmail('nospam*', Criterion\Operator::LIKE); ``` diff --git a/docs/search/criteria_reference/userid_criterion.md b/docs/search/criteria_reference/userid_criterion.md index 0468cffdbc..cfdf847d0f 100644 --- a/docs/search/criteria_reference/userid_criterion.md +++ b/docs/search/criteria_reference/userid_criterion.md @@ -15,6 +15,10 @@ The [`UserId` Search Criterion](/api/php_api/php_api_reference/classes/Ibexa-Con ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\UserId([14]); ``` diff --git a/docs/search/criteria_reference/userlogin_criterion.md b/docs/search/criteria_reference/userlogin_criterion.md index a3c6f048b4..74647dfbf1 100644 --- a/docs/search/criteria_reference/userlogin_criterion.md +++ b/docs/search/criteria_reference/userlogin_criterion.md @@ -20,10 +20,18 @@ Solr search engine and Elasticsearch support IN and EQ operators only. ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\UserLogin(['johndoe']); ``` ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\UserLogin('adm*', Criterion\Operator::LIKE); ``` diff --git a/docs/search/criteria_reference/usermetadata_criterion.md b/docs/search/criteria_reference/usermetadata_criterion.md index 54a9d0725b..ef6939f9b8 100644 --- a/docs/search/criteria_reference/usermetadata_criterion.md +++ b/docs/search/criteria_reference/usermetadata_criterion.md @@ -17,6 +17,10 @@ The [`UserMetadata` Search Criterion](/api/php_api/php_api_reference/classes/Ibe ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\UserMetadata(Criterion\UserMetadata::GROUP, Criterion\Operator::EQ, 12); ``` @@ -56,14 +60,18 @@ $query->query = new Criterion\UserMetadata(Criterion\UserMetadata::GROUP, Criter You can use the `UserMetadata` Criterion to search for blog posts created by the Contributor user group: -``` php hl_lines="7" +``` php hl_lines="11" +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + // ID of your custom Contributor User Group $contributorGroupId = 32; -$query = new LocationQuery; -$query->query = new Criterion\LogicalAnd([ +$query = new LocationQuery(); +$query->query = new Criterion\LogicalAnd( + [ new Criterion\ContentTypeIdentifier('blog_post'), - new Criterion\UserMetadata(Criterion\UserMetadata::GROUP, Criterion\Operator::EQ, $contributorGroupId) + new Criterion\UserMetadata(Criterion\UserMetadata::GROUP, Criterion\Operator::EQ, $contributorGroupId), ] ); ``` diff --git a/docs/search/criteria_reference/visibility_criterion.md b/docs/search/criteria_reference/visibility_criterion.md index 50ba1f4c47..86a4829471 100644 --- a/docs/search/criteria_reference/visibility_criterion.md +++ b/docs/search/criteria_reference/visibility_criterion.md @@ -21,6 +21,10 @@ Use Location Search to avoid this. ### PHP ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; + +$query = new Query(); $query->query = new Criterion\Visibility(Criterion\Visibility::HIDDEN); ``` diff --git a/docs/search/discounts_search_reference/discounts_criteria.md b/docs/search/discounts_search_reference/discounts_criteria.md index b9a380589c..ff024157d1 100644 --- a/docs/search/discounts_search_reference/discounts_criteria.md +++ b/docs/search/discounts_search_reference/discounts_criteria.md @@ -31,7 +31,7 @@ Use the `limit` and `offset` properties of [DiscountQuery](/api/php_api/php_api_ The following example shows how you can use the criteria to find all the currently active discounts: -```php hl_lines="13-20" +``` php hl_lines="13-20" [[= include_code('code_samples/discounts/src/Query/Search.php') =]] ``` diff --git a/docs/search/discounts_search_reference/discounts_sort_clauses.md b/docs/search/discounts_search_reference/discounts_sort_clauses.md index dffc69a580..2a77025ad2 100644 --- a/docs/search/discounts_search_reference/discounts_sort_clauses.md +++ b/docs/search/discounts_search_reference/discounts_sort_clauses.md @@ -23,7 +23,7 @@ Sort Clauses are found in the [`Ibexa\Contracts\Discounts\Value\Query\SortClause The following example shows how to use them to sort the searched discounts: -```php hl_lines="22-24" +``` php hl_lines="22-24" [[= include_code('code_samples/discounts/src/Query/Search.php') =]] ``` diff --git a/docs/search/extensibility/solr_document_field_mappers.md b/docs/search/extensibility/solr_document_field_mappers.md index bd26e95b83..cad7826565 100644 --- a/docs/search/extensibility/solr_document_field_mappers.md +++ b/docs/search/extensibility/solr_document_field_mappers.md @@ -56,7 +56,7 @@ The following example shows how you can index data from the parent location cont The example relies on a use case of indexing webinar data on the webinar events, which are children of the webinar. The field mapper could then look like this: -```php +``` php [[= include_code('code_samples/search/custom/src/Search/FieldMapper/WebinarEventParentNameFieldMapper.php') =]] ``` diff --git a/docs/search/search_api.md b/docs/search/search_api.md index 1af875bff8..a7c416d7f5 100644 --- a/docs/search/search_api.md +++ b/docs/search/search_api.md @@ -27,7 +27,7 @@ For example, to search for all content of a selected content type, use one Crite The following command takes the content type identifier as an argument and lists all results: -``` php hl_lines="14 16" +``` php {skip-validation} hl_lines="14 16" // ... [[= include_code('code_samples/api/public_php_api/src/Command/FindContentCommand.php', 5, 7) =]] // ... @@ -43,9 +43,18 @@ You can also use [`SearchService::findContent`](/api/php_api/php_api_reference/c To query for a single result, for example by providing a Content ID, use the [`SearchService::findSingle`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Core-Repository-SearchService.html#method_findSingle) method: ``` php +use Ibexa\Contracts\Core\Repository\SearchService; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Symfony\Component\Console\Output\OutputInterface; + +$contentId = 12345; $criterion = new Criterion\ContentId($contentId); -$result = $this->searchService->findSingle($criterion); -$output->writeln($result->getName()); + +/** @var SearchService $searchService */ +$result = $searchService->findSingle($criterion); + +/** @var OutputInterface $output */ +$output->writeln($result->getName() ?? ''); ``` !!! tip @@ -58,6 +67,9 @@ $output->writeln($result->getName()); You can change it by setting a different limit to the query: ``` php + use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; + + $query = new LocationQuery(); $query->limit = 100; ``` @@ -94,11 +106,19 @@ This enables iterating over results that are too large to handle due to memory c `BatchIterator` takes one of the available adapters ([`\Ibexa\Contracts\Core\Repository\Iterator\BatchIteratorAdapter`](/api/php_api/php_api_reference/namespaces/ibexa-contracts-core-repository-iterator-batchiteratoradapter.html)) and optional batch size. For example: ``` php +use Ibexa\Contracts\Core\Repository\Iterator\BatchIterator; +use Ibexa\Contracts\Core\Repository\Iterator\BatchIteratorAdapter; +use Ibexa\Contracts\Core\Repository\SearchService; +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Symfony\Component\Console\Output\OutputInterface; + $query = new LocationQuery(); -$iterator = new BatchIterator(new BatchIteratorAdapter\LocationSearchAdapter($this->searchService, $query)); +/** @var SearchService $searchService */ +$iterator = new BatchIterator(new BatchIteratorAdapter\LocationSearchAdapter($searchService, $query)); foreach ($iterator as $result) { + /** @var OutputInterface $output */ $output->writeln($result->valueObject->getContentInfo()->name); } ``` @@ -132,7 +152,7 @@ It doesn't use the `SearchService` and isn't based on indexed data. For example, the following command lists all content items under the specified parent location and sorts them by name in descending order: -``` php hl_lines="15-18" +``` php {skip-validation} hl_lines="15-18" // ... [[= include_code('code_samples/api/public_php_api/src/Command/FilterCommand.php', 5, 9) =]] @@ -143,7 +163,7 @@ For example, the following command lists all content items under the specified p The same Filter can be applied to find locations instead of content items, for example: -``` php hl_lines="20" +``` php {skip-validation} hl_lines="20" // ... [[= include_code('code_samples/api/public_php_api/src/Command/FilterLocationCommand.php', 5, 9) =]] @@ -173,6 +193,11 @@ You can use the following methods of the Filter: The following example filters for Folder content items under the parent location 2, sorts them by publication date and returns 10 results, starting from the third one: ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; +use Ibexa\Contracts\Core\Repository\Values\Filter\Filter; + $filter = new Filter(); $filter ->withCriterion(new Criterion\ContentTypeIdentifier('folder')) @@ -199,7 +224,7 @@ $filter You can use the `SearchService` or repository filtering in a controller, as long as you provide the required parameters. For example, in the code below, `locationId` is provided to list all children of a location by using the `SearchService`. -``` php hl_lines="22-24" +``` php {skip-validation} hl_lines="22-24" // ... [[= include_code('code_samples/api/public_php_api/src/Controller/CustomController.php', 5, 12) =]] // ... @@ -210,7 +235,7 @@ The rendering of results is then relegated to [templates](templates.md) (lines 2 When using Repository filtering, provide the results of `ContentService::find()` as parameters to the view: -``` php hl_lines="19" +``` php {skip-validation} hl_lines="19" // ... [[= include_code('code_samples/api/public_php_api/src/Controller/CustomFilterController.php', 5, 12) =]] // ... @@ -221,7 +246,7 @@ When using Repository filtering, provide the results of `ContentService::find()` To paginate search or filtering results, it's recommended to use the [Pagerfanta library](https://github.com/BabDev/Pagerfanta) and [[[= product_name =]]'s adapters for it.](https://github.com/ibexa/core/blob/5.0/src/lib/Pagination/Pagerfanta/Pagerfanta.php) -``` php +``` php {skip-validation} // ... [[= include_code('code_samples/api/public_php_api/src/Controller/PaginationController.php', 9, 15) =]] // ... @@ -291,6 +316,13 @@ For example, a content item has two locations: visible location A and hidden loc You perform the following query: ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\LocationId; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\Visibility; + +$query = new LocationQuery(); +$bLocationId = 12345; $query->filter = new Criterion\LogicalAnd([ new LocationId($bLocationId), new Visibility(Visibility::VISIBLE), @@ -365,12 +397,18 @@ The following example limits the number of terms returned to 5 and only consider To use a range aggregation, you must provide a `ranges` array containing a set of `Range` objects that define the borders of the specific range sets. ``` php -$query->aggregations[] = new IntegerRangeAggregation('range', 'person', 'age', -[ - new Query\Aggregation\Range(1,30), - new Query\Aggregation\Range(30,60), - new Query\Aggregation\Range(60,null), -]); +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Field\IntegerRangeAggregation; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range; + +$ranges = [ + Range::ofInt(1, 30), + Range::ofInt(30, 60), + Range::ofInt(60, null), +]; + +$query = new LocationQuery(); +$query->aggregations[] = new IntegerRangeAggregation('range', 'person', 'age', $ranges); ``` !!! note diff --git a/docs/search/search_engines/elasticsearch/configure_elasticsearch.md b/docs/search/search_engines/elasticsearch/configure_elasticsearch.md index 62cc6b6cc0..31334e7e92 100644 --- a/docs/search/search_engines/elasticsearch/configure_elasticsearch.md +++ b/docs/search/search_engines/elasticsearch/configure_elasticsearch.md @@ -181,7 +181,7 @@ If your Elasticsearch server is protected by HTTP authentication, you must provi In the basic authentication, you must pass the following parameters: ``` yaml - +: # ... authentication: type: basic @@ -376,14 +376,14 @@ Index names use the following pattern: You can create index templates with settings that apply to a specific language only, for example, to eliminate stop words from the index, or help divide concatenations. You use patterns to identify index templates that contain settings specific for a given language: - ``` yaml - ibexa_elasticsearch: +``` yaml +ibexa_elasticsearch: # ... index_templates: default_en_us: patterns: ['default_*', '*eng_us*'] - # ... - ``` + # ... +``` - `settings` - Settings under this key control all aspects related to an index. @@ -391,21 +391,21 @@ For more information and a list of available settings, see [Elasticsearch docume For example, you can define settings that convert text into a format that is optimized for search, like a normalizer that changes a case of all phrases in the index: - ``` yaml - ibexa_elasticsearch: - # ... - index_templates: - default: - # ... - settings: - analysis: - normalizer: - lowercase_normalizer: - type: custom - char_filter: [] - filter: lowercase - # ... - ``` +``` yaml +ibexa_elasticsearch: + # ... + index_templates: + default: + # ... + settings: + analysis: + normalizer: + lowercase_normalizer: + type: custom + char_filter: [] + filter: lowercase + # ... +``` - `mappings` - Settings under this key define mapping for fields in the index. diff --git a/docs/search/search_engines/solr_search_engine/configure_solr.md b/docs/search/search_engines/solr_search_engine/configure_solr.md index 10f92c8295..f8e835577e 100644 --- a/docs/search/search_engines/solr_search_engine/configure_solr.md +++ b/docs/search/search_engines/solr_search_engine/configure_solr.md @@ -72,7 +72,7 @@ The configuration above results in the following boosting (content type / Field) The second step requires you to use `\Novactive\EzSolrSearchExtra\Query\Content\Criterion\MultipleFieldsFullText` instead of default `\Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion\FullText`. The following example shows custom query which benefits from the custom fields created in the previous example. - ```php + ``` php {skip-validation} sortClauses = [new SortClause\ContentId()]; ``` diff --git a/docs/search/sort_clause_reference/contentname_sort_clause.md b/docs/search/sort_clause_reference/contentname_sort_clause.md index 9f1106a4b5..51fd8ceee3 100644 --- a/docs/search/sort_clause_reference/contentname_sort_clause.md +++ b/docs/search/sort_clause_reference/contentname_sort_clause.md @@ -13,6 +13,9 @@ The [`ContentName` Sort Clause](/api/php_api/php_api_reference/classes/Ibexa-Con ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; + $query = new LocationQuery(); $query->sortClauses = [new SortClause\ContentName()]; ``` diff --git a/docs/search/sort_clause_reference/contenttranslatedname_sort_clause.md b/docs/search/sort_clause_reference/contenttranslatedname_sort_clause.md index 957cc93109..317de17705 100644 --- a/docs/search/sort_clause_reference/contenttranslatedname_sort_clause.md +++ b/docs/search/sort_clause_reference/contenttranslatedname_sort_clause.md @@ -17,6 +17,9 @@ The `ContentTranslatedName` Sort Clause isn't available in [Repository filtering ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; + $query = new LocationQuery(); $query->sortClauses = [new SortClause\ContentTranslatedName()]; ``` diff --git a/docs/search/sort_clause_reference/contenttypename_sort_clause.md b/docs/search/sort_clause_reference/contenttypename_sort_clause.md index fc4c516ae2..80d031a018 100644 --- a/docs/search/sort_clause_reference/contenttypename_sort_clause.md +++ b/docs/search/sort_clause_reference/contenttypename_sort_clause.md @@ -13,6 +13,9 @@ The [`ContentTypeName` Sort Clause](/api/php_api/php_api_reference/classes/Ibexa ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; + $query = new Query(); $query->sortClauses = [new SortClause\Trash\ContentTypeName()]; ``` diff --git a/docs/search/sort_clause_reference/createdat_sort_clause.md b/docs/search/sort_clause_reference/createdat_sort_clause.md index 2ef171dc82..f68a4944fa 100644 --- a/docs/search/sort_clause_reference/createdat_sort_clause.md +++ b/docs/search/sort_clause_reference/createdat_sort_clause.md @@ -13,12 +13,15 @@ The `CreatedAt` Sort Clause sorts search results by the date and time of the cre ## Example ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; + $productQuery = new ProductQuery( null, null, [ new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\SortClause\CreatedAt( - \Ibexa\Contracts\ProductCatalog\Values\Product\Query\SortClause\CreatedAt::SORT_ASC) + \Ibexa\Contracts\ProductCatalog\Values\Product\Query\SortClause\CreatedAt::SORT_ASC + ), ] ); ``` diff --git a/docs/search/sort_clause_reference/customfield_sort_clause.md b/docs/search/sort_clause_reference/customfield_sort_clause.md index 7770198082..64e8602e17 100644 --- a/docs/search/sort_clause_reference/customfield_sort_clause.md +++ b/docs/search/sort_clause_reference/customfield_sort_clause.md @@ -23,6 +23,9 @@ The `CustomField` Sort Clause isn't available in [Repository filtering](search_a ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; + $query = new LocationQuery(); $query->sortClauses = [new SortClause\CustomField('my_custom_field_s')]; ``` diff --git a/docs/search/sort_clause_reference/customprice_sort_clause.md b/docs/search/sort_clause_reference/customprice_sort_clause.md index e042a16adb..1e03c725f9 100644 --- a/docs/search/sort_clause_reference/customprice_sort_clause.md +++ b/docs/search/sort_clause_reference/customprice_sort_clause.md @@ -20,11 +20,18 @@ The `CustomPrice` Sort Clause isn't available in the Legacy Search engine. ## Example ``` php +use Ibexa\Contracts\ProductCatalog\Values\CurrencyInterface; +use Ibexa\Contracts\ProductCatalog\Values\CustomerGroupInterface; +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; + +/** @var CurrencyInterface $currency */ +/** @var CustomerGroupInterface $customerGroup */ $sortClauses = [ new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\SortClause\CustomPrice( $currency, - ProductQuery::SORT_ASC, $customerGroup - ) + ProductQuery::SORT_ASC, + $customerGroup + ), ]; $productQuery = new ProductQuery(null, null, $sortClauses); ``` diff --git a/docs/search/sort_clause_reference/datemodified_sort_clause.md b/docs/search/sort_clause_reference/datemodified_sort_clause.md index a26a1f3749..a626be31a2 100644 --- a/docs/search/sort_clause_reference/datemodified_sort_clause.md +++ b/docs/search/sort_clause_reference/datemodified_sort_clause.md @@ -13,6 +13,9 @@ The [`DateModified` Sort Clause](/api/php_api/php_api_reference/classes/Ibexa-Co ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; + $query = new LocationQuery(); $query->sortClauses = [new SortClause\DateModified()]; ``` diff --git a/docs/search/sort_clause_reference/datepublished_sort_clause.md b/docs/search/sort_clause_reference/datepublished_sort_clause.md index 39c6bc4f1c..92a25e1f6e 100644 --- a/docs/search/sort_clause_reference/datepublished_sort_clause.md +++ b/docs/search/sort_clause_reference/datepublished_sort_clause.md @@ -13,6 +13,9 @@ The [`DatePublished` Sort Clause](/api/php_api/php_api_reference/classes/Ibexa-C ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; + $query = new LocationQuery(); $query->sortClauses = [new SortClause\DatePublished()]; ``` diff --git a/docs/search/sort_clause_reference/datetrashed_sort_clause.md b/docs/search/sort_clause_reference/datetrashed_sort_clause.md index e82baf72c4..4bfa6d9e41 100644 --- a/docs/search/sort_clause_reference/datetrashed_sort_clause.md +++ b/docs/search/sort_clause_reference/datetrashed_sort_clause.md @@ -13,6 +13,9 @@ The [`DateTrashed` Sort Clause](/api/php_api/php_api_reference/classes/Ibexa-Con ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; + $query = new Query(); $query->sortClauses = [new SortClause\Trash\DateTrashed()]; ``` diff --git a/docs/search/sort_clause_reference/depth_sort_clause.md b/docs/search/sort_clause_reference/depth_sort_clause.md index 78a0e8f45a..fabdb17a8e 100644 --- a/docs/search/sort_clause_reference/depth_sort_clause.md +++ b/docs/search/sort_clause_reference/depth_sort_clause.md @@ -13,6 +13,9 @@ The [`Location\Depth` Sort Clause](/api/php_api/php_api_reference/classes/Ibexa- ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; + $query = new LocationQuery(); -$query->sortClauses = [new SortClause\Depth()]; +$query->sortClauses = [new SortClause\Location\Depth()]; ``` diff --git a/docs/search/sort_clause_reference/field_sort_clause.md b/docs/search/sort_clause_reference/field_sort_clause.md index 5db7bf10c5..b32776ee18 100644 --- a/docs/search/sort_clause_reference/field_sort_clause.md +++ b/docs/search/sort_clause_reference/field_sort_clause.md @@ -21,6 +21,9 @@ The `Field` Sort Clause isn't available in [Repository filtering](search_api.md# ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; + $query = new LocationQuery(); $query->sortClauses = [new SortClause\Field('article', 'title')]; ``` diff --git a/docs/search/sort_clause_reference/id_sort_clause.md b/docs/search/sort_clause_reference/id_sort_clause.md index 1e869ae5a3..2132a64d37 100644 --- a/docs/search/sort_clause_reference/id_sort_clause.md +++ b/docs/search/sort_clause_reference/id_sort_clause.md @@ -13,6 +13,9 @@ The [`Location\Id` Sort Clause](/api/php_api/php_api_reference/classes/Ibexa-Con ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; + $query = new LocationQuery(); $query->sortClauses = [new SortClause\Location\Id()]; ``` diff --git a/docs/search/sort_clause_reference/ismainlocation_sort_clause.md b/docs/search/sort_clause_reference/ismainlocation_sort_clause.md index ef8f5bed55..b1c763e6b8 100644 --- a/docs/search/sort_clause_reference/ismainlocation_sort_clause.md +++ b/docs/search/sort_clause_reference/ismainlocation_sort_clause.md @@ -19,6 +19,9 @@ The `Location\IsMainLocation` Sort Clause isn't available in [Repository filteri ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; + $query = new LocationQuery(); -$query->sortClauses = [new SortClause\Location\InMainLocation()]; +$query->sortClauses = [new SortClause\Location\IsMainLocation()]; ``` diff --git a/docs/search/sort_clause_reference/maplocationdistance_sort_clause.md b/docs/search/sort_clause_reference/maplocationdistance_sort_clause.md index c13e240bb1..6ed59fd571 100644 --- a/docs/search/sort_clause_reference/maplocationdistance_sort_clause.md +++ b/docs/search/sort_clause_reference/maplocationdistance_sort_clause.md @@ -20,6 +20,9 @@ The `MapLocationDistance` Sort Clause isn't available in [Repository filtering]( ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; + $query = new LocationQuery(); $query->sortClauses = [new SortClause\MapLocationDistance('place', 'location', 49.542889, 20.111349)]; ``` diff --git a/docs/search/sort_clause_reference/order_created_sort_clause.md b/docs/search/sort_clause_reference/order_created_sort_clause.md index c11efc7e38..20a3a1f8c2 100644 --- a/docs/search/sort_clause_reference/order_created_sort_clause.md +++ b/docs/search/sort_clause_reference/order_created_sort_clause.md @@ -14,11 +14,16 @@ The `Created` Sort Clause sorts search results by the date and time when the ord ## Example ``` php +use Ibexa\Contracts\OrderManagement\Value\Order\OrderQuery; + +$criteria = null; + $orderQuery = new OrderQuery( $criteria, [ new \Ibexa\Contracts\OrderManagement\Value\Order\Query\SortClause\Created( - \Ibexa\Contracts\OrderManagement\Value\Order\Query\SortClause\Created::SORT_ASC) + \Ibexa\Contracts\OrderManagement\Value\Order\Query\SortClause\Created::SORT_ASC + ), ] ); ``` diff --git a/docs/search/sort_clause_reference/order_id_sort_clause.md b/docs/search/sort_clause_reference/order_id_sort_clause.md index 2df732073d..74db82f0b9 100644 --- a/docs/search/sort_clause_reference/order_id_sort_clause.md +++ b/docs/search/sort_clause_reference/order_id_sort_clause.md @@ -14,11 +14,16 @@ The `Id` Sort Clause sorts search results by order Id. ## Example ``` php +use Ibexa\Contracts\OrderManagement\Value\Order\OrderQuery; + +$criteria = null; + $orderQuery = new OrderQuery( $criteria, [ new \Ibexa\Contracts\OrderManagement\Value\Order\Query\SortClause\Id( - \Ibexa\Contracts\OrderManagement\Value\Order\Query\SortClause\Id::SORT_ASC) + \Ibexa\Contracts\OrderManagement\Value\Order\Query\SortClause\Id::SORT_ASC + ), ] ); ``` diff --git a/docs/search/sort_clause_reference/order_status_sort_clause.md b/docs/search/sort_clause_reference/order_status_sort_clause.md index e9711c752e..3173d9bf18 100644 --- a/docs/search/sort_clause_reference/order_status_sort_clause.md +++ b/docs/search/sort_clause_reference/order_status_sort_clause.md @@ -14,11 +14,16 @@ The `Status` Sort Clause sorts search results by order status. ## Example ``` php +use Ibexa\Contracts\OrderManagement\Value\Order\OrderQuery; + +$criteria = null; + $orderQuery = new OrderQuery( $criteria, [ new \Ibexa\Contracts\OrderManagement\Value\Order\Query\SortClause\Status( - \Ibexa\Contracts\OrderManagement\Value\Order\Query\SortClause\Status::SORT_ASC) + \Ibexa\Contracts\OrderManagement\Value\Order\Query\SortClause\Status::SORT_ASC + ), ] ); ``` diff --git a/docs/search/sort_clause_reference/order_updated_sort_clause.md b/docs/search/sort_clause_reference/order_updated_sort_clause.md index 9a17f8f2b3..87a3a63d8c 100644 --- a/docs/search/sort_clause_reference/order_updated_sort_clause.md +++ b/docs/search/sort_clause_reference/order_updated_sort_clause.md @@ -14,11 +14,16 @@ The `Updated` Sort Clause sorts search results by the date and time when order s ## Example ``` php +use Ibexa\Contracts\OrderManagement\Value\Order\OrderQuery; + +$criteria = null; + $orderQuery = new OrderQuery( $criteria, [ new \Ibexa\Contracts\OrderManagement\Value\Order\Query\SortClause\Updated( - \Ibexa\Contracts\OrderManagement\Value\Order\Query\SortClause\Updated::SORT_ASC) + \Ibexa\Contracts\OrderManagement\Value\Order\Query\SortClause\Updated::SORT_ASC + ), ] ); ``` diff --git a/docs/search/sort_clause_reference/path_sort_clause.md b/docs/search/sort_clause_reference/path_sort_clause.md index 26937e643f..ba5812567b 100644 --- a/docs/search/sort_clause_reference/path_sort_clause.md +++ b/docs/search/sort_clause_reference/path_sort_clause.md @@ -17,6 +17,9 @@ The [`Location\Path` Sort Clause](/api/php_api/php_api_reference/classes/Ibexa-C ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; + $query = new LocationQuery(); $query->sortClauses = [new SortClause\Location\Path()]; ``` diff --git a/docs/search/sort_clause_reference/payment_createdat_sort_clause.md b/docs/search/sort_clause_reference/payment_createdat_sort_clause.md index c8c82ffec6..5c9c6572bc 100644 --- a/docs/search/sort_clause_reference/payment_createdat_sort_clause.md +++ b/docs/search/sort_clause_reference/payment_createdat_sort_clause.md @@ -14,11 +14,16 @@ The `CreatedAt` Sort Clause sorts search results by the date and time when the p ## Example ``` php +use Ibexa\Contracts\Payment\Payment\PaymentQuery; + +$criteria = null; + $paymentQuery = new PaymentQuery( $criteria, [ new \Ibexa\Contracts\Payment\Payment\Query\SortClause\CreatedAt( - \Ibexa\Contracts\Payment\Payment\Query\SortClause\CreatedAt::SORT_ASC) + \Ibexa\Contracts\Payment\Payment\Query\SortClause\CreatedAt::SORT_ASC + ), ] ); ``` diff --git a/docs/search/sort_clause_reference/payment_id_sort_clause.md b/docs/search/sort_clause_reference/payment_id_sort_clause.md index 441cbd2edb..b1ae85c22f 100644 --- a/docs/search/sort_clause_reference/payment_id_sort_clause.md +++ b/docs/search/sort_clause_reference/payment_id_sort_clause.md @@ -14,11 +14,16 @@ The `Id` Sort Clause sorts search results by payment ID. ## Example ``` php +use Ibexa\Contracts\Payment\Payment\PaymentQuery; + +$criteria = null; + $paymentQuery = new PaymentQuery( $criteria, [ new \Ibexa\Contracts\Payment\Payment\Query\SortClause\Id( - \Ibexa\Contracts\Payment\Payment\Query\SortClause\Id::SORT_ASC) + \Ibexa\Contracts\Payment\Payment\Query\SortClause\Id::SORT_ASC + ), ] ); ``` diff --git a/docs/search/sort_clause_reference/payment_identifier_sort_clause.md b/docs/search/sort_clause_reference/payment_identifier_sort_clause.md index c8969c7f5e..9eb188771b 100644 --- a/docs/search/sort_clause_reference/payment_identifier_sort_clause.md +++ b/docs/search/sort_clause_reference/payment_identifier_sort_clause.md @@ -14,11 +14,16 @@ The `Identifier` Sort Clause sorts search results by payment identifier. ## Example ``` php +use Ibexa\Contracts\Payment\Payment\PaymentQuery; + +$criteria = null; + $paymentQuery = new PaymentQuery( $criteria, [ new \Ibexa\Contracts\Payment\Payment\Query\SortClause\Identifier( - \Ibexa\Contracts\Payment\Payment\Query\SortClause\Identifier::SORT_ASC) + \Ibexa\Contracts\Payment\Payment\Query\SortClause\Identifier::SORT_ASC + ), ] ); ``` diff --git a/docs/search/sort_clause_reference/payment_method_createdat_sort_clause.md b/docs/search/sort_clause_reference/payment_method_createdat_sort_clause.md index f89ad0c7d6..e9b386d399 100644 --- a/docs/search/sort_clause_reference/payment_method_createdat_sort_clause.md +++ b/docs/search/sort_clause_reference/payment_method_createdat_sort_clause.md @@ -14,11 +14,16 @@ The `CreatedAt` Sort Clause sorts search results by the date and time when the p ## Example ``` php +use Ibexa\Contracts\Payment\PaymentMethod\PaymentMethodQuery; + +$criteria = null; + $paymentMethodQuery = new PaymentMethodQuery( $criteria, [ new \Ibexa\Contracts\Payment\PaymentMethod\Query\SortClause\CreatedAt( - \Ibexa\Contracts\Payment\PaymentMethod\Query\SortClause\CreatedAt::SORT_ASC) + \Ibexa\Contracts\Payment\PaymentMethod\Query\SortClause\CreatedAt::SORT_ASC + ), ] ); ``` diff --git a/docs/search/sort_clause_reference/payment_method_enabled_sort_clause.md b/docs/search/sort_clause_reference/payment_method_enabled_sort_clause.md index 5c3a20df97..85e7f6e3e3 100644 --- a/docs/search/sort_clause_reference/payment_method_enabled_sort_clause.md +++ b/docs/search/sort_clause_reference/payment_method_enabled_sort_clause.md @@ -14,11 +14,16 @@ The `Enabled` Sort Clause sorts search results by payment method status. ## Example ``` php +use Ibexa\Contracts\Payment\PaymentMethod\PaymentMethodQuery; + +$criteria = null; + $paymentMethodQuery = new PaymentMethodQuery( $criteria, [ new \Ibexa\Contracts\Payment\PaymentMethod\Query\SortClause\Enabled( - \Ibexa\Contracts\Payment\PaymentMethod\Query\SortClause\Enabled::SORT_DESC) + \Ibexa\Contracts\Payment\PaymentMethod\Query\SortClause\Enabled::SORT_DESC + ), ] ); ``` diff --git a/docs/search/sort_clause_reference/payment_method_id_sort_clause.md b/docs/search/sort_clause_reference/payment_method_id_sort_clause.md index bd7bc8e50a..5173b48c3e 100644 --- a/docs/search/sort_clause_reference/payment_method_id_sort_clause.md +++ b/docs/search/sort_clause_reference/payment_method_id_sort_clause.md @@ -14,11 +14,16 @@ The `Id` Sort Clause sorts search results by payment method ID. ## Example ``` php +use Ibexa\Contracts\Payment\PaymentMethod\PaymentMethodQuery; + +$criteria = null; + $paymentMethodQuery = new PaymentMethodQuery( $criteria, [ new \Ibexa\Contracts\Payment\PaymentMethod\Query\SortClause\Id( - \Ibexa\Contracts\Payment\PaymentMethod\Query\SortClause\Id::SORT_ASC) + \Ibexa\Contracts\Payment\PaymentMethod\Query\SortClause\Id::SORT_ASC + ), ] ); ``` diff --git a/docs/search/sort_clause_reference/payment_method_identifier_sort_clause.md b/docs/search/sort_clause_reference/payment_method_identifier_sort_clause.md index 02fa6e64d6..8a70fd9bd2 100644 --- a/docs/search/sort_clause_reference/payment_method_identifier_sort_clause.md +++ b/docs/search/sort_clause_reference/payment_method_identifier_sort_clause.md @@ -14,11 +14,16 @@ The `Identifier` Sort Clause sorts search results by payment method identifier. ## Example ``` php +use Ibexa\Contracts\Payment\PaymentMethod\PaymentMethodQuery; + +$criteria = null; + $paymentMethodQuery = new PaymentMethodQuery( $criteria, [ new \Ibexa\Contracts\Payment\PaymentMethod\Query\SortClause\Identifier( - \Ibexa\Contracts\Payment\PaymentMethod\Query\SortClause\Identifier::SORT_ASC) + \Ibexa\Contracts\Payment\PaymentMethod\Query\SortClause\Identifier::SORT_ASC + ), ] ); ``` diff --git a/docs/search/sort_clause_reference/payment_method_updatedat_sort_clause.md b/docs/search/sort_clause_reference/payment_method_updatedat_sort_clause.md index 4c20548949..da117cf6c3 100644 --- a/docs/search/sort_clause_reference/payment_method_updatedat_sort_clause.md +++ b/docs/search/sort_clause_reference/payment_method_updatedat_sort_clause.md @@ -14,11 +14,16 @@ The `UpdatedAt` Sort Clause sorts search results by the date and time when payme ## Example ``` php +use Ibexa\Contracts\Payment\PaymentMethod\PaymentMethodQuery; + +$criteria = null; + $paymentMethodQuery = new PaymentMethodQuery( $criteria, [ new \Ibexa\Contracts\Payment\PaymentMethod\Query\SortClause\UpdatedAt( - \Ibexa\Contracts\Payment\PaymentMethod\Query\SortClause\UpdatedAt::SORT_DESC) + \Ibexa\Contracts\Payment\PaymentMethod\Query\SortClause\UpdatedAt::SORT_DESC + ), ] ); ``` diff --git a/docs/search/sort_clause_reference/payment_status_sort_clause.md b/docs/search/sort_clause_reference/payment_status_sort_clause.md index ea4afc15bf..d7f805f524 100644 --- a/docs/search/sort_clause_reference/payment_status_sort_clause.md +++ b/docs/search/sort_clause_reference/payment_status_sort_clause.md @@ -14,11 +14,16 @@ The `Status` Sort Clause sorts search results by payment status. ## Example ``` php +use Ibexa\Contracts\Payment\Payment\PaymentQuery; + +$criteria = null; + $paymentQuery = new PaymentQuery( $criteria, [ new \Ibexa\Contracts\Payment\Payment\Query\SortClause\Status( - \Ibexa\Contracts\Payment\Payment\Query\SortClause\Status::SORT_ASC) + \Ibexa\Contracts\Payment\Payment\Query\SortClause\Status::SORT_ASC + ), ] ); ``` diff --git a/docs/search/sort_clause_reference/payment_updatedat_sort_clause.md b/docs/search/sort_clause_reference/payment_updatedat_sort_clause.md index 82a65ab0a9..344505ba41 100644 --- a/docs/search/sort_clause_reference/payment_updatedat_sort_clause.md +++ b/docs/search/sort_clause_reference/payment_updatedat_sort_clause.md @@ -14,11 +14,16 @@ The `UpdatedAt` Sort Clause sorts search results by the date and time when payme ## Example ``` php +use Ibexa\Contracts\Payment\Payment\PaymentQuery; + +$criteria = null; + $paymentQuery = new PaymentQuery( $criteria, [ new \Ibexa\Contracts\Payment\Payment\Query\SortClause\UpdatedAt( - \Ibexa\Contracts\Payment\Payment\Query\SortClause\UpdatedAt::SORT_ASC) + \Ibexa\Contracts\Payment\Payment\Query\SortClause\UpdatedAt::SORT_ASC + ), ] ); ``` diff --git a/docs/search/sort_clause_reference/priority_sort_clause.md b/docs/search/sort_clause_reference/priority_sort_clause.md index 874bb8f919..d1eec92ae0 100644 --- a/docs/search/sort_clause_reference/priority_sort_clause.md +++ b/docs/search/sort_clause_reference/priority_sort_clause.md @@ -13,6 +13,9 @@ The [`Location\Priority` Sort Clause](/api/php_api/php_api_reference/classes/Ibe ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; + $query = new LocationQuery(); $query->sortClauses = [new SortClause\Location\Priority()]; ``` diff --git a/docs/search/sort_clause_reference/productavailability_sort_clause.md b/docs/search/sort_clause_reference/productavailability_sort_clause.md index 4129785d5a..9ef70c1406 100644 --- a/docs/search/sort_clause_reference/productavailability_sort_clause.md +++ b/docs/search/sort_clause_reference/productavailability_sort_clause.md @@ -13,11 +13,13 @@ The `ProductAvailability` Sort Clause sorts search results by whether they have ## Example ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; + $query = new ProductQuery( null, null, [ - new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\SortClause\ProductAvailability() + new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\SortClause\ProductAvailability(), ] ); ``` diff --git a/docs/search/sort_clause_reference/productcode_sort_clause.md b/docs/search/sort_clause_reference/productcode_sort_clause.md index 4eed6ce992..8b20582234 100644 --- a/docs/search/sort_clause_reference/productcode_sort_clause.md +++ b/docs/search/sort_clause_reference/productcode_sort_clause.md @@ -13,11 +13,13 @@ The `ProductCode` Sort Clause sorts search results by the product code. ## Example ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; + $query = new ProductQuery( null, null, [ - new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\SortClause\ProductCode() + new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\SortClause\ProductCode(), ] ); ``` diff --git a/docs/search/sort_clause_reference/productname_sort_clause.md b/docs/search/sort_clause_reference/productname_sort_clause.md index 4321cff756..a7f8b4c3cd 100644 --- a/docs/search/sort_clause_reference/productname_sort_clause.md +++ b/docs/search/sort_clause_reference/productname_sort_clause.md @@ -13,11 +13,13 @@ The `ProductName` Sort Clause sorts search results by the Product code. ## Example ``` php +use Ibexa\Contracts\ProductCatalog\Values\Product\ProductQuery; + $query = new ProductQuery( null, null, [ - new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\SortClause\ProductName() + new \Ibexa\Contracts\ProductCatalog\Values\Product\Query\SortClause\ProductName(), ] ); ``` diff --git a/docs/search/sort_clause_reference/random_sort_clause.md b/docs/search/sort_clause_reference/random_sort_clause.md index 2c83038981..a8963b33e6 100644 --- a/docs/search/sort_clause_reference/random_sort_clause.md +++ b/docs/search/sort_clause_reference/random_sort_clause.md @@ -19,6 +19,9 @@ In Elasticsearch engine, you cannot combine the `Random` Sort Clause with any ot ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; + $query = new LocationQuery(); $query->sortClauses = [new SortClause\Random()]; ``` diff --git a/docs/search/sort_clause_reference/score_sort_clause.md b/docs/search/sort_clause_reference/score_sort_clause.md index 87bb7f49c7..39215791c2 100644 --- a/docs/search/sort_clause_reference/score_sort_clause.md +++ b/docs/search/sort_clause_reference/score_sort_clause.md @@ -17,6 +17,9 @@ The `Score` Sort Clause isn't available in [Repository filtering](search_api.md# ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; + $query = new LocationQuery(); $query->sortClauses = [new SortClause\Score()]; ``` diff --git a/docs/search/sort_clause_reference/sectionidentifier_sort_clause.md b/docs/search/sort_clause_reference/sectionidentifier_sort_clause.md index 5999554176..3a11bc14e6 100644 --- a/docs/search/sort_clause_reference/sectionidentifier_sort_clause.md +++ b/docs/search/sort_clause_reference/sectionidentifier_sort_clause.md @@ -17,6 +17,9 @@ The [`SectionIdentifier` Sort Clause](/api/php_api/php_api_reference/classes/Ibe ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; + $query = new LocationQuery(); $query->sortClauses = [new SortClause\SectionIdentifier()]; ``` diff --git a/docs/search/sort_clause_reference/sectionname_sort_clause.md b/docs/search/sort_clause_reference/sectionname_sort_clause.md index 950df555e2..3abdd458e1 100644 --- a/docs/search/sort_clause_reference/sectionname_sort_clause.md +++ b/docs/search/sort_clause_reference/sectionname_sort_clause.md @@ -13,6 +13,9 @@ The [`SectionName` Sort Clause](/api/php_api/php_api_reference/classes/Ibexa-Con ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; + $query = new LocationQuery(); $query->sortClauses = [new SortClause\SectionName()]; ``` diff --git a/docs/search/sort_clause_reference/shipment_createdat_sort_clause.md b/docs/search/sort_clause_reference/shipment_createdat_sort_clause.md index 373aeb5d9e..b8526a0aa2 100644 --- a/docs/search/sort_clause_reference/shipment_createdat_sort_clause.md +++ b/docs/search/sort_clause_reference/shipment_createdat_sort_clause.md @@ -14,11 +14,15 @@ The `CreatedAt` Sort Clause sorts search results by the date and time when the s ## Example ``` php +use Ibexa\Contracts\Shipping\Shipment\ShipmentQuery; + +/** @var \Ibexa\Contracts\Shipping\Shipment\Query\CriterionInterface $criteria */ $shipmentQuery = new ShipmentQuery( $criteria, [ new \Ibexa\Contracts\Shipping\Shipment\Query\SortClause\CreatedAt( - \Ibexa\Contracts\Shipping\Shipment\Query\SortClause\CreatedAt::SORT_ASC) + \Ibexa\Contracts\Shipping\Shipment\Query\SortClause\CreatedAt::SORT_ASC + ), ] ); ``` diff --git a/docs/search/sort_clause_reference/shipment_id_sort_clause.md b/docs/search/sort_clause_reference/shipment_id_sort_clause.md index fa405de54e..55f63a6560 100644 --- a/docs/search/sort_clause_reference/shipment_id_sort_clause.md +++ b/docs/search/sort_clause_reference/shipment_id_sort_clause.md @@ -14,11 +14,15 @@ The `Id` Sort Clause sorts search results by shipment Id. ## Example ``` php +use Ibexa\Contracts\Shipping\Shipment\ShipmentQuery; + +/** @var \Ibexa\Contracts\Shipping\Shipment\Query\CriterionInterface $criteria */ $shipmentQuery = new ShipmentQuery( $criteria, [ new \Ibexa\Contracts\Shipping\Shipment\Query\SortClause\Id( - \Ibexa\Contracts\Shipping\Shipment\Query\SortClause\Id::SORT_ASC) + \Ibexa\Contracts\Shipping\Shipment\Query\SortClause\Id::SORT_ASC + ), ] ); ``` diff --git a/docs/search/sort_clause_reference/shipment_identifier_sort_clause.md b/docs/search/sort_clause_reference/shipment_identifier_sort_clause.md index 1bc1a60bf3..18a93a034e 100644 --- a/docs/search/sort_clause_reference/shipment_identifier_sort_clause.md +++ b/docs/search/sort_clause_reference/shipment_identifier_sort_clause.md @@ -14,11 +14,15 @@ The `Identifier` Sort Clause sorts search results by shipment identifier. ## Example ``` php +use Ibexa\Contracts\Shipping\Shipment\ShipmentQuery; + +/** @var \Ibexa\Contracts\Shipping\Shipment\Query\CriterionInterface $criteria */ $shipmentQuery = new ShipmentQuery( $criteria, [ new \Ibexa\Contracts\Shipping\Shipment\Query\SortClause\Identifier( - \Ibexa\Contracts\Shipping\Shipment\Query\SortClause\Identifier::SORT_ASC) + \Ibexa\Contracts\Shipping\Shipment\Query\SortClause\Identifier::SORT_ASC + ), ] ); ``` diff --git a/docs/search/sort_clause_reference/shipment_status_sort_clause.md b/docs/search/sort_clause_reference/shipment_status_sort_clause.md index 5a0cacf07b..f4a48e908a 100644 --- a/docs/search/sort_clause_reference/shipment_status_sort_clause.md +++ b/docs/search/sort_clause_reference/shipment_status_sort_clause.md @@ -14,11 +14,15 @@ The `Status` Sort Clause sorts search results by shipment status. ## Example ``` php +use Ibexa\Contracts\Shipping\Shipment\ShipmentQuery; + +/** @var \Ibexa\Contracts\Shipping\Shipment\Query\CriterionInterface $criteria */ $shipmentQuery = new ShipmentQuery( $criteria, [ new \Ibexa\Contracts\Shipping\Shipment\Query\SortClause\Status( - \Ibexa\Contracts\Shipping\Shipment\Query\SortClause\Status::SORT_ASC) + \Ibexa\Contracts\Shipping\Shipment\Query\SortClause\Status::SORT_ASC + ), ] ); ``` diff --git a/docs/search/sort_clause_reference/shipment_updatedat_sort_clause.md b/docs/search/sort_clause_reference/shipment_updatedat_sort_clause.md index 0b6260a8ed..412a452113 100644 --- a/docs/search/sort_clause_reference/shipment_updatedat_sort_clause.md +++ b/docs/search/sort_clause_reference/shipment_updatedat_sort_clause.md @@ -14,11 +14,15 @@ The `UpdatedAt` Sort Clause sorts search results by the date and time when shipm ## Example ``` php +use Ibexa\Contracts\Shipping\Shipment\ShipmentQuery; + +/** @var \Ibexa\Contracts\Shipping\Shipment\Query\CriterionInterface $criteria */ $shipmentQuery = new ShipmentQuery( $criteria, [ new \Ibexa\Contracts\Shipping\Shipment\Query\SortClause\UpdatedAt( - \Ibexa\Contracts\Shipping\Shipment\Query\SortClause\UpdatedAt::SORT_ASC) + \Ibexa\Contracts\Shipping\Shipment\Query\SortClause\UpdatedAt::SORT_ASC + ), ] ); ``` diff --git a/docs/search/sort_clause_reference/userlogin_sort_clause.md b/docs/search/sort_clause_reference/userlogin_sort_clause.md index f234780543..0389b84134 100644 --- a/docs/search/sort_clause_reference/userlogin_sort_clause.md +++ b/docs/search/sort_clause_reference/userlogin_sort_clause.md @@ -13,6 +13,9 @@ The [`UserLogin` Sort Clause](/api/php_api/php_api_reference/classes/Ibexa-Contr ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\Query; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; + $query = new Query(); $query->sortClauses = [new SortClause\Trash\UserLogin()]; ``` diff --git a/docs/search/sort_clause_reference/visibility_sort_clause.md b/docs/search/sort_clause_reference/visibility_sort_clause.md index 258ee5fb72..8ee670136b 100644 --- a/docs/search/sort_clause_reference/visibility_sort_clause.md +++ b/docs/search/sort_clause_reference/visibility_sort_clause.md @@ -15,6 +15,9 @@ Locations that aren't visible are ranked as higher values (for example, with asc ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\SortClause; + $query = new LocationQuery(); $query->sortClauses = [new SortClause\Location\Visibility()]; ``` diff --git a/docs/search/url_search_reference/id_url_sort_clause.md b/docs/search/url_search_reference/id_url_sort_clause.md index ba2420079e..6e21977453 100644 --- a/docs/search/url_search_reference/id_url_sort_clause.md +++ b/docs/search/url_search_reference/id_url_sort_clause.md @@ -13,8 +13,8 @@ The [`SortClause\Id` Sort Clause](/api/php_api/php_api_reference/classes/Ibexa-C ## Example ``` php -use Ibexa\Contracts\Core\Repository\Values\URL\URLQuery; use Ibexa\Contracts\Core\Repository\Values\URL\Query\SortClause; +use Ibexa\Contracts\Core\Repository\Values\URL\URLQuery; // ... diff --git a/docs/search/url_search_reference/logicaland_url_criterion.md b/docs/search/url_search_reference/logicaland_url_criterion.md index f7b77a1649..c4b0e6a60f 100644 --- a/docs/search/url_search_reference/logicaland_url_criterion.md +++ b/docs/search/url_search_reference/logicaland_url_criterion.md @@ -13,10 +13,14 @@ The [`LogicalAnd` URL Criterion](/api/php_api/php_api_reference/classes/Ibexa-Co ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\URL\Query\Criterion; +use Ibexa\Contracts\Core\Repository\Values\URL\URLQuery; + +$query = new URLQuery(); $query->filter = new Criterion\LogicalAnd( [ new Criterion\Validity(true), - new Criterion\Pattern('ibexa.co') + new Criterion\Pattern('ibexa.co'), ] ); ``` diff --git a/docs/search/url_search_reference/logicalnot_url_criterion.md b/docs/search/url_search_reference/logicalnot_url_criterion.md index 6222fad435..eed8ab36a4 100644 --- a/docs/search/url_search_reference/logicalnot_url_criterion.md +++ b/docs/search/url_search_reference/logicalnot_url_criterion.md @@ -15,7 +15,11 @@ It takes only one Criterion in the array parameter. ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\URL\Query\Criterion; +use Ibexa\Contracts\Core\Repository\Values\URL\URLQuery; + +$query = new URLQuery(); $query->filter = new Criterion\LogicalNot( - new Criterion\Pattern('ibexa.co') + new Criterion\Pattern('ibexa.co') ); ``` diff --git a/docs/search/url_search_reference/logicalor_url_criterion.md b/docs/search/url_search_reference/logicalor_url_criterion.md index 7e79da7f1f..aef8778e22 100644 --- a/docs/search/url_search_reference/logicalor_url_criterion.md +++ b/docs/search/url_search_reference/logicalor_url_criterion.md @@ -13,10 +13,14 @@ The [`LogicalOr` URL Criterion](/api/php_api/php_api_reference/classes/Ibexa-Con ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\URL\Query\Criterion; +use Ibexa\Contracts\Core\Repository\Values\URL\URLQuery; + +$query = new URLQuery(); $query->filter = new Criterion\LogicalOr( [ new Criterion\SectionIdentifier(['sports', 'news']), - new Criterion\Pattern('ibexa.co') + new Criterion\Pattern('ibexa.co'), ] ); ``` diff --git a/docs/search/url_search_reference/pattern_url_criterion.md b/docs/search/url_search_reference/pattern_url_criterion.md index 34ed0afb67..822ebac541 100644 --- a/docs/search/url_search_reference/pattern_url_criterion.md +++ b/docs/search/url_search_reference/pattern_url_criterion.md @@ -13,5 +13,9 @@ The [`Pattern` URL Criterion](/api/php_api/php_api_reference/classes/Ibexa-Contr ## Example ``` php +use Ibexa\Contracts\Core\Repository\Values\URL\Query\Criterion; +use Ibexa\Contracts\Core\Repository\Values\URL\URLQuery; + +$query = new URLQuery(); $query->filter = new Criterion\Pattern('ibexa.co'); ``` diff --git a/docs/search/url_search_reference/sectionid_url_criterion.md b/docs/search/url_search_reference/sectionid_url_criterion.md index 8c0a67f03b..5de5f9b9ea 100644 --- a/docs/search/url_search_reference/sectionid_url_criterion.md +++ b/docs/search/url_search_reference/sectionid_url_criterion.md @@ -13,5 +13,9 @@ The [`SectionId` URL Criterion](/api/php_api/php_api_reference/classes/Ibexa-Con ## Example ``` php -$query->filter = new Criterion\SectionId(['1', '3']); +use Ibexa\Contracts\Core\Repository\Values\URL\Query\Criterion; +use Ibexa\Contracts\Core\Repository\Values\URL\URLQuery; + +$query = new URLQuery(); +$query->filter = new Criterion\SectionId([1, 3]); ``` diff --git a/docs/search/url_search_reference/sectionidentifier_url_criterion.md b/docs/search/url_search_reference/sectionidentifier_url_criterion.md index e0069e6287..ce4209876b 100644 --- a/docs/search/url_search_reference/sectionidentifier_url_criterion.md +++ b/docs/search/url_search_reference/sectionidentifier_url_criterion.md @@ -12,6 +12,10 @@ The [SectionIdentifier URL Criterion](/api/php_api/php_api_reference/classes/Ibe ## Example -```php +``` php +use Ibexa\Contracts\Core\Repository\Values\URL\Query\Criterion; +use Ibexa\Contracts\Core\Repository\Values\URL\URLQuery; + +$query = new URLQuery(); $query->filter = new Criterion\SectionIdentifier(['standard', 'media']); ``` diff --git a/docs/search/url_search_reference/url_url_sort_clause.md b/docs/search/url_search_reference/url_url_sort_clause.md index 100e56354a..4d6aa1f43e 100644 --- a/docs/search/url_search_reference/url_url_sort_clause.md +++ b/docs/search/url_search_reference/url_url_sort_clause.md @@ -13,8 +13,8 @@ The [`SortClause\Url` Sort Clause](/api/php_api/php_api_reference/classes/Ibexa- ## Example ``` php -use Ibexa\Contracts\Core\Repository\Values\URL\URLQuery; use Ibexa\Contracts\Core\Repository\Values\URL\Query\SortClause; +use Ibexa\Contracts\Core\Repository\Values\URL\URLQuery; // ... diff --git a/docs/search/url_search_reference/validity_url_criterion.md b/docs/search/url_search_reference/validity_url_criterion.md index 89b637d604..f80bd7262c 100644 --- a/docs/search/url_search_reference/validity_url_criterion.md +++ b/docs/search/url_search_reference/validity_url_criterion.md @@ -12,6 +12,10 @@ The [Validity URL Criterion](/api/php_api/php_api_reference/classes/Ibexa-Contra ## Example -```php +``` php +use Ibexa\Contracts\Core\Repository\Values\URL\Query\Criterion; +use Ibexa\Contracts\Core\Repository\Values\URL\URLQuery; + +$query = new URLQuery(); $query->filter = new Criterion\Validity(true); ``` diff --git a/docs/snippets/search_term_aggregation_settings.md b/docs/snippets/search_term_aggregation_settings.md index e67da0f71d..d2352a020e 100644 --- a/docs/snippets/search_term_aggregation_settings.md +++ b/docs/snippets/search_term_aggregation_settings.md @@ -3,7 +3,7 @@ You can define additional limits to the results using the `setLimit()` and `setMinCount()` methods. The following example limits the number of terms returned to 5 and only considers terms that have 10 or more results: -``` php +``` php {skip-validation} $aggregation = new //... $aggregation->setLimit(5); $aggregation->setMinCount(10); diff --git a/docs/templating/image_variations.md b/docs/templating/image_variations.md index c5af1b4451..83ed70b922 100644 --- a/docs/templating/image_variations.md +++ b/docs/templating/image_variations.md @@ -26,7 +26,9 @@ ibexa: : reference: null filters: - : + filter_name: + - parameter1 + - parameter2 ``` Variation name must be unique. diff --git a/docs/templating/layout/add_login_form.md b/docs/templating/layout/add_login_form.md index d035abf03e..3e6e30e120 100644 --- a/docs/templating/layout/add_login_form.md +++ b/docs/templating/layout/add_login_form.md @@ -88,12 +88,12 @@ final class LoginFormViewSubscriber implements EventSubscriberInterface $view = $event->getContentView(); if (!($view instanceof LoginFormView)) { - return ; + return; } $view->addParameters([ 'foo' => 'foo', - 'bar' => 'bar' + 'bar' => 'bar', ]); if ($view->getLastAuthenticationException() instanceof CredentialsExpiredException) { diff --git a/docs/templating/render_content/render_content_in_php.md b/docs/templating/render_content/render_content_in_php.md index bff7c12663..ee6ad3bafc 100644 --- a/docs/templating/render_content/render_content_in_php.md +++ b/docs/templating/render_content/render_content_in_php.md @@ -21,7 +21,7 @@ It doesn't work with a `full` view when the [page layout](template_configuration Create the command in `src/Command/ViewCommand.php`: -```php hl_lines="57-61" +``` php hl_lines="57-61" [[= include_code('code_samples/front/render_content_in_php/src/Command/ViewCommand.php') =]] ``` diff --git a/docs/templating/templates/view_matcher_reference.md b/docs/templating/templates/view_matcher_reference.md index 438a5d39f9..b5b8bf984b 100644 --- a/docs/templating/templates/view_matcher_reference.md +++ b/docs/templating/templates/view_matcher_reference.md @@ -234,7 +234,7 @@ match: ``` yaml match: - '@Ibexa\Taxonomy\View\Matcher\TaxonomyEntryBased\Id': [1, 2, 3]' + '@Ibexa\Taxonomy\View\Matcher\TaxonomyEntryBased\Id': [1, 2, 3] ``` ## Taxonomy entry identifier diff --git a/docs/templating/urls_and_routes/custom_breadcrumbs.md b/docs/templating/urls_and_routes/custom_breadcrumbs.md index 3da8df6e42..690d60df47 100644 --- a/docs/templating/urls_and_routes/custom_breadcrumbs.md +++ b/docs/templating/urls_and_routes/custom_breadcrumbs.md @@ -47,7 +47,11 @@ custom_blog_index: To see the correct breadcrumb, you have to check the method in the controller itself: ``` php - if ($request->getMethod() != REQUEST::METHOD_POST) { + use Symfony\Component\HttpFoundation\Request; + use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; + + /** @var \Symfony\Component\HttpFoundation\Request $request */ + if ($request->getMethod() != Request::METHOD_POST) { throw new NotFoundHttpException(); } ``` diff --git a/docs/tutorials/beginner_tutorial/5_display_a_list_of_content_items.md b/docs/tutorials/beginner_tutorial/5_display_a_list_of_content_items.md index 3aaf2a0e35..4f994a85c9 100644 --- a/docs/tutorials/beginner_tutorial/5_display_a_list_of_content_items.md +++ b/docs/tutorials/beginner_tutorial/5_display_a_list_of_content_items.md @@ -57,7 +57,7 @@ For more information, see [Built-In Query Types](built-in_query_types.md). Here, you need to display `ride` objects that have been published (are visible). Create a `RideQueryType.php` file in `src/QueryType`: -``` php hl_lines="21 22" +``` php hl_lines="22-23" $parameters */ + public function getQuery(array $parameters = []): \Ibexa\Contracts\Core\Repository\Values\Content\LocationQuery { return new LocationQuery([ 'filter' => new Criterion\LogicalAnd( @@ -81,12 +82,13 @@ class RideQueryType implements QueryType new Criterion\Visibility(Criterion\Visibility::VISIBLE), new Criterion\ContentTypeIdentifier(['ride']), ] - ) + ), ]); } - public function getSupportedParameters() + public function getSupportedParameters(): array { + return []; } } ``` diff --git a/docs/tutorials/beginner_tutorial/7_embed_content.md b/docs/tutorials/beginner_tutorial/7_embed_content.md index 2c72c8db69..c9404e183b 100644 --- a/docs/tutorials/beginner_tutorial/7_embed_content.md +++ b/docs/tutorials/beginner_tutorial/7_embed_content.md @@ -129,19 +129,16 @@ Create a `src/Controller/RideController.php` file: namespace App\Controller; use Ibexa\Bundle\Core\Controller; -use Ibexa\Core\MVC\Symfony\View\ContentView; use Ibexa\Contracts\Core\Repository\ContentService; +use Ibexa\Core\MVC\Symfony\View\ContentView; class RideController extends Controller { - private $contentService; - - public function __construct(ContentService $contentService) + public function __construct(private readonly ContentService $contentService) { - $this->contentService = $contentService; } - public function viewRideWithLandmarksAction(ContentView $view) + public function viewRideWithLandmarksAction(ContentView $view): ContentView { $currentContent = $view->getContent(); $landmarksListId = $currentContent->getFieldValue('landmarks'); diff --git a/docs/tutorials/generic_field_type/1_implement_the_point2d_value_class.md b/docs/tutorials/generic_field_type/1_implement_the_point2d_value_class.md index c5f5fbe278..d0af45e5ac 100644 --- a/docs/tutorials/generic_field_type/1_implement_the_point2d_value_class.md +++ b/docs/tutorials/generic_field_type/1_implement_the_point2d_value_class.md @@ -42,7 +42,7 @@ You want to focus on what the field type exposes as an API. `src/FieldType/Point2D/Value.php` should have the following properties: -```php +``` php [[= include_code('code_samples/field_types/2dpoint_ft/steps/step_1/Value.php', 10, 14, remove_indent=True) =]] ``` @@ -53,7 +53,7 @@ This class represents the point 2D. The final code should look like this: -```php +``` php [[= include_file('code_samples/field_types/2dpoint_ft/src/FieldType/Point2D/Value.php', 0, 6) ~ include_file('code_samples/field_types/2dpoint_ft/src/FieldType/Point2D/Value.php', 7, 11) diff --git a/docs/tutorials/generic_field_type/2_define_point2d_field_type.md b/docs/tutorials/generic_field_type/2_define_point2d_field_type.md index 0ccf455ac8..0d8f8ed6d6 100644 --- a/docs/tutorials/generic_field_type/2_define_point2d_field_type.md +++ b/docs/tutorials/generic_field_type/2_define_point2d_field_type.md @@ -17,7 +17,7 @@ First, create `src/FieldType/Point2D/Type.php`. Add a `getFieldTypeIdentifier()` method to it. The new method returns the string that **uniquely** identifies your field type, in this case `point2d`: -```php +``` php [[= include_code('code_samples/field_types/2dpoint_ft/steps/step_2/Type.php') =]] ``` diff --git a/docs/tutorials/generic_field_type/3_create_form_for_point2d.md b/docs/tutorials/generic_field_type/3_create_form_for_point2d.md index e494e5e9da..1c032d65ad 100644 --- a/docs/tutorials/generic_field_type/3_create_form_for_point2d.md +++ b/docs/tutorials/generic_field_type/3_create_form_for_point2d.md @@ -10,7 +10,7 @@ To edit your new field type, create a `Point2DType.php` form in the `src/Form/Ty Next, add a `Point2DType` class that extends the `AbstractType` and implements the `buildForm()` method. This method adds fields for `x` and `y` coordinates. -```php +``` php [[= include_file('code_samples/field_types/2dpoint_ft/steps/step_3/Point2DType.php', 0, 18) =]][[= include_file('code_samples/field_types/2dpoint_ft/steps/step_3/Point2DType.php', 25, 26) =]] ``` @@ -31,14 +31,14 @@ Next, implement a `mapFieldValueForm()` method and invoke `FormInterface::add` m Final version of the Type class should have the following statements and functions: -```php hl_lines="7 10 19-26" +``` php hl_lines="7 10 19-26" [[= include_code('code_samples/field_types/2dpoint_ft/steps/step_3/Type.php') =]] ``` Finally, add a `configureOptions` method and set default value of `data_class` to `Value::class` in `src/Form/Type/Point2DType.php`. It allows your form to work on this object. -```php hl_lines="20-25" +``` php hl_lines="20-25" [[= include_code('code_samples/field_types/2dpoint_ft/src/Form/Type/Point2DType.php') =]] ``` diff --git a/docs/tutorials/generic_field_type/6_settings.md b/docs/tutorials/generic_field_type/6_settings.md index 73ee5a87f0..e659b9221c 100644 --- a/docs/tutorials/generic_field_type/6_settings.md +++ b/docs/tutorials/generic_field_type/6_settings.md @@ -15,7 +15,7 @@ You also specify coordinates as placeholder values `%x%` and `%y%`. Open `src/FieldType/Point2D/Type.php` and add a `getSettingsSchema` method according to the following code block: -```php hl_lines="18-27" +``` php hl_lines="18-27" [[= include_code('code_samples/field_types/2dpoint_ft/steps/step_6/Type.php') =]] ``` @@ -25,7 +25,7 @@ In this part you define and implement the edit form for your field type. Define a `Point2DSettingsType` class and add a `format` field in `src/Form/Type/Point2DSettingsType.php`: -```php +``` php [[= include_code('code_samples/field_types/2dpoint_ft/src/Form/Type/Point2DSettingsType.php') =]] ``` @@ -37,7 +37,7 @@ In `src/FieldType/Point2D/Type.php` you: - implement the `FieldDefinitionFormMapperInterface` interface - add a `mapFieldDefinitionForm` method at the end that defines the field settings -```php +``` php [[= include_file('code_samples/field_types/2dpoint_ft/src/FieldType/Point2D/Type.php', 0, 4) =]]// ... [[= include_file('code_samples/field_types/2dpoint_ft/src/FieldType/Point2D/Type.php', 7, 9) =]][[= include_file('code_samples/field_types/2dpoint_ft/src/FieldType/Point2D/Type.php', 10, 16) =]]// ... [[= include_file('code_samples/field_types/2dpoint_ft/src/FieldType/Point2D/Type.php', 41, 48) =]] @@ -45,7 +45,7 @@ In `src/FieldType/Point2D/Type.php` you:
Complete Type.php code -```php +``` php [[= include_code('code_samples/field_types/2dpoint_ft/src/FieldType/Point2D/Type.php') =]] ```
diff --git a/docs/tutorials/generic_field_type/7_add_a_validation.md b/docs/tutorials/generic_field_type/7_add_a_validation.md index 638dc71544..cab21ebb35 100644 --- a/docs/tutorials/generic_field_type/7_add_a_validation.md +++ b/docs/tutorials/generic_field_type/7_add_a_validation.md @@ -6,7 +6,7 @@ description: Learn how to validate custom field data. To provide basic validation that ensures both coordinates are provided, add assertions to the `src/FieldType/Point2D/Value.php`: -```php hl_lines="12 14" +``` php hl_lines="12 14" [[= include_code('code_samples/field_types/2dpoint_ft/src/FieldType/Point2D/Value.php') =]] ``` diff --git a/docs/tutorials/generic_field_type/8_data_migration.md b/docs/tutorials/generic_field_type/8_data_migration.md index 26afca8d94..dd3b5330d3 100644 --- a/docs/tutorials/generic_field_type/8_data_migration.md +++ b/docs/tutorials/generic_field_type/8_data_migration.md @@ -15,7 +15,7 @@ For more information on Serializer Component, see [Symfony documentation]([[= sy First, you need to add support for normalization in a `src/Serializer/Point2D/ValueNormalizer.php`: -```php +``` php [[= include_code('code_samples/field_types/2dpoint_ft/src/Serializer/Point2D/ValueNormalizer.php') =]] ``` @@ -27,7 +27,7 @@ First, you need to add support for normalization in a `src/Serializer/Point2D/Va To accept old versions of the field type you need to add support for denormalization in a `src/Serializer/Point2D/ValueDenormalizer.php`: -```php +``` php [[= include_code('code_samples/field_types/2dpoint_ft/src/Serializer/Point2D/ValueDenormalizer.php') =]] ``` @@ -35,7 +35,7 @@ To accept old versions of the field type you need to add support for denormaliza To change the format on the fly, you need to replace the constructor and class properties in `src/FieldType/Point2D/Value.php`: -```php +``` php [[= include_code('code_samples/field_types/2dpoint_ft/src/FieldType/Point2D/ValueFinal.php', 11, 24, remove_indent=True) =]] ``` diff --git a/docs/update_and_migration/from_1.x_2.x/update_db_to_2.5.md b/docs/update_and_migration/from_1.x_2.x/update_db_to_2.5.md index f0ae09fa07..945c1cad29 100644 --- a/docs/update_and_migration/from_1.x_2.x/update_db_to_2.5.md +++ b/docs/update_and_migration/from_1.x_2.x/update_db_to_2.5.md @@ -146,7 +146,7 @@ defined in the [Enterprise Beginner tutorial](page_and_form_tutorial.md) `app/Resources/views/layouts/sidebar.html.twig`: - ```php + ```html+twig
{% if zones[0].blocks %} @@ -197,7 +197,7 @@ defined in the [Enterprise Beginner tutorial](page_and_form_tutorial.md) `src/AppBundle/Block/RandomBlock.php`: - ``` php + ``` php {skip-validation}
{% if zones[0].blocks %} @@ -456,7 +456,7 @@ defined in the [Enterprise Beginner tutorial](page_and_form_tutorial.md) `src/AppBundle/Block/Event/Listener/RandomBlockListener.php` in place of `src/AppBundle/Block/RandomBlock.php`: - ``` php + ``` php {skip-validation} 'onCreateBookmark', - ] + ]; } public function onCreateBookmark(CreateBookmarkEvent $event): void @@ -27,13 +27,13 @@ public function onCreateBookmark(CreateBookmarkEvent $event): void **instead of:** -``` php +``` php {skip-validation} public function receive(Signal $signal) { if (!($signal instanceof CreateBookmarkSignal)) { return; } -} -// your code + // your code +} ``` diff --git a/docs/update_and_migration/from_2.5/update_code/8_update_rest.md b/docs/update_and_migration/from_2.5/update_code/8_update_rest.md index 4265bb374c..c349353cf1 100644 --- a/docs/update_and_migration/from_2.5/update_code/8_update_rest.md +++ b/docs/update_and_migration/from_2.5/update_code/8_update_rest.md @@ -21,7 +21,7 @@ you need to switch to Core Installer. **Use:** -``` php +``` yaml services: Acme\App\Installer\MyCustomInstaller: parent: EzSystems\PlatformInstallerBundle\Installer\CoreInstaller @@ -29,7 +29,7 @@ services: **instead of**: -``` php +``` yaml services: Acme\App\Installer\MyCustomInstaller: parent: ezplatform.installer.clean_installer @@ -42,7 +42,7 @@ Custom schema can be installed defining Symfony Event Subscriber subscribing to **Use:** -``` php +``` yaml services: Acme\App\Installer\MyCustomInstaller: parent: EzSystems\PlatformInstallerBundle\Installer\DbBasedInstaller @@ -50,7 +50,7 @@ services: **instead of:** -``` php +``` yaml services: Acme\App\Installer\MyCustomInstaller: parent: ezplatform.installer.db_based_installer diff --git a/docs/update_and_migration/from_4.3/update_from_4.3_new_commerce.md b/docs/update_and_migration/from_4.3/update_from_4.3_new_commerce.md index e8e0420c8d..af83553e97 100644 --- a/docs/update_and_migration/from_4.3/update_from_4.3_new_commerce.md +++ b/docs/update_and_migration/from_4.3/update_from_4.3_new_commerce.md @@ -151,7 +151,7 @@ You don't have to remove third-party bundles (`FOS\` to `JMS\`) if they're used === "[[= product_name_content =]]" - ``` php + ``` text FOS\CommentBundle\FOSCommentBundle Tedivm\StashBundle\TedivmStashBundle WhiteOctober\BreadcrumbsBundle\WhiteOctoberBreadcrumbsBundle @@ -178,7 +178,7 @@ You don't have to remove third-party bundles (`FOS\` to `JMS\`) if they're used === "[[= product_name_exp =]]" - ``` php + ``` text FOS\CommentBundle\FOSCommentBundle Tedivm\StashBundle\TedivmStashBundle WhiteOctober\BreadcrumbsBundle\WhiteOctoberBreadcrumbsBundle @@ -205,7 +205,7 @@ You don't have to remove third-party bundles (`FOS\` to `JMS\`) if they're used === "[[= product_name_com =]]" - ``` php + ``` text FOS\CommentBundle\FOSCommentBundle Tedivm\StashBundle\TedivmStashBundle WhiteOctober\BreadcrumbsBundle\WhiteOctoberBreadcrumbsBundle diff --git a/docs/update_and_migration/from_4.3/update_from_4.3_old_commerce.md b/docs/update_and_migration/from_4.3/update_from_4.3_old_commerce.md index b3e5d5a6d8..2cd058d86a 100644 --- a/docs/update_and_migration/from_4.3/update_from_4.3_old_commerce.md +++ b/docs/update_and_migration/from_4.3/update_from_4.3_old_commerce.md @@ -156,7 +156,7 @@ Add the following dependencies in the `require` section in `composer.json`: Next, remove the entries with new packages alongside with routing and configuration in `config/routes/ibexa_cart.yaml`, `config/routes/ibexa_checkout.yaml` and `config/routes/ibexa_storefront.yaml`: -```php +``` php {skip-validation} Ibexa\Bundle\Cart\IbexaCartBundle::class => ['all' => true], Ibexa\Bundle\Checkout\IbexaCheckoutBundle::class => ['all' => true], Ibexa\Bundle\Storefront\IbexaStorefrontBundle::class => ['all' => true], diff --git a/docs/update_and_migration/from_4.6/update_from_4.6.md b/docs/update_and_migration/from_4.6/update_from_4.6.md index 40d86db014..b6a0e0528e 100644 --- a/docs/update_and_migration/from_4.6/update_from_4.6.md +++ b/docs/update_and_migration/from_4.6/update_from_4.6.md @@ -161,8 +161,11 @@ merge with your custom settings if needed, and commit them to Git. If the new bundle `ibexa/core-search` has not been added by the recipes, enable it by adding the following line in `config/bundles.php`: -```php +``` php +return [ + // ... Ibexa\Bundle\CoreSearch\IbexaCoreSearchBundle::class => ['all' => true], +]; ``` ## v4.6.13 diff --git a/docs/update_and_migration/from_4.6/update_to_5.0.md b/docs/update_and_migration/from_4.6/update_to_5.0.md index 0bf7390ee1..5c1376d778 100644 --- a/docs/update_and_migration/from_4.6/update_to_5.0.md +++ b/docs/update_and_migration/from_4.6/update_to_5.0.md @@ -50,17 +50,20 @@ It's recommended to activate one rule set at a time and preview the output by ru Your configuration could look like the following example: -```php +``` php +use Ibexa\Contracts\Rector\Sets\IbexaSetList; +use Rector\Config\RectorConfig; + return RectorConfig::configure() ->withPaths( - [ + [ __DIR__ . '/src', - ] + ] ) ->withSets( - [ + [ IbexaSetList::IBEXA_46->value, - ] + ] ) ->withPhpSets(php83: true) ->withComposerBased(symfony: true) @@ -463,11 +466,15 @@ Again, it's recommended to activate one rule set at a time and preview the outpu As this update spans across a broad range of versions, multiple rules can be considered as in the example below. -```php +``` php //… -use Rector\Symfony\Set\SymfonySetList; +use Ibexa\Contracts\Rector\Sets\IbexaSetList; +use Rector\Config\RectorConfig; use Rector\Symfony\Set\SensiolabsSetList; -//… +use Rector\Symfony\Set\SymfonySetList; + +return RectorConfig::configure() + // ... ->withSets( [ IbexaSetList::IBEXA_50->value, diff --git a/docs/update_and_migration/migrate_to_ibexa_dxp/migrating_from_ez_publish_platform.md b/docs/update_and_migration/migrate_to_ibexa_dxp/migrating_from_ez_publish_platform.md index 5956b5e224..57ecbf3d99 100644 --- a/docs/update_and_migration/migrate_to_ibexa_dxp/migrating_from_ez_publish_platform.md +++ b/docs/update_and_migration/migrate_to_ibexa_dxp/migrating_from_ez_publish_platform.md @@ -576,7 +576,7 @@ To use the script, do the following: **2.** Add `ezflow-migration-toolkit` to `AppKernel.php`. -``` php +``` php {skip-validation} // AppKernel.php new EzSystems\EzFlowMigrationToolkitBundle\EzSystemsEzFlowMigrationToolkitBundle() ``` @@ -612,7 +612,7 @@ You can see a report summarizing the results of the migration. **6.** Add `MigrationBundle` to `AppKernel.php`. -``` php +``` php {skip-validation} // AppKernel.php new MigrationBundle\MigrationBundle() ``` diff --git a/docs/users/invitations.md b/docs/users/invitations.md index 446e852902..ddcebdd860 100644 --- a/docs/users/invitations.md +++ b/docs/users/invitations.md @@ -30,13 +30,13 @@ If the SiteAccess isn't set, it falls back to the default `site` value. For example, use the following [configuration](configuration.md#configuration-files): ```yaml - ibexa: - system: - : - user_invitation: - hash_expiration_time: P7D - templates: - mail: "@@App/invitation/mail.html.twig" +ibexa: + system: + : + user_invitation: + hash_expiration_time: P7D + templates: + mail: "@@App/invitation/mail.html.twig" ``` Here, you can specify which template should be used for the invitation mail, and what should be the expiration time for the invitation link included in that mail. diff --git a/docs/users/oauth_server.md b/docs/users/oauth_server.md index 45ac506920..0470d21be2 100644 --- a/docs/users/oauth_server.md +++ b/docs/users/oauth_server.md @@ -34,7 +34,7 @@ Add the tables needed by the bundle: Then, in `config/bundles.php`, at the end of an array with a list of bundles, add the following two lines : -```php +``` php segmentationService->removeSegmentGroup($group); +[[= include_code('code_samples/api/public_php_api/src/Command/SegmentCommand.php', 67, 67, remove_indent=True) =]] ``` diff --git a/docs/users/user_authentication.md b/docs/users/user_authentication.md index 45287e9abc..81635e1c28 100644 --- a/docs/users/user_authentication.md +++ b/docs/users/user_authentication.md @@ -31,7 +31,45 @@ Finally, the user is assigned back into the event's token for the rest of the pr The following example uses the [memory user provider]([[= symfony_doc =]]/security/user_providers.html#memory-user-provider), maps memory user to [[= product_name_base =]] repository user, and [chains]([[= symfony_doc =]]/security/user_providers.html#chain-user-provider) with the [[= product_name_base =]] user provider to be able to use both. -Create a `src/EventSubscriber/AuthenticationTokenCreatedSubscriber.php` that subscribes to the `AuthenticationTokenCreatedEvent` event and maps an authenticated in-memory user to an [[= product_name_base =]] user when necessary: +It's possible to customize the user class used by extending `Ibexa\Core\MVC\Symfony\Security\EventListener\SecurityListener` service, which defaults to `Ibexa\Core\MVC\Symfony\Security\EventListener\SecurityListener`. + +You can override `getUser()` to return whatever user class you want, as long as it implements `Ibexa\Core\MVC\Symfony\Security\UserInterface`. + +The following is an example of using the in-memory user provider: + +``` yaml +# config/packages/security.yaml +security: + providers: + # Chaining in_memory and ibexa user providers + chain_provider: + chain: + providers: [in_memory, ibexa] + ibexa: + id: ibexa.security.user_provider + in_memory: + memory: + users: + # You will then be able to login with username "user" and password "userpass" + user: { password: userpass, roles: [ 'ROLE_USER' ] } + # The "in memory" provider requires an encoder for Symfony\Component\Security\Core\User\User + encoders: + Symfony\Component\Security\Core\User\User: plaintext +``` + +### Implement the listener + +In the `config/services.yaml` file: + +``` yaml +services: + App\EventListener\InteractiveLoginListener: + arguments: ['@ibexa.api.service.user'] + tags: + - { name: kernel.event_subscriber } +``` + +Don't mix `MVCEvents::INTERACTIVE_LOGIN` event (specific to [[= product_name =]]) and `SecurityEvents::INTERACTIVE_LOGIN` event (fired by Symfony security component). ``` php [[= include_file('code_samples/user_management/in_memory/src/EventSubscriber/AuthenticationTokenCreatedSubscriber.php') =]] diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 67fa1606c9..9b5861650f 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,5 +1,143 @@ parameters: ignoreErrors: + - + message: '#^Offset ''acme'' does not exist on array\{alias\: string, storage\: array\{engine\: string, connection\: string, config\?\: array\\}, search\: array\{engine\: string, connection\: string\}, fields_groups\: array\{default\: string, list\: array\\}, options\: array\\}\.$#' + identifier: offsetAccess.notFound + count: 1 + path: code_samples/_inline_php/administration/configuration/repository_configuration/ab545148cd13f7537467f6c43859d757ba15120b5df7d9933e6236336f1bf5e1.php + + - + message: '#^Dead catch \- Ibexa\\Contracts\\Core\\Repository\\Exceptions\\NotFoundException is never thrown in the try block\.$#' + identifier: catch.neverThrown + count: 1 + path: code_samples/_inline_php/api/php_api/php_api/1207fc11956ce57c9503ab18d8fb6316f391ed152816968fccfb020a4d498420.php + + - + message: '#^Dead catch \- Ibexa\\Contracts\\Core\\Repository\\Exceptions\\UnauthorizedException is never thrown in the try block\.$#' + identifier: catch.neverThrown + count: 1 + path: code_samples/_inline_php/api/php_api/php_api/1207fc11956ce57c9503ab18d8fb6316f391ed152816968fccfb020a4d498420.php + + - + message: '#^Instantiated class MyValue not found\.$#' + identifier: class.notFound + count: 1 + path: code_samples/_inline_php/api/rest_api/extending_rest_api/creating_new_rest_resource/6886002ea53abecb63d61d585bc055fc9df36a19db675e286408a52f40aa794c.php + + - + message: '#^Variable \$args might not be defined\.$#' + identifier: variable.undefined + count: 1 + path: code_samples/_inline_php/api/rest_api/extending_rest_api/creating_new_rest_resource/6886002ea53abecb63d61d585bc055fc9df36a19db675e286408a52f40aa794c.php + + - + message: '#^Call to an undefined method Symfony\\Component\\Notifier\\Recipient\\RecipientInterface\:\:getUser\(\)\.$#' + identifier: method.notFound + count: 1 + path: code_samples/_inline_php/commerce/transactional_emails/extend_transactional_emails/9512b966ae24a637ff0bba4d63a51f6418567d4c1245ea3d61272890838582a4.php + + - + message: '#^Property Ibexa\\Contracts\\Core\\Repository\\Values\\Content\\Content\:\:\$fields is not writable\.$#' + identifier: assign.propertyReadOnly + count: 1 + path: code_samples/_inline_php/content_management/field_types/field_type_reference/countryfield/3cd88088ebfaab6dc8aab79fd8d9e380586a05e9a250f208935020a274d6a77f.php + + - + message: '#^Expression "\[''isISBN13'' \=\> \\true\]" on a separate line does not do anything\.$#' + identifier: expr.resultUnused + count: 1 + path: code_samples/_inline_php/content_management/field_types/field_type_reference/isbnfield/678db783359b1c65999e5fed725950d32aaab547ab82f6bda18afcafa3392e8b.php + + - + message: '#^Expression "\[''StringLengthValidator'' \=\> \[''maxStringLength'' \=\> 60, ''minStringLength'' \=\> 1\]\]" on a separate line does not do anything\.$#' + identifier: expr.resultUnused + count: 1 + path: code_samples/_inline_php/content_management/field_types/field_type_reference/textlinefield/abeeb0a02156f9dd413b5f54292d97783f49043458623888d904267ffa60acde.php + + - + message: '#^Expression "\[''stringLength'' \=\> \[''minStringLength'' \=\> \[''type'' \=\> ''int'', ''default'' \=\> 0\], ''maxStringLength'' \=\> \[''type'' \=\> ''int'', ''default'' \=\> \\null\]\]\]" on a separate line does not do anything\.$#' + identifier: expr.resultUnused + count: 1 + path: code_samples/_inline_php/content_management/field_types/field_type_validation/9ff627c9326c9d9aa0613061d4b96d5e0b22526a04e1c3cf6c671bdc73f537e7.php + + - + message: '#^Expression "\[''backupData'' \=\> \[''type'' \=\> ''bool'', ''default'' \=\> \\false\], ''defaultValue'' \=\> \[''type'' \=\> ''string'', ''default'' \=\> ''Default Value''\]\]" on a separate line does not do anything\.$#' + identifier: expr.resultUnused + count: 1 + path: code_samples/_inline_php/content_management/field_types/type_and_value/4d9e52e02d6e226f71015653d598f662f6b4d4eb0af9e99b4c49d5389af19671.php + + - + message: '#^Call to an undefined method object\:\:loadObject\(\)\.$#' + identifier: method.notFound + count: 1 + path: code_samples/_inline_php/infrastructure_and_maintenance/cache/persistence_cache/353177557bb0bc90eb5b4270a1c24e9544452d429462edff6f2aab293e6999e9.php + + - + message: '#^Property App\\MyService\:\:\$contentService is never read, only written\.$#' + identifier: property.onlyWritten + count: 1 + path: code_samples/_inline_php/multisite/siteaccess/injecting_siteaccess/8c8e5bbb699fa46d35caf839176460dccbdd53431e04edd95c7ea25a7e638d9c.php + + - + message: '#^Property App\\MyService\:\:\$siteAccessService is never read, only written\.$#' + identifier: property.onlyWritten + count: 1 + path: code_samples/_inline_php/multisite/siteaccess/injecting_siteaccess/8c8e5bbb699fa46d35caf839176460dccbdd53431e04edd95c7ea25a7e638d9c.php + + - + message: '#^Variable \$this might not be defined\.$#' + identifier: variable.undefined + count: 1 + path: code_samples/_inline_php/search/criteria_reference/ancestor_criterion/4a5427b7ae43106059e9d543fcbf5e7b66602c10052ab6ff67750e041857c6ad.php + + - + message: '#^Variable \$this might not be defined\.$#' + identifier: variable.undefined + count: 1 + path: code_samples/_inline_php/search/criteria_reference/parentlocationid_criterion/c85766351eda977c61c12ab7d00c11cba956bde544bbdff4cad24e0bbf7717d9.php + + - + message: '#^Method App\\QueryType\\RideQueryType\:\:getSupportedParameters\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: code_samples/_inline_php/tutorials/beginner_tutorial/5_display_a_list_of_content_items/ccb9d8424978af9df4ec24d732f91c6f7cab90b6879eecd0ea97fef21b833b3b.php + + - + message: '#^Cannot access property \$destinationContentIds on Ibexa\\Contracts\\Core\\FieldType\\Value\|null\.$#' + identifier: property.nonObject + count: 1 + path: code_samples/_inline_php/tutorials/beginner_tutorial/7_embed_content/d8ad5ae7972b67d11cb172c321b891e268d5a346d166f73c5570d61b9b372a7d.php + + - + message: '#^Access to constant ANNOTATIONS_TO_ATTRIBUTES on an unknown class Rector\\Symfony\\Set\\SensiolabsSetList\.$#' + identifier: class.notFound + count: 1 + path: code_samples/_inline_php/update_and_migration/from_4.6/update_to_5.0/20a5c589183c1b8ee4f67c7a0c9352320eb7349e3f06f89c61e245ea4b7f585f.php + + - + message: '#^Access to undefined constant Ibexa\\Core\\MVC\\Symfony\\MVCEvents\:\:INTERACTIVE_LOGIN\.$#' + identifier: classConstant.notFound + count: 1 + path: code_samples/_inline_php/users/user_authentication/661a7600ac0964cdf501697eda6461ec2a7a1c3813025f1fbb4ffa16ec174b53.php + + - + message: '#^Call to method setApiUser\(\) on an unknown class eIbexa\\Core\\MVC\\Symfony\\Event\\InteractiveLoginEvent\.$#' + identifier: class.notFound + count: 1 + path: code_samples/_inline_php/users/user_authentication/661a7600ac0964cdf501697eda6461ec2a7a1c3813025f1fbb4ffa16ec174b53.php + + - + message: '#^Method App\\EventListener\\InteractiveLoginListener\:\:onInteractiveLogin\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: code_samples/_inline_php/users/user_authentication/661a7600ac0964cdf501697eda6461ec2a7a1c3813025f1fbb4ffa16ec174b53.php + + - + message: '#^Parameter \$event of method App\\EventListener\\InteractiveLoginListener\:\:onInteractiveLogin\(\) has invalid type eIbexa\\Core\\MVC\\Symfony\\Event\\InteractiveLoginEvent\.$#' + identifier: class.notFound + count: 1 + path: code_samples/_inline_php/users/user_authentication/661a7600ac0964cdf501697eda6461ec2a7a1c3813025f1fbb4ffa16ec174b53.php + - message: '#^Class App\\Form\\Type\\TextToTextOptionsType extends generic class Symfony\\Component\\Form\\AbstractType but does not specify its types\: TData$#' identifier: missingType.generics @@ -683,3 +821,4 @@ parameters: identifier: argument.type count: 1 path: code_samples/workflow/custom_workflow/src/EventListener/LegalTransitionListener.php + diff --git a/phpstan.neon b/phpstan.neon index def4a36323..3b3b56df27 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -8,3 +8,4 @@ parameters: paths: - code_samples treatPhpDocTypesAsCertain: false + reportUnmatchedIgnoredErrors: false diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000000..e084420e57 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,14 @@ + + + + + tests/ + + + diff --git a/tests/ConfigurationProvider.php b/tests/ConfigurationProvider.php new file mode 100644 index 0000000000..4dfbe49523 --- /dev/null +++ b/tests/ConfigurationProvider.php @@ -0,0 +1,178 @@ +container = $this->buildContainer(); + } + + public function hasExtension(string $alias): bool + { + return $this->container->hasExtension($alias); + } + + public function createConfiguration(string $alias): ConfigurationInterface + { + return $this->container->getExtension($alias)->getConfiguration([], $this->container); + } + + /** + * Recursively resolves %parameter% placeholders using the container's + * parameter bag, mirroring what the real Symfony kernel does before + * passing config to the Config component. Unknown parameters (custom app + * params not present in the test container) are left as-is. + * + * @param array $config + * + * @return array + */ + public function resolveParameters(array $config): array + { + /** @var array $result */ + $result = $this->resolveValue($this->container->getParameterBag(), $config); + + return $result; + } + + private function resolveValue(ParameterBagInterface $bag, mixed $value): mixed + { + if (is_array($value)) { + return array_map(fn (mixed $v): mixed => $this->resolveValue($bag, $v), $value); + } + + if (!is_string($value)) { + return $value; + } + + try { + return $bag->resolveValue($value); + } catch (ParameterNotFoundException) { + return $value; + } + } + + private function buildContainer(): ContainerBuilder + { + $container = new ContainerBuilder(); + $container->setParameter('kernel.debug', false); + $container->setParameter('kernel.bundles', []); + $container->setParameter('kernel.bundles_metadata', []); + $container->setParameter('kernel.project_dir', sys_get_temp_dir()); + $container->setParameter('kernel.environment', 'test'); + + $bundles = self::discoverBundles(); + + // Register all extensions before calling build() on any bundle, + // because some bundles call $container->getExtension('ibexa') during build(). + foreach ($bundles as $bundle) { + try { + $extension = $bundle->getContainerExtension(); + if ($extension !== null) { + $container->registerExtension($extension); + } + } catch (\Throwable) { + // Skip bundles whose extension cannot be instantiated. + } + } + + // build() registers parsers/factories into the extensions. + foreach ($bundles as $bundle) { + try { + $bundle->build($container); + } catch (\Throwable) { + // Skip bundles whose build() fails (e.g. missing sibling extensions). + } + } + + return $container; + } + + /** + * Returns all installed bundles with SecurityBundle and IbexaCoreBundle + * guaranteed first (other bundles may call getExtension('ibexa') or + * getExtension('security') during their build()). + * + * @return list + */ + private static function discoverBundles(): array + { + // These must be registered before any bundle that calls + // $container->getExtension('ibexa'/'security') inside build(). + $bundles = [ + new SecurityBundle(), + new IbexaCoreBundle(), + ]; + + $seen = [SecurityBundle::class, IbexaCoreBundle::class]; + + $vendorBase = __DIR__ . '/../vendor'; + $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($vendorBase)); + + foreach ($iterator as $file) { + if (!$file->isFile() || !preg_match('/\w+Bundle\.php$/', $file->getFilename())) { + continue; + } + + $content = file_get_contents($file->getPathname()); + preg_match('/^namespace (.+);/m', $content, $nsMatch); + preg_match('/^(?:(?:final|abstract)\s+)?class (\w+Bundle)\b/m', $content, $clsMatch); + + if (empty($nsMatch[1]) || empty($clsMatch[1])) { + continue; + } + + $fqcn = $nsMatch[1] . '\\' . $clsMatch[1]; + + if (!class_exists($fqcn) || in_array($fqcn, $seen, true)) { + continue; + } + + $reflection = new \ReflectionClass($fqcn); + if ($reflection->isAbstract() || !$reflection->implementsInterface(BundleInterface::class)) { + continue; + } + + $seen[] = $fqcn; + + try { + $bundles[] = new $fqcn(); + } catch (\Throwable) { + // Skip bundles that cannot be instantiated without arguments. + } + } + + return $bundles; + } +} diff --git a/tests/InlineSamples/InlinePhpPipelineTest.php b/tests/InlineSamples/InlinePhpPipelineTest.php new file mode 100644 index 0000000000..e02405ca65 --- /dev/null +++ b/tests/InlineSamples/InlinePhpPipelineTest.php @@ -0,0 +1,367 @@ +extractor = new MarkdownExtractor('php'); + $this->writer = new InlinePhpWriter(); + $this->syncer = new InlinePhpSyncer(); + } + + // ------------------------------------------------------------------------- + // Helpers + // ------------------------------------------------------------------------- + + /** + * Runs the full pipeline for the first block found in $md. + * + * @param array $fixerReplacements str_replace()-style substitutions applied + * to the built file content to simulate cs-fixer. + * + * @return string|null Updated Markdown, or null when the pipeline produced no change. + */ + private function pipeline(string $md, array $fixerReplacements = []): ?string + { + $blocks = iterator_to_array($this->extractor->extract($md)); + self::assertNotEmpty($blocks, 'No PHP blocks found in Markdown'); + + $block = $blocks[0]; + $phpFile = $this->writer->build('docs/test.md', $block['line'], $block['body']); + + if ($fixerReplacements !== []) { + $phpFile = strtr($phpFile, $fixerReplacements); + } + + return $this->syncer->sync($phpFile, $md); + } + + /** + * Runs the pipeline for ALL blocks in $md, applying the same fixer replacements to each, + * and patches the Markdown accumulating all changes (highest line first, as the real + * script does). + * + * @param array $fixerReplacements + */ + private function pipelineAll(string $md, array $fixerReplacements = []): string + { + $blocks = iterator_to_array($this->extractor->extract($md)); + self::assertNotEmpty($blocks); + + // Collect per-block PHP files and sort by descending line (highest first). + $items = array_map( + fn (array $block): array => [ + 'line' => $block['line'], + 'phpFile' => strtr( + $this->writer->build('docs/test.md', $block['line'], $block['body']), + $fixerReplacements, + ), + ], + $blocks, + ); + usort($items, static fn (array $a, array $b): int => $b['line'] <=> $a['line']); + + foreach ($items as ['phpFile' => $phpFile, 'line' => $line]) { + $updated = $this->syncer->sync($phpFile, $md); + if ($updated !== null) { + $md = $updated; + } + } + + return $md; + } + + // ------------------------------------------------------------------------- + // No-op: pipeline returns null when cs-fixer changes nothing + // ------------------------------------------------------------------------- + + public function testNoOpForPlainSnippet(): void + { + $md = "text\n\n```php\n\$x = 1;\n```\n"; + self::assertNull($this->pipeline($md)); + } + + public function testNoOpForSnippetWithPhpTag(): void + { + $md = "text\n\n```php\npipeline($md)); + } + + public function testNoOpForSnippetWithPhpTagAndBlankLine(): void + { + // The blank line between pipeline($md)); + } + + public function testNoOpForIndentedSnippet(): void + { + $md = "!!! note\n\n ```php\n \$x = 1;\n ```\n"; + self::assertNull($this->pipeline($md)); + } + + public function testNoOpForIndentedSnippetWithPhpTagAndBlankLine(): void + { + $md = "!!! note\n\n ```php\n pipeline($md)); + } + + // ------------------------------------------------------------------------- + // Changes are applied correctly + // ------------------------------------------------------------------------- + + public function testChangeAppliedToPlainSnippet(): void + { + $md = "text\n\n```php\n\$x=1;\n```\n"; + $result = $this->pipeline($md, ['$x=1;' => '$x = 1;']); + + self::assertNotNull($result); + self::assertStringContainsString('$x = 1;', $result); + self::assertStringNotContainsString('$x=1;', $result); + } + + public function testChangeAppliedPreservesPhpTag(): void + { + $md = "text\n\n```php\npipeline($md, ['$x=1;' => '$x = 1;']); + + self::assertNotNull($result); + self::assertStringContainsString("pipeline($md, ['$x=1;' => '$x = 1;']); + + self::assertNotNull($result); + self::assertStringContainsString("pipeline($md, ['$x=1;' => '$x = 1;']); + + self::assertNotNull($result); + self::assertStringContainsString(' $x = 1;', $result); + } + + public function testChangeAppliedToIndentedSnippetWithPhpTagAndBlankLine(): void + { + $md = "!!! note\n\n ```php\n pipeline($md, ['$x=1;' => '$x = 1;']); + + self::assertNotNull($result); + self::assertStringContainsString(" pipeline($md, [ + "use B\\Baz;\nuse A\\Bar;" => "use A\\Bar;\nuse B\\Baz;", + ]); + + self::assertNotNull($result); + self::assertStringContainsString("use A\\Bar;\nuse B\\Baz;", $result); + self::assertStringContainsString(" $fixerReplacements + */ + #[DataProvider('provideIdempotencyCases')] + public function testPipelineIsIdempotent(string $md, array $fixerReplacements): void + { + // First pass (may or may not change the Markdown). + $updated = $this->pipeline($md, $fixerReplacements) ?? $md; + + // Second pass: re-extract from the updated Markdown; fixer makes no further changes. + $blocks = iterator_to_array($this->extractor->extract($updated)); + self::assertNotEmpty($blocks); + + $block = $blocks[0]; + $phpFile = $this->writer->build('docs/test.md', $block['line'], $block['body']); + + self::assertNull( + $this->syncer->sync($phpFile, $updated), + 'A second sync after no fixer changes must return null', + ); + } + + /** + * @return iterable}> + */ + public static function provideIdempotencyCases(): iterable + { + yield 'plain snippet, no change' => ["text\n\n```php\n\$x = 1;\n```\n", []]; + yield 'plain snippet, spacing fixed' => ["text\n\n```php\n\$x=1;\n```\n", ['$x=1;' => '$x = 1;']]; + yield ' ["text\n\n```php\n ["text\n\n```php\n '$x = 1;']]; + yield ' ["text\n\n```php\n ["text\n\n```php\n '$x = 1;']]; + yield 'indented, no change' => ["!!! note\n\n ```php\n \$x = 1;\n ```\n", []]; + yield 'indented, spacing fixed' => ["!!! note\n\n ```php\n \$x=1;\n ```\n", ['$x=1;' => '$x = 1;']]; + } + + // ------------------------------------------------------------------------- + // Multiple blocks in the same Markdown file + // ------------------------------------------------------------------------- + + public function testAllBlocksUpdatedInMultiBlockFile(): void + { + $md = implode("\n", [ + 'intro', + '', + '```php', + '$a=1;', + '```', + '', + 'middle', + '', + '```php', + '$b=2;', + '```', + '', + ]); + + $result = $this->pipelineAll($md, ['$a=1;' => '$a = 1;', '$b=2;' => '$b = 2;']); + + self::assertStringContainsString('$a = 1;', $result); + self::assertStringContainsString('$b = 2;', $result); + } + + public function testLaterBlockCorrectAfterEarlierBlockAddsLines(): void + { + // First block gains a line (blank line restored between pipelineAll($md, ['$a=1;' => '$a = 1;', '$b=2;' => '$b = 2;']); + + self::assertStringContainsString('$a = 1;', $result); + // Second block must still be in its own php fence. + self::assertMatchesRegularExpression('/```php\n\$b = 2;\n```/', $result); + } + + public function testMultiBlockIdempotent(): void + { + $md = implode("\n", [ + '```php', + '$a=1;', + '```', + '', + '```php', + '$b=2;', + '```', + '', + ]); + + // First pass with fixer changes. + $updated = $this->pipelineAll($md, ['$a=1;' => '$a = 1;', '$b=2;' => '$b = 2;']); + + // Second pass: no fixer changes — everything should stay the same. + $blocks = iterator_to_array($this->extractor->extract($updated)); + $items = array_map( + fn (array $block): array => [ + 'line' => $block['line'], + 'phpFile' => $this->writer->build('docs/test.md', $block['line'], $block['body']), + ], + $blocks, + ); + usort($items, static fn (array $a, array $b): int => $b['line'] <=> $a['line']); + + foreach ($items as ['phpFile' => $phpFile]) { + self::assertNull( + $this->syncer->sync($phpFile, $updated), + 'No change expected on second pass', + ); + } + } + + // ------------------------------------------------------------------------- + // Surrounding Markdown content is never modified + // ------------------------------------------------------------------------- + + public function testSurroundingMarkdownIsUntouched(): void + { + $md = "# Heading\n\nSome prose.\n\n```php\n\$x=1;\n```\n\nMore prose.\n\n> A blockquote.\n"; + $result = $this->pipeline($md, ['$x=1;' => '$x = 1;']); + + self::assertNotNull($result); + self::assertStringContainsString('# Heading', $result); + self::assertStringContainsString('Some prose.', $result); + self::assertStringContainsString('More prose.', $result); + self::assertStringContainsString('> A blockquote.', $result); + } + + public function testFenceLanguageTagIsPreserved(): void + { + $md = "```php\n\$x=1;\n```\n"; + $result = $this->pipeline($md, ['$x=1;' => '$x = 1;']); + + self::assertNotNull($result); + self::assertStringContainsString('```php', $result); + } + + public function testFenceWithHlLinesAnnotationIsPreserved(): void + { + $md = "```php hl_lines=\"1 2\"\n\$x=1;\n\$y=2;\n```\n"; + $result = $this->pipeline($md, ['$x=1;' => '$x = 1;', '$y=2;' => '$y = 2;']); + + self::assertNotNull($result); + self::assertStringContainsString('```php hl_lines="1 2"', $result); + } +} diff --git a/tests/InlineSamples/InlinePhpSyncer.php b/tests/InlineSamples/InlinePhpSyncer.php new file mode 100644 index 0000000000..aaa484409f --- /dev/null +++ b/tests/InlineSamples/InlinePhpSyncer.php @@ -0,0 +1,211 @@ + + * + * + * After php-cs-fixer has reformatted the file, this class maps the changes back: + * 1. Locates the "// Source:" comment to find the original line number. + * 2. Strips the header to recover the reformatted body. + * 3. Restores the $m[1], 'line' => (int) $m[2]]; + } + } + + return null; + } + + /** + * Applies changes from a reformatted _inline_php file back to its source Markdown content. + * + * @return string|null Updated Markdown content, or null if nothing changed or the source + * location cannot be mapped. + */ + public function sync(string $phpFileContent, string $mdContent): ?string + { + $location = $this->parseSourceLocation($phpFileContent); + if ($location === null) { + return null; + } + + $fixedBody = $this->extractBody($phpFileContent); + + return $this->applyToMarkdown($fixedBody, $location['line'], $mdContent); + } + + /** + * Extracts the snippet body from a _inline_php file by stripping the auto-generated header. + * + * Uses the "// (auto-generated ...)" line as the end-of-header anchor so that the + * body is located correctly even when a refactoring tool (e.g. Rector) removes the + * blank separator line between the header and the body. + * The $line) { + if (str_starts_with($line, '// (auto-generated by tools/extract-inline-php.php')) { + $autoGenIdx = $i; + break; + } + } + + if ($autoGenIdx === null) { + return ''; + } + + // Body starts right after the marker; skip one optional blank separator. + // The blank may be absent when a refactoring tool (e.g. Rector) collapses it. + $cursor = $autoGenIdx + 1; + if (isset($lines[$cursor]) && $lines[$cursor] === '') { + ++$cursor; + } + + $bodyLines = array_slice($lines, $cursor); + + // cs-fixer ensures a single trailing newline; drop the resulting empty last element. + if (end($bodyLines) === '') { + array_pop($bodyLines); + } + + return implode("\n", $bodyLines); + } + + /** + * Replaces the body of the fenced code block at $bodyLine in $mdContent with $fixedBody. + * + * @param string $fixedBody Reformatted body as stored in the _inline_php file: + * without the = count($mdLines)) { + return null; + } + + // Detect admonition indentation from the opening fence line. + preg_match('/^(?P *)```/', $mdLines[$fenceIdx], $indentMatch); + $indent = $indentMatch['indent'] ?? ''; + + // Locate the closing fence (same indentation prefix + ```). + $closingFence = $indent . '```'; + $closingIdx = null; + for ($i = $bodyStartIdx; $i < count($mdLines); ++$i) { + if ($mdLines[$i] === $closingFence) { + $closingIdx = $i; + break; + } + } + + if ($closingIdx === null) { + return null; + } + + $originalBodyLines = array_slice($mdLines, $bodyStartIdx, $closingIdx - $bodyStartIdx); + + // Detect whether the original snippet opened with $line !== '' ? $indent . $line : $line, + $fixedBodyLines, + ); + $fixedBody = implode("\n", $fixedBodyLines); + } + + if (implode("\n", $originalBodyLines) === $fixedBody) { + return null; + } + + array_splice($mdLines, $bodyStartIdx, $closingIdx - $bodyStartIdx, $fixedBodyLines); + + return implode("\n", $mdLines); + } +} diff --git a/tests/InlineSamples/InlinePhpSyncerTest.php b/tests/InlineSamples/InlinePhpSyncerTest.php new file mode 100644 index 0000000000..7013707d61 --- /dev/null +++ b/tests/InlineSamples/InlinePhpSyncerTest.php @@ -0,0 +1,458 @@ +syncer = new InlinePhpSyncer(); + $this->writer = new InlinePhpWriter(); + } + + // ------------------------------------------------------------------------- + // Helpers + // ------------------------------------------------------------------------- + + /** + * Delegates to InlinePhpWriter::build() — the production class — so syncer tests + * always use the canonical file format. + */ + private function buildPhpFile(string $sourcePath, int $bodyLine, string $mdBody): string + { + return $this->writer->build($sourcePath, $bodyLine, $mdBody); + } + + /** + * Returns the 1-based line number of the first body line for the first fenced PHP block + * found in $md, using MarkdownExtractor. + */ + private static function bodyLineOf(string $md): int + { + $extractor = new MarkdownExtractor('php'); + $blocks = iterator_to_array($extractor->extract($md)); + self::assertNotEmpty($blocks, 'No PHP blocks found in Markdown'); + + return $blocks[0]['line']; + } + + // ------------------------------------------------------------------------- + // parseSourceLocation + // ------------------------------------------------------------------------- + + public function testParseSourceLocationReturnsNullWhenCommentMissing(): void + { + $content = "syncer->parseSourceLocation($content)); + } + + public function testParseSourceLocationExtractsPathAndLine(): void + { + $content = $this->buildPhpFile('docs/api/example.md', 42, '$x = 1;'); + $location = $this->syncer->parseSourceLocation($content); + + self::assertNotNull($location); + self::assertSame('docs/api/example.md', $location['path']); + self::assertSame(42, $location['line']); + } + + public function testParseSourceLocationToleratesDeclarationInsertedByFixer(): void + { + // php-cs-fixer may insert declare(strict_types=1) before the source comment. + $content = "syncer->parseSourceLocation($content); + + self::assertNotNull($location); + self::assertSame('docs/foo.md', $location['path']); + self::assertSame(7, $location['line']); + } + + // ------------------------------------------------------------------------- + // sync — no change cases + // ------------------------------------------------------------------------- + + public function testSyncReturnsNullForMissingSourceComment(): void + { + $md = "text\n\n```php\n\$x = 1;\n```\n"; + $phpFile = "syncer->sync($phpFile, $md)); + } + + public function testSyncReturnsNullWhenBodyIsUnchanged(): void + { + $md = "text\n\n```php\n\$x = 1;\n```\n"; + $bodyLine = self::bodyLineOf($md); + $phpFile = $this->buildPhpFile('docs/test.md', $bodyLine, '$x = 1;'); + + self::assertNull($this->syncer->sync($phpFile, $md)); + } + + public function testSyncReturnsNullWhenPhpTagSnippetIsUnchanged(): void + { + $md = "text\n\n```php\nbuildPhpFile('docs/test.md', $bodyLine, "syncer->sync($phpFile, $md)); + } + + public function testSyncReturnsNullWhenBlankLineSnippetIsUnchanged(): void + { + // The blank line after buildPhpFile('docs/test.md', $bodyLine, "syncer->sync($phpFile, $md)); + } + + public function testSyncReturnsNullWhenDeclareSnippetIsUnchanged(): void + { + // Canonical form has a blank line between buildPhpFile('docs/test.md', $bodyLine, "syncer->sync($phpFile, $md)); + } + + // ------------------------------------------------------------------------- + // sync — body line out of range + // ------------------------------------------------------------------------- + + public function testSyncReturnsNullForBodyLineOutOfRange(): void + { + $md = "one line\n"; + // Line 999 does not exist in this tiny Markdown. + $phpFile = $this->buildPhpFile('docs/test.md', 999, '$x = 1;'); + + self::assertNull($this->syncer->sync($phpFile, $md)); + } + + // ------------------------------------------------------------------------- + // sync — simple code changes + // ------------------------------------------------------------------------- + + public function testSyncAppliesSimpleCodeChange(): void + { + $md = "text\n\n```php\n\$x=1;\n```\n"; + $bodyLine = self::bodyLineOf($md); + // Simulate cs-fixer adding spaces around = + $phpFile = $this->buildPhpFile('docs/test.md', $bodyLine, '$x = 1;'); + + $result = $this->syncer->sync($phpFile, $md); + + self::assertNotNull($result); + self::assertStringContainsString('$x = 1;', $result); + // Surrounding Markdown structure is preserved + self::assertStringContainsString('text', $result); + self::assertStringContainsString('```php', $result); + } + + public function testSyncAppliesMultiLineCodeChange(): void + { + $md = "```php\n\$a=1;\n\$b=2;\n```\n"; + $bodyLine = self::bodyLineOf($md); + $phpFile = $this->buildPhpFile('docs/test.md', $bodyLine, "\$a = 1;\n\$b = 2;"); + + $result = $this->syncer->sync($phpFile, $md); + + self::assertNotNull($result); + self::assertStringContainsString("\$a = 1;\n\$b = 2;", $result); + } + + public function testSyncWorksWhenBlankSeparatorRemovedByRefactoringTool(): void + { + // Rector (and similar tools) may remove the blank line between the auto-generated + // header and the body. The syncer must not produce an empty body in that case. + $md = "```php\n\$x = 1;\n```\n"; + $bodyLine = self::bodyLineOf($md); + + // Build a normal file then strip the blank separator to simulate Rector's behaviour. + $normalFile = $this->buildPhpFile('docs/test.md', $bodyLine, '$x = 1;'); + $fileWithoutBlank = str_replace( + "// (auto-generated by tools/extract-inline-php.php — do not edit)\n\n", + "// (auto-generated by tools/extract-inline-php.php — do not edit)\n", + $normalFile, + ); + + // A refactoring tool also changed the body. + $fileWithChange = str_replace('$x = 1;', '$x = 2;', $fileWithoutBlank); + + $result = $this->syncer->sync($fileWithChange, $md); + + self::assertNotNull($result); + self::assertStringContainsString('$x = 2;', $result); + } + + // ------------------------------------------------------------------------- + // sync — buildPhpFile('docs/test.md', $bodyLine, "syncer->sync($phpFile, $md); + + self::assertNotNull($result); + self::assertStringContainsString("buildPhpFile('docs/test.md', $bodyLine, '$x = 1;'); + + $result = $this->syncer->sync($phpFile, $md); + + self::assertNotNull($result); + self::assertStringNotContainsString('buildPhpFile('docs/test.md', $bodyLine, "syncer->sync($fixedPhpFile, $md); + + self::assertNotNull($result); + self::assertStringContainsString("buildPhpFile('docs/test.md', $bodyLine, "syncer->sync($fixedPhpFile, $md); + + self::assertNotNull($result); + // The fixed body must come immediately after buildPhpFile('docs/test.md', $bodyLine, '$x = 1;'); + + $result = $this->syncer->sync($phpFile, $md); + + self::assertNotNull($result); + // The 4-space indent must be re-applied to the body line. + self::assertStringContainsString(' $x = 1;', $result); + } + + public function testSyncHandlesIndentedBlockWithPhpTagAndBlankLine(): void + { + $md = "!!! note\n\n ```php\n buildPhpFile('docs/test.md', $bodyLine, "syncer->sync($fixedPhpFile, $md); + + self::assertNotNull($result); + // Both the indent and the blank line must be preserved. + self::assertStringContainsString(" $replacements Simulated cs-fixer changes: old => new. + */ + #[DataProvider('provideRoundtripCases')] + public function testRoundtripAppliesChangesAndIsIdempotent( + string $md, + array $replacements, + string $expectedSnippet + ): void { + $extractor = new MarkdownExtractor('php'); + + // --- First pass: extract, simulate fix, sync --- + $blocks = iterator_to_array($extractor->extract($md)); + self::assertNotEmpty($blocks); + + $block = $blocks[0]; + $phpFile = $this->buildPhpFile('docs/test.md', $block['line'], $block['body']); + + $fixedPhpFile = strtr($phpFile, $replacements); + $hasChange = $fixedPhpFile !== $phpFile; + + $updatedMd = $this->syncer->sync($fixedPhpFile, $md); + + if (!$hasChange) { + self::assertNull($updatedMd, 'No change by fixer; sync must return null'); + + return; + } + + self::assertNotNull($updatedMd); + self::assertStringContainsString($expectedSnippet, $updatedMd); + + // --- Second pass: idempotency check --- + // Re-extract from the updated Markdown; cs-fixer produces no further changes this time. + $blocks2 = iterator_to_array($extractor->extract($updatedMd)); + self::assertNotEmpty($blocks2); + + $block2 = $blocks2[0]; + $phpFile2 = $this->buildPhpFile('docs/test.md', $block2['line'], $block2['body']); + + self::assertNull( + $this->syncer->sync($phpFile2, $updatedMd), + 'Second sync on an already-updated Markdown must return null (idempotent)', + ); + } + + /** + * @return iterable, string}> + */ + public static function provideRoundtripCases(): iterable + { + yield 'plain snippet, spacing fix' => [ + "text\n\n```php\n\$x=1;\n```\n", + ['$x=1;' => '$x = 1;'], + '$x = 1;', + ]; + + yield 'snippet with [ + "text\n\n```php\n '$x = 1;'], + " [ + "text\n\n```php\n '$x = 1;'], + " [ + "text\n\n```php\n\$x = 1;\n```\n", + [], // no replacements + '$x = 1;', + ]; + + yield 'indented snippet, spacing fix' => [ + "!!! note\n\n ```php\n \$x=1;\n ```\n", + ['$x=1;' => '$x = 1;'], + ' $x = 1;', + ]; + + yield 'multiline snippet, import ordering' => [ + "```php\n 'use A\\Bar;' . "\n" . 'use B\\Foo;'], + "use A\\Bar;\nuse B\\Foo;", + ]; + + yield 'snippet with declare(strict_types=1), spacing fix' => [ + "text\n\n```php\n '$x = 1;'], + "extract($md)); + self::assertCount(2, $blocks); + + [$blockA, $blockB] = $blocks; + + $phpFileA = $this->buildPhpFile('docs/test.md', $blockA['line'], $blockA['body']); + // Simulate cs-fixer removing the blank line after buildPhpFile('docs/test.md', $blockB['line'], $blockB['body']); + $fixedPhpFileB = str_replace('$b=2;', '$b = 2;', $phpFileB); + + // Apply block A first (it changes line count), then block B. + // Block B must still land in the right place. + $md1 = $this->syncer->sync($fixedPhpFileA, $md) ?? $md; + $md2 = $this->syncer->sync($fixedPhpFileB, $md1) ?? $md1; + + self::assertStringContainsString('$a=99;', $md2); + self::assertStringContainsString('$b = 2;', $md2); + // The second block must still be in a php fence + self::assertMatchesRegularExpression('/```php\n\$b = 2;\n```/', $md2); + } +} diff --git a/tests/InlineSamples/InlinePhpWriter.php b/tests/InlineSamples/InlinePhpWriter.php new file mode 100644 index 0000000000..af3cf40c87 --- /dev/null +++ b/tests/InlineSamples/InlinePhpWriter.php @@ -0,0 +1,69 @@ + + * + * + * Important: the writer = new InlinePhpWriter(); + } + + // ------------------------------------------------------------------------- + // Header structure + // ------------------------------------------------------------------------- + + public function testFileAlwaysStartsWithPhpOpeningTag(): void + { + $content = $this->writer->build('docs/example.md', 5, '$x = 1;'); + self::assertStringStartsWith("writer->build('docs/example.md', 5, '$x = 1;'); + self::assertStringStartsWith("writer->build('docs/api/example.md', 42, '$x = 1;'); + self::assertStringContainsString('// Source: docs/api/example.md:42', $content); + } + + public function testAutoGeneratedCommentIsPresent(): void + { + $content = $this->writer->build('docs/example.md', 1, '$x = 1;'); + self::assertStringContainsString( + '// (auto-generated by tools/extract-inline-php.php — do not edit)', + $content, + ); + } + + public function testBlankLineSeparatesHeaderFromBody(): void + { + $content = $this->writer->build('docs/example.md', 1, '$x = 1;'); + // The blank line sits between the auto-generated comment and the body. + self::assertStringContainsString( + "// (auto-generated by tools/extract-inline-php.php — do not edit)\n\n\$x = 1;", + $content, + ); + } + + public function testFileEndsWithSingleTrailingNewline(): void + { + $content = $this->writer->build('docs/example.md', 1, '$x = 1;'); + self::assertStringEndsWith("\$x = 1;\n", $content); + // Not two newlines + self::assertStringNotContainsString("\$x = 1;\n\n", $content); + } + + // ------------------------------------------------------------------------- + // Body without writer->build('docs/example.md', 10, '$foo = bar();'); + self::assertStringContainsString('$foo = bar();', $content); + } + + public function testMultiLineBodyIsPreserved(): void + { + $body = "\$a = 1;\n\$b = 2;\nreturn \$a + \$b;"; + $content = $this->writer->build('docs/example.md', 5, $body); + self::assertStringContainsString($body, $content); + } + + // ------------------------------------------------------------------------- + // Body with writer->build('docs/example.md', 3, "writer->build('docs/example.md', 4, "writer->build('docs/example.md', 7, " writer->build('docs/example.md', 3, $body); + // Namespace must be in the file body (after the header blank line). + self::assertStringContainsString('namespace App\\Foo;', $content); + self::assertSame(1, substr_count($content, 'writer->build($sourcePath, $line, $body)); + } + + /** + * @return iterable + */ + public static function provideExactContent(): iterable + { + yield 'plain body' => [ + 'docs/api/example.md', 5, '$x = 1;', '$x = 1;', + ]; + + yield 'multiline plain body' => [ + 'docs/api/example.md', 10, "\$a = 1;\n\$b = 2;", "\$a = 1;\n\$b = 2;", + ]; + + yield 'body with php tag, no blank line' => [ + 'docs/foo.md', 3, " [ + 'docs/foo.md', 4, " [ + 'docs/bar.md', 7, + " [ + 'docs/foo.md', 10, + " [ + 'docs/foo.md', 5, + "declare(strict_types=1);\n\$x = 1;", + '$x = 1;', + ]; + } +} diff --git a/tests/InlineSamples/MarkdownExtractor.php b/tests/InlineSamples/MarkdownExtractor.php new file mode 100644 index 0000000000..4f0bcdfbc9 --- /dev/null +++ b/tests/InlineSamples/MarkdownExtractor.php @@ -0,0 +1,95 @@ + + * - ``` + * - ``` hl_lines="..." + * - Blocks indented inside admonitions (4-space prefix) + * + * Blocks containing [[= include_file(...) =]], [[= include_code(...) =]], or --8<-- are skipped + * because they reference code_samples/ files that are validated separately. + * + * Blocks whose opening fence contains the marker "skip-validation" are also + * skipped, e.g.: ```php {skip-validation} + * The marker uses pymdownx superfences' attribute injection syntax ({...}) so that + * it is silently ignored during rendering (bare hyphenated tokens break superfences). + */ +final class MarkdownExtractor +{ + /** + * Pattern components: + * - ^( *) captures optional leading indentation (admonitions indent by 4 spaces) + * - ```\s* matches the opening fence with optional space before language tag + * - (?P[^\n]*) captures the rest of the opening line (hl_lines, custom markers…) + * - (.*?) captures the block body (non-greedy) + * - \n\1``` requires the closing fence to match the same indentation + */ + private string $fencePattern; + + private const string SKIP_PATTERN = '/include_(?:file|code)\s*\(|--8<--/'; + + private const string SKIP_VALIDATION_MARKER = 'skip-validation'; + + public function __construct(string $language) + { + $this->fencePattern = '/^(?P *)```\s*' . preg_quote($language, '/') . '(?P[^\n]*)\n(?P.*?)\n(?P=indent)```/ms'; + } + + /** + * @return iterable + */ + public function extract(string $content): iterable + { + if (!preg_match_all($this->fencePattern, $content, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) { + return; + } + + foreach ($matches as $match) { + $info = $match['info'][0]; + $body = $match['body'][0]; + $offset = $match['body'][1]; + + if (str_contains($info, self::SKIP_VALIDATION_MARKER)) { + continue; + } + + if (preg_match(self::SKIP_PATTERN, $body)) { + continue; + } + + $indent = $match['indent'][0]; + if ($indent !== '') { + $body = $this->stripIndentation($body, strlen($indent)); + } + + $line = substr_count(substr($content, 0, $offset), "\n") + 1; + + yield ['body' => $body, 'line' => $line]; + } + } + + private function stripIndentation(string $body, int $spaces): string + { + $prefix = str_repeat(' ', $spaces); + $lines = explode("\n", $body); + $stripped = array_map( + static fn (string $line): string => str_starts_with($line, $prefix) + ? substr($line, $spaces) + : $line, + $lines + ); + + return implode("\n", $stripped); + } +} diff --git a/tests/InlineSamples/MarkdownExtractorTest.php b/tests/InlineSamples/MarkdownExtractorTest.php new file mode 100644 index 0000000000..7cf6e312aa --- /dev/null +++ b/tests/InlineSamples/MarkdownExtractorTest.php @@ -0,0 +1,224 @@ +extractor = new MarkdownExtractor('yaml'); + } + + public function testExtractsNothing(): void + { + self::assertEmpty(iterator_to_array($this->extractor->extract('No code blocks here.'))); + self::assertEmpty(iterator_to_array($this->extractor->extract(''))); + } + + public function testIgnoresNonYamlFences(): void + { + $content = <<<'MD' + ```php + $x = 1; + ``` + + ```json + {"key": "value"} + ``` + MD; + + self::assertEmpty(iterator_to_array($this->extractor->extract($content))); + } + + public function testExtractsSingleBlock(): void + { + $content = <<<'MD' + Some text. + + ```yaml + foo: bar + ``` + + More text. + MD; + + $blocks = iterator_to_array($this->extractor->extract($content)); + + self::assertCount(1, $blocks); + self::assertSame('foo: bar', $blocks[0]['body']); + } + + public function testExtractsMultipleBlocks(): void + { + $content = <<<'MD' + ```yaml + first: 1 + ``` + + ```yaml + second: 2 + ``` + MD; + + $blocks = iterator_to_array($this->extractor->extract($content)); + + self::assertCount(2, $blocks); + self::assertSame('first: 1', $blocks[0]['body']); + self::assertSame('second: 2', $blocks[1]['body']); + } + + public function testReportsCorrectLineNumber(): void + { + $content = "line1\nline2\nline3\n```yaml\nfoo: bar\n```\n"; + + $blocks = iterator_to_array($this->extractor->extract($content)); + + self::assertCount(1, $blocks); + // The body starts on line 5 (after 4 preceding newlines inside the fence open) + self::assertSame(5, $blocks[0]['line']); + } + + public function testAcceptsSpaceBeforeLanguageTag(): void + { + $content = "``` yaml\nfoo: bar\n```\n"; + + $blocks = iterator_to_array($this->extractor->extract($content)); + + self::assertCount(1, $blocks); + self::assertSame('foo: bar', $blocks[0]['body']); + } + + public function testAcceptsTrailingAnnotations(): void + { + $content = "```yaml hl_lines=\"1 2\"\nfoo: bar\n```\n"; + + $blocks = iterator_to_array($this->extractor->extract($content)); + + self::assertCount(1, $blocks); + self::assertSame('foo: bar', $blocks[0]['body']); + } + + public function testStripsAdmonitionIndentation(): void + { + $content = <<<'MD' + !!! note + + ```yaml + foo: bar + baz: qux + ``` + MD; + + $blocks = iterator_to_array($this->extractor->extract($content)); + + self::assertCount(1, $blocks); + self::assertSame("foo: bar\nbaz: qux", $blocks[0]['body']); + } + + public function testSkipsBlocksWithIncludeFile(): void + { + $content = <<<'MD' + ```yaml + [[= include_file('some/file.yaml') =]] + ``` + MD; + + self::assertEmpty(iterator_to_array($this->extractor->extract($content))); + } + + public function testSkipsBlocksWithIncludeCode(): void + { + $content = <<<'MD' + ```yaml + [[= include_code('some/file.yaml', 1, 10) =]] + ``` + MD; + + self::assertEmpty(iterator_to_array($this->extractor->extract($content))); + } + + public function testSkipsBlocksWithSnippetMarker(): void + { + $content = <<<'MD' + ```yaml + --8<-- + some/file.yaml + --8<-- + ``` + MD; + + self::assertEmpty(iterator_to_array($this->extractor->extract($content))); + } + + public function testSkipsOnlyMatchingBlocksWhenMixed(): void + { + $content = <<<'MD' + ```yaml + [[= include_file('foo.yaml') =]] + ``` + + ```yaml + [[= include_code('bar.yaml', 1, 5) =]] + ``` + + ```yaml + real: config + ``` + MD; + + $blocks = iterator_to_array($this->extractor->extract($content)); + + self::assertCount(1, $blocks); + self::assertSame('real: config', $blocks[0]['body']); + } + + /** + * @param array $expected + */ + #[DataProvider('provideMultilineBlocks')] + public function testExtractsMultilineBody(string $content, array $expected): void + { + $blocks = iterator_to_array($this->extractor->extract($content)); + + self::assertCount(count($expected), $blocks); + foreach ($expected as $i => $exp) { + self::assertSame($exp['body'], $blocks[$i]['body'], "body at index $i"); + self::assertSame($exp['line'], $blocks[$i]['line'], "line at index $i"); + } + } + + /** + * @return iterable}> + */ + public static function provideMultilineBlocks(): iterable + { + yield 'nested mapping' => [ + "```yaml\nparent:\n child: value\n```\n", + [['body' => "parent:\n child: value", 'line' => 2]], + ]; + + yield 'sequence' => [ + "```yaml\nlist:\n - a\n - b\n```\n", + [['body' => "list:\n - a\n - b", 'line' => 2]], + ]; + + yield 'two blocks with correct lines' => [ + "```yaml\nfoo: 1\n```\n\nsome text\n\n```yaml\nbar: 2\n```\n", + [ + ['body' => 'foo: 1', 'line' => 2], + ['body' => 'bar: 2', 'line' => 8], + ], + ]; + } +} diff --git a/tests/ValidationBaseline.php b/tests/ValidationBaseline.php new file mode 100644 index 0000000000..223669e8a1 --- /dev/null +++ b/tests/ValidationBaseline.php @@ -0,0 +1,75 @@ +|null */ + private ?array $entries = null; + + public function __construct( + private readonly string $baselineFile, + private readonly string $repoRoot, + ) { + } + + public function isInBaseline(string $relativePath, ?string $bodyHash, string $errorMessage): bool + { + foreach ($this->getEntries() as $entry) { + $entryPath = $entry['path'] ?? ''; + + // Path: exact match or trailing-suffix match (allows glob-like partial paths) + if ($relativePath !== $entryPath && !str_ends_with($relativePath, ltrim($entryPath, '/'))) { + continue; + } + + // Hash (optional): must match exactly when provided; line is ignored for matching + if (isset($entry['hash']) && $bodyHash !== null && $entry['hash'] !== $bodyHash) { + continue; + } + + // Message (optional): treated as a regex pattern + if (isset($entry['message']) && !preg_match($entry['message'], $errorMessage)) { + continue; + } + + return true; + } + + return false; + } + + /** + * @return list + */ + private function getEntries(): array + { + if ($this->entries !== null) { + return $this->entries; + } + + if (!file_exists($this->baselineFile)) { + return $this->entries = []; + } + + $parsed = \Symfony\Component\Yaml\Yaml::parseFile($this->baselineFile); + + return $this->entries = $parsed['ignoreErrors'] ?? []; + } +} diff --git a/tests/Yaml/CodeSample.php b/tests/Yaml/CodeSample.php new file mode 100644 index 0000000000..3d582da9b7 --- /dev/null +++ b/tests/Yaml/CodeSample.php @@ -0,0 +1,16 @@ +bodyHash = hash('sha256', $body); + } +} diff --git a/tests/Yaml/YamlSamplesProvider.php b/tests/Yaml/YamlSamplesProvider.php new file mode 100644 index 0000000000..0624536097 --- /dev/null +++ b/tests/Yaml/YamlSamplesProvider.php @@ -0,0 +1,96 @@ + + */ + public function getCodeSampleYaml(): iterable + { + yield from $this->iterateCodeSampleYaml(); + yield from $this->iterateMarkdownYamlBlocks(); + } + + /** + * Yields every .yaml file found recursively under code_samples/. + * + * @return iterable + */ + private function iterateCodeSampleYaml(): iterable + { + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator(self::CODE_SAMPLES_DIR, RecursiveDirectoryIterator::SKIP_DOTS) + ); + + /** @var \SplFileInfo $file */ + foreach ($iterator as $file) { + if (!$file->isFile() || $file->getExtension() !== 'yaml') { + continue; + } + + $body = file_get_contents($file->getRealPath()); + + if ($body === false) { + continue; + } + + yield new CodeSample($file->getRealPath(), 0, $body); + } + } + + /** + * Yields every fenced YAML block found in .md files under docs/. + * + * @return iterable + */ + private function iterateMarkdownYamlBlocks(): iterable + { + $extractor = new MarkdownExtractor('yaml'); + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator(self::DOCS_DIR, RecursiveDirectoryIterator::SKIP_DOTS) + ); + + /** @var \SplFileInfo $file */ + foreach ($iterator as $file) { + if (!$file->isFile() || $file->getExtension() !== 'md') { + continue; + } + + $path = $file->getRealPath(); + $content = file_get_contents($path); + + if ($content === false) { + continue; + } + + foreach ($extractor->extract($content) as $block) { + yield new CodeSample($path, $block['line'], $block['body']); + } + } + } +} diff --git a/tests/Yaml/YamlTest.php b/tests/Yaml/YamlTest.php new file mode 100644 index 0000000000..54b781bca8 --- /dev/null +++ b/tests/Yaml/YamlTest.php @@ -0,0 +1,170 @@ +isInBaseline($filePath, $bodyHash, $e->getMessage())) { + self::markTestSkipped(sprintf( + 'Known baseline issue in %s at line %d: %s', + $filePath, + $line, + $e->getMessage(), + )); + } + + self::fail(sprintf( + 'YAML parse error in %s at line %d [hash:%s]: %s', + $filePath, + $line, + $bodyHash, + $e->getMessage(), + )); + } + + $this->addToAssertionCount(1); + } + + /** + * @param int $line Starting line of the config block (0 for standalone YAML files). + */ + #[DataProvider('provideBundleConfigs')] + public function testBundleConfigurationIsValid( + string $extensionName, + mixed $config, + string $filePath, + int $line, + string $bodyHash + ): void { + $configuration = self::configurationProvider()->createConfiguration($extensionName); + $processor = new Processor(); + + $config = self::configurationProvider()->resolveParameters(is_array($config) ? $config : []); + + try { + $processor->processConfiguration($configuration, [$config]); + } catch (\Exception $e) { + if (self::baseline()->isInBaseline($filePath, $bodyHash, $e->getMessage())) { + self::markTestSkipped(sprintf( + 'Known baseline issue for "%s" in %s:%d: %s', + $extensionName, + $filePath, + $line, + $e->getMessage(), + )); + } + + self::fail(sprintf( + 'Invalid configuration for "%s" in %s:%d [hash:%s] — %s', + $extensionName, + $filePath, + $line, + $bodyHash, + $e->getMessage(), + )); + } + + $this->addToAssertionCount(1); + } + + /** + * Yields all standalone YAML files from code_samples/ plus every fenced + * YAML block extracted from docs Markdown files. + * + * @return iterable + */ + public static function provideYamlSources(): iterable + { + foreach (self::samplesProvider()->getCodeSampleYaml() as $item) { + yield self::makeLabel($item->path, $item->line) => [$item->path, $item->line, $item->body, $item->bodyHash]; + } + } + + /** + * Yields one entry per (extension, config) pair found in YAML files and + * in fenced YAML blocks from docs Markdown files. + * + * @return iterable + */ + public static function provideBundleConfigs(): iterable + { + foreach (self::provideYamlSources() as [$filePath, $line, $body, $bodyHash]) { + $path = self::relativePath($filePath); + try { + $parsed = Yaml::parse($body, Yaml::PARSE_CUSTOM_TAGS); + } catch (\Throwable) { + continue; + } + + if (!is_array($parsed)) { + continue; + } + + foreach ($parsed as $extensionName => $config) { + if (!is_string($extensionName) || !self::configurationProvider()->hasExtension($extensionName)) { + continue; + } + + yield sprintf('%s (%s)', $extensionName, self::makeLabel($path, $line)) => [$extensionName, $config, $path, $line, $bodyHash]; + } + } + } + + private static function configurationProvider(): ConfigurationProvider + { + static $provider = null; + + return $provider ??= new ConfigurationProvider(); + } + + private static function samplesProvider(): YamlSamplesProvider + { + static $provider = null; + + return $provider ??= new YamlSamplesProvider(); + } + + private static function baseline(): ValidationBaseline + { + static $baseline = null; + + return $baseline ??= new ValidationBaseline(self::BASELINE_FILE, realpath(self::REPO_ROOT)); + } + + private static function makeLabel(string $absolutePath, int $lineNumber): string + { + return ltrim(str_replace(realpath(self::REPO_ROOT), '', $absolutePath), '/') . ':' . $lineNumber; + } + + private static function relativePath(string $absolutePath): string + { + return ltrim(str_replace(realpath(self::REPO_ROOT), '', $absolutePath), '/'); + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 0000000000..9374e6f3a2 --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,40 @@ +isDir() && $item->getFilename() === 'src') { + $loader->addPsr4('App\\', $item->getRealPath()); + } +} diff --git a/tests/generate-yaml-baseline.php b/tests/generate-yaml-baseline.php new file mode 100644 index 0000000000..6b092ba0e3 --- /dev/null +++ b/tests/generate-yaml-baseline.php @@ -0,0 +1,151 @@ +#!/usr/bin/env php +/dev/null', + escapeshellarg($phpunitBin), + escapeshellarg($tmpLog), +); + +passthru($cmd); + +if (!file_exists($tmpLog)) { + if ($previousBaseline !== null) { + file_put_contents($outFile, $previousBaseline); + } + fwrite(STDERR, "ERROR: PHPUnit did not produce a JUnit log file.\n"); + exit(1); +} + +$xml = simplexml_load_file($tmpLog); +unlink($tmpLog); + +if ($xml === false) { + fwrite(STDERR, "ERROR: Could not parse JUnit XML.\n"); + exit(1); +} + +$repoRoot = dirname(__DIR__); +$entries = []; + +// Collect all failures/errors at any nesting depth using XPath +/** @var \SimpleXMLElement[] $testcases */ +$testcases = $xml->xpath('//testcase[failure or error]') ?: []; + +foreach ($testcases as $testcase) { + $failure = $testcase->failure ?? $testcase->error ?? null; + if ($failure === null) { + continue; + } + + $message = (string) $failure; + // Extract file path and line from failure message + // Patterns: + // "Invalid configuration for "X" in path/to/file.yaml: error" + // "Invalid configuration for "X" in path/to/file.md:123 — error" + // "YAML parse error in path/to/file.md at line 123: error" + $path = null; + $line = null; + $bodyHash = null; + $errorMessage = null; + + if (preg_match('/Invalid configuration for "[^"]*" in ([^\n:]+?):(\d+) \[hash:([a-f0-9]+)\] — (.+)/s', $message, $m)) { + $path = trim($m[1]); + $line = (int) $m[2]; + $bodyHash = $m[3]; + $errorMessage = trim(explode("\n", $m[4])[0]); + } elseif (preg_match('/Invalid configuration for "[^"]*" in ([^\n:]+?): (.+)/s', $message, $m)) { + $path = trim($m[1]); + $errorMessage = trim(explode("\n", $m[2])[0]); + } elseif (preg_match('/YAML parse error in ([^\n]+?) at line (\d+) \[hash:([a-f0-9]+)\]: (.+)/s', $message, $m)) { + $path = trim($m[1]); + $line = (int) $m[2]; + $bodyHash = $m[3]; + $errorMessage = trim(explode("\n", $m[4])[0]); + } + + if ($path === null) { + continue; + } + + // Convert absolute path to relative + if (str_starts_with($path, $repoRoot)) { + $path = ltrim(substr($path, strlen($repoRoot)), '/'); + } + + $entry = ['path' => $path]; + if ($line !== null) { + $entry['line'] = $line; + } + if ($bodyHash !== null) { + $entry['hash'] = $bodyHash; + } + if ($errorMessage !== null) { + // Store as a regex: escape special chars, keep it readable + $entry['message'] = '~' . preg_quote($errorMessage, '~') . '~'; + } + + $key = $path . ':' . ($bodyHash ?? $line ?? ''); + $entries[$key] = $entry; +} + +ksort($entries); + +// Render as YAML manually (keep it readable without needing a YAML library) +$lines = []; +$lines[] = '# Auto-generated by `composer yaml-update-baseline`. Do not edit manually.'; +$lines[] = '# To suppress a failure: regenerate this file after confirming it is expected.'; +$lines[] = '# To fix a suppressed failure: fix the doc error and regenerate.'; +$lines[] = 'ignoreErrors:'; + +foreach ($entries as $entry) { + $lines[] = ' -'; + $lines[] = sprintf(' path: %s', $entry['path']); + if (isset($entry['line'])) { + $lines[] = sprintf(' line: %d', $entry['line']); + } + if (isset($entry['hash'])) { + $lines[] = sprintf(' hash: %s', $entry['hash']); + } + if (isset($entry['message'])) { + // Wrap message in single quotes, escaping internal single quotes + $msg = str_replace("'", "''", $entry['message']); + $lines[] = sprintf(" message: '%s'", $msg); + } +} + +$content = implode("\n", $lines) . "\n"; +$outFile = __DIR__ . '/yaml-validation-baseline.yaml'; +file_put_contents($outFile, $content); + +$count = count($entries); +echo "Baseline written to tests/yaml-validation-baseline.yaml ({$count} entries)\n"; +if ($count === 0) { + echo "No failures found — baseline is empty. All tests pass!\n"; +} diff --git a/tests/yaml-validation-baseline.yaml b/tests/yaml-validation-baseline.yaml new file mode 100644 index 0000000000..4146548509 --- /dev/null +++ b/tests/yaml-validation-baseline.yaml @@ -0,0 +1,399 @@ +# Auto-generated by `composer yaml-update-baseline`. Do not edit manually. +# To suppress a failure: regenerate this file after confirming it is expected. +# To fix a suppressed failure: fix the doc error and regenerate. +ignoreErrors: + - + path: code_samples/forms/custom_form_attribute/config/custom_services.yaml + line: 0 + hash: 9d00873c2b34dc269f7846d4f4462a2a9d0308566818ca845c802d0778d91469 + message: '~Unable to parse at line 1 \(near " App\\FormBuilder\\FieldType\\Field\\Mapper\\CheckboxWithRichtextDescriptionFieldMapper\:"\)\.~' + - + path: code_samples/mcp/mcp.matrix.yaml + line: 0 + hash: 18f640cd008ed9f1761db531c1426cd6707d316c5f9727f540187959ca57a514 + message: '~The value "\" is not allowed for path "ibexa\.repositories\.\\.mcp\.\\.session\.type"\. Permissible values\: "file", "psr16"\.~' + - + path: code_samples/workflow/custom_workflow/config/packages/workflows.yaml + line: 0 + hash: 48b8c1ee7a1f481c5c83d1d90ed43723cc8dd59fac24adc798f0492d7fac7a89 + message: '~The child config "stages" under "ibexa\.system\.default\.workflows\.quick_review" must be configured\.~' + - + path: docs/administration/back_office/back_office_elements/extending_thumbnails.md + line: 108 + hash: 65a44481f05186cf38bb2efd4583c49faf2b58dc4c197d40a611cd8610a77d97 + message: '~Unable to parse at line 1 \(near " App\\Thumbnails\\FieldValueUrl\:"\)\.~' + - + path: docs/administration/back_office/configure_product_tour.md + line: 26 + hash: 4cfc5ac559eb8db38edb6c8a29872883a95886b61cdae2b343a5ebaf4a9bca8e + message: '~The value "\" is not allowed for path "ibexa\.system\.\\>\.product_tour\.\\.type"\. Permissible values\: "general", "targetable"\.~' + - + path: docs/cdp/cdp_data_customization.md + line: 29 + hash: bb2ecc0b96ca61cd004b9c1806e78d6afc3197a68acb723db7a52cfd5bdc89d6 + message: '~Unable to parse at line 1 \(near " App\\Export\\User\\DateOfBirthUserItemProcessor\:"\)\.~' + - + path: docs/commerce/checkout/customize_checkout.md + line: 130 + hash: fb889cba0ffc081e7d0b0387d32835ae8e5d3c033f26144cb4d54b3e121f428a + message: '~Invalid configuration for path "framework\.workflows\.workflows\.ibexa_checkout"\: "supports" or "support_strategy" should be configured\.~' + - + path: docs/commerce/order_management/configure_order_management.md + line: 51 + hash: 30a04aef21c825d6b59c938c2b5bb4078abd7156526a7f9f1b7b13203ff56ed7 + message: '~The child config "transitions" under "framework\.workflows\.workflows\.ibexa_order" must be configured\.~' + - + path: docs/commerce/payment/enable_paypal_payments.md + line: 40 + hash: bc714d63a541c63d24e2a882cc8c67b685fcee24feb0d80a327f02a4c3b0bef8 + message: '~Unrecognized option "payment_method" under "ibexa"\. Available options are "http_cache", "image_placeholder", "imagemagick", "locale_conversion", "orm", "repositories", "router", "siteaccess", "system", "ui", "url_alias", "url_wildcards"\.~' + - + path: docs/commerce/payment/enable_stripe_payments.md + line: 41 + hash: 09750e5c042fe1d6abc20d4088674195d78ca70ce113f8869818a76de1a8023a + message: '~Unrecognized option "payment_method" under "ibexa"\. Available options are "http_cache", "image_placeholder", "imagemagick", "locale_conversion", "orm", "repositories", "router", "siteaccess", "system", "ui", "url_alias", "url_wildcards"\.~' + - + path: docs/commerce/payment/payum_integration.md + line: 55 + hash: c3f14ff441a95545c360aaab308050a2629a81f07d76d4fb65133ab89a6ad30d + message: '~Unrecognized option "payment_method" under "ibexa"\. Available options are "http_cache", "image_placeholder", "imagemagick", "locale_conversion", "orm", "repositories", "router", "siteaccess", "system", "ui", "url_alias", "url_wildcards"\.~' + - + path: docs/commerce/transactional_emails/extend_transactional_emails.md + line: 17 + hash: f7073192f3b22201fe8d86bb71c76b4026f14efbfe6bb28ddbed657d93eca29c + message: '~The child config "transitions" under "framework\.workflows\.workflows\.ibexa_payment" must be configured\.~' + - + path: docs/content_management/collaborative_editing/configure_collaborative_editing.md + line: 48 + hash: 629d37dcc688c9b11daec8de8c601522830f3b2175ac6ac692db3f17b89a01d7 + message: '~The child config "firewalls" under "security" must be configured\.~' + - + path: docs/content_management/collaborative_editing/configure_collaborative_editing.md + line: 78 + hash: c6488fad354e039350fd0c18bdd0b6dc2a1ff7300dbae9151155490278b840a0 + message: '~Invalid type for path "ibexa\.repositories\.\\.collaboration\.participants\.auto_invite"\. Expected "bool", but got "string"\.~' + - + path: docs/content_management/data_migration/data_migration_actions.md + line: 163 + hash: 023288ce392e2e051ac32ea3525bdecebc301a860789c8d2128042885122bfa9 + message: '~Unable to parse at line 1 \(near " actions\:"\)\.~' + - + path: docs/content_management/data_migration/data_migration_actions.md + line: 106 + hash: 29c25d5ed7cc6b7c435b3d2b6f4e64946ea4f37a27b1e32330a205757a74e56e + message: '~Unable to parse at line 1 \(near " actions\:"\)\.~' + - + path: docs/content_management/data_migration/data_migration_actions.md + line: 142 + hash: 379c053c8d40a701b0931b2e753d1256ece028d3c2e96a86fad3c884d480a48f + message: '~Unable to parse at line 1 \(near " actions\:"\)\.~' + - + path: docs/content_management/data_migration/data_migration_actions.md + line: 79 + hash: 6ebbedc8bf843bdc28aa23e5604ad9795153e5abcf808839229b08a37386f7eb + message: '~Unable to parse at line 1 \(near " actions\:"\)\.~' + - + path: docs/content_management/data_migration/data_migration_actions.md + line: 186 + hash: 93777839119c361b8b3a2708d47240128ef27643dce015decc1bf4edf0e8cb8f + message: '~Unable to parse at line 1 \(near " actions\:"\)\.~' + - + path: docs/content_management/data_migration/data_migration_actions.md + line: 119 + hash: c730d746b624933585bd7f985fc773625750b8385a3755e7735d50e49e4964b2 + message: '~Unable to parse at line 1 \(near " actions\:"\)\.~' + - + path: docs/content_management/data_migration/data_migration_actions.md + line: 88 + hash: d330a24eee42024868c98fcffb2c446706570fea05d05ec3b7309297ba49e3b4 + message: '~Unable to parse at line 1 \(near " actions\:"\)\.~' + - + path: docs/content_management/data_migration/data_migration_actions.md + line: 99 + hash: e4d25af95785fe407cc135a608c778ff3232db0ce36e0bf5ce2039b249e29dc7 + message: '~Unable to parse at line 1 \(near " actions\:"\)\.~' + - + path: docs/content_management/data_migration/importing_data.md + line: 227 + hash: 5fff20465655d9e52a258e3c1b1347a62b0f558d9e733bb377c003d5021822eb + message: '~Unable to parse at line 1 \(near " \- fieldDefIdentifier\: show_children"\)\.~' + - + path: docs/content_management/data_migration/importing_data.md + line: 255 + hash: 7cec0a6d723dcb0d3d87904910e4870f05b885764116e447b8a4fe19025b8289 + message: '~Unable to parse at line 1 \(near " \- fieldDefIdentifier\: project_directory"\)\.~' + - + path: docs/content_management/data_migration/importing_data.md + line: 247 + hash: a08babaebc91ceb742a9a81a04be4d9e975291019794a0658bef1f99e62dccea + message: '~Unable to parse at line 1 \(near " \- fieldDefIdentifier\: some_field"\)\.~' + - + path: docs/content_management/data_migration/importing_data.md + line: 340 + hash: c94bdd7b27818ae0138b8c5bdba1ff33d77e25918609c1741f2c4d4236dcaff1 + message: '~Unable to parse at line 1 \(near " \- fieldDefIdentifier\: image"\)\.~' + - + path: docs/content_management/taxonomy/taxonomy.md + line: 195 + hash: 968846dbeb558b9eb914194845153634b45d8a993977bc321fc9df8e3d29d9cb + message: '~The child config "default_embedding_max_tokens" under "ibexa_taxonomy\.text_to_taxonomy" must be configured\: Maximum number of tokens sent when generating embeddings~' + - + path: docs/content_management/workflow/workflow.md + line: 135 + hash: 0fdf8c632c4f5abed2f8af4fa177bf8afd9b129a48ff1fb611923135b856f865 + message: '~The child config "matcher_value_templates" under "ibexa\.system\.default\.workflows_config" must be configured\: Matcher templates configuration\.~' + - + path: docs/customer_management/cp_page_builder.md + line: 35 + hash: 6915e3e4985cf6b8d99ae25c59ddf2f735fa927fdddb4b2a9e095475b86d02db + message: '~The child config "default_siteaccess" under "ibexa\.siteaccess" must be configured\: Name of the default siteaccess~' + - + path: docs/customer_management/cp_page_builder.md + line: 119 + hash: 833557b1406f91474d3420c809f8cf7ffc7ebefcf12aa37e66d31c291c73a2e6 + message: '~The child config "default_siteaccess" under "ibexa\.siteaccess" must be configured\: Name of the default siteaccess~' + - + path: docs/customer_management/cp_page_builder.md + line: 207 + hash: 98de256c0b149da15bea944ff56da3dad8bf968f5aad2d2882855d8844541dc1 + message: '~The child config "list" under "ibexa\.siteaccess" must be configured\: Available SiteAccess list~' + - + path: docs/discounts/extend_discounts.md + line: 227 + hash: 06089de0d522e5dc8e3a4973eeba57034d001867540768e1805211242768f23a + message: '~Unable to parse at line 1 \(near " App\\Discounts\\RecentDiscountPrioritizationStrategy\:"\)\.~' + - + path: docs/discounts/extend_discounts.md + line: 62 + hash: 24653d7f59ac0fca6cb86161ebf94516d356563f36bc69a65d1e210a13cba6e2 + message: '~Unable to parse at line 1 \(near " App\\Discounts\\ExpressionProvider\\CurrentUserRegistrationDateResolver\:"\)\.~' + - + path: docs/discounts/extend_discounts.md + line: 185 + hash: 415de44b6fd825b157660aec16d415842cb0dadb636b1c0014ba167fc1115973 + message: '~Unable to parse at line 1 \(near " App\\Discounts\\Rule\\PurchasingPowerParityRuleFactory\:"\)\.~' + - + path: docs/discounts/extend_discounts.md + line: 209 + hash: 8459adf86ffd3f1fe5cccf1c12d887d783c6b6e85be7dfc77ea6c3229ba9569e + message: '~Unable to parse at line 1 \(near " App\\Discounts\\Rule\\PurchaseParityValueFormatter\:"\)\.~' + - + path: docs/discounts/extend_discounts.md + line: 80 + hash: 9bf9dc0f20ec840e7c362adf00680d1e67d66f9a1fe6788d32950b3dd250feae + message: '~Unable to parse at line 1 \(near " App\\Discounts\\ExpressionProvider\\IsAnniversaryResolver\:"\)\.~' + - + path: docs/discounts/extend_discounts.md + line: 137 + hash: e049b49c97fe7c51ab27f584e15f9283a83664ed3b4d8b2fcae1866a15d46c72 + message: '~Unable to parse at line 1 \(near " App\\Discounts\\Condition\\IsAccountAnniversaryConditionFactory\:"\)\.~' + - + path: docs/discounts/extend_discounts_wizard.md + line: 140 + hash: 2e79e1bc175f608e6b74a9e28e9145367f4210f44e254c4f188911df6d368645 + message: '~Unable to parse at line 1 \(near " App\\Form\\FormMapper\\PurchasingPowerParityValueMapper\: \~"\)\.~' + - + path: docs/getting_started/first_steps.md + line: 120 + hash: d6956fc656de2808d27e294db9f4a5a1a66630f046ea21b8e75da2f658984f99 + message: '~The child config "default_siteaccess" under "ibexa\.siteaccess" must be configured\: Name of the default siteaccess~' + - + path: docs/infrastructure_and_maintenance/cache/http_cache/reverse_proxy.md + line: 145 + hash: 15a7e49dc68c59afa39e10276a448edf6f9e501374b2a75d43c0edaa7882f5e2 + message: '~The child config "fastly" under "ibexa\.system\.my_siteaccess_group\.http_cache" must be configured\.~' + - + path: docs/infrastructure_and_maintenance/cache/http_cache/reverse_proxy.md + line: 128 + hash: 68ea24e38b23f9efbfe4d689cffb5eb147ea6f332dc334fecc3f25f0117c4fb8 + message: '~The child config "fastly" under "ibexa\.system\.my_siteaccess_group\.http_cache" must be configured\.~' + - + path: docs/infrastructure_and_maintenance/security/development_security.md + line: 20 + hash: 0521cbcc27827c7ee2160a512158a19c89f1d51eb64a69d1b4600eb45a2505dd + message: '~Unrecognized option "require_previous_session" under "security\.firewalls\.ibexa_front\.form_login"\. Available options are "always_use_default_target_path", "check_path", "csrf_parameter", "csrf_token_id", "default_target_path", "enable_csrf", "failure_forward", "failure_handler", "failure_path", "failure_path_parameter", "form_only", "login_path", "password_parameter", "post_only", "provider", "remember_me", "success_handler", "target_path_parameter", "use_forward", "use_referer", "username_parameter"\.~' + - + path: docs/infrastructure_and_maintenance/security/security_checklist.md + line: 142 + hash: 65986b42415e23ed46aec11a3fb7398b138665b9fb75432e1457c7ebf89d18ec + message: '~The child config "firewalls" under "security" must be configured\.~' + - + path: docs/multisite/languages/languages.md + line: 78 + hash: 7d34665cd5af51823e88b55935ea40dfa550684bf2c3af7eba20349adfbb6be4 + message: '~The child config "match" under "ibexa\.siteaccess" must be configured\: Siteaccess match configuration\. First key is the matcher class, value is passed to the matcher\. Key can be a service identifier \(prepended by "@"\), or a FQ class name \(prepended by "\\"\)~' + - + path: docs/multisite/languages/languages.md + line: 135 + hash: 85fc7f295269781688143689f90a32b0f08231b74037ba73bf15d088108492d8 + message: '~The child config "match" under "ibexa\.siteaccess" must be configured\: Siteaccess match configuration\. First key is the matcher class, value is passed to the matcher\. Key can be a service identifier \(prepended by "@"\), or a FQ class name \(prepended by "\\"\)~' + - + path: docs/multisite/multisite_configuration.md + line: 57 + hash: 15dee03480731709d21c89105139a95add1377abb22ea78061b47fff1e013bba + message: '~The child config "list" under "ibexa\.siteaccess" must be configured\: Available SiteAccess list~' + - + path: docs/multisite/multisite_configuration.md + line: 28 + hash: 306a74d1cc587b13c8d3378a9b05815d16cfe0a0e10f9766685e8f39e81f98fd + message: '~The child config "list" under "ibexa\.siteaccess" must be configured\: Available SiteAccess list~' + - + path: docs/multisite/multisite_configuration.md + line: 69 + hash: c5a5cb7578b56189855285f63f16910ef708767ddc9389730d537f97725b5a89 + message: '~The child config "list" under "ibexa\.siteaccess" must be configured\: Available SiteAccess list~' + - + path: docs/multisite/set_up_translation_siteaccess.md + line: 43 + hash: 4038aedf899c1fc78ce0a57750c6c8dc31a317d0178ea3e612554da1e4bbe564 + message: '~The child config "default_siteaccess" under "ibexa\.siteaccess" must be configured\: Name of the default siteaccess~' + - + path: docs/multisite/site_factory/site_factory.md + line: 58 + hash: a1f0951071e5dec4f362284872b59167d59d3ff180e607e089c8a84488fb2c3d + message: '~The child config "list" under "ibexa\.siteaccess" must be configured\: Available SiteAccess list~' + - + path: docs/multisite/site_factory/site_factory.md + line: 40 + hash: e51a407b99ce4b87b710537f7caf45ad7528f720e4f2a1caf3c67ad647cc83f1 + message: '~The child config "list" under "ibexa\.siteaccess" must be configured\: Available SiteAccess list~' + - + path: docs/multisite/site_factory/site_factory_configuration.md + line: 81 + hash: 8721257146510878c104fbcddf27e0bf14afb71aba069a5a38b31f86b8d90db2 + message: '~The child config "siteaccess_group" under "ibexa_site_factory\.templates\.\" must be configured\.~' + - + path: docs/multisite/siteaccess/siteaccess_matching.md + line: 72 + hash: 1713ad609895c28fec2118385b9ec1605a7a299f4909c2fbd5c1363006fdb8ed + message: '~The child config "list" under "ibexa\.siteaccess" must be configured\: Available SiteAccess list~' + - + path: docs/multisite/siteaccess/siteaccess_matching.md + line: 178 + hash: 1b1fddbc3630d435957596321f59276f8fbb9faba14e3bee49749173eddefdc2 + message: '~The child config "list" under "ibexa\.siteaccess" must be configured\: Available SiteAccess list~' + - + path: docs/multisite/siteaccess/siteaccess_matching.md + line: 32 + hash: 2a4a8871fdaf5ba2c788513e81ef70506902f198baa2bc451e28c0e1e20f4c67 + message: '~The child config "list" under "ibexa\.siteaccess" must be configured\: Available SiteAccess list~' + - + path: docs/multisite/siteaccess/siteaccess_matching.md + line: 91 + hash: 691944c34e02c072fbca08e59c43ede5fbd019d1cefc776cd18a512927892d47 + message: '~The child config "list" under "ibexa\.siteaccess" must be configured\: Available SiteAccess list~' + - + path: docs/multisite/siteaccess/siteaccess_matching.md + line: 123 + hash: 78630816bedadf40ecf85287910909a1cfc6b6beebd398807581ae4c3d06ca4a + message: '~The child config "list" under "ibexa\.siteaccess" must be configured\: Available SiteAccess list~' + - + path: docs/multisite/siteaccess/siteaccess_matching.md + line: 108 + hash: 8946bcd67708bd70885f51c5731ee749a649eb66844f1d69cdc18cb81705083a + message: '~The child config "list" under "ibexa\.siteaccess" must be configured\: Available SiteAccess list~' + - + path: docs/multisite/siteaccess/siteaccess_matching.md + line: 194 + hash: a1f0951071e5dec4f362284872b59167d59d3ff180e607e089c8a84488fb2c3d + message: '~The child config "list" under "ibexa\.siteaccess" must be configured\: Available SiteAccess list~' + - + path: docs/multisite/siteaccess/siteaccess_matching.md + line: 140 + hash: ac6a06d9a33e4dcd9c73d2077eca6c6b3398b93cfda729ec7b18f24a45dcc976 + message: '~The child config "list" under "ibexa\.siteaccess" must be configured\: Available SiteAccess list~' + - + path: docs/multisite/siteaccess/siteaccess_matching.md + line: 161 + hash: bca418b7db9ad6c24b726a098611f793080df90e6a77bd71b378b7c2827b8026 + message: '~The child config "list" under "ibexa\.siteaccess" must be configured\: Available SiteAccess list~' + - + path: docs/multisite/siteaccess/siteaccess_matching.md + line: 237 + hash: e6259973305f42d67138e6b99f919b28b817968c03743bc8533540a5d3453d12 + message: '~The child config "list" under "ibexa\.siteaccess" must be configured\: Available SiteAccess list~' + - + path: docs/permissions/limitation_reference.md + line: 28 + hash: c989b346cda18ba902f44d6dfb2aa9129a1da96c87fcd7be9df0f84710155ebc + message: '~Unable to parse at line 3 \(near " ibexa\.api\.role\.limitation_type\.function_list\:"\)\.~' + - + path: docs/personalization/attribute_search_in_elasticsearch.md + line: 16 + hash: 4109336477914bb243c21073b32efd591f427b50f63f9305c39386055b915cd4 + message: '~Invalid output type in \{"\"\:\{"title"\:"\"\}\}\. Output type id should be type of int\.~' + - + path: docs/product_catalog/enable_purchasing_products.md + line: 106 + hash: 86fafb34287eaa9ce0fc52bec555e34c8e91f61778421cff734c8d42eb40e300 + message: '~Unable to parse at line 1 \(near " none\:"\)\.~' + - + path: docs/product_catalog/product_catalog_configuration.md + line: 77 + hash: 86fafb34287eaa9ce0fc52bec555e34c8e91f61778421cff734c8d42eb40e300 + message: '~Unable to parse at line 1 \(near " none\:"\)\.~' + - + path: docs/recommendations/raptor_integration/tracking_functions.md + line: 33 + hash: c2988244a58202f4c2260adddb526aee1315ea134e47dc4cef1fec2aa4bded02 + message: '~Duplicate key "connector_raptor" detected at line 6 \(near " tracking_type\: ''client'' \# Returns \ tags"\)\.~' + - + path: docs/release_notes/ez_platform_v2.4.md + line: 221 + hash: ce8c6170b6011d2a9c41b665109aaaafbcbfacc10d9d5b047c53647a10e58b84 + message: '~Unrecognized option "require_previous_session" under "security\.firewalls\.ezpublish_front\.form_login"\. Available options are "always_use_default_target_path", "check_path", "csrf_parameter", "csrf_token_id", "default_target_path", "enable_csrf", "failure_forward", "failure_handler", "failure_path", "failure_path_parameter", "form_only", "login_path", "password_parameter", "post_only", "provider", "remember_me", "success_handler", "target_path_parameter", "use_forward", "use_referer", "username_parameter"\.~' + - + path: docs/templating/design_engine/add_new_design.md + line: 16 + hash: 00526df40a7b678b4caa97a887e2c6a47689cf3e2e3d52ff42b7ef1b9a74aa0d + message: '~The child config "match" under "ibexa\.siteaccess" must be configured\: Siteaccess match configuration\. First key is the matcher class, value is passed to the matcher\. Key can be a service identifier \(prepended by "@"\), or a FQ class name \(prepended by "\\"\)~' + - + path: docs/templating/templates/template_configuration.md + line: 99 + hash: 2c225195371a55292ddf28e3ab7ef44855d194211bf48753fc65da1a93ef112c + message: '~Duplicate key "match" detected at line 3 \(near "match\: \[\]"\)\.~' + - + path: docs/update_and_migration/from_3.3/to_4.0.md + line: 237 + hash: 95c533291d7910e0abb29943e38be57ca5d60b5535ae4f051bbf8d5e0f5c7497 + message: '~Unrecognized option "ezrichtext" under "ibexa\.system\.admin_group\.fieldtypes"\. Available options are "ibexa_image_asset", "ibexa_richtext"\.~' + - + path: docs/update_and_migration/from_4.3/update_from_4.3_old_commerce.md + line: 168 + hash: 4bde18b55236541ba54dfba017b724848ef5b509a1ffa59f367dd64c45180136 + message: '~The child config "list" under "ibexa\.siteaccess" must be configured\: Available SiteAccess list~' + - + path: docs/update_and_migration/from_4.6/update_from_4.6.md + line: 517 + hash: a773b166515790f4dbce61a47e2553e73de5c4040e3aa3c21d8b63b3e8bfb688 + message: '~Unrecognized option "trace" under "ibexa_elasticsearch\.connections\.default"\. Available options are "authentication", "connection_pool", "connection_selector", "debug", "elastic_cloud_id", "hosts", "index_templates", "node_pool_resurrect", "node_pool_selector", "retries", "ssl"\.~' + - + path: docs/update_and_migration/from_4.6/update_from_4.6.md + line: 80 + hash: be04e17ca47844960603374e75d17e91e15afb8d6a74be42a7fab5b156121ab6 + message: '~Unrecognized option "Ibexa\\Contracts\\Shipping\\Notification\\ShipmentStatusChange" under "ibexa\.system\.my_siteacces_name\.notifications\.subscriptions"\. Available option is "timeout"\.~' + - + path: docs/update_and_migration/from_5.0/update_from_5.0.md + line: 238 + hash: 105a4065685d2da256b76b8b6f35f0893e0b04e278ed03445c3df07de6b6182f + message: '~Unrecognized option "trace" under "ibexa_elasticsearch\.connections\.default"\. Available options are "authentication", "connection_pool", "connection_selector", "debug", "elastic_cloud_id", "hosts", "index_templates", "node_pool_resurrect", "node_pool_selector", "retries", "ssl"\.~' + - + path: docs/update_and_migration/migrate_to_ibexa_dxp/migrating_from_ez_publish_platform.md + line: 535 + hash: 0578015f89f42b10f703e4fa171d2283db34626cb66fe4802663cd46faf95e4f + message: '~Mapping values are not allowed in multi\-line blocks at line 2 \(near " ezpublish\.persistence\.slug_converter\:"\)\.~' + - + path: docs/update_and_migration/migrate_to_ibexa_dxp/migrating_from_ez_publish_platform.md + line: 546 + hash: 1c88285aea32c1ee15509cdb4f296773e3e47c804b26699e98a1c6dac51eb66f + message: '~Unable to parse at line 1 \(near " ezpublish\.persistence\.slug_converter\:"\)\.~' + - + path: docs/users/oauth_server.md + line: 78 + hash: 44b149828628395857cf579b36ec8b838e136e016e372061af2499c567c408ae + message: '~The child config "firewalls" under "security" must be configured\.~' + - + path: docs/users/user_authentication.md + line: 41 + hash: e2b6b72606d335bd6ea3e22e20264ec836ef310e253d9fb371474f35dc8a3c75 + message: '~Unrecognized option "encoders" under "security"\. Available options are "access_control", "access_decision_manager", "access_denied_url", "erase_credentials", "expose_security_errors", "firewalls", "hide_user_not_found", "password_hashers", "providers", "role_hierarchy", "session_fixation_strategy"\.~' diff --git a/tools/extract-inline-php.php b/tools/extract-inline-php.php new file mode 100644 index 0000000000..3fb9fac9ee --- /dev/null +++ b/tools/extract-inline-php.php @@ -0,0 +1,140 @@ +#!/usr/bin/env php +isDir()) { + rmdir($item->getRealPath()); + } else { + unlink($item->getRealPath()); + } + } + + rmdir($dir); +} + +// Clean up the output directory from the previous run to avoid stale files +// (e.g. from docs that were renamed, moved, or had snippets removed). +removeDirectory(OUTPUT_DIR); + +// Always recreate the root output directory so downstream tools (Rector, +// PHP-CS-Fixer) that receive it as a path argument don't fail when there +// happen to be zero snippets to extract. +if (!mkdir(OUTPUT_DIR, 0755, true) && !is_dir(OUTPUT_DIR)) { + fwrite(STDERR, 'ERROR: Could not create directory: ' . OUTPUT_DIR . "\n"); + exit(1); +} + +$extractor = new MarkdownExtractor('php'); +$writer = new InlinePhpWriter(); + +$iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator(DOCS_DIR, RecursiveDirectoryIterator::SKIP_DOTS), +); + +$fileCount = 0; +$snippetCount = 0; + +/** @var SplFileInfo $file */ +foreach ($iterator as $file) { + if (!$file->isFile() || $file->getExtension() !== 'md') { + continue; + } + + $mdPath = $file->getRealPath(); + $content = file_get_contents($mdPath); + + if ($content === false) { + continue; + } + + $blocks = iterator_to_array($extractor->extract($content)); + + if (empty($blocks)) { + continue; + } + + // Relative path from docs/ root, e.g. "commerce/cart/cart_api.md" + $relativeFromDocs = ltrim(substr($mdPath, strlen(realpath(DOCS_DIR))), DIRECTORY_SEPARATOR); + + // Strip .md extension and use as subdirectory name + $subDir = OUTPUT_DIR . DIRECTORY_SEPARATOR . substr($relativeFromDocs, 0, -3); + + if (!is_dir($subDir) && !mkdir($subDir, 0755, true) && !is_dir($subDir)) { + fwrite(STDERR, "ERROR: Could not create directory: $subDir\n"); + exit(1); + } + + // Relative path used in the source comment, e.g. "docs/commerce/cart/cart_api.md" + $sourceRelPath = 'docs/' . str_replace(DIRECTORY_SEPARATOR, '/', $relativeFromDocs); + + foreach ($blocks as $block) { + $line = $block['line']; + $body = $block['body']; + + $hash = hash('sha256', $body); + $outputFile = $subDir . DIRECTORY_SEPARATOR . "{$hash}.php"; + + file_put_contents($outputFile, $writer->build($sourceRelPath, $line, $body)); + ++$snippetCount; + } + + ++$fileCount; +} + +echo sprintf( + "Extracted %d PHP snippet%s from %d Markdown file%s → code_samples/_inline_php/\n", + $snippetCount, + $snippetCount !== 1 ? 's' : '', + $fileCount, + $fileCount !== 1 ? 's' : '', +); diff --git a/tools/sync-inline-php-to-markdown.php b/tools/sync-inline-php-to-markdown.php new file mode 100644 index 0000000000..e10f2e8f93 --- /dev/null +++ b/tools/sync-inline-php-to-markdown.php @@ -0,0 +1,122 @@ +#!/usr/bin/env php +/{sha256(body)}.php, prepending an auto-generated header. + * + * + * + * + * After php-cs-fixer reformats the files, this script: + * 1. Groups all _inline_php files by their source Markdown path. + * 2. Processes each group in descending line order so that patching a later block + * never shifts the line numbers of earlier blocks that are still to be processed. + * 3. For each file, delegates the sync logic to InlinePhpSyncer and writes the result. + * + * Run automatically after php-cs-fixer via `composer fix-cs`. + */ + +declare(strict_types=1); + +require_once __DIR__ . '/../vendor/autoload.php'; + +use Ibexa\Tests\Documentation\InlineSamples\InlinePhpSyncer; + +const INLINE_PHP_DIR = __DIR__ . '/../code_samples/_inline_php'; +const REPO_ROOT = __DIR__ . '/..'; + +$syncer = new InlinePhpSyncer(); + +// --- Pass 1: collect all _inline_php files grouped by their source Markdown path. --- + +/** @var array> $byMdPath */ +$byMdPath = []; + +$iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator(INLINE_PHP_DIR, RecursiveDirectoryIterator::SKIP_DOTS), +); + +/** @var SplFileInfo $file */ +foreach ($iterator as $file) { + if (!$file->isFile() || $file->getExtension() !== 'php') { + continue; + } + + $content = file_get_contents($file->getRealPath()); + if ($content === false) { + continue; + } + + $location = $syncer->parseSourceLocation($content); + if ($location === null) { + fwrite(STDERR, "WARNING: No '// Source:' comment found in {$file->getRealPath()}, skipping.\n"); + continue; + } + + $mdPath = REPO_ROOT . '/' . $location['path']; + $byMdPath[$mdPath][] = ['phpPath' => $file->getRealPath(), 'line' => $location['line']]; +} + +// --- Pass 2: for each Markdown file, apply patches in descending line order. --- +// This ensures that modifying a block at line N does not shift the line numbers +// of blocks at lines < N that are yet to be processed. + +$patchCount = 0; + +foreach ($byMdPath as $mdPath => $entries) { + if (!is_file($mdPath)) { + fwrite(STDERR, "WARNING: Source file not found: $mdPath, skipping.\n"); + continue; + } + + $mdContent = file_get_contents($mdPath); + if ($mdContent === false) { + fwrite(STDERR, "WARNING: Cannot read $mdPath, skipping.\n"); + continue; + } + + // Sort highest body line first so earlier patches do not invalidate later line numbers. + usort($entries, static fn (array $a, array $b): int => $b['line'] <=> $a['line']); + + $mdChanged = false; + + foreach ($entries as ['phpPath' => $phpPath, 'line' => $line]) { + $phpContent = file_get_contents($phpPath); + if ($phpContent === false) { + continue; + } + + $updated = $syncer->sync($phpContent, $mdContent); + if ($updated === null) { + continue; + } + + $mdContent = $updated; + $mdChanged = true; + + echo "Updated: " . substr($mdPath, strlen(REPO_ROOT) + 1) . " (block at line $line)\n"; + ++$patchCount; + } + + if ($mdChanged) { + file_put_contents($mdPath, $mdContent); + } +} + +echo sprintf( + "Synced %d block%s back to Markdown files.\n", + $patchCount, + $patchCount !== 1 ? 's' : '', +); +