THE CONTENT MANAGER LOVES THE TREE
MAXIMILIAN BERGHOFF - 13.06.2017 - PHP USERGROUP JUTLAND
Maximilian Berghoff
@ElectricMaxxx
github.com/electricmaxxx
Maximilian.Berghoff@may ower.de
May ower GmbH - Würzburg
TREE
HIERARCHICAL STRUCTURED DATA
Business Need: Editable text blocks  
Scenario: Create text blocks  
  Given a content manager 
  When he creates an arbritrary text block  
  Then then the user of the website would see it  
Scenario: Edit text blocks  
  Given a content manager 
  When he edits text block 
  Then then the user of the website would see the change  
    
Business Need: Editable text blocks  
Scenario: Create text blocks  
  Given a content manager 
  When he creates a specific text block  
  And defines a position 
  Then then the user would see it at this  position 
Scenario: Edit text blocks  
  Given a content manager 
  When he edits text block or its  position 
  Then then the user would see the in  position and content 
    
POSITION IN EINER APP
on a Page
Content
Menü (Label)
on a Page of a speci c URL
Business Need: Editable text blocks  
Scenario: Create text blocks  
  Given a content manager 
  When he creates a specific text block  
  And defines a position among the content of the page  
  Then then the user of the website would see it  
Scenario: Edit text blocks  
  Given a content manager 
  When he moves the text block among the content of a page  
  Then then the user would see the in position and content  
    
Business Need: Editable text blocks  
Scenario: Create text blocks  
  Given a content manager 
  When he creates a specific text block  
  And defines a position among the content of the page 
  Then then the user of the website would see it  
Scenario: Edit text blocks  
  Given a content manager 
  When he moves the text block  among the content of a page 
  Then then the user would see the in position and content  
    
POSITIONING IN THE CONTENT
Visual
Queue (Ein Block nach dem anderen)
Structure
<!DOCTYPE html> 
<html lang="en"> 
<head>
    <meta charset="UTF­8">  
    <title>Tree Example</title>  
</head>
<body>
    <div class="navigation">  
    </div> 
    <div class="content">  
    </div> 
    <div class="footer"></div>  
</body>
</html>
    
/content/header/content-block-1
/content/header/content-block-2
/content/main/content-block-3
/content/main/content-block-4
/content/footer/content-block-5
/content/footer/content-block-6
Business Need: Editable text blocks  
Scenario: Create text blocks  
  Given a content manager 
  When he creates a specific text block  
  And defines a position as a content path of the page 
  Then then the user of the website would see it  
Scenario: Edit text blocks  
  Given a content manager 
  When he moves the text block  
  And defines a new content path  
  Then then the user would see the in position and content  
    
THEORY
HIERARCHICAL STRUCTURED DATA IN RDBMS
ADJACENCY LIST
id parent_id name
1 NULL home
2 1 header
3 2 content-block-1
4 2 content-block-2
INSERT NODE
INSERT INTO content (parent_id, name) VALUES (2, content­block­7);  
id parent_id name
1 NULL home
2 1 header
3 2 content-block-1
4 2 content-block-2
5 2 content-block-7
MOVE NODE (SUBTREE)
UPDATE content set parent_id = 1 where id = 5;  
id parent_id name
1 NULL home
2 1 header
3 2 content-block-1
4 2 content-block-2
5 1 content-block-7
PATH ENUMERATION
id path name
1 1/ home
2 1/2/ header
3 1/2/3/ content-block-1
4 1/2/4/ content-block-2
NESTED SET
id left right name
1 1 8 home
2 2 7 header
3 3 6 content-block-1
4 4 5 content-block-2
NESTED SET - ADD
id left right name
1 1 12 home
2 2 7 header
3 3 6 content-block-1
4 4 5 content-block-2
5 8 11 main
6 9 10 content-block-3
NESTED SET - MOVE (DELETE + ADD)
id left right name
1 1 12 home
2 2 5 header
3 3 4 content-block-1
4 8 9 content-block-2
5 6 11 main
6 7 10 content-block-3
CLOSURE TABLE
CONTENT TABLE
id name
1 home
2 header
3 content-block-1
4 content-block-2
CLOSURE TABLE
MANY-TO-MANY
ancestor descendant
1 1
1 2
1 3
1 4
2 2
2 3
2 4
3 3
4 4
EXPERIMENT
LETS TRY TO USE DIRECTORIES
OPERATIONS
create a node (Folder, File)
Update Properties - i.e. the content
move a node
delete a node
get a node
CONSTRAINTS
a node has a name
a node has a path
a node has properties - i.e. content
a node can have children
UNIVERSAL INTERFACE
JCR - CONTENT REPOSITORY FOR JAVA WORLD
Describes De nition of Workspace, Session, Node and
Properties
Current Spec: 283
Persisting content as in XML
CONTENT REPOSITORY
Database for digital content
Management to search/query, add, move, delete content
hierarchical structure
Import/Export
Versioning
Locking
WHAT ABOUT PHP?
PHPCR
Porting of JCR into PHP
Interface
Implementations:
Jackrabit
Doctrine-DBAL
WORKSPACE
CR consists of one or more workspaces
Each Workspace contains an acyclic graph (tree) of items
Edges de ne parent child relation
SESSION
Connection by a user through credentials to a speci c
workspace
Possibility for Access Control for that user
Contains a complete Representation of the workspace
        $factoryclass = 'JackalopeRepositoryFactoryJackrabbit';  
        $parameters = [ 
            'jackalope.jackrabbit_uri' => ' ' 
        ]; 
        $factory = new $factoryclass();  
        $repository = $factory­>getRepository($parameters);  
        $credentials = new PHPCRSimpleCredentials('admin', 'admin');  
        $session = $repository­>login($credentials, 'default');  
    
