PHPackages                             zenstruck/content-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. [Framework](/categories/framework)
4. /
5. zenstruck/content-bundle

AbandonedArchivedSymfony-bundle[Framework](/categories/framework)

zenstruck/content-bundle
========================

Simple CMS for Symfony2 using Doctrine2 Class Table Inheritance

v1.3.5(12y ago)132641MITPHP

Since Aug 13Pushed 6y ago1 watchersCompare

[ Source](https://github.com/kbond/ZenstruckContentBundle)[ Packagist](https://packagist.org/packages/zenstruck/content-bundle)[ Docs](http://zenstruck.com/project/ZenstruckContentBundle)[ RSS](/packages/zenstruck-content-bundle/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (1)Dependencies (4)Versions (12)Used By (0)

Information
===========

[](#information)

[![Build Status](https://camo.githubusercontent.com/a7d32bd424fff05c079ebc5ca4d27d6b998a17120f24219c8672596a9489fcbc/68747470733a2f2f7365637572652e7472617669732d63692e6f72672f6b626f6e642f5a656e73747275636b436f6e74656e7442756e646c652e706e67)](http://travis-ci.org/kbond/ZenstruckContentBundle)

This Bundle allows for various *content-types* using Doctrine2's Inheritance (see for more information). It allows for all your content-types to inherit from a single `Node`. The problem with Doctrine2's implementation is it requires you set all your inherited Entities in the top most Entity. With this Bundle they are setup in your `config.yml`.

Configuration
=============

[](#configuration)

1. Create a `Node` class:

    ```
    // path/to/your/bundle/Entity/Node.php

    namespace YourApplicationBundle\Entity;

    use Zenstruck\Bundle\ContentBundle\Entity\Node as BaseNode;

    /**
     * @orm:Entity
     */
    class Node extends BaseNode
    {
        // add any node fields (or leave empty)
    }
    ```
2. Create one or more content-type Entities (extending from your `Node` entity):

    ```
    // path/to/your/bundle/Entity/BlogPost.php

    namespace YourApplicationBundle\Entity;

    /**
     * @orm:Entity
     */
    class BlogPost extends Node
    {
        /**
         * @orm:Column(type="text", nullable=true)
         */
        protected $body;

        public function getBody()
        {
            return $this->body;
        }

        public function setBody($body)
        {
            $this->body = $body;
        }
    }
    ```

    **Note**: They can also extend eachother (`BlogPost->Page->Node`)
3. Add your node class and any new content-types to your `config.yml`:

    ```
    zenstruck_content:
            node_class: YourApplicationBundle\Entity\Node
        content_types:
            blog_post:  YourApplicationBundle\Entity\BlogPost
            ...
    ```

    **Note:** in the above example the *machine name* of class `BlogPost` is `blog_post`. This naming convention is important.
4. (optional) To use the controller that this bundle provides activate it in your `config.yml`:

    ```
    zenstruck_content:
        use_controller: true
    ```
5. (optional) If you used the controller in step 4, add the routing:

    ```
    zenstruck_content:
        resource: "@ZenstruckContentBundle/Resources/config/routing.xml"
    ```

Reference
=========

[](#reference)

Manager
-------

[](#manager)

There is a manager class that is available from the service container via the id `zenstruck_content.manager`.

### Breadcrumbs

[](#breadcrumbs)

The manager contains a function called `getAncestors(Node $node)`. This returns an array of Ancestor nodes based on the path of the current `Node` given.

For instance, if you pass a node with path `foo/bar/baz` it will return an array of nodes with path's `foo` and `foo/bar` if they exist and in that order.

#### Usage

[](#usage)

```
// controller
$manager = $this->container->get('zenstruck_content.manager');
$manager->getAncestors($node);
```

Inheritance Type
----------------

[](#inheritance-type)

By default Doctrine2's *Class Table Inheritance* is used. This means each content-type extending from `Node` is it's own table linking back to the base `node` table. There is also the option of using *Class Table Inheritance*. All content types will be stored in the same table.

You can enable this in your `config.yml`:

```
zenstruck_content:
    inheritance_type: single_table
```

Template
--------

[](#template)

To provide your own templates set the `default_template` option in your `config.yml`:

```
zenstruck_content:
    default_template: YourApplicationBundle:Content:node.html.twig
```

**Note:** the default template name must be `node`.

InheritedUniqueEntity constraint
--------------------------------

[](#inheriteduniqueentity-constraint)

This bundles comes with a custom `UniqueEntity` validation constraint. The default Doctrine one has problems with inheritance. It only checks the values of entities within it's current scope and children. For instance if you have this structure: `BlogPost->Page->Node`and place the default Doctrine `UniqueEntity` constraint on a field in `Page`. Saving a `BlogPost` with a field that is the same as one in `Page` will not cause the constraint to become invalid.

The `InheritedUniqueEntity` constraint packaged with this bundle does.

### Usage

[](#usage-1)

The following demonstrates adding a UniqueEntity constraint on the `body` field of the `Page`entity. All classes that inherit from `Page` will have this constraint in the `Page` scope.

```
namespace Acme\DemoBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Zenstruck\Bundle\ContentBundle\Validator\InheritedUniqueEntity;

/**
 * Acme\DemoBundle\Entity\Node
 *
 * @ORM\Table(name="page")
 * @ORM\Entity
 * @InheritedUniqueEntity(field="body")
 */
class Page extends Node
{

    /**
     * @var string $body
     *
     * @ORM\Column(name="body", type="string", length=255, nullable=true)
     */
    protected $body;

    //...
}
```

Sitemap Generation
------------------

[](#sitemap-generation)

This bundle comes with a Sitemap Generator for use with [DpnXmlSitemapBundle](https://github.com/dreipunktnull/DpnXmlSitemapBundle)

Usage
-----

[](#usage-2)

1. Install and configure [DpnXmlSitemapBundle](https://github.com/dreipunktnull/DpnXmlSitemapBundle)
2. Enable sitemap generator in your `config.yml`:

    ```
    zenstruck_content:
        sitemap:
            enabled: true
    ```
3. By default, the generator uses the `findAll` method on the `Node`'s entity manager. To use a different method change it in your `config.yml`:

    ```
    zenstruck_content:
        sitemap:
            entity_manager_method: myCustomMethod
    ```

The sitemap should be available at `/sitemap.xml`.

Full Default Configuration
--------------------------

[](#full-default-configuration)

```
zenstruck_content:
    node_class:           ~ # Required
    node_type_name:       node
    manager_class:        ~
    use_controller:       false
    use_form:             false
    inheritance_type:     class_table
    discriminator_column: content_type
    default_template:     ZenstruckContentBundle:Node:node.html.twig
    content_types: []
    sitemap:
        enabled:                false
        entity_manager_method:  findAll
```

###  Health Score

33

—

LowBetter than 75% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity19

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity70

Established project with proven stability

 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

Every ~60 days

Total

9

Last Release

4540d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/707369cc916e0ea1aacbf077dcba464f611cef879f024d8944311a54a15224b3?d=identicon)[kbond](/maintainers/kbond)

---

Top Contributors

[![kbond](https://avatars.githubusercontent.com/u/127811?v=4)](https://github.com/kbond "kbond (70 commits)")

---

Tags

content management

### Embed Badge

![Health badge](/badges/zenstruck-content-bundle/health.svg)

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

###  Alternatives

[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.3M152](/packages/sulu-sulu)[prestashop/prestashop

PrestaShop is an Open Source e-commerce platform, committed to providing the best shopping cart experience for both merchants and customers.

9.0k15.4k](/packages/prestashop-prestashop)[contao/core-bundle

Contao Open Source CMS

1231.6M2.4k](/packages/contao-core-bundle)[ec-cube/ec-cube

EC-CUBE EC open platform.

78527.0k1](/packages/ec-cube-ec-cube)[open-dxp/opendxp

Content &amp; Product Management Framework (CMS/PIM)

7310.3k29](/packages/open-dxp-opendxp)[forumify/forumify-platform

121.8k11](/packages/forumify-forumify-platform)

PHPackages © 2026

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