EXTENDING A SYMFONY APPLICATION BY CMS FEATURES
MAXIMILIAN BERGHOFF - 30.05.2017 - SYMFONY USERGROUP BERLIN
Maximilian Berghoff
@ElectricMaxxx
github.com/electricmaxxx
Maximilian.Berghoff@may ower.de
May ower GmbH - Würzburg
ONCE UPON A TIME ...
SYMFONY APPLICATION
THE LITTLE CONTENT
static content pages (legals, company info, ...)
content blocks (news, events, abstracts, ...)
content by business domain (product info, highlights, ...)
CONTENT EDITOR
EDITABLE ALL CONTENT
SEO
Editable Routing
Editable Menu Structure
CMS
Typo 3
Wordpress
Joomla
Drupal
...
DIY
Content editing
Persisting dif cult structured content
dynamic routing
i18n
SEO
Publish work ow
Nice User Interface
ONCE UPON A TIME
SYMFONY APPLICATION
FRAMEWORK
CONTENT MANAGEMENT FRAMEWORK
WHAT IS CONTENT?
text blocks
HTML snippets
Media les (images, videos, ...)
List/Containers of snippets, text or references
BEHIND THE SCENES:
PHPCR
CMF = LOTS OF PIECES
PHPCR - INTERFACE
JACKALOPE DoctrineDBAL
Jackrabbit
DOCTRINE
phpcr-odm
DoctrinePHPCRBundle
SYMFONY CMF
Components (routing, resources)
Bundles (core, routing, content, menu, ...)
ACTION
von Thiemo Schuff (Eigenes Werk) [ ],CC BY-SA 3.0 via Wikimedia
Commons
DYNAMIC ROUTING
use SymfonyCmfBundleRoutingBundleDoctrinePhpcrRoute;
NodeHelper::createPath($manager­>getPhpcrSession(), '/cms/routes');  
$routeBase = $manager­>find(null, '/cms/routes');
$route = new Route(); 
$route­>setPosition($routeBase, 'route_only');  
$route­>addDefaults(array('_controller' => 'default:routeOnlyAction'));  
$manager­>persist($route);  
$manager­>flush(); 
use SymfonyCmfBundleRoutingBundleDoctrinePhpcrRoute;
NodeHelper::createPath($manager­>getPhpcrSession(), '/cms/routes');  
$routeBase = $manager­>find(null, '/cms/routes');
$route = new Route(); 
$route­>setPosition($routeBase, 'route_only');  
$route­>addDefaults(array('_controller' => 'default:routeOnlyAction'));  
$manager­>persist($route);  
$manager­>flush(); 
use SymfonyCmfBundleRoutingBundleDoctrinePhpcrRoute;
NodeHelper::createPath($manager­>getPhpcrSession(), '/cms/routes');  
$routeBase = $manager­>find(null, '/cms/routes');
$route = new Route(); 
$route­>setPosition($routeBase, 'route_only');  
$route­>addDefaults(array('_controller' => 'default:routeOnlyAction'));  
$manager­>persist($route);  
$manager­>flush(); 
use SymfonyCmfBundleRoutingBundleDoctrinePhpcrRoute;
NodeHelper::createPath($manager­>getPhpcrSession(), '/cms/routes');  
$routeBase = $manager­>find(null, '/cms/routes');
$route = new Route(); 
$route­>setPosition($routeBase, 'route_only');  
$route­>addDefaults(array('_controller' => 'default:routeOnlyAction'));  
$manager­>persist($route);  
$manager­>flush(); 
use SymfonyCmfBundleRoutingBundleDoctrinePhpcrRoute;
NodeHelper::createPath($manager­>getPhpcrSession(), '/cms/routes');  
$routeBase = $manager­>find(null, '/cms/routes');
$route = new Route(); 
$route­>setPosition($routeBase, 'route_only');  
$route­>addDefaults(array('_controller' => 'default:routeOnlyAction'));  
$manager­>persist($route);  
$manager­>flush(); 
ADVANCED
$contentParent = $manager­>find(null, '/cms/content');  
$routeParent = $manager­>find(null, '/cms/routes');  
$menuParent = $manager­>find(null, '/cms/menu');  
 $enRoute = new Route(); 
 $enRoute­>setPosition($routeParent, 'en');  
 $manager­>persist($enRoute);  
 $deRoute = new Route();  
 $deRoute­>setPosition($routeParent, 'de');  
 $manager­>persist($deRoute);  
