Skip to content
Merged
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
2 changes: 1 addition & 1 deletion code_samples/back_office/images/config/packages/views.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
parameters:
ibexa.<site_access>.image_asset_view_defaults:
ibexa.site_access.config.<scope>.image_asset_view_defaults:
full:
commons:
template: '@@ibexadesign/commons_asset_view.html.twig'
Expand Down
22 changes: 15 additions & 7 deletions code_samples/back_office/images/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,26 @@ services:
- '@Ibexa\Core\Helper\TranslationHelper'

App\Connector\Dam\Handler\WikimediaCommonsHandler:
arguments:
$httpClient: '@http_client'
tags:
- { name: 'ibexa.platform.connector.dam.handler', source: 'commons' }
- { name: 'ibexa.platform.connector.dam.handler', source: 'commons' }

App\Connector\Dam\Transformation\TransformationFactory:
arguments:
$httpClient: '@http_client'
App\Connector\Dam\Transformation\WikimediaCommonsTransformationFactory:
tags:
- { name: 'ibexa.platform.connector.dam.transformation_factory', source: 'commons' }

commons_asset_variation_generator:
class: Ibexa\Connector\Dam\Variation\URLBasedVariationGenerator
tags:
- { name: ibexa.platform.connector.dam.variation_generator, source: commons }
- { name: 'ibexa.platform.connector.dam.variation_generator', source: 'commons' }

commons_search_tab:
class: Ibexa\Platform\Connector\Dam\View\Search\Tab\GenericSearchTab
public: false
arguments:
$identifier: 'commons'
$source: 'commons'
$name: 'Wikimedia Commons'
$searchFormType: 'Ibexa\Platform\Connector\Dam\Form\Search\GenericSearchType'
$formFactory: '@form.factory'
tags:
- { name: 'ibexa.admin_ui.tab', group: 'connector-dam-search' }
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,7 @@ public function search(Query $query, int $offset = 0, int $limit = 20): AssetSea
$assets = [];
foreach ($response['query']['search'] as $result) {
$identifier = str_replace('File:', '', $result['title']);
$asset = $this->fetchAsset($identifier);
if ($asset) {
$assets[] = $asset;
}
$assets[] = $this->fetchAsset($identifier);
}

return new AssetSearchResult(
Expand All @@ -47,25 +44,25 @@ public function search(Query $query, int $offset = 0, int $limit = 20): AssetSea
);
}

