Por qué
Python community 2010




             http://www.flickr.com/photos/27734462@N00/4456118597
PHP community, 2010




           http://www.flickr.com/photos/27734462@N00/4456830956
http://www.flickr.com/photos/57768341@N00/3387704295
Symfony2 al rescate




              http://www.flickr.com/photos/18597080@N04/2566928348
Un entorno común




            http://www.flickr.com/photos/61414741@N00/77346889Text
http://www.flickr.com/photos/10209031@N08/4542049217
http://www.flickr.com/photos/38158467@N00/83109701
Text
Los componentes de
   Symfony2 son
     genéricos
 pero Internet está
llena de contenido
Los componentes de
   Symfony2 son
     genéricos
 pero Internet está
llena de contenido
Drupal está muy bien

 si eres un usuario
Drupal está muy bien

 si eres un usuario
Vamos a intentarlo
¿TinyMCE y a correr?
No, a lo loco
Queremos...
Queremos...
Estructura en árbol
Queremos...
Estructura en árbol

Documentos sin
estructura
Queremos...
Estructura en árbol

Documentos sin
estructura

Querys para el árbol
Queremos...
Estructura en árbol

Documentos sin
estructura

Querys para el árbol

Fulltext
Queremos...
Estructura en árbol

Documentos sin
estructura

Querys para el árbol

Fulltext

Usable en hosting
compartido...
Queremos...
Estructura en árbol

Documentos sin
estructura

Querys para el árbol

Fulltext

Usable en hosting
compartido...

...pero escalable
Queremos...
Estructura en árbol

Documentos sin
estructura

Querys para el árbol

Fulltext

Usable en hosting
compartido...

...pero escalable

Que sea un estándar
Queremos...
Estructura en árbol

Documentos sin
estructura

Querys para el árbol

Fulltext

Usable en hosting
compartido...

...pero escalable

Que sea un estándar

...y tenga varias
implementaciones!
Queremos...
Estructura en árbol    Versionable

Documentos sin
estructura

Querys para el árbol

Fulltext

Usable en hosting
compartido...

...pero escalable

Que sea un estándar

...y tenga varias
implementaciones!
Queremos...
Estructura en árbol    Versionable

Documentos sin         Traducible
estructura

Querys para el árbol

Fulltext

Usable en hosting
compartido...

...pero escalable

Que sea un estándar

...y tenga varias
implementaciones!
Queremos...
Estructura en árbol    Versionable

Documentos sin         Traducible
estructura
                       Rutas editables
Querys para el árbol

Fulltext

Usable en hosting
compartido...

...pero escalable

Que sea un estándar

...y tenga varias
implementaciones!
Queremos...
Estructura en árbol    Versionable

Documentos sin         Traducible
estructura
                       Rutas editables
Querys para el árbol
                       Miles de ellas
Fulltext

Usable en hosting
compartido...

...pero escalable

Que sea un estándar

...y tenga varias
implementaciones!
Queremos...
Estructura en árbol    Versionable

Documentos sin         Traducible
estructura
                       Rutas editables
Querys para el árbol
                       Miles de ellas
Fulltext
                       Menús
Usable en hosting
compartido...

...pero escalable

Que sea un estándar

...y tenga varias
implementaciones!
Queremos...
Estructura en árbol    Versionable

Documentos sin         Traducible
estructura
                       Rutas editables
Querys para el árbol
                       Miles de ellas
Fulltext
                       Menús
Usable en hosting
compartido...          ACL
...pero escalable

Que sea un estándar

...y tenga varias
implementaciones!
Queremos...
Estructura en árbol    Versionable

Documentos sin         Traducible
estructura
                       Rutas editables
Querys para el árbol
                       Miles de ellas
Fulltext
                       Menús
Usable en hosting
compartido...          ACL
...pero escalable      Admin panel
Que sea un estándar

...y tenga varias
implementaciones!
Queremos...
Estructura en árbol    Versionable

Documentos sin         Traducible
estructura
                       Rutas editables
Querys para el árbol
                       Miles de ellas
Fulltext
                       Menús
Usable en hosting
compartido...          ACL
...pero escalable      Admin panel
Que sea un estándar    Editable inline
...y tenga varias
implementaciones!
Queremos...
Estructura en árbol    Versionable

Documentos sin         Traducible
estructura
                       Rutas editables
Querys para el árbol
                       Miles de ellas
Fulltext
                       Menús
