Skip to content

Added testing of embedded PHP snippets#3166

Draft
mnocon wants to merge 3 commits into
test-yamlsfrom
test-php-snippets
Draft

Added testing of embedded PHP snippets#3166
mnocon wants to merge 3 commits into
test-yamlsfrom
test-php-snippets

Conversation

@mnocon
Copy link
Copy Markdown
Contributor

@mnocon mnocon commented Apr 24, 2026

This PR makes it possible to run code quality checks (PHPStan, CS-Fixer, Rector, Deptrac) on embedded PHP code samples.

Thanks to this, we no longer need to extract the code samples to separate files - they can stay within the Markdown files, making it easier to work with them, with keeping the advantage of the code quality tools.

How it works

Before a code quality tool is run, the code samples are extracted from Markdown files.

They are not extracted if:

  • the code sample uses one of the include_file/include_code functions
  • the code sample is marked with skip-validation

The rest of the are extracted to code_samples/_inline_php for the tools to pick up.

When the tool can automatically fix the issue (CS-Fixer, Rector), the changes are synced back to the Markdown files.

All the existing inline code samples are marked with skip-validation, to keep this PR small and allow us using this for new usages - the fixing of code samples will be done in a follow-up.

@mnocon mnocon changed the base branch from 5.0 to test-yamls April 24, 2026 07:13
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 24, 2026

Preview of modified files: Too many files modified in a single PR, preview link list is skipped. (310 files > 100)

@mnocon mnocon changed the title Test and fix embedded PHP snippets Added testing of embedded PHP snippets May 16, 2026
@mnocon mnocon force-pushed the test-php-snippets branch from 7463431 to 6ed6be0 Compare May 16, 2026 13:11
@github-actions
Copy link
Copy Markdown

code_samples/ change report

Before (on target branch)After (in current PR)

code_samples/api/graphql/src/GraphQL/Schema/MyFieldDefinitionMapper.php

docs/api/graphql/graphql_custom_ft.md@62:``` php

code_samples/api/graphql/src/GraphQL/Schema/MyFieldDefinitionMapper.php

docs/api/graphql/graphql_custom_ft.md@62:``` php
docs/api/graphql/graphql_custom_ft.md@63:[[= include_file('code_samples/api/graphql/src/GraphQL/Schema/MyFieldDefinitionMapper.php', 0, 16) =]][[= include_file('code_samples/api/graphql/src/GraphQL/Schema/MyFieldDefinitionMapper.php', 36, 37) =]]
docs/api/graphql/graphql_custom_ft.md@64:```
docs/api/graphql/graphql_custom_ft.md@63:[[= include_code('code_samples/api/graphql/src/GraphQL/Schema/MyFieldDefinitionMapper.php', 1, 17) =]]
docs/api/graphql/graphql_custom_ft.md@64:[[= include_code('code_samples/api/graphql/src/GraphQL/Schema/MyFieldDefinitionMapper.php', 38, 39) =]]
docs/api/graphql/graphql_custom_ft.md@65:```

001⫶<?php declare(strict_types=1);
002⫶
003⫶namespace App\GraphQL\Schema;
004⫶
005⫶use Ibexa\Contracts\Core\Repository\Values\ContentType\ContentType;
006⫶use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;
007⫶use Ibexa\Contracts\GraphQL\Schema\Domain\Content\Mapper\FieldDefinition\FieldDefinitionMapper;
008⫶use Ibexa\GraphQL\Schema\Domain\Content\Mapper\FieldDefinition\DecoratingFieldDefinitionMapper;
009⫶use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
010⫶
011⫶class MyFieldDefinitionMapper extends DecoratingFieldDefinitionMapper implements FieldDefinitionMapper
012⫶{
013⫶ protected function getFieldTypeIdentifier(): string
014⫶ {
015⫶ return 'my_field_type';
016⫶ }

001⫶<?php declare(strict_types=1);
002⫶
003⫶namespace App\GraphQL\Schema;
004⫶
005⫶use Ibexa\Contracts\Core\Repository\Values\ContentType\ContentType;
006⫶use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;
007⫶use Ibexa\Contracts\GraphQL\Schema\Domain\Content\Mapper\FieldDefinition\FieldDefinitionMapper;
008⫶use Ibexa\GraphQL\Schema\Domain\Content\Mapper\FieldDefinition\DecoratingFieldDefinitionMapper;
009⫶use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
010⫶
011⫶class MyFieldDefinitionMapper extends DecoratingFieldDefinitionMapper implements FieldDefinitionMapper
012⫶{
013⫶ protected function getFieldTypeIdentifier(): string
014⫶ {
015⫶ return 'my_field_type';
016⫶ }
017⫶}
017⫶
018⫶}


