PHPackages                             truffo/ez-content-decorator-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. truffo/ez-content-decorator-bundle

ActiveLibrary

truffo/ez-content-decorator-bundle
==================================

A short description of what your package does

1.0.0(10y ago)11.5kMITPHPPHP &gt;=5.4.0

Since Aug 3Pushed 10y agoCompare

[ Source](https://github.com/truffo/ez-content-decorator-bundle)[ Packagist](https://packagist.org/packages/truffo/ez-content-decorator-bundle)[ Docs](https://github.com/truffo/ez-content-decorator-bundle)[ RSS](/packages/truffo-ez-content-decorator-bundle/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependenciesVersions (2)Used By (0)

ez-content-decorator
====================

[](#ez-content-decorator)

Introduction
------------

[](#introduction)

Lorsqu'on travaile sur des templates, eZ Publish fournit généralement 2 objects :

- location : représentant la localisation dans l'arborescence
- content : représentant le contenu proprement dit

Ces 2 éléments suffisent dans la majorité des cas, mais très vite, le besoin d'étendre ces 2 objets se fait ressentir.

Un exemple classique consiste à récupérer dans le controleur la liste des enfants d'une location à travers une LocationQuery, on va le paginer et le passer à la vue.

La vue affichera un listing avec un chapo, le chapo sera constitué soit du champ chapo soit du champ du contenu principal coupant à un certains nombres de caractères.

Bref, un grand classique du Web.

Classiquement, on va répéter ses opérations des dizaines et dizaines de fois. Et, comme il y a plusieurs développeurs sur le projets, chacun va avoir des petites différences :

- entre ceux qui préfère exclure les types de contenus qui ne conviennent pas, et ceux qui préfère inclure uniquement ceux qui conviennet
- entre ceux qui préfère calculer le maximum de chose dans un controleur et ceux vont déléguer à des sous requetes

On a trouvé un manque d'harmonie et des copier / coller d'un type de contenu à l'autre, et à chaque changement c'est le bal des retours lients interminables, en gros, on a un terreau à dette technique.

\## L'idée : un décorator

Ce bundle fournit un mécanisme très simple pour apporter une solution concrète à cette problématique, il permet d'avoir très simplement et très rapidements des décorator qui encapsule nos types de contenus dans une structure plus souple.

L'idée est simple, il s'agit d'abord de regrouper sous une même classe les éléments qui constituent un contenu :

- la location
- le content

C'est la classe ContentDecorator. Bon, ok cela ne sert pas à grand chose.

Cette classe va nous servir de classe de base pour définir nos decorators pour les instance concrète.

```
class Article extends ContentDecorator {
     public function getPropertyArticle()
}
class Blog extends ContentDecorator {
     public function getPropertyBlog()
}
```

Chaque classe permet de définir des méthodes qui sont propres à chaque type de contenu.

Enfin, on exploite la configuration sémantique pour faire le lien entre la classe et type de contenu.

```
ezcontentdecorator.global.class_mapping:
  article: \getPropertyArticle();

$blog = $contentDecoratorFactory->getContentDecorator($blogLocation);
echo $blog->getPropertyBlog();
```

Chargement automatique
----------------------

[](#chargement-automatique)

A ce stade, pour exploiter ce mécanisme, il faut :

- charger le décorateur à chaque appel dans le contrôleur
- charger le décorateur directement dans la vue via un opérateur Twig custom

Ce n'est pas terrible comme solution, surtout qu'eZ Publish fournit, un Event le PreContentView Listener qui nous permettre de charger automatiquement le decorateur et injecter les variables dans le template.

```
/**
 * @param PreContentViewEvent $event
 */
public function onPreContentView( PreContentViewEvent $event )
{
    $contentView = $event->getContentView();

    /** @var \Truffo\eZContentDecoratorBundle\Decorator\ContentDecoratorFactory $contentDecoratorFactory */
    $contentDecoratorFactory = $this->container->get('ezcontentdecorator.services.factory');

    if ($contentView->hasParameter('location')) {
        $location = $contentView->getParameter('location');
        /** @var \Truffo\eZContentDecoratorBundle\Decorator\ContentDecorator $contentDecorator */
        $contentDecorator = $contentDecoratorFactory->getContentDecorator($location);
        $contentView->addParameters([
            $contentDecorator->getContentTypeIdentifier() => $contentDecorator,
            'decorator' => $contentDecorator
        ]);
    }
}
```

On a ainsi 2 variables qui sont automatiquement disponibles dans tout les templates qui ont une Location en paramètre :

- &lt;nom\_du\_type\_de\_contenu&gt;
- decorator

Elles sont identiques, ce sont juste des sucres syntaxiques.

Ainsi dans une vue full d'un article, on pourrait avoir le code suivant :

```
{{ ez_render_field(article.content, "title") }}
{{ article.propertyArticle }}
```

ou son équivalent

```
{{ ez_render_field(decorator.content, "title") }}
{{ decorator.propertyArticle }}
```

Chargement automatique dans les listes
--------------------------------------

[](#chargement-automatique-dans-les-listes)

On a trouver une solution pour charger automatiquement dans les vues contenant une location. Maintenant, pour les résultats de recherche, c'est presque aussi simple.

Une bonne pratique consiste à utiliser à systématiquement un pager (PagerFanta) pour récupérer les résultats d'une query via le SearchService. Ce composant à l'avantage de permettre d'injecter des adpaters.

Le LocationDecoratorSearchAdapter injecte automatiquement notre décorator à chaque instance des locations retournées.

Dans nos repositories, on peux avoir quelques choses qui ressemble à cela :

```
public function getArticleList($location, $limit = 10, $page = 1)
{
    $query = new LocationQuery();
    $query->criterion =
    new Criterion\LogicalAnd(array(
         new Criterion\ContentTypeIdentifier(['article']),
         new Criterion\Subtree($location->pathString),
         new Criterion\Visibility(Criterion\Visibility::VISIBLE)
    ));
    $query->sortClauses = [  new SortClause\Field('article', 'publication_date', Query::SORT_DESC, 'fre-FR') ];
    return LocationDecoratorSearchAdapter::buildPager($query, $searchService, $contentDecoratorFactory
    , $limit, $page)
}
```

et dans notre controlleur

```
$params += ['items' => $helper->getArticleList($location)];
return $this->get('ez_content')->viewLocation($locationId, $viewType, $layout, $params);
```

Ainsi dans notre vue, on a directement des décorateurs :

```
{% for item in items %}
    {{ ez_render_field(item.content, "title") }}
    {{ decorator.propertyArticle }}
{% endfor %}
```

La réutilisabilité horizontale avec les traits
----------------------------------------------

[](#la-réutilisabilité-horizontale-avec-les-traits)

Les mécanismes présentés ci-dessus sont encore plus puissants si on utilise les égalements les traits de PHP. Reprenons notre exemple du chapo, on va pouvoir écrire quelques choses qui ressemble à ceci :

```
interface Chapoable
{
     public function chapo();
}

traits Chapo {
     public function chapo()
     {
         // Notre logique pour construire un chapo ...
     }
}

class Article implements Chapoable {
     use Chapo;
}

class Page implements Chapoable
{
     use Chapo;
}
```

```
{{ article.chapo }}
```

Une bonne convention sur le nommage des champs dans les différents type de contenu, avec ce bundle et les traits. On peux exploiter au maximum la réutilisabilité et la concision du code, CQFD.

###  Health Score

28

—

LowBetter than 54% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity17

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity58

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

3932d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/223b81b4a7932ef4d7d804a12d8da2ef5b7e4045ca37ed3f5cc9ece9f4682202?d=identicon)[truffo](/maintainers/truffo)

---

Top Contributors

[![truffo](https://avatars.githubusercontent.com/u/3169185?v=4)](https://github.com/truffo "truffo (10 commits)")

---

Tags

ezpublishdecorator

### Embed Badge

![Health badge](/badges/truffo-ez-content-decorator-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/truffo-ez-content-decorator-bundle/health.svg)](https://phpackages.com/packages/truffo-ez-content-decorator-bundle)
```

###  Alternatives

[robclancy/presenter

Decorate your objects using presenters. Primarily to keep presentation logic out of your models.

3451.1M8](/packages/robclancy-presenter)[acclimate/container

Provides adapters for various third-party service containers.

219390.6k15](/packages/acclimate-container)[kaliop/ezmigrationbundle

Kaliop eZ-Migration Bundle

54358.0k9](/packages/kaliop-ezmigrationbundle)[netgen/admin-ui-bundle

Netgen Admin UI implements an alternate administration UI for eZ Platform, based on eZ Publish Legacy administration interface

3325.4k4](/packages/netgen-admin-ui-bundle)[netgen/information-collection-bundle

Information collection alike feature for Ibexa Platform

1945.1k8](/packages/netgen-information-collection-bundle)[netgen/remote-media-bundle

Remote media field type implementation

189.4k4](/packages/netgen-remote-media-bundle)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
