Accessing Magnolia CMS from PHP
Jackalope and the PHP Content Repository
Housekeeping
How to post questions
Webinar recording and slides
Contacting us
Hashtags
Agenda
Introduction
PHPCR
Integration with Magnolia
Q & A
Grégory Joseph
David Buchmann
About JCR/PHPCR Content Repository is a way to decouple storage logic from application logic
Write applications once, switch storage backends
Do not re-invent the content storage wheel
PHPCR is JCR translated to PHP, part of the upcoming JCR 2.1
Data in a CMS is mostly unstructured
RDBMS are not a good fit, hurray for NoSQL
CMS often organize content as a tree/graph
Most NoSQL not a good fit, hurray for Graph DBs
CMS should be able to store content versions
JCR / PHPCR Features
Tree access
Access by UUID
Search nodes
Versioning
Capability discovery
XML import and export
Locking & Transactions (*)
Permissions & Access Control (*)
Observation
(*) Not yet implemented in Jackalope
JCR / PHPCR concepts
Hierarchical document store
All content is stored in a tree of nodes
Nodes have a name and a type
Nodes have child nodes and properties with values
Values can be strings or numbers, but also binary file data or references to other nodes
Nodes
Think of XML elements
Can be created, deleted, modified, copied...
Must have a path (same name siblings are allowed by default)
Path is constructed by parent path and own name
For example: /my/path/under/water/fish
Parent path: /my/path/under/water
Node name: fish
Properties to store actual data (string, number, etc as well as references to other nodes)
Primary Node Types
Defines allowed names and types for properties and child nodes
Every node must have a primary node type
Use nt:unstructured to allow anything
Some other built-in types: nt:address, nt:folder, nt:file ...
Define custom types to control your "schema"
Mixin Node Types
No multiple inheritance for primary type.
Mixins bring "traits" to your nodes.
Mixin node types can be assigned to a node during that node's lifetime
Workspaces
Multiple workspaces, each with its own node tree
Each workspace is similar to a Unix file system
Workspaces are like branches in git/svn, allowing to clone and merge content
But can also be used independently
Magnolia CMS uses them to separate content, image repository and so on
Differences between JCR and PHPCR
Loose typing: No need for Value and ValueFactory
No typed RangeIterator but simple Traversable
Shortcut methods Node::getPropertyValue
Node and Property are Traversable
Various PHPCR implementations
Jackalope
Jackrabbit (Davex) transport layer
Doctrine DBAL transport layer
Midgard2 PHPCR
Magnolia and PHPCR Magnolia CMS stores data in JCR
Uses the Jackrabbit JCR implementation
PHP Jackalope uses jackrabbit for storage
Magnolia and PHPCR: Scenarios Show data from Magnolia CMS a PHP website
Update Magnolia CMS Website from PHP application
Use Symfony CMF as flexible frontend, Magnolia CMS as powerful editor
Migrate your content from PHP to Magnolia CMS or vice versa
Installation
Code along if you are watching the recorded session
Prerequisites
PHP 5.3.3 or later, including the PHP command line interface
Magnolia CMS 4.5 or later (and of course the Java interpreter)
Git version control tool (version 1.6 or later)
Setup Magnolia
Magnolia CMS Jackrabbit DavEx module (http://liip.to/magnoliajackrabbit)
Copy all .jar files from download to INSTALL_PATH/apache-tomcat-6.0.32/webapps/magnoliaAuthor/WEB-INF/lib/
Restart Magnolia CMS
Log into Magnolia CMS as superuser and accept to update the installation
Version 0.1: Enable additional HTTP methods: Configuration > server/IPConfig/allow-all/methods : GET,POST,PROPFIND,PUT,DELETE,REPORT,HEAD,SEARCH
Setup the PHP project
curl -s http://getcomposer.org/installer | php --
./composer.phar init
./composer.phar require jackalope/jackalope-jackrabbit
./composer.phar install
More information at http://jackalope.github.com/
PHPCR code examples
Connecting via PHPCR
// file test.php
require_once(__DIR__ . 'vendor/autoload.php');
$parameters = array(
'jackalope.jackrabbit_uri'
=> 'http://localhost:8080/magnoliaAuthor/.davex/'
);
$repository = Jackalope\RepositoryFactoryJackrabbit::
getRepository($parameters);
$creds = new \PHPCR\SimpleCredentials(
'superuser','superuser');
$website = $repository->login($creds, 'website');
Reading a value
$path = '/demo-project/about/history';
$node = $website->getNode($path);
$title = $node->getPropertyValue('title');
echo "$title\n";
php test.php
$ History
Read binary data
// init code as before
$repository = Jackalope\RepositoryFactoryJackrabbit::
getRepository($parameters);
$dms = $repository->login($creds, 'dms');
$path = '/demo-project/downloads/Magnolia_Flyer_4-0';
$node = $dms->getNode($path);
$properties = $node->getNode('document')
->getPropertiesValues();
echo "Found document, mime-type: " .
$properties['jcr:mimeType'] . "\n";
$filename = $properties['fileName'] . '.' .
$properties['extension'];
file_put_contents($filename, $properties['jcr:data']);
echo "Saved to $filename\n";
Saves the file to the current directory
Updating and creating properties
$path = '/demo-project/about/history';
$node = $website->getNode($path);
// update existing property
$node->setProperty('title', 'Updated Company History');
// create a new property
$node->setProperty('foo', 'bar');
// always need to save when writing to commit changes
$website->save();
Creating a new node
// add a folder node to the repository
$node = $dms->getNode('/demo-docs/internet');
$name = 'test-folder';
$type = 'mgnl:content';
$folderNode = $node->addNode($name, $type);
$folderNode->setProperty ("title", "Test Folder");
$folderNode->setProperty ("type", "folder");
// save changes
$dms->save();
Tree Traversal API
$path = '/demo-project/about/subsection-articles';
$node = $session->getNode($path);
foreach ($node->getNodes() as $child) {
if ($child->hasProperty('abstract')) {
$abstract =
$child->getPropertyValue('abstract');
echo $child->getPath() . ": $abstract\n";
}
}
Search via SQL2 API
$qm = $website->getWorkspace()->getQueryManager();
$sql = "SELECT *
FROM [mgnl:page]
WHERE ISDESCENDANTNODE('/demoproject/about')";
$query = $qm->createQuery($sql, 'JCR-SQL2');
$queryResult = $query->execute();
foreach ($queryResult->getNodes() as $node) {
if ($node->hasProperty('title')) {
$title = $node->getPropertyValue('title');
echo $node->getPath . ": $title\n";
}
}
Doctrine PHPCR ODM
VIDEO
Conclusions
Not all data fits well in PHPCR/JCR
For example aggregation is better done in an RDBMS
Store web store product description in PHPCR/JCR
Store web store inventory and orders in RDBMS
Door swings both ways, so remember
Play with it today!
See it in action!
Next steps
Release a stable version 1.0 of Jackalope
Security and ACL support
Jackrabbit Oak support
Many individuals contribute to the effort
0x616469 (Adrian Schlegel)
adou600 (Adrien Nicolet)
beberlei (Benjamin Eberlei)
bergie (Henri Bergius)
bmatzner (Bernd Matzner)
brki (Brian King)
chirimoya (Thomas Schedler)
chregu (Christian Stocker)
cordoval (Luis Cordova)
craigmarvelley (Craig Marvelley)
cryptocompress (Crypto Compress)
damz (Damien Tournoud)
dbojdo (Daniel Bojdo)
dbu (David Buchmann)
dotZoki (Zoran)
ebi (Tobias Ebnöther)
fabian (Fabian Vogler)
flojon (Jonas Flodén)
iambrosi (Ismael Ambrosi)
jakuza (Jacopo Romei)
justinrainbow (Justin Rainbow)
k-fish/kdambekalns (Karsten Dambekalns)
krizon (Kristian Zondervan)
lapistano (Bastian Feder)
lsmith77 (Lukas K. Smith)
mdekrijger
micheleorselli (Michele Orselli)
nacmartin (Nacho MartÃn)
nicam (Pascal Helfenstein)
Ocramius (Marco Pivetta)
ornicar (Thibault Duplessis)
pajooh (arash)
petesiss (Pete Sisson)
piotras
pitpit (Damien Pitard)
rande (Thomas)
richardmiller (Richard Miller)
rndstr (Roland Schilter)
robertlemke (Robert Lemke)
sebastien-roch (Sébastien Roch)
Seldaek (Jordi Boggiano)
simensen (Beau Simensen)
sixty-nine (Daniel Barsotti)
sjopet
starkj (Johannes Stark)
stof (Christophe Coevoet)
uwej711 (Uwe Jäger)
vedranzgela (Vedran Zgela)
videlalvaro (Alvaro Videla)
...
Several companies and organisations are investing into the effort
Many projects have expressed interest
Thank you !
Questions?