Usable en hosting
compartido...          ACL
...pero escalable      Admin panel
Que sea un estándar    Editable inline
...y tenga varias      Que no haga falta
implementaciones!      saberlo todo
¿Cuánto tardaremos en hacer esa
           animalada?




                     http://www.flickr.com/photos/83476873@N00/110993877
Ya está hecha
    (O casi)
Componentes
PHPCR
el estándar
API estándar


JCR “phpizado”
Estructura
Estructura
Estructura
Estructura
Estructura
paths
Estructura
node
paths types
Estructura
mixins
node
paths types
Estructura
mixins
node
paths types
propiedades


     {
         title
         text
         jcr:created
         phpcr:class
STRING    BINARY
URL       DATE
BOOLEAN   NAME
LONG      PATH
DOUBLE    WEAKREFERENCE
DECIMAL   REFERENCE
Tipos de propiedades

STRING    BINARY
URL       DATE
BOOLEAN   NAME
LONG      PATH
DOUBLE    WEAKREFERENCE
DECIMAL   REFERENCE
Conexión


use JackalopeRepositoryFactoryJackrabbit as Factory;

$parameters = array(
    'jackalope.jackrabbit_uri'
        => 'http://localhost:8080/server'
);

$repository = Factory::getRepository($parameters);

$creds = new PHPCRSimpleCredentials('user','pw');
$session = $repository->login($creds, 'default');
CRUD


// Crear
$root = $session->getRootNode();
$node = $root->addNode('test', 'nt:unstructured');
// Leer
$node = $session->getNode('/test');
// Actualizar
$node->setProperty('prop', 'value');
// Eliminar
$node->remove();
Guardar las modificaciones




      $session->save();
Obtener hijos




foreach ($node as $child) {
    var_dump($child->getName());
}
Obtener hijos filtrando




foreach ($node->getNodes('di*') as $child) {
    var_dump($child->getName());
}
Consultas en SQL2

$qm = $workspace->getQueryManager();

$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());
}
Consultas con QOM
$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());
Consultas con interfaz fluida


$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();
Implementaciones

   (estándar)
Doctrine
PHPCR-ODM
el object document mapper
Documentos
namespace Foo;

use DoctrineODMPHPCRMapping as PHPCR;
/** @PHPCRDocument */
class Bar
{
  /** @PHPCRId */
  public $id;

    /**
     * @PHPCRParentDocument
     */
    public $parent;

    /** @PHPCRNodename */
    public $nodename;

    /** @PHPCRString */
    public $text;

}
Referencias
/**
 * Hijo con nombre "el-logo"
 * @PHPCRChild(name="el-logo")
 */
public $logo;

/**
 * Hijos que empiecen con "a"
 * @PHPCRChildren(filter="a*")
 */
public $children;

/** @PHPCRReferenceOne */
public $reference;

/** @PHPCRReferrers */
public $referrers;
CRUD
Ya conoces la
   interfaz
CRUD
Ya conoces la
   interfaz
Versiones con ODM
// @Document(versionable="simple")
$document = $dm->find(null, $id);

// crear versión
$dm->checkpoint($document);

// obtener últimas dos versiones
$history = $dm->getAllLinearVersions($document, 2);

// obtener versión
$version = reset($history);
$pre = $dm->findVersionByName(null, $id, $version['versionname']);
echo $pre->text;

// restablecer versión
$dm->restoreVersion($pre, true);

//eliminar versión
$dm->deleteVersion($pre2);
Las versiones tienen
    mucha tela
  Pero si la ignoras no te hace daño
Las versiones tienen
    mucha tela
  Pero si la ignoras no te hace daño
Traducciones con
     ODM
Documentos multilingües
/** @PHPCRDocument(translator="attribute") */
class Article
{
    /**
     * The language this document currently is in
     * @PHPCRLocale
     */
    public $locale;

    /**
     * Untranslated property
     * @PHPCRDate
     */
    public $publishDate;

    /**
     * Translated property
     * @PHPCRString(translated=true)
     */

    public $topic;

    /**
     * Language specific image
     * @PHPCRBinary(translated=true)
     */
    public $image;
}
Crear traducción



$article = new Article();
$article->topic = 'hola';
$dm->persist($article);
$dm->bindTranslation($article, 'es');
$dm->flush();
Obtener traducción




$article = $dm->findTranslation(null, '/test', 'es');
¿A qué lenguas está traducido?




$locales = $dm->getLocalesFor($article);
MultilangContentBundle


Documentos base para contenido, rutas y
menús

Selector de lengua

Las traducciones se almacenan en nodos hijo
Rutas
El problema


El usuario quiere definir sus urls

Y quiere unos cientos de miles
Solucionado!


