Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

moving docs to phpcr-docs. only keeping the doc about conversion from…

… jcr to phpcr here.
  • Loading branch information...
commit 8675242b6f64da8949ce8299a6f14fd0747b90ee 1 parent e2f532d
@dbu dbu authored
View
2  README.md
@@ -26,7 +26,7 @@ There exist a couple of implementations for PHPCR that you can use. See below fo
## Further reading
-* [Tutorial](https://github.com/phpcr/phpcr/blob/master/doc/Tutorial.md)
+* [Tutorial](https://github.com/phpcr/phpcr-docs/blob/master/tutorial/Tutorial.md)
* [API Reference](http://phpcr.github.com/doc/html/index.html)
View
729 doc/Tutorial.md
@@ -1,728 +1 @@
-# PHPCR Tutorial
-
-This is an introduction into the PHP content repository. You will mostly see code examples. It should work with any PHPCR implementation. We propose using [Jackalope Jackrabbit](https://github.com/jackalope/jackalope-jackrabbit) to get started as it supports all features described here.
-
-
-## Installing Jackalope
-
-Just follow the README of the jackalope-jackrabbit repository.
-
-
-## Browser to see what is in the repository
-
-We recommend installing the [PhpcrBrowser](https://github.com/symfony-cmf/phpcrbrowser) so that you can see what data you currently have in your repository.
-
-
-# In a nutshell
-
-The shortest self-contained example should output a line with 'value':
-
- <?php
- require("/path/to/jackalope-jackrabbit/vendor/.composer/autoload.php");
-
- $factoryclass = '\Jackalope\RepositoryFactoryJackrabbit';
- $parameters = array('jackalope.jackrabbit_uri' => 'http://localhost:8080/server');
- // end of implementation specific configuration
-
- $factory = new $factoryclass();
- $repository = $factory->getRepository($parameters);
- $credentials = new \PHPCR\SimpleCredentials('admin','admin');
- $session = $repository->login($credentials, 'default');
- $root = $session->getRootNode();
- $node = $root->addNode('test', 'nt:unstructured');
- $node->setProperty('prop', 'value');
- $session->save();
-
- // data is stored now. in a follow-up request you can do
- $node = $session->getNode('/test');
- echo $node->getPropertyValue('prop'); // outputs "value"
-
-Still with us? Good, lets get in a bit deeper...
-
-## Introduction
-
-In the following chapters, we will show how to use the API. But first, you need a very brief overview of the core elements of PHPCR. After reading this tutorial, you should browse through the API documentation to get an idea what operations you can do on each of those elements. See the conclusions for links if you want to have more background.
-
-* Node, Property: An object model for data structured similar to XML. A node is like the xml element, the property like the xml attribute. Properties are acquired from their nodes or directly from the session by their path. Nodes are acquired from parent nodes or from the session by their path. Both are Item, sharing the methods of that base interface. Names can be namespaced as in xml, and additionally may contain whitespaces or other not xml-legal characters.
-* Session: The authenticated connection to one workspace in the repository. Repository and workspace are immutable inside the Session. The session is the main interface to interact with the actual data. Sessions are acquired from a repository
-* Repository: Linking to one storage location with possibly many workspaces. Repositories are created with the help of the repository factory.
-* RepositoryFactory: Create repository instances for your implementation with implementation specific parameters.
-* Workspace: Provides general operations on the workspace of the Session it is acquired from.
-
-
-Not every implementation has to support all chapters of the specification. PHPCR is a modular standard and has a built-in way to discover the capabilities of your implementation.
-TODO: Add a section about capability testing to show how to write portable code.
-
-
-### Bootstrapping
-
-You will need to make sure your php classes are available. Usually this means activating an autoloader. For a standalone project, just use the file generated by composer at vendor/.composer/autoload.php
-PHPCR and Jackalope follow the PSR-0 standard. If you want your own autoloading, use a PSR-0 compatible autoloader and configure it to find the code folder.
-
-Once you have autoloading set up, bootstrap jackalope-jackrabbit like this:
-
- // factory (the *only* implementation specific part)
- $factoryclass = '\Jackalope\RepositoryFactoryJackrabbit';
- // the parameters would typically live in a configuration file
- // see your implementation for required and optional parameters
- $parameters = array('jackalope.jackrabbit_uri' => 'http://localhost:8080/server');
-
- // end of implementation specific configuration
- // from here on, the whole code does not need to be changed when using different implementations
-
- $factory = new $factoryclass();
- $repository = $factory->getRepository($parameters);
- if (null === $repository) {
- var_dump($parameters);
- die('There where missing parameters, the factory could not create a repository');
- }
-
- // the login parameters would typically live in a configuration file
-
- $workspacename = 'default';
- $user = 'admin';
- $pass = 'admin';
-
- // create credentials and log in to get a session
- $credentials = new \PHPCR\SimpleCredentials($user, $pass);
- try {
- $session = $repository->login($credentials, $workspacename);
- } catch(\PHPCR\LoginException $e) {
- die('Invalid credentials: '.$e->getMessage());
- } catch(\PHPCR\NoSuchWorkspaceException $e) {
- die("No workspace $workspacename: ".$e->getMessage());
- }
-
- // if we get here, we have a session object that can be used to read and write the repository
-
-
-### Get some data into the repository
-
-We will discuss the import feature in more detail later, but to have some data, we just import something here. Create an XML file test.xml like this:
-
- <data>
- <node title="Test" content="This is some test content" />
- <sibling>
- <child1 title="Child1 title" />
- <child2 />
- <otherchild />
- <yetanother>
- <child />
- </yetanother>
- </sibling>
- </data>
-
-Now import this into the repository:
-
- $session->importXML('/', 'test.xml', ImportUUIDBehaviorInterface::IMPORT_UUID_CREATE_NEW);
- $session->save();
-
-
-### Reading data and traversal
-
-You can wrap any code into try catch blocks. See the [API doc](http://phpcr.github.com/doc/html/index.html) for what exceptions to expect on which calls. With PHPCR being ported from Java, there is a lot of Exceptions defined.
-But as this is PHP, you don't have to catch them. As long as your content is as the code expects, it won't matter.
-
- $node = $session->getNode('/data/node');
- echo $node->getName(); // will be 'node'
- echo $node->getPath(); // will be '/data/node'
-
-
-#### Reading properties
-
- // get the php value of a property (type automatically determined from stored information)
- echo $node->getPropertyValue('title');
-
- // get the Property object to operate on
- $property = $node->getProperty('content');
- echo 'Size of '.$property->getPath().' is '.$property->getLength();
-
- // read a property that could be very long
- $property = $node->getProperty('content');
-
- // if it is binary convert into string
- $data = $property->getString();
- echo $data;
-
- // get binary stream. could be more performant with binary property
- $stream = $property->getBinary();
- fpassthru($stream);
- fclose($stream);
-
- fpassthru($node->getPropertyValue('binary-prop')); // the above in short if you just want to dump a file that is in a binary propery
-
-Note: the backend stores the property types. When getting property values, they are returned
-with that type, unless you use one of the explicit PropertyInterface::getXX methods.
-For that case, type conversion is attempted and an exception thrown if this is not possible.
-
-See the API doc for a list of all supported types.
-
- // get all properties of this node
- foreach ($node->getPropertiesValues() as $name => $value) {
- echo "$name: $value\n";
- }
- // get the properties of this node with a name starting with 'a'
- foreach ($node->getPropertiesValues("t*") as $name => $value) {
- echo "$name: $value\n";
- }
-
-
-#### Traversing the hierarchy
-
- // getting a node by path relative to the node
- $othernode = $node->getNode('../sibling'); // /sibling
-
- // get all child nodes. the $node is Iterable, the iterator being all children
- $node = $session->getNode('/data/sibling');
- foreach ($node as $name => $child) {
- if ($child->hasProperties()) {
- echo "$name has properties\n";
- } else {
- echo "$name does not have properties\n";
- }
- }
-
- // get child nodes with the name starting with 'c'
- foreach ($node->getNodes('c*') as $name => $child) {
- echo "$name\n";
- }
-
- // get child nodes with the name starting with 'o' or ending with '2' or named 'yetanother'
- foreach ($node->getNodes(array('o*', '*2', 'yetanother')) as $name => $child) {
- echo "$name\n";
- }
-
- // get the parent node
- $parent = $node->getParent(); // /
-
- // build a breadcrumb of the node ancestry
- $node = $session->getNode('/data/sibling/yetanother');
- $i = 0;
- $breadcrumb = array();
- do {
- $i++;
- $parent = $node->getAncestor($i);
- $breadcrumb[$parent->getPath()] = $parent->getName();
- } while ($parent != $node);
- var_dump($breadcrumb);
-
-
-#### Node and property references
-
-Nodes can be referenced by unique id (if they are mix:referenceable) or by path. getValue returns the referenced node instance.
-Properties can only be referenced by path because they can not have a unique id.
-
-The test document we imported above does not contain the type information we
-need to show this example. Lets create a special one and load it into the repository with Session::importXML:
-
-
- <sv:node
- xmlns:mix="http://www.jcp.org/jcr/mix/1.0"
- xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
- xmlns:xs="http://www.w3.org/2001/XMLSchema"
- xmlns:jcr="http://www.jcp.org/jcr/1.0"
- xmlns:sv="http://www.jcp.org/jcr/sv/1.0"
- xmlns:rep="internal"
-
- sv:name="idExample"
- >
- <sv:property sv:name="jcr:primaryType" sv:type="Name">
- <sv:value>nt:unstructured</sv:value>
- </sv:property>
-
- <sv:node sv:name="target">
- <sv:property sv:name="jcr:primaryType" sv:type="Name">
- <sv:value>nt:unstructured</sv:value>
- </sv:property>
- <sv:property sv:name="jcr:mixinTypes" sv:type="Name">
- <sv:value>mix:referenceable</sv:value>
- </sv:property>
- <sv:property sv:name="jcr:uuid" sv:type="String">
- <sv:value>13543fc6-1abf-4708-bfcc-e49511754b40</sv:value>
- </sv:property>
- <sv:property sv:name="someproperty" sv:type="String">
- <sv:value>Some value</sv:value>
- </sv:property>
- </sv:node>
-
- <sv:node sv:name="source">
- <sv:property sv:name="jcr:primaryType" sv:type="Name">
- <sv:value>nt:unstructured</sv:value>
- </sv:property>
- <sv:property sv:name="reference" sv:type="WeakReference">
- <sv:value>13543fc6-1abf-4708-bfcc-e49511754b40</sv:value>
- </sv:property>
- <sv:property sv:name="path" sv:type="Path">
- <sv:value>../target/someproperty</sv:value>
- </sv:property>
- </sv:node>
-
- </sv:node>
-
-
-Now import the contents of that file instead of the other one. With this data, you can do this:
-
-
- $node = $session->getNode('/idExample/source');
- // will return you a node if the property is of type REFERENCE or WEAKREFERENCE
- $othernode = $node->getPropertyValue('reference');
-
- // force a node
- $property = $node->getProperty('reference');
- // will additionally try to resolve a PATH or NAME property and even work
- // if the property is a STRING that happens to be a valid UUID or to
- // denote an existing path
- $othernode = $property->getNode();
-
- // get a referenced property
- $property = $node->getProperty('path');
- $otherproperty = $property->getProperty();
- echo $otherproperty->getName(); // someproperty
- echo $otherproperty->getValue(); // Some value
-
-
-#### Shareable nodes
-
-Optional feature, not yet implemented in Jackalope.
-
-Graph structure instead of a tree, nodes can have more than one parent.
-
-
-#### Same name siblings
-
-Optional feature, not fully tested in Jackalope.
-
-Nodes with the same parent can have the same name. They are distinguished by an index, as in xpath.
-
-
-### Query: Search the database
-
- // get the query interface from the workspace
- $workspace = $session->getWorkspace();
- $queryManager = $workspace->getQueryManager();
-
- $sql = "SELECT * FROM [nt:unstructured]
- WHERE [nt:unstructured].[title] = 'Test'
- ORDER BY [nt:unstructured].title";
- $query = $queryManager->createQuery($sql, 'JCR-SQL2');
- $query->setLimit(10);
- $query->setOffset(10);
- $queryResult = $query->execute();
-
- foreach ($queryResult->getNodes() as $path => $node) {
- echo $node->getName();
- }
-
-
-#### Without building nodes
-
-There can be a little performance boost if you do not need to fetch the nodes
-but just want to access one value of each node.
-
- foreach ($queryResult as $path => $row) {
- echo $path . ' scored ' . $row->getScore();
-
- $row->getValue('a-value-you-know-exists');
- }
-
-Large search results can be dangerous for performance. See below for some
-performance tips.
-
-
-#### Using Query Object Model (QOM) for building complex queries
-
-PHPCR provides two languages to build complex queries. SQL2 and Query Object Model (QOM). While SQL2 expresses a query in a syntax similar to SQL, QOM expresses the query as a tree of PHPCR objects.
-
-In this section we will cover QOM. See the [JCR docs](http://phpcr.github.com/doc/html/index.html) for an exposition of both languages.
-
-You can access the QueryObjectModelFactory from the session:
-
- $qomFactory = $mySession->getWorkspace()->getQueryManager()->getQOMFactory();
-
-The QOM factory has a method to build a QOM query given four parameters, and [provides methods](http://phpcr.github.com/doc/html/phpcr/query/qom/queryobjectmodelfactoryinterface.html) to build these four parameters:
-
- $queryObjectModel = $QOMFactory->createQuery(SourceInterface source, ConstraintInterface constraint, array orderings, array columns);
-
-`source` is made out of one or more selectors. Each selector selects a subset of nodes. Queries with more than one selector have joins. A query with two selectors will have a join, a query with three selectors will have two joins, and so on.
-
-`constraint` filters the set of node-tuples to be retrieved. Constraint may be combined in a tree of constraints to perform a more complex filtering. Examples of constraints are:
-
-* Absolute or relative paths: nodes descendant of a path, nodes children of a path, nodes reachable by a path.
-* Name of the node.
-* Value of a property.
-* Length of a property.
-* Existence of a property.
-* Full text search.
-
-`orderings` determine the order in which the filtered node-tuples will appear in the query results. The relative order of two node-tuples is determined by evaluating the specified orderings, in list order, until encountering an ordering for which one node-tuple precedes the other.
-
-`columns` are the columns to be included in the tabular view of query results. If no columns are specified, the columns available in the tabular view are implementation determined. In Jackalope include, for each selector, a column for each single-valued non-residual property of the selector's node type.
-
-The simplest case is to select all `[nt:unstructured]` nodes:
-
- $source = $qomFactory->selector('[nt:unstructured]');
- $query = $qomFactory->createQuery($source, null, array(), array());
-
-
-#### The Query Builder: a fluent interface for QOM
-
-Sometimes you may prefer to build a query in several steps. For that reason, the phpcr-utils library provides a fluent wrapper for QOM: the QueryBuilder. It works with any PHPCR implementation.
-
-An example of query built with QueryBuilder:
-
- use PHPCR\Query\QOM\QueryObjectModelConstantsInterface;
- use PHPCR\Util\QOM\QueryBuilder;
-
- $qf = $qomFactory;
- $qb = new QueryBuilder($qomFactory);
- //add the source
- $qb->from($qomFactory->selector('nt:unstructured'))
- //some composed constraint
- ->andWhere($qf->comparison($qf->propertyValue('title'),
- QueryObjectModelConstantsInterface::JCR_OPERATOR_EQUAL_TO,
- $qf->literal('Test')))
- //orderings
- ->orderBy($qf->propertyValue('title'))
- //set an offset
- ->setFirstResult(15)
- //and the maximum number of node-tuples to retrieve
- ->setMaxResults(25);
- $result = $qb->execute();
-
-
-### Writing data
-
-With PHPCR, you never use 'new'. The node works as a factory to create new nodes and properties. This has the nice side effect that you can not add a node where there is no parent.
-
-Everything you do on the Session, Node and Property objects is only visible locally in this session until you save the session.
-
- // add a new node as child of $node
- $newnode = $node->addNode('new node', 'nt:unstructured'); // until we have shown node types, just use nt:unstructured as type
-
- // set a property on the new node
- $newproperty = $newnode->setProperty('my property', 'my value');
-
- // persist the changes permanently. now they also become visible in other sessions
- $session->save();
-
-
- // have a reference
- $targetnode = $session->getNode('/data/siblings/yetanother');
-
- // make sure the target node is referenceable.
- $targetnode->addMixin('mix:referenceable');
- // depending on the implementation, you might need to save the session at
- // this point to have the identifier generated
-
- // add a reference property to the node. because the property value is a
- // Node, PHPCR will automatically detect that you want a reference
- $node->setProperty('my reference', $targetnode);
-
- $session->save();
-
-
-#### Moving and deleting nodes
-
- // move the node yetanother and all its children from its parent /sibling to
- // the new parent /sibling/child1
- // the target parent must already exist, it is not automatically created
- // as the move includes the target name, it can also be used to rename nodes
- $session->move('/data/sibling/yetanother', '/data/sibling/child1/yetanother');
-
- // for this session, everything that was at /sibling/yetanother is now under /sibling/child1/yetanother
- // i.e. /sibling/child1/yetanother/child
- // once the session is saved, the move is persisted and visible in other sessions
-
- // immediatly move the node in the persistent storage
- $workspace = $session->getWorkspace();
- $workspace->move('/data/sibling/yetanother', '/data/sibling/child1/yetanother');
-
- // copy a node and its children (only available on workspace, not inside session)
- $workspace->copy('/data/sibling/yetanother', '/data/sibling/child1/yetanother');
-
- // delete a node
- $session->removeItem('/data/sibling/child1/yetanother');
-
-
-#### Orderable child nodes
-
-While moving is about changing the parent of a node, ordering is used to set the
-position inside the child list. Preserving and altering order is an optional
-feature of PHPCR.
-
-The only method needed is Node::orderBefore
-
- $node->addNode('first');
- $node->addNode('second'); // new nodes are added to the end of the list
- // order is: first, second
-
- // ordering is done on the parent node. the first argument is the name of
- // the child node to be reordered, the second the name of the node to moved
- // node is placed before
- $node->orderBefore('second', 'first');
- // now the order is: second, first
-
-
-### Versioning
-
-Versioning is used to track changes in nodes with the possibility to get back to older versions.
-
-A node with the mixin type mix:versionable or mix:simpleVersionable can be
-versioned. Versioned nodes have a version history, containing the root version
-and all versions created. Each version contains the meta data (previous
-versions, next versions and creation date) and provides a snapshot of the node
-at that point, called "frozen node".
-
- $node->setProperty('foo', 'fafa');
- // mark the node as versionable
- $node->addMixin('mix:versionable');
-
- // version operations are done through the VersionManager
- $versionManager = $session->getWorkspace()->getVersionManager();
-
- // put the versionable node into edit mode
- $versionManager->checkout($node->getPath());
- $node->setProperty('foo', 'bar'); // need a change to see something
- $session->save(); // you can only create versions of saved nodes
- // create a new version of the node with our changes
- $version = $versionManager->checkin($node->getPath());
- // Version extends the Node interface. The version is the node with additional functionality
-
- // walk back the versions
- $oldversion = $version->getLinearPredecessor();
- // the version objects are just the meta data. call getFrozenNode on them
- // to get a snapshot of the data when the version was created
- echo $version->getName() . ': ' . $version->getFrozenNode()->getPropertyValue('foo'); // 1.0: bar
- echo $oldversion->getName() . ': ' . $oldversion->getFrozenNode()->getPropertyValue('foo'); // jcr:rootVersion: fafa
-
- // get the full version history
- $history = $versionManager->getVersionHistory($node->getPath());
- foreach ($history->getAllFrozenNodes() as $node) {
- echo $node->getPropertyValue('foo');
- }
-
- // restore an old version
- $node->setProperty('foo', 'different');
- $session->save(); // restoring is only possible if the session is clean
- $current = $versionManager->getBaseVersion($node->getPath());
- $versionManager->restore(true, $current);
- echo $node->getProperty('foo'); // fafa
-
-
-### Locking
-
-In PHPCR, you can lock nodes to prevent concurrency issues. There is two basic types of locks:
-
-* Session based locks are only kept until your session ends and released automatically on logout.
-* If a lock is not session based, it is identified by a lock token and stays in place until it times out
-
-Note that jackalope currently only implements session based locks.
-
- // get the lock manager
- $workspace = $session->getWorkspace();
- $lockManager = $workspace->getLockManager();
- var_dump($lockManager->isLocked('/data/sibling')); // should be false
- $lockManager->lock('/data/sibling', true, true); // lock child nodes as well, release when session closed
- // now only this session may change the node //sibling and its descendants
- var_dump($lockManager->isLocked('/data/sibling')); // should be true
- var_dump($lockManager->isLocked('/data/sibling/child1')); // should be true because we locked deep
-
- $lock = $lockManager->getLock('/data/sibling');
- var_dump($lock->isLockOwningSession()); // true, this is our lock, not somebody else's
- var_dump($lock->getSecondsRemaining()); // PHP_INT_MAX because this lock has no timeout
- var_dump($lock->isLive()); // true
-
- $node = $lock->getNode(); // this gets us the node for /sibling
- $node === $lockManager->getLock('/data/sibling')->getNode(); // getnode always returns the lock owning node
-
- $lockManager->unlock('/data/sibling'); // we could also let $session->logout() unlock when using session based lock
- var_dump($lockManager->isLocked('/data/sibling')); // false
- var_dump($lock->isLive()); // false
-
-
-### Transactions
-
-The PHPCR API in itself uses some sort of 'transaction' model by only
-persisting changes on session save. If you need transactions over more than one
-save operation or including workspace operations that are dispatched immediatly,
-you can use transactions.
-
-Note that Jackalope does not support the full transactions.
-
- // get the transaction manager.
- $workspace = $session->getWorkspace()
- $transactionManager = $workspace->getTransactionManager();
- // start a transaction
- $transactionManager->begin();
- $session->removeNode('/data/sibling');
- $session->getRootNode()->addNode('insideTransaction');
- $session->save(); // wrote to the backend but not yet visible to other sessions
- $workspace->move('/data/node', '/new'); // will only move the new node if session has been saved. still not visible to other sessions
- $transactionManager->commit(); // now everything become persistent and visible to others
-
- // you can abort a transaction
- try {
- ...
- } catch(\Exception $e) {
- if ($transactionManager->inTransaction()) {
- $transactionManager->rollback();
- }
- ...
- }
-
-
-### Import and export data
-
-As promised, here are some more details on importing and exporting data. There
-are two formats:
-
-* The *document view* translates the data into a XML document with node names
- as xml elements and properties as attributes and thus very readable. Type
- information is lost, and illegal XML characters are encoded.
-* The *system view* is a more strict XML document defining the exact structure
- of the repository with all type information. However, it is more verbose.
-
-As an analogy, think about an SQL dump file with SQL statements and the dump of
-an SQL table into a csv file. You can restore the data from both, but the SQL
-dump knows every detail about your field types and so on while the CSV just
-knows the data.
-
-When exporting, you tell explicitly to which format you want to export.
-
- $file = fopen('/tmp/document.xml', 'w+');
-
- // dump the tree at /foo/bar into a document view file
- $session->exportDocumentView(
- '/data/sibling',
- $file,
- true // skip binary properties to not have large files in the dump
- false // recursivly output the child nodes as well
- );
-
- $file = fopen('/tmp/system.xml', 'w+');
- // export the tree at /foo/bar into a system view xml file
- $session->exportSystemView(
- '/',
- $file,
- false // do not skip binary properties
- false
- );
-
-Importing detects the format automatically. If the document is a valid JCR
-system view, it is interpreted according to that format, otherwise if it is a
-valid XML document it is imported as document.
-
- $filename = 'dump.xml';
- $session->getRootNode()->addNode('imported_data', 'nt:unstructured');
- $session->importXML(
- '/imported_data', // attach the imported data at this node
- $filename,
- ImportUUIDBehaviorInterface::IMPORT_UUID_CREATE_NEW
- );
-
-When importing nodes with a uuid, a couple of different behaviors can be used:
-
-* IMPORT_UUID_CREATE_NEW: Create new UUIDs for nodes that are imported, so you never get collisions.
-* IMPORT_UUID_COLLISION_THROW: Throw an exception if a node with the same UUID already exists.
-* IMPORT_UUID_COLLISION_REMOVE_EXISTING: Remove an existing node if an imported node has the same UUID.
-* IMPORT_UUID_COLLISION_REPLACE_EXISTING: Replace existing node with the imported node. This can lead to the imported data being put in various places.
-
-
-### Observation
-
-Observation enables an application to receive notifications of persistent changes to a workspace.
-JCR defines a general event model and specific APIs for asynchronous and journaled observation.
-A repository may support asynchronous observation, journaled observation or both.
-
-Note that Jackrabbit supports the full observation API but Jackalope currently only implements event journal reading.
-
-Write operations in Jackalope will generate journal entries as expected.
-
- use PHPCR\Observation\EventInterface; // Contains the constants for event types
-
- // Get the observation manager
- $workspace = $session->getWorkspace();
- $observationManager = $workspace->getObservationManager();
-
- // Get the unfiltered event journal and go through its content
- $journal = $observationManager->getEventJournal();
- $journal->skipTo(strtotime('-1 day'); // Skip all the events prior to yesterday
- foreach ($journal as $event) {
- // Do something with $event (it's a Jackalope\Observation\Event instance)
- echo $event->getType() . ' - ' . $event->getPath()
- }
-
- // Filtering and using the journal as an iterator
- // You can filter the event journal on several criteria, here we keep events for node and properties added
- $journal = $observationManager->getEventJournal(EventInterface::NODE_ADDED | EventInterface::PROPERTY_ADDED);
-
- while ($journal->valid()) {
- $event = $journal->current();
- // Do something with $event
- $journal->next();
- }
-
-
-### Node Types
-
-PHPCR supports node types. Node types define what properties and children a node can or must have. The JCR specification explains exhaustivly what node types exist and what they are required to have or not.
-
-In a nutshell:
-* nt:unstructured does not define any required properties but allows any property or child.
-* nt:file and nt:folder are built-in node types useful to map a file structure in the repository. (With jackalope-jackrabbit, files and folders are exposed over webdav)
-* for your own things, use nt:unstructured and PHPCR will behave like a NoSQL database
-* if you need to store additional properties or children on existing node types like files, note that while a node can have only one primary type, every node can have any mixin types. Define a mixin type declaring your additional properties, register it with PHPCR and addMixin it to the nodes that need it.
-
-
-## Performance considerations
-
-While PHPCR can perform reasonably well, you should be careful. You are working with an object model mapping interlinked data. Implementations are supposed to lazy load data only when necessary. But you should take care to only request what you actually need.
-
-The implementations will also use some sort of storage backend (Jackrabbit, (no)SQL database, ...). There might be a huge performance impact in configuring that storage backend optimally. Look into your implementation documentation if there are recommendations how to optimize storage.
-
-One thing *not* to worry about is requesting the same node with Session::getNode or Node::getNode/s several times. You always get the same object instance back without overhead.
-
-
-### Only request what you need
-
-Remember that you can filter nodes on Node::getNodes if you only need a list of specific nodes or all nodes in some namespace.
-
-The values of binary properties can potentially have a huge size and should only loaded when really needed. If you just need the size, you can get the property instance and do a $property->getSize() instead of filesize($node->getPropertyValue). Any decent implementation will not preload the binary stream when you access the property object.
-
-When getting the properties from a node, you can use Node::getPropertiesValues(filter, false). This allows the implementation to avoid instantiating Property objects for the property values (and saves you coding). The second boolean parameter tells wheter to dereference reference properties. If you do not need the referenced objects, pass false and you will get the UUID or path strings instead of node objects.(If you need one of them, you can still get it with Session::getNodeByIdentifier. But then the implementation will certainly not be able to optimize if you get several referenced nodes.)
-
-
-### But request in one call as much as possible of what you need
-
-If you need to get several nodes where you know the paths, use Session::getNodes with an array of those nodes to get all of them in one batch, saving round trip time to the storage backend.
-
-Also use Node::getNodes with a list of nodes rather than repeatedly calling Node::getNode.
-
-
-### Search
-
-TODO: intelligent filtering criteria to do as little in-memory operations to apply criteria.
-
-If you do not need the node objects but just some value, query for that value and use the result Row to avoid instantiating Node objects alltogether. If you need the Node objects, help PHPCR to optimize by using QueryResult::getNodes and iterating over the nodes instead of getting the rows, iterating over them and calling getNode on each row. (Actually, if you first do the getNodes(), you can then iterate over the rows and get the individual nodes and still use the special row methods as the implementation should have prefetched data on the getNodes.)
-
-
-## Conclusions
-
-We hope this tutorial helps to get you started. If you miss anything, have suggestions or questions, please contact us on jackalope-dev@googlegroups.com or #jackalope on irc.freenode.net
-
-### Further reading
-
-Browse through the [API documentation](http://phpcr.github.com/doc/html/index.html) to see what each of the core elements mentioned in the introduction can do.
-
-To fully understand the concepts behind the content repository API, we suggest reading [the Java content repository specification](http://www.day.com/specs/jcr/2.0/index.html) and
-then the [simplifications we did for PHP](https://github.com/phpcr/phpcr/blob/master/doc/JCR_TO_PHPCR.txt).
-
-
-### Not yet implemented
-
-A couple of other advanced functionalities are defined by the API. They are not yet implemented in any PHPCR implementation. This document will be updated once there is an implementation for them.
-
-* Permissions and capabilities
-* Access control management
-* Lifecycle managment
-* Retention and hold
+THIS TUTORIAL HAS BEEN MOVED TO [phpcr-docs](https://github.com/phpcr/phpcr-docs/blob/master/tutorial/Tutorial.md)
View
BIN  doc/slides/JCRvsRDBMSvsNoSQL.png
Deleted file not rendered
View
BIN  doc/slides/content_graph.png
Deleted file not rendered
View
BIN  doc/slides/liip_ch_website.png
Deleted file not rendered
View
BIN  doc/slides/phpcr.png
Deleted file not rendered
View
BIN  doc/slides/phpcr_companies.png
Deleted file not rendered
View
BIN  doc/slides/phpcr_projects.png
Deleted file not rendered
View
630 doc/slides/slides.html
@@ -1,630 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
-
- <!-- To render these slides you need Slippy https://github.com/Seldaek/slippy -->
-
- <title>PHPCR Introduction</title>
-
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-
- <meta name="author" content="PHPCR" />
- <meta name="email" content="phpcr-users@googlegroups.com" />
- <meta name="date" content="2012-03-22" />
- <meta name="venue" content="The Internets" />
-
- <!-- Slippy core file and dependencies -->
- <script type="text/javascript" src="jquery.min.js"></script>
- <script type="text/javascript" src="jquery.history.js"></script>
- <script type="text/javascript" src="slippy.js"></script>
- <!-- Slippy structural styles -->
- <link type="text/css" rel="stylesheet" href="slippy.css"/>
- <!-- Slippy theme -->
- <link type="text/css" rel="stylesheet" href="slippy-pure.css"/>
- <!-- Syntax highlighting core file -->
- <script type="text/javascript" src="highlighter/shCore.js"></script>
- <!-- Syntax highlighting brushes, remove those you don't need -->
- <script type="text/javascript" src="highlighter/shBrushPhp.js"></script>
- <script type="text/javascript" src="highlighter/shBrushPlain.js"></script>
- <script type="text/javascript" src="highlighter/shBrushXml.js"></script>
- <!-- Syntax highlighting styles-->
- <link type="text/css" rel="stylesheet" href="highlighter/shCore.css"/>
- <link type="text/css" rel="stylesheet" href="highlighter/shThemeEclipse.css"/>
-
- <style type="text/css">
- body > * {
- font-size: 1.2em;
- }
-
- body {
- background: #fff;
- }
-
- div.syntaxhighlighter {
- background: #aaa !important;
- }
-
- span.file {
- font-size: 0.8em;
- color: #f00;
- float: right;
- margin: -.2em .5em 0 0;
- }
-
- .smallcode {
- font-size: 0.8em;
- }
-
- strong {
- color: #662222;
- }
-
- li {
- line-height: 1.2em;
- }
- </style>
- <!-- Slippy init code -->
- <script type="text/javascript">
- $(function() {
- $(".slide").slippy({
- });
- SyntaxHighlighter.all();
- });
- </script>
- </head>
-
- <body>
- <div class="slide" style="text-align:center">
- <h1>PHP Content Repository Specification</h1>
- <h1><a href="http://phpcr.github.com">phpcr.github.com</a></h1>
- </div>
-
- <div class="slide" style="text-align:center">
- <h2>Data in a CMS is mostly unstructured</h2>
- <h2>RDBMS are not a good fit, hurray for NoSQL</h2>
- <h2><img src="square_in_a_circle.png" alt="like fitting a square into a circle" /></h2>
- </div>
-
- <div class="slide" style="text-align:center">
- <h2>CMS often organize content as a tree/graph</h2>
- <h2>Most NoSQL not a good fit, hurray for Graph DBs</h2>
- <h2><img src="content_graph.png" alt="content graph" /></h2>
- </div>
-
- <div class="slide" style="text-align:center">
- <h2>CMS should be able to store content versions</h2>
- <h2><img src="versioning.png" alt="multiple versions" /></h2>
- </div>
-
- <div class="slide" style="text-align:center">
- <h2>Complexity shouldn't overwhelm developers</h2>
- <p style="font-size:1.3em;">Need a solution that can scale both from small to large projects and we rather not reinvent the wheel!</p>
- </div>
-
- <div class="slide">
- <h2 style="text-align:center">Enter PHPCR</h2><br/>
- <p style="font-size:1.2em;">PHPCR provides a <strong>standardized API</strong> that can be used by any PHP content management system to interface with any content repository.</p>
- </div>
-
- <div class="slide">
- <h2 style="text-align:center">About PHPCR</h2><br/>
- <ul>
- <li>Java Content Repository (JCR) standard adaptation</li>
- <li>Write applications once, switch storage backends</li>
- <li>Do not re-invent the content storage wheel</li>
- <li>PHPCR has been <a href="http://java.net/jira/browse/JSR_333-28" target="_blank">added</a> to the JCR 2.1 spec at the request of David Nüschler, JCR spec lead</li>
- </ul>
- </div>
-
- <div class="slide">
- <h2>PHPCR implementations</h2>
- <ul>
- <li>Jackalope
- <ul>
- <li>Jackrabbit (Davex) transport layer</li>
- <li>Doctrine DBAL transport layer</li>
- <li>MongoDB transport layer</li>
- </ul>
- </li>
- <li>Midgard2 PHPCR</li>
- <li>...</li>
- </ul>
- </div>
-
- <div class="slide">
- <h2>PHPCR Features</h2>
- <ul>
- <li>Tree access</li>
- <li>Access by UUID</li>
- <li>Search nodes</li>
- <li>Versioning</li>
- <li>Capability discovery</li>
- <li>XML import and export</li>
- <li>Locking &amp; Transactions</li>
- <li>Permissions &amp; Access Control (*)</li>
- <li>Observation</li>
- </ul>
- <br/>
- <p>(*) Not yet implemented in Jackalope</p>
- </div>
-
- <div class="slide">
- <h1>PHPCR concepts</h1>
- </div>
-
- <div class="slide">
- <h2>Hierarchical document store</h2>
- <ul>
- <li>All content is stored in a tree of nodes</li>
- <li>Nodes have a name and a type</li>
- <li>Nodes have child nodes and properties with values</li>
- <li>Values can be strings or numbers, but also binary file data or references to other nodes</li>
- </ul>
- </div>
-
- <div class="slide">
- <h2>Nodes</h2>
- <ul>
- <li>Think of XML elements</li>
- <li>Can be created, deleted, modified, copied...</li>
- <li>Must have a path (same name siblings are allowed by default)</li>
- <li>Path is constructed by the parents path and their own name<br/>&nbsp;
- <ul>
- <li>For example: <tt>/my/path/under/water/fish</tt><br/>&nbsp;</li>
- <li>Parent path: <tt>/my/path/under/water</tt></li>
- <li>Node name: <tt>fish</tt></li>
- </ul>
- </li>
- </ul>
- </div>
-
- <div class="slide">
- <h2>Properties</h2>
- <ul>
- <li>A <strong>Node</strong> has named <strong>Properties</strong> with values</li>
- <li>May use namespaces to avoid name collisions
- <ul><li>jcr:created, jcr:mimeType, phpcr:class</li></ul>
- </li>
- <li>Use one of the following types
- <ul><li>STRING, URI, BOOLEAN, LONG, DOUBLE, DECIMAL, BINARY, DATE, NAME, PATH, WEAKREFERENCE, REFERENCE</li></ul>
- </li>
- </ul>
- </div>
-
- <div class="slide">
- <h2>Primary Node Types</h2>
- <ul>
- <li>Defines allowed names and types for properties and child nodes</li>
- <li>Every node must have a primary node type</li>
- <li>Use <tt>nt:unstructured</tt> to allow anything</li>
- <li>Some other built-in types: <tt>nt:address, nt:folder, nt:file</tt> ...</li>
- <li>Define custom types to control your "schema"</li>
- </ul>
- </div>
-
- <div class="slide">
- <h2>Mixin Node Types</h2>
- <ul>
- <li>No multiple inheritance for primary type.</li>
- <li>Mixins bring traits to your nodes.</li>
- <li>Mixin node types can be assigned to a node during that node's lifetime</li>
- </ul>
- </div>
-
- <div class="slide">
- <h2>Mixin Node Type Examples</h2>
- <ul>
- <li>mix:referenceable implies availability of property
- <ul>
- <li><tt>jcr:uuid</tt> containing a unique id</li>
- </ul>
- </li>
- <li>mix:versionable extends mix:referenceable, implies availability of additional properties
- <ul>
- <li><tt>jcr:versionHistory, jcr:predecessors, jcr:baseVersion, jcr:isCheckedOut, jcr:mergeFailed</tt> properties)</li>
- </ul>
- </li>
- </ul>
- </div>
-
- <div class="slide">
- <h2>Workspaces</h2>
- <ul>
- <li>Multiple workspaces, each with its own node tree</li>
- <li>Each workspace is similar to a Unix file system</li>
- <li>Workspaces are like branches in git/svn, allowing to clone and merge content</li>
- <li>But can also be used independently</li>
- </ul>
- </div>
-
- <div class="slide" style="text-align:center">
- <h2>PHPCR</h2>
- <p><img src="phpcr.png" alt="PHPCR class interaction diagramm" />
- <small style="white-space: nowrap; float:right; font-size: 16pt;">Source: phpcr.github.com</small></p>
- </div>
-
- <div class="slide">
- <h1>PHPCR code examples</h1>
- </div>
-
- <div class="slide">
- <h2>Connecting via PHPCR</h2>
- <pre class="brush: php">
- // start of implementation specific configuration //
- use Jackalope\RepositoryFactoryJackrabbit as Factory;
-
- $parameters = array(
- 'jackalope.jackrabbit_uri'
- => 'http://localhost:8080/server'
- );
-
- $repository = Factory::getRepository($parameters);
- // end of implementation specific configuration //
-
- $creds = new \PHPCR\SimpleCredentials('user','pw');
- $session = $repository->login($creds, 'default');
- </pre>
- </div>
-
- <div class="slide">
- <h2>CRUD operations</h2>
- <pre class="brush: php">
- $root = $session->getRootNode();
-
- // Node always added as child of another node
- $node = $root->addNode('test', 'nt:unstructured');
- // new node is immediately available in memory
- $node = $session->getNode('/test');
-
- // Create or update a property
- $node->setProperty('prop', 'value');
-
- // Persist the changes, /test is now available for all sessions
- $session->save();
-
- // Delete a node and all its children
- $node->remove();
- $session->save();
- </pre>
- </div>
-
- <div class="slide">
- <h2>Tree Traversal API</h2>
- <pre class="brush: php">
- $node = $session->getNode('/site/content');
-
- foreach ($node->getNodes() as $child) {
- var_dump($child->getName());
- }
-
- // or in short
- foreach ($node as $child) {
- var_dump($child->getName());
- }
-
- // filter on node names
- foreach ($node->getNodes('di*') as $child) {
- var_dump($child->getName());
- }
- </pre>
- </div>
-
- <div class="slide">
- <h2>Versioning API</h2>
- <pre class="brush: php">
- // make versionable
- $node = $session->getNode('/site/content/about');
- $node->addMixin('mix:versionable');
- $session->save();
-
- $vm = $session->getWorkspace()->getVersionManager();
-
- $node->setProperty('title', 'About');
-
- // create initial version
- $session->save();
-
- // check-in (create version)
- // and check-out (prepare for further updates)
- // persisted immediately without a save() call
- $vm->checkpoint($node->getPath());
- </pre>
- </div>
-
- <div class="slide">
- <h2>Versioning API</h2>
- <pre class="brush: php">
- // update node with some changes
- $node->setProperty('title', 'Ups');
- $session->save();
-
- // create another version, leave in read only state
- $vm->checkin($node->getPath());
-
- $base = $vm->getBaseVersion($node->getPath());
- $current = $base->getLinearPredecessor();
- $previous = $current->getLinearPredecessor();
-
- // get snapshot of old version to look around
- $frozenNode = $previous->getFrozenNode();
- echo $frozenNode->getProperty('title'); // About
-
- // set the live data back to what is in this version
- $vm->restore(true, $previous);
-
- $node = $session->getNode('/site/content/about');
- echo $node->getProperty('title'); // About
- </pre>
- </div>
-
- <div class="slide">
- <h2>Search via SQL2 API</h2>
- <pre class="brush: php">
- $qm = $workspace->getQueryManager();
-
- // unlike SQL, in SQL2 "*" does not return all columns
- // but at least the path and match score
- $sql = "SELECT * FROM [nt:unstructured]
- WHERE [nt:unstructured].type = 'nav'
- AND ISDESCENDANTNODE('/some/path')
- ORDER BY score, [nt:unstructured].title";
- $query = $qm->createQuery($sql, 'JCR-SQL2');
- $query->setLimit($limit);
- $query->setOffset($offset);
- $queryResult = $query->execute();
-
- foreach ($queryResult->getNodes() as $node) {
- var_dump($node->getPath());
- }
- </pre>
- </div>
-
- <div class="slide">
- <h2>Search via QOM API</h2>
- <pre class="brush: php">
- $qm = $workspace->getQueryManager();
- $factory = $qm->getQOMFactory();
-
- // SELECT * FROM nt:file INNER JOIN nt:folder ON ISCHILDNODE(child, parent)
- $factory->createQuery(
- $factory->join(
- $factory->selector('nt:file'),
- $factory->selector('nt:folder'),
- Constants::JCR_JOIN_TYPE_INNER,
- $factory->childNodeJoinCondition('child', 'parent')),
- null,
- array(),
- array());
- </pre>
- </div>
-
- <div class="slide">
- <h2>Search via Fluent Query API</h2>
- <p>(With phpcr-utils)</p>
- <pre class="brush: php">
- $qm = $workspace->getQueryManager();
- $factory = $qm->getQOMFactory();
-
- // SELECT * FROM nt:unstructured WHERE name NOT IS NULL
- $qb = new QueryBuilder($factory);
- $qb->select($factory->selector('nt:unstructured'))
- ->where($factory->propertyExistence('name'))
- ->setFirstResult(10)
- ->setMaxResults(10)
- ->execute();
- </pre>
- </div>
-
- <div class="slide">
- <h2>Quality</h2>
- <p style="font-size:1.2em">A test suite for PHPCR makes sure all implementations interpret the specification the same way.</p>
- <ul>
- <li>Higher quality of implementations</li>
- <li>Discover interpretation issues, better compatibility</li>
- <li>Implementors need to write less tests of their own</li>
- </ul>
- </div>
-
- <div class="slide">
- <h2>Quality</h2>
-
- <p style="font-size:1.2em">Test results using Jackalope with the Jackrabbit backend.</p>
- <pre style="font-size:0.8em; margin-top:20px">
-Soitgoes:jackalope-jackrabbit lsmith$ phpunit -c tests/phpunit.xml.dist
-PHPUnit 3.6.5 by Sebastian Bergmann.
-
-.........................................SSS..............I.I 61 / 1088 ( 5%)
-.I.I........................I...............I..I........SI... 122 / 1088 ( 11%)
-............................................................. 183 / 1088 ( 16%)
-.S.......I....................S..S........................... 244 / 1088 ( 22%)
-........SS...............SSSS..S............................. 305 / 1088 ( 28%)
-.......................................SSSSS................. 366 / 1088 ( 33%)
-.......S..............I......S..........I.................... 427 / 1088 ( 39%)
-....SS..................S.................................... 488 / 1088 ( 44%)
-............................................................. 549 / 1088 ( 50%)
-............................................................. 610 / 1088 ( 56%)
-......S..............................S....................... 671 / 1088 ( 61%)
-...........................................SSSSSS..S......... 732 / 1088 ( 67%)
-S.....II...............S.S................................... 793 / 1088 ( 72%)
-......SSSS.S.......S......................................... 854 / 1088 ( 78%)
-............................................................. 915 / 1088 ( 84%)
-............................................................. 976 / 1088 ( 89%)
-............................................................. 1037 / 1088 ( 95%)
-..............................................S..
-
-Time: 01:06, Memory: 184.50Mb
-
-OK, but incomplete or skipped tests!
-Tests: 1077, Assertions: 5979, Incomplete: 13, Skipped: 43.
- </pre>
- </div>
-
- <div class="slide">
- <h2>Quality</h2>
-
- <p style="font-size:1.2em">Test results using Jackalope with the Doctrine DBAL backend.</p>
- <pre style="font-size:0.8em; margin-top:20px">
-Soitgoes:jackalope-doctrine-dbal lsmith$ phpunit -c tests/phpunit.xml.dist
-Updating schema...done.
-PHPUnit 3.6.5 by Sebastian Bergmann.
-
-.......................S.S..............I.I.I.I................ 63 / 709 ( 8%)
-........I...............I..I........SI.......................S. 126 / 709 ( 17%)
-........................................S.......I.............. 189 / 709 ( 26%)
-......S..S...................................SS.........S.....S 252 / 709 ( 35%)
-SSS..S......SS..............................................S.. 315 / 709 ( 44%)
-...........SSSSS.......S..S..S.........SS.......S....S.I......S 378 / 709 ( 53%)
-..S.......IS................SSSSSSSSSSSSSSSSSSS.......S........ 441 / 709 ( 62%)
-...........S................................................... 504 / 709 ( 71%)
-............................................................... 567 / 709 ( 79%)
-.............................................................SS 630 / 709 ( 88%)
-.SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 693 / 709 ( 97%)
-SSSSSSSSSSSSI
-
-Time: 13 seconds, Memory: 177.25Mb
-
-OK, but incomplete or skipped tests!
-Tests: 617, Assertions: 4660, Incomplete: 12, Skipped: 130.
- </pre>
- </div>
-
- <div class="slide">
- <h1>Doctrine PHPCR ODM</h1>
- <ul>
- <li>Object - Document mapper to map plain php objects to phpcr data</li>
- <li>Supports the phcpr concepts like children and references</li>
- <li><a href="http://cmf.symfony.com/slides/doctrine-phpcr-odm.html">See the phpcr-odm slides</a></li>
- </ul>
- </div>
-
- <div class="slide">
- <h1>Conclusions</h1>
- </div>
-
- <div class="slide">
- <h2>Not all data fits well in PHPCR/JCR</h2>
- <ul>
- <li>For example aggregation is better done in an RDBMS</li>
- <li>Store web store product description in PHPCR/JCR</li>
- <li>Store web store inventory and orders in RDBMS</li>
- </ul>
- </div>
-
- <div class="slide" style="text-align:center">
- <h2>Door swings both ways, so remember</h2>
- <h2><img src="square_in_a_circle.png" alt="like fitting a square into a circle" /></h2>
- </div>
-
- <div class="slide" style="text-align:center">
- <h1>Play with it today!</h1>
- <h2><a href="https://github.com/phpcr/phpcr/blob/master/doc/Tutorial.md">PHPCR Tutorial</a></h2><br/>
- <h1>See it in action!</h1>
- <h2><a href="https://github.com/symfony-cmf/cmf-sandbox">Symfony2 CMF sandbox</a></h2>
- </div>
-
- <div class="slide">
- <h2>Next steps</h2>
- <ul>
- <li>More performance optimizations in Jackalope</li>
- <li>Push the Jackalope DoctrineDBAL transport</li>
- <li>Security and ACL support</li>
- <li>Observation support</li>
- </ul>
- </div>
-
- <div class="slide">
- <h2>Many individuals contribute to the effort</h2>
- <br />
- <table style="font-size: 0.85em">
- <tr>
- <td>
- <ul>
- <li>adou600 (Adrien Nicolet)</li>
- <li>beberlei (Benjamin Eberlei)</li>
- <li>bergie (Henri Bergius)</li>
- <li>brki (Brian King)</li>
- <li>chirimoya (Thomas Schedler)</li>
- <li>chregu (Christian Stocker)</li>
- <li>cordoval (Luis Cordova)</li>
- <li>damz (Damien Tournoud)</li>
- <li>dbu (David Buchmann)</li>
- <li>dotZoki (Zoran)</li>
- <li>ebi (Tobias Ebnöther)</li>
- <li>iambrosi (Ismael Ambrosi)</li>
- <li>jakuza (Jacopo Romei)</li>
- <li>justinrainbow (Justin Rainbow)</li>
- <li>k-fish (Karsten Dambekalns)</li>
- <li>krizon (Kristian Zondervan)</li>
- </ul>
- </td>
- <td>
- <ul>
- <li>lapistano (Bastian Feder)</li>
- <li>lsmith77 (Lukas K. Smith)</li>
- <li>micheleorselli (Michele Orselli)</li>
- <li>nacmartin (Nacho Martín)</li>
- <li>nicam (Pascal Helfenstein)</li>
- <li>Ocramius (Marco Pivetta)</li>
- <li>ornicar (Thibault Duplessis)</li>
- <li>piotras</li>
- <li>pitpit (Damien Pitard)</li>
- <li>robertlemke (Robert Lemke)</li>
- <li>rndstr (Roland Schilter)</li>
- <li>Seldaek (Jordi Boggiano)</li>
- <li>sixty-nine (Daniel Barsotti)</li>
- <li>uwej711 (Uwe Jäger)</li>
- <li>vedranzgela (Vedran Zgela)</li>
- <li>videlalvaro (Alvaro Videla)</li>
- </ul>
- </td>
- </tr>
- </table>
- </div>
-
- <div class="slide" style="text-align:center">
- <h2>Several companies and organisations are investing into the effort</h2>
- <h2><img src="phpcr_companies.png" alt="Liip, Ideato, Nemein, IKS" /></h2>
- </div>
-
- <div class="slide" style="text-align:center">
- <h2>Many projects have expressed interest</h2>
- <h2><img src="phpcr_projects.png" alt="Symfony2 CMF, Midgard, Typo3, Nooku, ezPublish, Drupal" /></h2>
- </div>
-
- <div class="slide">
- <h2>Github projects</h2>
- <ul>
- <li><a href="https://github.com/phpcr/phpcr">PHPCR</a></li>
- <li><a href="https://github.com/phpcr/phpcr-api-tests">PHPCR test suite</a></li>
- <li><a href="https://github.com/jackalope/jackalope">Jackalope</a></li>
- <li><a href="https://github.com/midgardproject/phpcr-midgard2">Midgard2 CR</a></li>
- <li><a href="https://github.com/doctrine/phpcr-odm">PHPCR ODM</a></li>
- </ul>
- </div>
-
- <div class="slide">
- <h2>Resources</h2>
- <ul>
- <li><a href="irc://freenode/#jackalope">#jackalope IRC</a></li>
- <li><a href="irc://freenode/#phpcr">#phpcr IRC</a></li>
- <li><a href="http://phpcr.github.com">http://phpcr.github.com</a></li>
- <li><a href="http://jcp.org/en/jsr/detail?id=283">JSR 283 (aka JCR 2, especially Chapter 3)</a></li>
- <li><a href="http://jcp.org/en/jsr/detail?id=333">JSR 333 (aka JCR 2.1)</a></li>
- <li><a href="http://wiki.apache.org/jackrabbit/DavidsModel">David's Model</a></li>
- <li><a href="http://www.h2database.com/jcr/grammar.html">SQL2 Grammar</a></li>
- </ul>
- </div>
-
- <div class="layout" data-name="default">
- <div class="vcenter">
- <content></content>
- </div>
- </div>
-
- <div class="footer">
- <span class="right"><a href="irc://freenode/#phpcr">#phpcr IRC</a></span>
- <span class="left"><a href="http://phpcr.github.com">phpcr.github.com</a></span>
- <hr class="defloat" />
- </div>
- </body>
-</html>
View
BIN  doc/slides/square_in_a_circle.png
Deleted file not rendered
View
BIN  doc/slides/versioning.png
Deleted file not rendered
Please sign in to comment.
Something went wrong with that request. Please try again.