Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CI] [POC] Added code samples testing with Deptrac #2562

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ jobs:
- name: Run PHPStan analysis
run: composer phpstan

- name: Deptrac
run: composer deptrac

code-samples-inclusion-check:
name: Check code samples inclusion
runs-on: ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ __pycache__/*
.php-cs-fixer.cache
composer.lock
tools/php-cs-fixer/vendor
.deptrac.cache
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,31 @@

## Testing the code samples

### PHPStan
This repository uses PHPStan to test the code samples. To run the tests locally execute the commands below:
```bash
composer update
composer phpstan
```

Regenerate the baseline by running:
```bash
composer phpstan -- --generate-baseline

Check failure on line 66 in README.md

View workflow job for this annotation

GitHub Actions / vale

[vale] README.md#L66

[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'
Raw output
{"message": "[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'", "location": {"path": "README.md", "range": {"start": {"line": 66, "column": 25}}}, "severity": "ERROR"}
```

### Deptrac

This repository uses Deptrac to test the code samples. To run the tests locally execute the commands below:

Check failure on line 71 in README.md

View workflow job for this annotation

GitHub Actions / vale

[vale] README.md#L71

[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'
Raw output
{"message": "[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'", "location": {"path": "README.md", "range": {"start": {"line": 71, "column": 5}}}, "severity": "ERROR"}

Check failure on line 71 in README.md

View workflow job for this annotation

GitHub Actions / vale

[vale] README.md#L71

[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'
Raw output
{"message": "[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'", "location": {"path": "README.md", "range": {"start": {"line": 71, "column": 43}}}, "severity": "ERROR"}
```bash
composer update

Check failure on line 73 in README.md

View workflow job for this annotation

GitHub Actions / vale

[vale] README.md#L73

[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'
Raw output
{"message": "[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'", "location": {"path": "README.md", "range": {"start": {"line": 73, "column": 1}}}, "severity": "ERROR"}

Check failure on line 73 in README.md

View workflow job for this annotation

GitHub Actions / vale

[vale] README.md#L73

[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'
Raw output
{"message": "[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'", "location": {"path": "README.md", "range": {"start": {"line": 73, "column": 40}}}, "severity": "ERROR"}
composer deptrac
```

Check failure on line 75 in README.md

View workflow job for this annotation

GitHub Actions / vale

[vale] README.md#L75

[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'
Raw output
{"message": "[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'", "location": {"path": "README.md", "range": {"start": {"line": 75, "column": 14}}}, "severity": "ERROR"}

Regenerate the baseline by running:
```bash
vendor/bin/deptrac --formatter=baseline
```

Check failure on line 81 in README.md

View workflow job for this annotation

GitHub Actions / vale

[vale] README.md#L81

[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'
Raw output
{"message": "[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'", "location": {"path": "README.md", "range": {"start": {"line": 81, "column": 5}}}, "severity": "ERROR"}

Check failure on line 81 in README.md

View workflow job for this annotation

GitHub Actions / vale

[vale] README.md#L81

[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'
Raw output
{"message": "[Ibexa.VariablesGlobal] Use global variable '[[= product_name_base =]]' instead of 'Ibexa'", "location": {"path": "README.md", "range": {"start": {"line": 81, "column": 45}}}, "severity": "ERROR"}
## Where to View

https://doc.ibexa.co
2 changes: 1 addition & 1 deletion code_samples/api/commerce/src/Command/CartCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
use Ibexa\Contracts\Cart\Value\EntryAddStruct;
use Ibexa\Contracts\Cart\Value\EntryUpdateStruct;
use Ibexa\Contracts\Checkout\Reorder\ReorderService;
use Ibexa\Contracts\Core\Repository\PermissionResolver;
use Ibexa\Contracts\Core\Repository\UserService;
use Ibexa\Contracts\OrderManagement\OrderServiceInterface;
use Ibexa\Contracts\ProductCatalog\CurrencyServiceInterface;
use Ibexa\Contracts\ProductCatalog\ProductServiceInterface;
use Ibexa\Core\Repository\Permission\PermissionResolver;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace App\Command;

use Ibexa\Migration\MigrationService;
use Ibexa\Contracts\Migration\MigrationService;
use Ibexa\Migration\Repository\Migration;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use Ibexa\Contracts\Core\Repository\PermissionResolver;
use Ibexa\Contracts\Core\Repository\UserService;
use Ibexa\Segmentation\Service\SegmentationService;
use Ibexa\Contracts\Segmentation\SegmentationServiceInterface;
use Ibexa\Segmentation\Value\SegmentCreateStruct;
use Ibexa\Segmentation\Value\SegmentGroupCreateStruct;
use Symfony\Component\Console\Command\Command;
Expand All @@ -13,13 +13,13 @@

class SegmentCommand extends Command
{
private SegmentationService $segmentationService;
private SegmentationServiceInterface $segmentationService;

private UserService $userService;

private PermissionResolver $permissionResolver;

public function __construct(SegmentationService $segmentationService, UserService $userService, PermissionResolver $permissionResolver)
public function __construct(SegmentationServiceInterface $segmentationService, UserService $userService, PermissionResolver $permissionResolver)
{
$this->segmentationService = $segmentationService;
$this->permissionResolver = $permissionResolver;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

use DateTime;
use DateTimeInterface;
use Ibexa\Calendar\EventSource\InMemoryEventSource;
use Ibexa\Contracts\Calendar\EventCollection;
use Ibexa\Contracts\Calendar\EventSource\EventSourceInterface;
use Ibexa\Contracts\Calendar\EventSource\InMemoryEventSource;

class EventSourceFactory
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

namespace App\Calendar\Holidays;

use Ibexa\Calendar\EventAction\EventActionCollection;
use Ibexa\Contracts\Calendar\Event;
use Ibexa\Contracts\Calendar\EventAction\EventActionCollection;
use Ibexa\Contracts\Calendar\EventType\EventTypeInterface;

class EventType implements EventTypeInterface
Expand Down
18 changes: 0 additions & 18 deletions code_samples/back_office/images/src/PlaceholderProvider.php

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public function acceptValue(Limitation $limitationValue): void
}
}

/** @return \Ibexa\Core\FieldType\ValidationError[] */
/** @return \Ibexa\Contracts\Core\FieldType\ValidationError[] */
public function validate(Limitation $limitationValue): array
{
$validationErrors = [];
Expand Down
12 changes: 10 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,20 @@
"ibexa/solr": "5.0.x-dev",
"ibexa/version-comparison": "5.0.x-dev",
"league/oauth2-google": "^4.0",
"ibexa/core-search": "~5.0.x-dev"
"ibexa/core-search": "~5.0.x-dev",
"qossmic/deptrac": "^2.0"
},
"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"
"phpstan": "phpstan analyse",
"deptrac": "deptrac analyse"
},
"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"
},
"config": {
"allow-plugins": false
Expand Down
185 changes: 185 additions & 0 deletions deptrac.baseline.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
deptrac:
skip_violations:
App\Attribute\Percent\Form\PercentValueFormMapper:
- Ibexa\Bundle\ProductCatalog\Validator\Constraints\AttributeValue
App\Attribute\Percent\PercentOptionsFormMapper:
- Ibexa\Bundle\ProductCatalog\Validator\Constraints\AttributeDefinitionOptions
App\Attribute\Percent\Storage\PercentStorageConverter:
- Ibexa\ProductCatalog\Local\Persistence\Legacy\Attribute\Float\StorageSchema
App\Attribute\Percent\Storage\PercentStorageDefinition:
- Ibexa\ProductCatalog\Local\Persistence\Legacy\Attribute\Float\StorageSchema
App\Block\Listener\MyBlockListener:
- Ibexa\FieldTypePage\FieldType\Page\Block\Renderer\BlockRenderEvents
- Ibexa\FieldTypePage\FieldType\Page\Block\Renderer\Event\PreRenderEvent
App\CatalogFilter\ProductNameFilterFormMapper:
- Ibexa\Bundle\ProductCatalog\Form\Type\TagifyType
App\Checkout\Workflow\Strategy\NewWorkflow:
- Ibexa\Checkout\Value\Workflow\Workflow
App\Checkout\Workflow\Strategy\NewWorkflowConditionalStep:
- Ibexa\Checkout\Value\Workflow\Workflow
App\Command\CalendarCommand:
- Ibexa\Scheduler\Calendar\EventAction\RescheduleEventActionContext
App\Command\CatalogCommand:
- Ibexa\ProductCatalog\Local\Repository\Values\Catalog\Status
App\Command\CreateImageCommand:
- Ibexa\Core\FieldType\Image\Value
App\Command\MigrationCommand:
- Ibexa\Migration\Repository\Migration
App\Command\PaymentMethodCommand:
- Ibexa\Payment\Values\PaymentMethodType
App\Command\SegmentCommand:
- Ibexa\Segmentation\Value\SegmentCreateStruct
- Ibexa\Segmentation\Value\SegmentGroupCreateStruct
App\Command\ShippingMethodCommand:
- Ibexa\ProductCatalog\Local\Repository\Values\Region
- Ibexa\Shipping\Value\ShippingMethodType
App\Command\ViewCommand:
- Ibexa\Core\MVC\Symfony\View\Builder\ContentViewBuilder
- Ibexa\Core\MVC\Symfony\View\Renderer\TemplateRenderer
App\Controller\AllContentListController:
- Ibexa\AdminUi\Form\Factory\FormFactory
- Ibexa\Core\Pagination\Pagerfanta\LocationSearchAdapter
App\Controller\BreadcrumbController:
- Ibexa\Bundle\Core\Controller
App\Controller\Checkout\OnePageCheckout:
- Ibexa\Bundle\Checkout\Controller\AbstractStepController
App\Controller\Checkout\Step\SelectSeatStepController:
- Ibexa\Bundle\Checkout\Controller\AbstractStepController
App\Controller\CustomCheckoutController:
- Ibexa\Bundle\Core\Controller
App\Controller\CustomController:
- Ibexa\Bundle\Core\Controller
App\Controller\CustomFilterController:
- Ibexa\Bundle\Core\Controller
- Ibexa\Core\MVC\Symfony\View\ContentView
App\Controller\PaginationController:
- Ibexa\Bundle\Core\Controller
- Ibexa\Core\Pagination\Pagerfanta\ContentSearchAdapter
App\Controller\RelationController:
- Ibexa\Core\MVC\Symfony\View\View
App\Controller\SvgController:
- Ibexa\Core\Helper\TranslationHelper
- Ibexa\Core\IO\IOServiceInterface
- Ibexa\Core\MVC\Symfony\Controller\Controller
App\Corporate\EventSubscriber\ApplicationDetailsViewSubscriber:
- Ibexa\Bundle\CorporateAccount\EventSubscriber\AbstractViewSubscriber
- Ibexa\Core\MVC\Symfony\SiteAccess\SiteAccessServiceInterface
- Ibexa\Core\MVC\Symfony\View\View
- Ibexa\CorporateAccount\View\ApplicationDetailsView
App\Corporate\EventSubscriber\VerifyStateEventSubscriber:
- Ibexa\CorporateAccount\Event\ApplicationWorkflowEvents
- Ibexa\CorporateAccount\Persistence\Legacy\ApplicationState\HandlerInterface
- Ibexa\CorporateAccount\Persistence\Values\ApplicationStateUpdateStruct
App\EventListener\TextAnchorMenuTabListener:
- Ibexa\AdminUi\Menu\ContentEditAnchorMenuBuilder
- Ibexa\AdminUi\Menu\Event\ConfigureMenuEvent
App\EventSubscriber\BreadcrumbsMenuSubscriber:
- Ibexa\Bundle\Storefront\Menu\Builder\BreadcrumbsMenuBuilder
App\EventSubscriber\FormFieldDefinitionSubscriber:
- Ibexa\FormBuilder\Definition\FieldAttributeDefinitionBuilder
- Ibexa\FormBuilder\Event\FieldDefinitionEvent
- Ibexa\FormBuilder\Event\FormEvents
App\EventSubscriber\MyMenuSubscriber:
- Ibexa\AdminUi\Menu\Event\ConfigureMenuEvent
- Ibexa\AdminUi\Menu\MainMenuBuilder
App\Event\RandomBlockListener:
- Ibexa\FieldTypePage\FieldType\Page\Block\Renderer\BlockRenderEvents
- Ibexa\FieldTypePage\FieldType\Page\Block\Renderer\Event\PreRenderEvent
App\Event\Subscriber\BlockEmbedEventEventSubscriber:
- Ibexa\FieldTypePage\FieldType\Page\Block\Renderer\BlockRenderEvents
- Ibexa\FieldTypePage\FieldType\Page\Block\Renderer\Event\PreRenderEvent
App\Event\Subscriber\RichTextBlockSubscriber:
- Ibexa\FieldTypePage\FieldType\Page\Block\Renderer\BlockRenderEvents
- Ibexa\FieldTypePage\FieldType\Page\Block\Renderer\Event\PreRenderEvent
- Ibexa\FieldTypePage\FieldType\Page\Block\Renderer\Twig\TwigRenderRequest
- Ibexa\FieldTypeRichText\RichText\DOMDocumentFactory
App\FieldType\HelloWorld\Comparison\Comparable:
- Ibexa\VersionComparison\ComparisonValue\StringComparisonValue
App\FieldType\HelloWorld\Comparison\HelloWorldComparisonEngine:
- Ibexa\VersionComparison\Engine\Value\StringComparisonEngine
App\FieldType\HelloWorld\Comparison\HelloWorldComparisonResult:
- Ibexa\VersionComparison\Result\Value\StringComparisonResult
App\FieldType\HelloWorld\Comparison\Value:
- Ibexa\VersionComparison\ComparisonValue\StringComparisonValue
App\FormBuilder\FieldType\Field\Mapper\CheckboxWithRichtextDescriptionFieldMapper:
- Ibexa\FormBuilder\FieldType\Field\Mapper\GenericFieldMapper
App\FormBuilder\Field\Mapper\CountryFieldMapper:
- Ibexa\FormBuilder\FieldType\Field\Mapper\GenericFieldMapper
App\FormBuilder\FormSubmission\Converter\RichtextDescriptionFieldSubmissionConverter:
- Ibexa\FormBuilder\FormSubmission\Converter\BooleanFieldSubmissionConverter
App\FormBuilder\Form\Type\FieldAttribute\AttributeRichtextDescriptionType:
- Ibexa\FieldTypeRichText\Form\Type\RichTextType
App\Form\Type\OnePageCheckoutType:
- Ibexa\Bundle\Checkout\Form\Type\AddressType
- Ibexa\Bundle\Payment\Form\Type\PaymentMethodChoiceType
- Ibexa\Bundle\Shipping\Form\Type\ShippingMethodChoiceType
App\GraphQL\Schema\MyCustomFieldDefinitionMapper:
- Ibexa\GraphQL\Schema\Domain\Content\Mapper\FieldDefinition\DecoratingFieldDefinitionMapper
App\Kernel:
- Ibexa\Bundle\Core\DependencyInjection\IbexaCoreExtension
App\Migrations\Action\AssignSection:
- Ibexa\Migration\ValueObject\Step\Action
App\Migrations\Action\AssignSectionExecutor:
- Ibexa\Migration\StepExecutor\ActionExecutor\ExecutorInterface
- Ibexa\Migration\ValueObject\Step\Action
App\Migrations\Matcher\SectionIdentifierGenerator:
- Ibexa\Migration\Generator\CriterionGenerator\GeneratorInterface
App\Migrations\Matcher\SectionIdentifierNormalizer:
- Ibexa\Bundle\Migration\Serializer\Normalizer\Criterion\AbstractCriterionNormalizer
App\Migrations\Step\ReplaceNameStep:
- Ibexa\Migration\ValueObject\Step\StepInterface
App\Migrations\Step\ReplaceNameStepExecutor:
- Ibexa\Core\FieldType\TextLine\Value
- Ibexa\Migration\ValueObject\Step\StepInterface
App\Migrations\Step\ReplaceNameStepNormalizer:
- Ibexa\Migration\ValueObject\Step\StepInterface
App\Notification\MyRenderer:
- Ibexa\Core\Notification\Renderer\NotificationRenderer
App\OAuth\GoogleResourceOwnerMapper:
- Ibexa\OAuth2Client\ResourceOwner\ResourceOwnerToExistingOrNewUserMapper
App\QueryType\LatestContentQueryType:
- Ibexa\Core\QueryType\QueryType
App\QueryType\MenuQueryType:
- Ibexa\Core\QueryType\QueryType
App\QueryType\OptionsBasedLatestContentQueryType:
- Ibexa\Core\QueryType\OptionsResolverBasedQueryType
- Ibexa\Core\QueryType\QueryType
App\Rest\Controller\DefaultController:
- Ibexa\Rest\Message
- Ibexa\Rest\Server\Controller
App\Rest\InputParser\GreetingInput:
- Ibexa\Rest\Input\BaseParser
App\Rest\ValueObjectVisitor\RestLocation:
- Ibexa\Rest\Server\Output\ValueObjectVisitor\RestLocation
- Ibexa\Rest\Server\Values\URLAliasRefList
App\Search\Model\Suggestion\ProductSuggestion:
- Ibexa\ProductCatalog\Local\Repository\Values\Product
App\Security\Limitation\CustomLimitationType:
- Ibexa\Core\Base\Exceptions\InvalidArgumentException
- Ibexa\Core\Base\Exceptions\InvalidArgumentType
- Ibexa\Core\FieldType\ValidationError
App\Security\Limitation\Mapper\CustomLimitationFormMapper:
- Ibexa\AdminUi\Limitation\LimitationFormMapperInterface
- Ibexa\Core\Limitation\LimitationIdentifierToLabelConverter
App\Security\Limitation\Mapper\CustomLimitationValueMapper:
- Ibexa\AdminUi\Limitation\LimitationValueMapperInterface
App\Security\MyPolicyProvider:
- Ibexa\Bundle\Core\DependencyInjection\Security\PolicyProvider\YamlPolicyProvider
App\Setting\Group\MyGroup:
- Ibexa\User\UserSetting\Group\AbstractGroup
App\Setting\Unit:
- Ibexa\Core\Base\Exceptions\InvalidArgumentException
App\ShippingMethodType\Storage\StorageDefinition:
- Ibexa\Shipping\Persistence\Legacy\ShippingMethod\AbstractOptionsStorageSchema
App\ShippingMethodType\Storage\StorageSchema:
- Ibexa\Shipping\Persistence\Legacy\ShippingMethod\AbstractOptionsStorageSchema
App\Tab\Dashboard\Everyone\EveryoneArticleTab:
- Ibexa\AdminUi\Tab\Dashboard\PagerLocationToDataMapper
- Ibexa\Core\Pagination\Pagerfanta\LocationSearchAdapter
App\View\Matcher\Owner:
- Ibexa\Core\MVC\Symfony\Matcher\ContentBased\MatcherInterface
- Ibexa\Core\MVC\Symfony\View\ContentValueView
- Ibexa\Core\MVC\Symfony\View\LocationValueView
- Ibexa\Core\MVC\Symfony\View\View
AttributeTypeExtension:
- Ibexa\PageBuilder\Form\Type\Attribute\AttributeType
27 changes: 27 additions & 0 deletions deptrac.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
imports:
- deptrac.baseline.yaml

deptrac:
paths:
- ./code_samples
layers:
- name: CodeSamples
collectors:
- type: directory
value: code_samples
- name: IbexaContracts
collectors:
- type: classLike
value: .*Ibexa\\Contracts\\.*
- name: IbexaNotContracts
collectors:
- type: bool
must:
- type: classLike
value: .*Ibexa\\.*
must_not:
- type: classLike
value: .*Ibexa\\Contracts.*
ruleset:
CodeSamples:
- IbexaContracts
6 changes: 1 addition & 5 deletions docs/content_management/images/images.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,17 +108,13 @@ You can also pass two additional parameters:
With a placeholder generator you can download or generate placeholder images for any missing image.
It proves useful when you're working on an existing database and are unable to download uploaded images to your local development environment, due to, for example, a large size of files.

If the original image cannot be resolved, the `PlaceholderAliasGenerator::getVariation` method generates a placeholder by delegating it to the implementation of the `PlaceholderProvider` interface, and saves it under the original path.
If the original image cannot be resolved, the `PlaceholderAliasGenerator::getVariation` method generates a placeholder by delegating it to the implementation of the [PlaceholderProvider](https://github.com/ibexa/core/blob/main/src/bundle/Core/Imagine/PlaceholderProvider.php) interface, and saves it under the original path.

In [[= product_name =]], there are two implementations of the `PlaceholderProvider` interface:

- [GenericProvider](#genericprovider)
- [RemoteProvider](#remoteprovider)

``` php
[[= include_file('code_samples/back_office/images/src/PlaceholderProvider.php') =]]
```

### GenericProvider

The [`GenericProvider`](https://github.com/ibexa/core/blob/main/src/bundle/Core/Imagine/PlaceholderProvider.php) package generates placeholders with basic information about the original image (see [example 1](#configuration-examples)).
Expand Down
Loading
Loading