navigation:
    pattern: "/{url}"
    defaults: { _controller: service.controller:indexAction }
    requirements:
        url: .*
Solucionado!
DynamicRouter

Las rutas son documentos en la BD

La ruta puede especificar un controlador...

...o usar uno por defecto
DynamicRouter
symfony_cmf_routing_extra:
    dynamic:
        enabled: true
        controllers_by_alias:
            demo_alias: sandbox_main.controller:aliasAction
        controllers_by_class:
            SandboxMainBundleDocumentDemoClassContent: 
sandbox_main.controller:classAction

            SymfonyCmfBundleRoutingExtraBundleDocument
RedirectRoute: 
symfony_cmf_routing_extra.redirect_controller:redirectAction

        templates_by_class:
            SandboxMainBundleDocumentEditableStaticContent:
SandboxMainBundle:EditableStaticContent:index.html.twig
DynamicRouter
symfony_cmf_routing_extra:
    dynamic:
        enabled: true
        controllers_by_alias:
            demo_alias: sandbox_main.controller:aliasAction
        controllers_by_class:
            SandboxMainBundleDocumentDemoClassContent: 
sandbox_main.controller:classAction

            SymfonyCmfBundleRoutingExtraBundleDocument
RedirectRoute: 
symfony_cmf_routing_extra.redirect_controller:redirectAction

        templates_by_class:
            SandboxMainBundleDocumentEditableStaticContent:
SandboxMainBundle:EditableStaticContent:index.html.twig
DynamicRouter
symfony_cmf_routing_extra:
    dynamic:
        enabled: true
        controllers_by_alias:
            demo_alias: sandbox_main.controller:aliasAction
        controllers_by_class:
            SandboxMainBundleDocumentDemoClassContent: 
sandbox_main.controller:classAction

            SymfonyCmfBundleRoutingExtraBundleDocument
RedirectRoute: 
symfony_cmf_routing_extra.redirect_controller:redirectAction

        templates_by_class:
            SandboxMainBundleDocumentEditableStaticContent:
SandboxMainBundle:EditableStaticContent:index.html.twig
DynamicRouter
symfony_cmf_routing_extra:
    dynamic:
        enabled: true
        controllers_by_alias:
            demo_alias: sandbox_main.controller:aliasAction
        controllers_by_class:
            SandboxMainBundleDocumentDemoClassContent: 
sandbox_main.controller:classAction

            SymfonyCmfBundleRoutingExtraBundleDocument
RedirectRoute: 
symfony_cmf_routing_extra.redirect_controller:redirectAction

        templates_by_class:
            SandboxMainBundleDocumentEditableStaticContent:
SandboxMainBundle:EditableStaticContent:index.html.twig
ChainRouter


symfony_cmf_routing_extra:
    chain:
        routers_by_id:
            symfony_cmf_routing_extra.dynamic_router: 20
            router.default: 100
¡Más!
MenuBundle, MultilangContentBundle
BlockBundle
PhpcrAdminBundle
En resumen...
Participa
    adou600 (Adrien Nicolet)                •   lapistano (Bastian Feder)
•   beberlei (Benjamin Eberlei)             •   lsmith77 (Lukas K. Smith)
•   bergie (Henri Bergius)                  •   micheleorselli (Michele Orselli)
•   brki (Brian King)                       •   nacmartin (Nacho Martín)
•   chirimoya (Thomas Schedler)             •   nicam (Pascal Helfenstein)
•   chregu (Christian Stocker)              •   Ocramius (Marco Pivetta)
•   cordoval (Luis Cordova)                 •   ornicar (Thibault Duplessis)
•   damz (Damien Tournoud)                  •   piotras
•   dbu (David Buchmann)                    •   pitpit (Damien Pitard)
•   dotZoki (Zoran)                         •   robertlemke (Robert Lemke)
•   ebi (Tobias Ebnöther)                   •   rndstr (Roland Schilter)
•   iambrosi (Ismael Ambrosi)               •   Seldaek (Jordi Boggiano)
•   jakuza (Jacopo Romei)                   •   sixty-nine (Daniel Barsotti)
•   justinrainbow (Justin Rainbow)          •   uwej711 (Uwe Jäger)
•   k-fish (Karsten Dambekalns)              •   vedranzgela (Vedran Zgela)
•   krizon (Kristian Zondervan)             •   videlalvaro (Alvaro Videla)


                              http://cmf.symfony.com

                                 #symfony-cmf IRC
Gracias
Nacho Martín

nacho@limenius.com
@nacmartin

Symfony 2 CMF