docs/api/graphql/graphql_custom_ft.md@77:```php
docs/api/graphql/graphql_custom_ft.md@78:[[= include_file('code_samples/api/graphql/src/GraphQL/Schema/MyFieldDefinitionMapper.php', 19, 22, remove_indent=True) =]]
docs/api/graphql/graphql_custom_ft.md@79:```
docs/api/graphql/graphql_custom_ft.md@78:```php
docs/api/graphql/graphql_custom_ft.md@79:[[= include_code('code_samples/api/graphql/src/GraphQL/Schema/MyFieldDefinitionMapper.php', 21, 24, remove_indent=True) =]]
docs/api/graphql/graphql_custom_ft.md@80:```

001⫶if (!$this->canMap($fieldDefinition)) {
002⫶ return parent::mapToFieldValueInputType($contentType, $fieldDefinition);
003⫶}


001⫶if (!$this->canMap($fieldDefinition)) {
002⫶ return parent::mapToFieldValueInputType($contentType, $fieldDefinition);
003⫶}

docs/api/graphql/graphql_custom_ft.md@101:```php
docs/api/graphql/graphql_custom_ft.md@102:[[= include_file('code_samples/api/graphql/src/GraphQL/Schema/MyFieldDefinitionMapper.php') =]]
docs/api/graphql/graphql_custom_ft.md@103:```
docs/api/graphql/graphql_custom_ft.md@102:```php
docs/api/graphql/graphql_custom_ft.md@103:[[= include_file('code_samples/api/graphql/src/GraphQL/Schema/MyFieldDefinitionMapper.php') =]]
docs/api/graphql/graphql_custom_ft.md@104:```

001⫶<?php declare(strict_types=1);
002⫶
003⫶namespace App\GraphQL\Schema;
004⫶
005⫶use Ibexa\Contracts\Core\Repository\Values\ContentType\ContentType;
006⫶use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;
007⫶use Ibexa\Contracts\GraphQL\Schema\Domain\Content\Mapper\FieldDefinition\FieldDefinitionMapper;
008⫶use Ibexa\GraphQL\Schema\Domain\Content\Mapper\FieldDefinition\DecoratingFieldDefinitionMapper;
009⫶use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
010⫶
011⫶class MyFieldDefinitionMapper extends DecoratingFieldDefinitionMapper implements FieldDefinitionMapper
012⫶{
013⫶ protected function getFieldTypeIdentifier(): string
014⫶ {
015⫶ return 'my_field_type';
016⫶ }
017⫶

001⫶<?php declare(strict_types=1);
002⫶
003⫶namespace App\GraphQL\Schema;
004⫶
005⫶use Ibexa\Contracts\Core\Repository\Values\ContentType\ContentType;
006⫶use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;
007⫶use Ibexa\Contracts\GraphQL\Schema\Domain\Content\Mapper\FieldDefinition\FieldDefinitionMapper;
008⫶use Ibexa\GraphQL\Schema\Domain\Content\Mapper\FieldDefinition\DecoratingFieldDefinitionMapper;
009⫶use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
010⫶
011⫶class MyFieldDefinitionMapper extends DecoratingFieldDefinitionMapper implements FieldDefinitionMapper
012⫶{
013⫶ protected function getFieldTypeIdentifier(): string
014⫶ {
015⫶ return 'my_field_type';
016⫶ }
017⫶
018⫶    public function mapToFieldValueInputType(ContentType $contentType, FieldDefinition $fieldDefinition): ?string
019⫶ {
020⫶ if (!$this->canMap($fieldDefinition)) {
021⫶ return parent::mapToFieldValueInputType($contentType, $fieldDefinition);
022⫶ }
023⫶
024⫶ return $this->nameMyFieldInputType($contentType, $fieldDefinition);
025⫶ }
026⫶
027⫶ private function nameMyFieldInputType(ContentType $contentType, FieldDefinition $fieldDefinition): string
028⫶ {
029⫶ $converter = new CamelCaseToSnakeCaseNameConverter(null, false);
030⫶
031⫶ return sprintf(
032⫶ '%s%sInput',
033⫶ $converter->denormalize($contentType->identifier),
034⫶ $converter->denormalize($fieldDefinition->identifier)
035⫶ );
036⫶ }
037⫶}
018⫶    #[\Override]
019⫶ public function mapToFieldValueInputType(ContentType $contentType, FieldDefinition $fieldDefinition): ?string
020⫶ {
021⫶ if (!$this->canMap($fieldDefinition)) {
022⫶ return parent::mapToFieldValueInputType($contentType, $fieldDefinition);
023⫶ }
024⫶
025⫶ return $this->nameMyFieldInputType($contentType, $fieldDefinition);
026⫶ }
027⫶
028⫶ private function nameMyFieldInputType(ContentType $contentType, FieldDefinition $fieldDefinition): string
029⫶ {
030⫶ $converter = new CamelCaseToSnakeCaseNameConverter(null, false);
031⫶
032⫶ return sprintf(
033⫶ '%s%sInput',
034⫶ $converter->denormalize($contentType->identifier),
035⫶ $converter->denormalize($fieldDefinition->identifier)
036⫶ );
037⫶ }
038⫶}


