A decoupled Content Management Framework

14 november - 010PHP

Willem-Jan Zijderveld

Developer at Beeldspraak

@willemjanz

github.com/wjzijderveld

blog.willem-jan.net

In this talk

  • What is Symfony CMF
  • Under the hood: PHPCR
  • The components
  • What's brewing

What is Symfony CMF

  • Toolbox
  • Aimed at developers
    • Set of bundles
    • Scalability
    • Usability
    • Documentation
    • Testing
  • Community Driven

Under the hood: PHPCR

PHP Content Repository

  • Proven technique
  • Defines a interface
  • Decouple the storage from you application
  • Lots of features

PHPCR

Interface any PHP content management application with any content repository

PHPCR

Write applications once, switch storage backends when needed

PHPCR: Quick overview

  • Store content in a tree of nodes
  • Each node has a name and a type
  • Nodes can have children
  • Nodes can have properties with values
  • A value can be almost anything

Best of both worlds

  • RDBMS
    • Transactions
    • Query
    • Structure
    • Integrity
  • Filesystem
    • Binary
    • Hierarchy
    • Locking
    • Access Control
  • And more
    • Unstructured
    • Versioning
    • Full-Text
    • Multi-value

Example


<jcr:root>
  <cms>
    <pages>
      <home title="Homepage">
        <block
          title="News"
          content="Today: Symfony CMF presentation"/>
      </home>
      <contact
        title="Contact"
        content="symfony-cmf-devs@googlegroups.com"/>
    </pages>
  </cms>
</jcr:root>
                    

Node home

  • Path: /cms/pages/home
  • Parent: /cms/pages
  • Name: home

Doctrine PHPCR ODM

  • Object to Document mapper
  • Persist your objects as PHPCR nodes

I thought this talk was about Symfony CMF?

The components

  • CoreBundle
  • Routing + RoutingBundle
  • ContentBundle
  • BlockBundle
  • CreateBundle
  • MediaBundle
  • MenuBundle

CoreBundle

  • Publish Workflow
  • Templating
  • Multi-language support
  • More...

CoreBunde

Publish Workflow

Implement your publication workflow

Uses Symfony Security Component with Access Voters

Article.php
<?php
class Article implements PublishableInterface, PublishTimePeriodInterface
{
    /** @var \DateTime */
    private $isPublishable;

    public function isPublishable() {
        return $this->isPublishable;
    }
}
                    
MyController.php
<?php
// check if current user is allowed to see this document
$pwc = $container->get('cmf_core.publish_workflow.checker');
if (!$pwc->isGranted(
    PublishWorkflowChecker::VIEW_ATTRIBUTE,
    $document
)) { // f.e. redirect to 404 }
                    

Most of the time, this is handled by the RequestListener

CoreBundle

Templating

Provides some basic helpers

  • cmf_is_published
  • cmf_children
  • cmf_next/cmf_prev
  • ...

CoreBundle

Templating


{% for newsItem in cmf_children(page)|reverse %}
    <li>
        <a href="{{ path(newsItem) }}">{{ newsItem.title }}</a>
        ({{ newsItem.publishStartDate | date('Y-m-d')  }})
    </li>
{% endfor %}
                    

CoreBundle

Multi-language support

  • Configuration for all Bundles
  • TranslatableInterface

Routing + RoutingBundle

  • Extends Symfony Routing Component
  • Introduces ChainRouter
  • Has the possibility to load routes from the database
  • Bundle simply integrates the component

ChainRouter

  • Add prioritized routers
  • Stops on first match
  • Can use the full Request

Dynamic Router

  • Lookup routes in your database
  • Generate URLs based on path or object

Enhance your routes

  • RouteContentEnhancer
  • FieldMapEnchancer
  • FieldByClassEnhancer
  • FieldPresenceEnhancer

RouteContentEnhancer

When the found route is an instance of RouteObjectInterface

<?php class Route implements RouteObjectInterface {}

Set's the contentDocument in the route

<?php $route->getContent(); ?>

FieldMapEnhancer

Sets a value in the route, based on a hashmap

<?php
use Symfony\Cmf\Component\Routing\Enhancer\FieldMapEnhancer;
$hashMap = array('foo' => '010PHP');
$enhancer = new FieldMapEnhancer('bar', 'title', $hashMap);

Imagine a Route, that has a property bar with value foo

After the enhancer is applied, the route will also have a property title with value 010PHP

FieldByClassEnhancer

Looks like FieldMap enhancer

Checks with instanceOf instead of comparing value

Used to set a controller based on Document

FieldPresenceEnhancer

Simply set's a value when a field is present

Can also be used to set a default value

Is used to set the default Controller

ContentBundle

  • Default Document
  • Default Controller
  • References routes
  • References menu nodes

BlockBundle

Create and use blocks of content in your website.

Makes perfect sense as childnodes in your Content Repository

BlockBundle

Common behaviour

  • Aimed at PHPCR
  • Settings
  • Implements PublishableInterface
  • Support Multi-language

BlockBundle

Available types

  • StringBlock
  • SimpleBlock
  • ContainerBlock
  • ReferenceBlock
  • ActionBlock
  • RssBlock
  • ImagineBlock
  • SlideshowBlock

 

Very easy to create your own block

BlockBundle

Template usage


{{ sonata_block_render({
    'name': 'presentationBlock'
}) }}
                    

CreateBundle

  • Integrates CreateJS and CreatePHP into Symfony2
  • Uses RDFa meta-data (like Doctrine's mapping)
  • Support for CKEditor and Hallo.js

 

Twig example

{% createphp page as="rdf" noautotag %}
    <div {{ createphp_attributes(rdf) }}>
        <h1 class="my-title" {{ createphp_attributes( rdf.title ) }}>
            {{ createphp_content( rdf.title ) }}
        </h1>
        <div {{ createphp_attributes( rdf.body ) }}>
            {{ createphp_content( rdf.body ) }}
        </div>
    </div>
{% endcreatephp %}
                    

MediaBundle

  • Basic documents
  • Controllers for showing and downloading
  • Helper for uploading
  • Adapters for 3rd-party integration
    • LiipImagine
    • elFinder
    • Gaufrette

MenuBundle

  • Integrates KnpMenu into Symfony CMF
  • Can point to content or a route

MenuBundle


{{ knp_menu_render('main-menu') }}
                    

Simple isn't it?

Even more Bundles

  • CmfTreeBrowserBundle
  • CmfBlogBundle
  • CmfSearchBundle
  • CmfSimpleCms
  • LuneticsLocaleBundle
  • SonataDoctrinePhpcrAdminBundle
  • ...

What's brewing?

1.0 has been released!

1.1 scheduled a month after Symfony 2.4

So somewhere in December

Release cycle

Who is using it?

Drupal ServerGrove
Typo3 Ez Publish

Contribute!

Questions?

  • Freenode: #symfony-cmf
  • http://cmf.symfony.com
  • symfony-cmf-devs@googlegroups.com