$enRoute = new Route(); 
$enRoute­>setPosition($routeParent, 'en');  
$manager­>persist($enRoute);  
$deRoute = new Route(); 
$deRoute­>setPosition($routeParent, 'de');  
$manager­>persist($deRoute);  
$enServiceRoute = new Route();  
$enServiceRoute­>setPosition($enRoute, 'services') ; 
$manager­>persist($enServiceRoute);
$deServiceRoute = new Route();  
$deServiceRoute­>setPosition($deRoute, 'dienstleistungen') ; 
$manager­>persist($deServiceRoute);  
$enServiceRoute = new Route();  
$enServiceRoute­>setName('services');  
$enServiceRoute­>setParentDocument($enRoute) ; 
$manager­>persist($enServiceRoute);
$deServiceRoute = new Route();  
$deServiceRoute­>setName('dienstleistungen');  
$deServiceRoute­>setParentDocument($deRoute) ; 
$manager­>persist($deServiceRoute);  
use SymfonyCmfBundleContentBundleDoctrinePhpcrStaticContent;
$content = new StaticContent();  
$content­>setParentDocument($contentParent);  
$content­>setName('symfony­service');  
$manager­>persist($content);  
$content­>setTitle('Symfony Service');  
$content­>setBody('A page about Symfony service');  
$manager­>bindTranslation($content, 'en');  
$contentRoute = new Route();  
$contentRoute­>setPosition($enServiceRoute, 'symfony­service');  
$contentRoute­>setContent($content);  
$manager­>persist($contentRoute);  
$content­>setTitle('Symfony Service');  
$content­>setBody('A page about Symfony service');  
$manager­>bindTranslation($content, 'en');  
$contentRoute = new Route();  
$contentRoute­>setPosition($enServiceRoute, 'symfony­service');  
$contentRoute­>setContent($content);  
$manager­>persist($contentRoute);  
$content­>setTitle('Symfony Service');  
$content­>setBody('A page about Symfony service');  
$manager­>bindTranslation($content, 'en');  
$contentRoute = new Route();  
$contentRoute­>setPosition($enServiceRoute, 'symfony­service');  
$contentRoute­>setContent($content);  
$manager­>persist($contentRoute);  
$content­>setTitle('Symfony Dienstleistungen');  
$content­>setBody('Eine Seite über Symfony Dienstleistungen');  
$manager­>bindTranslation($content, 'de');  
$contentRoute = new Route();  
$contentRoute­>setPosition($deServiceRoute, 'symfony­dienstleistungen');
$contentRoute­>setContent($content);  
$manager­>persist($contentRoute);  
/de/dienstleistungen/symfony-dienstleistungen
/en/services/symfony-service
cmf_routing: 
    dynamic: 
        templates_by_class: 
            ..StaticContent: ApplicationBundle:Page:index.html.twig  
    chain: 
        routers_by_id: 
            cmf_routing.dynamic_router: 200  
            router.default:             100  
$menu = new Menu(); 
$menu­>setPosition($menuParent, 'footer');  
$manager­>persist($menu);  
$menuNode = new MenuNode();  
$menuNode­>setParentDocument($menu);  
$menuNode­>setContent($content);  
$menuNode­>setName('symfony­service');  
$manager­>persist($menuNode);
$menuNode­>setLabel('Symfony Services');  
$manager­>bindTranslation($menuNode, 'en');  
$menuNode­>setLabel('Symfony Dienstleistungen');  
$manager­>bindTranslation($menuNode, 'de');  
$menuNode = new MenuNode();  
$menuNode­>setParentDocument($menu);  
$menuNode­>setContent($content);  
$menuNode­>setName('symfony­service');  
$manager­>persist($menuNode);
$menuNode­>setLabel('Symfony Services');  
$manager­>bindTranslation($menuNode, 'en');  
$menuNode­>setLabel('Symfony Dienstleistungen');  
$manager­>bindTranslation($menuNode, 'de');  
SEO
$content = new DemoSeoContent();  
$content­>setParentDocument($contentParent);  
$content­>setName('seo­service');  
$content­>setTitle('SEO Service');  
$content­>setBody('A page about SEO service');
$metaData = new SeoMetadata();  
$metaData­>setMetaDescription('Description in Metadata');  
$content­>setSeoMetadata($metaData);
$manager­>persist($content);  
use DoctrineODMPHPCRMappingAnnotations as PHPCRODM;
class DemoSeoContent extends StaticContent implements  
    SeoAwareInterface, 
    TitleReadInterface 
{
    /* @PHPCRODMChild / 
    protected $seoMetadata;  
    public function getSeoTitle()  
    {
        return 'By extractor ­ ' . $this­>getTitle();  
    }
}
CONCLUSION
QUESTIONS?
Ask Now!
Twitter: @ElectricMaxxx
Mail: Maximilian.Berghoff@may ower.de
LINKS
Website
Documentation
Mailinglist
IRC
Sandbox
Code Examples mentioned here
THANK YOU!

Extending a symfony application by cms features