public function fetchAsset(string $id): ?Asset
public function fetchAsset(string $id): Asset
{
$metadataUrl = 'https://commons.wikimedia.org/w/api.php?action=query&prop=imageinfo&iiprop=extmetadata&format=json'
. '&titles=File%3a' . urlencode($id)
;

$jsonResponse = file_get_contents($metadataUrl);
if ($jsonResponse === false) {
return null;
throw new \RuntimeException('Couldn\'t retrieve asset metadata');
}

$response = json_decode($jsonResponse, true);
if (!isset($response['query']['pages'])) {
return null;
throw new \RuntimeException('Couldn\'t parse asset metadata');
}

$pageData = array_values($response['query']['pages'])[0] ?? null;
if (!isset($pageData['imageinfo'][0]['extmetadata'])) {
return null;
throw new \RuntimeException('Couldn\'t parse image asset metadata');
}

$imageInfo = $pageData['imageinfo'][0]['extmetadata'];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,20 @@

class WikimediaCommonsTransformationFactory implements TransformationFactoryInterface
{
public function build(?string $transformationName = null, array $transformationParameters = []): ?Transformation
/** @param array<string, scalar> $transformationParameters */
public function build(?string $transformationName = null, array $transformationParameters = []): Transformation
{
if (null === $transformationName) {
return new Transformation(null, array_map('strval', $transformationParameters));
}
Comment on lines +10 to +15
Copy link
Contributor Author

@adriendupuis adriendupuis Apr 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Unsplash connector way to deal with this is "ignore" 😅🤞


$transformations = $this->buildAll();

return $transformations[$transformationName] ?? null;
if (array_key_exists($transformationName, $transformations)) {
return $transformations[$transformationName];
}

throw new \InvalidArgumentException(sprintf('Unknown transformation "%s".', $transformationName));
}

public function buildAll(): array
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ezimageasset.dam_asset.page_url: Image page
ezimageasset.dam_asset.author: Image author
ezimageasset.dam_asset.license: License
ezimageasset.dam_asset.license_url: License page
59 changes: 46 additions & 13 deletions docs/content_management/images/add_image_asset_from_dam.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,11 @@

### Create DAM handler

This class handles searching through Wikimedia Commons for images and fetching assets.
This class handles searching through Wikimedia Commons for images and fetching image assets.

In `src\Connector\Dam\Handler` folder, create the `WikimediaCommonsHandler.php` file that resembles the following example, which uses `search()` and `fetchAsset()` functions to query the server for images and return asset objects, respectively:
In `src\Connector\Dam\Handler` folder, create the `WikimediaCommonsHandler.php` file that resembles the following example,
which implements [`search()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Connector-Dam-Handler-Handler.html#method_search) to query the server

Check failure on line 100 in docs/content_management/images/add_image_asset_from_dam.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/content_management/images/add_image_asset_from_dam.md#L100

[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": "docs/content_management/images/add_image_asset_from_dam.md", "range": {"start": {"line": 100, "column": 70}}}, "severity": "ERROR"}
and [`fetchAsset()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Connector-Dam-Handler-Handler.html#method_fetchAsset) to return asset objects:

Check failure on line 101 in docs/content_management/images/add_image_asset_from_dam.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/content_management/images/add_image_asset_from_dam.md#L101

[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": "docs/content_management/images/add_image_asset_from_dam.md", "range": {"start": {"line": 101, "column": 61}}}, "severity": "ERROR"}

```php
[[= include_file('code_samples/back_office/images/src/Connector/Dam/Handler/WikimediaCommonsHandler.php') =]]
Expand All @@ -105,15 +107,17 @@
Then, in `config\services.yaml`, register the handler as a service:

```yaml
[[= include_file('code_samples/back_office/images/config/services.yaml', 9, 14) =]]
[[= include_file('code_samples/back_office/images/config/services.yaml', 9, 12) =]]
```

The `source` parameter passed in the tag is an identifier of this new DAM connector and is used in other places to glue elements together.

### Create transformation factory

The transformation factory maps [[= product_name =]]'s image variations to corresponding variations from Wikimedia Commons.

In `src\Connector\Dam\Transformation` folder, create the `WikimediaCommonsTransformationFactory.php` file that resembles the following example:

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):

Check failure on line 120 in docs/content_management/images/add_image_asset_from_dam.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/content_management/images/add_image_asset_from_dam.md#L120

[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": "docs/content_management/images/add_image_asset_from_dam.md", "range": {"start": {"line": 120, "column": 97}}}, "severity": "ERROR"}

```php
[[= include_file('code_samples/back_office/images/src/Connector/Dam/Transformation/WikimediaCommonsTransformationFactory.php') =]]
Expand All @@ -122,15 +126,15 @@
Then register the transformation factory as a service:

```yaml
[[= include_file('code_samples/back_office/images/config/services.yaml', 15, 20) =]]
[[= include_file('code_samples/back_office/images/config/services.yaml', 13, 16) =]]
```

### Register variations generator

The variation generator applies map parameters coming from the transformation factory to build a fetch request to the DAM.
The solution uses the built-in `URLBasedVariationGenerator` class, which adds all the map elements as query parameters to the request.

For example, the handler generates the following URL with `new AssetUri()`:
For example, the handler generates the following URL with [`new AssetUri()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Connector-Dam-AssetUri.html#method___construct):

Check failure on line 137 in docs/content_management/images/add_image_asset_from_dam.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/content_management/images/add_image_asset_from_dam.md#L137

[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": "docs/content_management/images/add_image_asset_from_dam.md", "range": {"start": {"line": 137, "column": 117}}}, "severity": "ERROR"}

`https://commons.wikimedia.org/w/index.php?title=Special:Redirect/file/Ibexa_Logo.svg`

Expand All @@ -141,28 +145,57 @@
For this to happen, register the variations generator as a service:

```yaml
[[= include_file('code_samples/back_office/images/config/services.yaml', 21, 25) =]]
[[= include_file('code_samples/back_office/images/config/services.yaml', 17, 21) =]]
```

### Create Twig template for Admin UI
### Set tab for "Select from DAM" modal

To select an image from the DAM, a modal window pop in with tabs & panels for different search sub-interfaces.

In this example, the search only use the main text input.
Its tab and its corresponding panel are a service created by combining existing components (as many [back office tabs](back_office_tabs.md)).

The tab service uses directly the dedicated base tab `GenericSearchTab`,
passes it the dedicated base form `GenericSearchType`,
links it to `commons` DAM source,
is identified as `commons`,
is tagged with `ibexa.admin_ui.tab` tag,
and set in the `connector-dam-search` [tab group](back_office_tabs.md#tab-groups).

```yaml
[[= include_file('code_samples/back_office/images/config/services.yaml', 22, 33) =]]
```

The template defines how images that come from Wikimedia Commons appear in the back office.
### Create Twig template

In `templates/bundles/WikimediaCommonsConnector/`, add the `commons_asset_view.html.twig` file that resembles the following example:
The template defines how images that come from Wikimedia Commons appear.

In `templates/themes/standard/`, add the `commons_asset_view.html.twig` file that resembles the following example:

```html+twig
[[= include_file('code_samples/back_office/images/templates/themes/standard/commons_asset_view.html.twig') =]]
```

Then, register the template and a fallback template in configuration files:
Then, register the template and a fallback template in configuration files
(replace `<scope>` with [appropriate value](siteaccess_aware_configuration.md) like `default` so it's used everywhere including the back office):

```yaml
[[= include_file('code_samples/back_office/images/config/packages/views.yaml') =]]
```

### Provide back office translation

In the back office, an image asset field is displayed followed by a table of metadata.

As some new specific ones are used in this example, some new translations are needed.

```yaml
[[= include_file('code_samples/back_office/images/translations/ibexa_fieldtypes_preview.en.yaml') =]]
```

### Add Wikimedia Commons connection to DAM configuration

You can now configure a connection with Wikimedia Commons under the `ibexa.system.<scope>.content.dam` key:
You can now configure a connection with Wikimedia Commons under the `ibexa.system.<scope>.content.dam` key using the source identifier `commons`:

```yaml
ibexa:
Expand Down
Loading