http://localhost:8080
        $factoryclass = 'JackalopeRepositoryFactoryJackrabbit';  
        $parameters = [ 
            'jackalope.jackrabbit_uri' => ' ' 
        ]; 
        $factory = new $factoryclass();  
        $repository = $factory­>getRepository($parameters);  
        $credentials = new PHPCRSimpleCredentials('admin', 'admin');  
        $session = $repository­>login($credentials, 'default');  
    
http://localhost:8080
        $factoryclass = 'JackalopeRepositoryFactoryJackrabbit';  
        $parameters = [ 
            'jackalope.jackrabbit_uri' => ' ' 
        ]; 
        $factory = new $factoryclass();  
        $repository = $factory­>getRepository($parameters);  
        $credentials = new PHPCRSimpleCredentials('admin', 'admin');  
        $session = $repository­>login($credentials, 'default');  
    
http://localhost:8080
        $factoryclass = 'JackalopeRepositoryFactoryJackrabbit';  
        $parameters = [ 
            'jackalope.jackrabbit_uri' => ' ' 
        ]; 
        $factory = new $factoryclass();  
        $repository = $factory­>getRepository($parameters);  
        $credentials = new PHPCRSimpleCredentials('admin', 'admin');  
        $session = $repository­>login($credentials, 'default');  
    
http://localhost:8080
        $root = $session­>getRootNode();  
        $node = $root­>addNode('test', 'nt:unstructured');  
        $node­>setProperty('prop', 'value');  
        $session­>save();  
        $node = $session­>getNode('/test');  
        echo $node­>getPropertyValue('prop'); // outputs "value"  
    
        $root = $session­>getRootNode();  
        $node = $root­>addNode('test', 'nt:unstructured');  
        $node­>setProperty('prop', 'value');  
        $session­>save();  
        $node = $session­>getNode('/test');  
        echo $node­>getPropertyValue('prop'); // outputs "value"  
    
        $root = $session­>getRootNode();  
        $node = $root­>addNode('test', 'nt:unstructured');  
        $node­>setProperty('prop', 'value');  
        $session­>save();  
        $node = $session­>getNode('/test');  
        echo $node­>getPropertyValue('prop');  
         // outputs "value"  
    
        $workspace = $session­>getWorkspace();  
        $queryManager = $workspace­>getQueryManager();  
        $sql = "SELECT * FROM [nt:unstructured]  
            WHERE [nt:unstructured].[title] = 'Test'  
            ORDER BY [nt:unstructured].content";  
        $query = $queryManager­>createQuery($sql, 'JCR­SQL2');  
        $query­>setLimit(10); // limit number of results to be returned  
        $query­>setOffset(1); // set an offset to skip first n results  
        $queryResult = $query­>execute();  
        foreach ($queryResult­>getNodes() as $path => $node) {  
            echo $node­>getName();  
        } 
    
QUERYMANAGER
Ordering
Fulltext search
JOINs
Casting
DOCTRINE PHPCR
Doctrine Component
Doctrine Bundle - For Symfony Integration
SYMFONY CMF
WHEN?
hierarchical structured data
CMS features (content, menu, route)
Products and variants
WHEN NOT?
Relational data
Lots of references
CONCLUSION
QUESTIONS?
Ask Now!
Twitter: @ElectricMaxxx
Mail: Maximilian.Berghoff@may ower.de
LINKS
Website - PHPCR
Website - CMF
Documentation - PHPCR
JCR SPEC 283
THANK YOU!

The content manager loves the tree