code_samples/catalog/custom_catalog_filter/src/CatalogFilter/DataTransformer/ProductNameCriterionTransformer.php

docs/product_catalog/create_custom_catalog_filter.md@50:``` php
docs/product_catalog/create_custom_catalog_filter.md@51:[[= include_file('code_samples/catalog/custom_catalog_filter/src/CatalogFilter/DataTransformer/ProductNameCriterionTransformer.php') =]]
docs/product_catalog/create_custom_catalog_filter.md@52:```

001⫶<?php
002⫶
003⫶declare(strict_types=1);
004⫶
005⫶namespace App\CatalogFilter\DataTransformer;
006⫶
007⫶use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\ProductName;
008⫶use Symfony\Component\Form\DataTransformerInterface;
009⫶use Symfony\Component\Form\Exception\TransformationFailedException;
010⫶


code_samples/catalog/custom_catalog_filter/src/CatalogFilter/DataTransformer/ProductNameCriterionTransformer.php

docs/product_catalog/create_custom_catalog_filter.md@50:``` php
docs/product_catalog/create_custom_catalog_filter.md@51:[[= include_file('code_samples/catalog/custom_catalog_filter/src/CatalogFilter/DataTransformer/ProductNameCriterionTransformer.php') =]]
docs/product_catalog/create_custom_catalog_filter.md@52:```

001⫶<?php
002⫶
003⫶declare(strict_types=1);
004⫶
005⫶namespace App\CatalogFilter\DataTransformer;
006⫶
007⫶use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\ProductName;
008⫶use Symfony\Component\Form\DataTransformerInterface;
009⫶use Symfony\Component\Form\Exception\TransformationFailedException;
010⫶
011⫶final class ProductNameCriterionTransformer implements DataTransformerInterface
012⫶{
013⫶ public function transform($value): ?string
014⫶ {
015⫶ if (null === $value) {
016⫶ return null;
017⫶ }
018⫶
019⫶ if (!$value instanceof ProductName) {
020⫶ throw new TransformationFailedException('Expected a ' . ProductName::class . ' object.');
021⫶ }
022⫶
023⫶ return $value->getName();
024⫶ }
025⫶
026⫶ public function reverseTransform($value): ?ProductName
027⫶ {
028⫶ if ($value === null) {
029⫶ return null;
030⫶ }
011⫶/**
012⫶ * @implements \Symfony\Component\Form\DataTransformerInterface<
013⫶ * \Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion\ProductName,
014⫶ * \Ibexa\Bundle\ProductCatalog\Form\Data\Catalog\CatalogFilterPriceData
015⫶ * >
016⫶ */
017⫶final class ProductNameCriterionTransformer implements DataTransformerInterface
018⫶{
019⫶ public function transform($value): ?string
020⫶ {
021⫶ if (null === $value) {
022⫶ return null;
023⫶ }
024⫶
025⫶ if (!$value instanceof ProductName) {
026⫶ throw new TransformationFailedException('Expected a ' . ProductName::class . ' object.');
027⫶ }
028⫶
029⫶ return $value->getName();
030⫶ }
031⫶
031⫶
032⫶        if (!is_string($value)) {
033⫶ throw new TransformationFailedException('Invalid data, expected a string value');
034⫶ }
035⫶
036⫶ return new ProductName($value);
037⫶ }
038⫶}
032⫶    public function reverseTransform($value): ?ProductName
033⫶ {
034⫶ if ($value === null) {
035⫶ return null;
036⫶ }
037⫶
038⫶ if (!is_string($value)) {
039⫶ throw new TransformationFailedException('Invalid data, expected a string value');
040⫶ }
041⫶
042⫶ return new ProductName($value);
043⫶ }
044⫶}


Download colorized diff

@sonarqubecloud
Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant