Explorar o código

Refactor templates to be more customizable

Thomas Rabaix %!s(int64=14) %!d(string=hai) anos
pai
achega
645e56a904

+ 35 - 3
Admin/Admin.php

@@ -348,6 +348,8 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
 
     protected $filterTheme = array('SonataAdminBundle:Form:filter_admin_fields.html.twig');
 
+    protected $templates  = array();
+
     protected $extensions = array();
 
     /**
@@ -957,7 +959,7 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
      */
     public function getListTemplate()
     {
-        return 'SonataAdminBundle:CRUD:list.html.twig';
+        return $this->getTemplate('list');
     }
 
     /**
@@ -967,7 +969,7 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
      */
     public function getEditTemplate()
     {
-        return 'SonataAdminBundle:CRUD:edit.html.twig';
+        return $this->getTemplate('edit');
     }
 
     /**
@@ -977,7 +979,37 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
      */
     public function getShowTemplate()
     {
-        return 'SonataAdminBundle:CRUD:show.html.twig';
+        return $this->getTemplate('show');
+    }
+
+    /**
+     * @param array $templates
+     * @return void
+     */
+    public function setTemplates(array $templates)
+    {
+        $this->templates = $templates;
+    }
+
+    /**
+     * @return array
+     */
+    public function getTemplates()
+    {
+        return $this->templates;
+    }
+
+    /**
+     * @param $name
+     * @return null|string
+     */
+    public function getTemplate($name)
+    {
+        if (isset($this->templates[$name])) {
+            return $this->templates[$name];
+        }
+
+        return null;
     }
 
     /**

+ 69 - 4
Admin/Pool.php

@@ -23,11 +23,19 @@ class Pool
 
     protected $adminClasses = array();
 
+    protected $templates    = array();
+
+    /**
+     * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
+     */
     public function __construct(ContainerInterface $container)
     {
         $this->container = $container;
     }
 
+    /**
+     * @return array
+     */
     public function getGroups()
     {
         $groups = $this->adminGroups;
@@ -41,6 +49,9 @@ class Pool
         return $groups;
     }
 
+    /**
+     * @return array
+     */
     public function getDashboardGroups()
     {
         $groups = $this->adminGroups;
@@ -108,38 +119,92 @@ class Pool
         return $this->container->get($id);
     }
 
+    /**
+     * @return null|\Symfony\Component\DependencyInjection\ContainerInterface
+     */
     public function getContainer()
     {
         return $this->container;
     }
 
-    public function setAdminGroups($adminGroups)
+    /**
+     * @param array $adminGroups
+     * @return void
+     */
+    public function setAdminGroups(array $adminGroups)
     {
         $this->adminGroups = $adminGroups;
     }
 
+    /**
+     * @return array
+     */
     public function getAdminGroups()
     {
         return $this->adminGroups;
     }
 
-    public function setAdminServiceIds($adminServiceIds)
+    /**
+     * @param array $adminServiceIds
+     * @return void
+     */
+    public function setAdminServiceIds(array $adminServiceIds)
     {
         $this->adminServiceIds = $adminServiceIds;
     }
 
+    /**
+     * @return array
+     */
     public function getAdminServiceIds()
     {
         return $this->adminServiceIds;
     }
 
-    public function setAdminClasses($adminClasses)
+    /**
+     * @param array $adminClasses
+     * @return void
+     */
+    public function setAdminClasses(array $adminClasses)
     {
         $this->adminClasses = $adminClasses;
     }
 
+    /**
+     * @return array
+     */
     public function getAdminClasses()
     {
         return $this->adminClasses;
     }
-}
+
+    /**
+     * @param array $templates
+     * @return void
+     */
+    public function setTemplates(array $templates)
+    {
+        $this->templates = $templates;
+    }
+
+    /**
+     * @return array
+     */
+    public function getTemplates()
+    {
+        return $this->templates;
+    }
+
+    /**
+     * @param $name
+     * @return null|string
+     */
+    public function getTemplate($name)
+    {
+        if (isset($this->templates[$name])) {
+            return $this->templates[$name];
+        }
+
+        return null;
+    }
+}

+ 2 - 2
Controller/CRUDController.php

@@ -109,10 +109,10 @@ class CRUDController extends Controller
     public function getBaseTemplate()
     {
         if ($this->isXmlHttpRequest()) {
-            return $this->container->getParameter('sonata.admin.templates.ajax');
+            return $this->admin->getTemplate('ajax');
         }
 
-        return $this->container->getParameter('sonata.admin.templates.layout');
+        return $this->admin->getTemplate('layout');
     }
 
     /**

+ 9 - 2
Controller/CoreController.php

@@ -15,17 +15,24 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 use Symfony\Component\HttpFoundation\Response;
 
+
 class CoreController extends Controller
 {
+    /**
+     * @return string
+     */
     public function getBaseTemplate()
     {
         if ($this->get('request')->isXmlHttpRequest()) {
-            return $this->container->getParameter('sonata.admin.templates.ajax');
+            return $this->container->get('sonata.admin.pool')->getTemplate('ajax');
         }
 
-        return $this->container->getParameter('sonata.admin.templates.layout');
+        return $this->container->get('sonata.admin.pool')->getTemplate('layout');
     }
 
+    /**
+     * @return \Symfony\Bundle\FrameworkBundle\Controller\Response
+     */
     public function dashboardAction()
     {
         return $this->render('SonataAdminBundle:Core:dashboard.html.twig', array(

+ 4 - 0
DependencyInjection/Compiler/AddDependencyCallsCompilerPass.php

@@ -193,6 +193,10 @@ class AddDependencyCallsCompilerPass implements CompilerPassInterface
 
         $definition->addMethodCall('configure');
 
+        if (!$definition->hasMethodCall('setTemplates')) {
+            $definition->addMethodCall('setTemplates', array($settings['templates']));
+        }
+
         return $definition;
     }
 

+ 5 - 3
DependencyInjection/Configuration.php

@@ -83,11 +83,13 @@ class Configuration implements ConfigurationInterface
 
                 ->arrayNode('templates')
                     ->children()
-                        ->scalarNode('layout')->cannotBeEmpty()->end()
-                        ->scalarNode('ajax')->cannotBeEmpty()->end()
+                        ->scalarNode('layout')->defaultValue('SonataAdminBundle::standard_layout.html.twig')->end()
+                        ->scalarNode('ajax')->defaultValue('SonataAdminBundle::ajax_layout.html.twig')->end()
+                        ->scalarNode('list')->defaultValue('SonataAdminBundle:CRUD:list.html.twig')->end()
+                        ->scalarNode('show')->defaultValue('SonataAdminBundle:CRUD:show.html.twig')->end()
+                        ->scalarNode('edit')->defaultValue('SonataAdminBundle:CRUD:edit.html.twig')->end()
                     ->end()
                 ->end()
-        
             ->end()
         ->end();
     }

+ 0 - 4
Resources/config/templates.xml

@@ -4,9 +4,5 @@
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
 
-    <parameters>
-        <parameter key="sonata.admin.templates.layout">SonataAdminBundle::standard_layout.html.twig</parameter>
-        <parameter key="sonata.admin.templates.ajax">SonataAdminBundle::ajax_layout.html.twig</parameter>
-    </parameters>
 
 </container>

+ 1 - 0
Resources/doc/index.rst

@@ -21,6 +21,7 @@ Reference Guide
    reference/filter_field_definition
    reference/form_field_definition
    reference/form_types_and_transformers
+   reference/templates
    reference/saving_hooks
    reference/routing
    reference/dashboard

+ 28 - 0
Resources/doc/reference/templates.rst

@@ -0,0 +1,28 @@
+Templates
+=========
+
+By default, an Admin class used a set of templates, it is possible to tweak the default values by editing the configuration
+
+.. code-block:: yaml
+
+    sonata_admin:
+        templates:
+            # default global templates
+            layout:  SonataAdminBundle::standard_layout.html.twig
+            ajax:    SonataAdminBundle::ajax_layout.html.twig
+
+            # default value if done set, actions templates, should extends a global templates
+            list:    SonataAdminBundle:CRUD:list.html.twig
+            show:    SonataAdminBundle:CRUD:show.html.twig
+            edit:    SonataAdminBundle:CRUD:edit.html.twig
+
+
+Usage of each template :
+
+* layout : based layout used by the dashboard and an admin class
+* ajax : default layout used when an ajax request is performed
+* list : the template to use for the list action
+* show : the template to use for the show action
+* edit : the template to use for the edit and create action
+
+The default values will be set only if the ``Admin::setTemplates`` is not called by the Container.

+ 14 - 0
Resources/views/Core/actions.html.twig

@@ -0,0 +1,14 @@
+{#
+
+This file is part of the Sonata package.
+
+(c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
+
+For the full copyright and license information, please view the LICENSE
+file that was distributed with this source code.
+
+#}
+
+<div class="right">
+    {% block actions %}{% endblock %}
+</div>

+ 24 - 0
Resources/views/Core/breadcrumb.html.twig

@@ -0,0 +1,24 @@
+{#
+
+This file is part of the Sonata package.
+
+(c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
+
+For the full copyright and license information, please view the LICENSE
+file that was distributed with this source code.
+
+#}
+<div class="sonata-ba-breadcrumbs">
+    <h1>
+    {% block breadcrumb %}
+        {% if action is defined %}
+            {% for label, uri in admin.breadcrumbs(action) %}
+                {% if not loop.first  %}
+                    &gt;
+                {% endif %}
+                <a href="{{ uri }}">{{ label }}</a>
+            {% endfor %}
+        {% endif %}
+    {% endblock %}
+    </h1>
+</div>

+ 14 - 0
Resources/views/Core/footer.html.twig

@@ -0,0 +1,14 @@
+{#
+
+This file is part of the Sonata package.
+
+(c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
+
+For the full copyright and license information, please view the LICENSE
+file that was distributed with this source code.
+
+#}
+
+<div class="span-24 last">
+    {% block footer %}{% endblock %}
+</div>

+ 19 - 0
Resources/views/Core/head_javascripts.html.twig

@@ -0,0 +1,19 @@
+{#
+
+This file is part of the Sonata package.
+
+(c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
+
+For the full copyright and license information, please view the LICENSE
+file that was distributed with this source code.
+
+#}
+
+{% block javascripts %}
+    <script src="{{ asset('bundles/sonatajquery/jquery-1.4.4.js') }}" type="text/javascript"></script>
+    <script src="{{ asset('bundles/sonatajquery/jquery-ui-1.8.6.custom.js') }}" type="text/javascript"></script>
+    <script src="{{ asset('bundles/sonatajquery/jquery-ui-i18n.js') }}" type="text/javascript"></script>
+    <script src="{{ asset('bundles/sonataadmin/qtip/jquery.qtip-1.0.0-rc3.min.js') }}" type="text/javascript"></script>
+    <script src="{{ asset('bundles/sonataadmin/jquery/jquery.form.js') }}" type="text/javascript"></script>
+    <script src="{{ asset('bundles/sonataadmin/base.js') }}" type="text/javascript"></script>
+{% endblock %}

+ 24 - 0
Resources/views/Core/head_stylesheets.html.twig

@@ -0,0 +1,24 @@
+{#
+
+This file is part of the Sonata package.
+
+(c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
+
+For the full copyright and license information, please view the LICENSE
+file that was distributed with this source code.
+
+#}
+
+{% block stylesheets %}
+    <!-- jQuery code -->
+    <link rel="stylesheet" href="{{ asset('bundles/sonatajquery/themes/flick/jquery-ui-1.8.6.custom.css') }}" type="text/css" media="all" />
+
+    <!-- blueprint code -->
+    <link rel="stylesheet" href="{{ asset('bundles/sonatablueprint/screen.css') }}" type="text/css" media="screen, projection">
+    <link rel="stylesheet" href="{{ asset('bundles/sonatablueprint/print.css') }}" type="text/css" media="print">
+    <!--[if lt IE 8]><link rel="stylesheet" href="{{ asset('bundles/sonatablueprint/ie.css') }}" type="text/css" media="screen, projection"><![endif]-->
+
+    <!-- base application asset -->
+    <link rel="stylesheet" href="{{ asset('bundles/sonataadmin/css/layout.css') }}" type="text/css" media="all">
+    <link rel="stylesheet" href="{{ asset('bundles/sonataadmin/css/colors.css') }}" type="text/css" media="all">
+{% endblock %}

+ 24 - 0
Resources/views/Core/head_title.html.twig

@@ -0,0 +1,24 @@
+{#
+
+This file is part of the Sonata package.
+
+(c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
+
+For the full copyright and license information, please view the LICENSE
+file that was distributed with this source code.
+
+#}
+
+<title>
+    {% block title %} {% trans from 'SonataAdminBundle' %}Admin{% endtrans %}
+        {% if action is defined %}
+            -
+            {% for label, uri in admin.breadcrumbs(action) %}
+                {% if not loop.first  %}
+                    &gt;
+                {% endif %}
+                {{ label }}
+            {% endfor %}
+        {% endif %}
+    {% endblock %}
+</title>

+ 20 - 0
Resources/views/Core/header.html.twig

@@ -0,0 +1,20 @@
+{#
+
+This file is part of the Sonata package.
+
+(c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
+
+For the full copyright and license information, please view the LICENSE
+file that was distributed with this source code.
+
+#}
+
+<div class="span-24 last header">
+    <div class="span-20">
+        <a href="{{ url('sonata_admin_dashboard') }}" class="home">{% trans from 'SonataAdminBundle' %}Admin{% endtrans %}</a>
+    </div>
+
+    <div class="span-4 last">
+        {% block user_panel %}{#Add here logout option / user options#}{% endblock %}
+    </div>
+</div>

+ 22 - 0
Resources/views/Core/notice.html.twig

@@ -0,0 +1,22 @@
+{#
+
+This file is part of the Sonata package.
+
+(c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
+
+For the full copyright and license information, please view the LICENSE
+file that was distributed with this source code.
+
+#}
+
+{# flash notice defined in CRUDController after actions- 3 levels #}
+{% for notice_level in ['success','error','notice'] %}
+
+    {% set session_var = 'sonata_flash_' ~ notice_level %}
+    {% if app.session.hasFlash(session_var) %}
+        <div class="{{notice_level}}">
+        {{ app.session.flash(session_var) | trans([],'SonataAdminBundle') }}
+       </div>
+    {% endif %}
+
+{% endfor %}

+ 20 - 96
Resources/views/standard_layout.html.twig

@@ -13,102 +13,29 @@ file that was distributed with this source code.
     <head>
         <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 
-        {% block stylesheets %}
-            <!-- jQuery code -->
-            <link rel="stylesheet" href="{{ asset('bundles/sonatajquery/themes/flick/jquery-ui-1.8.6.custom.css') }}" type="text/css" media="all" />
-
-            <!-- blueprint code -->
-            <link rel="stylesheet" href="{{ asset('bundles/sonatablueprint/screen.css') }}" type="text/css" media="screen, projection">
-            <link rel="stylesheet" href="{{ asset('bundles/sonatablueprint/print.css') }}" type="text/css" media="print">
-            <!--[if lt IE 8]><link rel="stylesheet" href="{{ asset('bundles/sonatablueprint/ie.css') }}" type="text/css" media="screen, projection"><![endif]-->
-
-            <!-- base application asset -->
-            <link rel="stylesheet" href="{{ asset('bundles/sonataadmin/css/layout.css') }}" type="text/css" media="all">
-            <link rel="stylesheet" href="{{ asset('bundles/sonataadmin/css/colors.css') }}" type="text/css" media="all">
-        {% endblock %}
-
-        {% block stylesheets_extension %}{% endblock %}
-
-        {% block javascripts %}
-            <script src="{{ asset('bundles/sonatajquery/jquery-1.4.4.js') }}" type="text/javascript"></script>
-            <script src="{{ asset('bundles/sonatajquery/jquery-ui-1.8.6.custom.js') }}" type="text/javascript"></script>
-            <script src="{{ asset('bundles/sonatajquery/jquery-ui-i18n.js') }}" type="text/javascript"></script>
-            <script src="{{ asset('bundles/sonataadmin/qtip/jquery.qtip-1.0.0-rc3.min.js') }}" type="text/javascript"></script>
-            <script src="{{ asset('bundles/sonataadmin/jquery/jquery.form.js') }}" type="text/javascript"></script>
-            <script src="{{ asset('bundles/sonataadmin/base.js') }}" type="text/javascript"></script>
-        {% endblock %}
-
-        {% block javascripts_extension %}{% endblock %}
-
-        <title>
-            {% block title %} {% trans from 'SonataAdminBundle' %}Admin{% endtrans %}
-                {% if action is defined %}
-                    -
-                    {% for label, uri in admin.breadcrumbs(action) %}
-                        {% if not loop.first  %}
-                            &gt;
-                        {% endif %}
-                        {{ label }}
-                    {% endfor %}
-                {% endif %}
-            {% endblock %}
-        </title>
+        {% include 'SonataAdminBundle:Core:head_stylesheets.html.twig' %}
+        {% include 'SonataAdminBundle:Core:head_javascripts.html.twig' %}
+        {% include 'SonataAdminBundle:Core:head_title.html.twig' %}
     </head>
     <body>
-
         {# initialize block value #}
-        {% set _preview      = block('preview') %}
-        {% set _form         = block('form') %}
-        {% set _show         = block('show') %}
-        {% set _list_table   = block('list_table') %}
-        {% set _list_filters = block('list_filters') %}
-        {% set _side_menu    = block('side_menu') %}
-        {% set _content      = block('content') %}
-
 
         <div class="container">
-            <div class="span-24 last header">
-                <div class="span-20">
-                    <a href="{{ url('sonata_admin_dashboard') }}" class="home">{% trans from 'SonataAdminBundle' %}Admin{% endtrans %}</a>
-                </div>
 
-                <div class="span-4 last">
-                    {% block user_panel %}{#Add here logout option / user options#}{% endblock %}
-                </div>
-            </div>
+            {% set _preview      = block('preview') %}
+            {% set _form         = block('form') %}
+            {% set _show         = block('show') %}
+            {% set _list_table   = block('list_table') %}
+            {% set _list_filters = block('list_filters') %}
+            {% set _side_menu    = block('side_menu') %}
+            {% set _content      = block('content') %}
 
-            <div class="span-24 last content clear">
-                <div class="right">
-                    {% block actions %}{% endblock %}
-                </div>
-
-                <div class="sonata-ba-breadcrumbs">
-                    <h1>
-                    {% block breadcrumb %}
-                        {% if action is defined %}
-                            {% for label, uri in admin.breadcrumbs(action) %}
-                                {% if not loop.first  %}
-                                    &gt;
-                                {% endif %}
-                                <a href="{{ uri }}">{{ label }}</a>
-                            {% endfor %}
-                        {% endif %}
-                    {% endblock %}
-                    </h1>
-                </div>
-
-                {# flash notice defined in CRUDController after actions- 3 levels #}
-                {% for notice_level in ['success','error','notice'] %}
-
-                   {% set session_var = 'sonata_flash_' ~ notice_level %}
-                    {% if app.session.hasFlash(session_var) %}
-                        <div class="{{notice_level}}">
-                        {{ app.session.flash(session_var) | trans([],'SonataAdminBundle') }}
-                       </div>
-                    {% endif %}
-
-                {% endfor %}
+            {% include 'SonataAdminBundle:Core:header.html.twig' %}
 
+            <div class="span-24 last content clear">
+                {% include 'SonataAdminBundle:Core:actions.html.twig' %}
+                {% include 'SonataAdminBundle:Core:breadcrumb.html.twig' %}
+                {% include 'SonataAdminBundle:Core:notice.html.twig' %}
             </div>
 
             {% if _preview is not empty %}
@@ -120,10 +47,10 @@ file that was distributed with this source code.
             <div class="span-24 last content clear">
 
                 {% if _side_menu is not empty %}
-                        <div class="span-4">
-                            <div class="sonata-ba-side-menu">{{ _side_menu|raw }}</div>
-                        </div>
-                        <div class="span-18 last content">
+                    <div class="span-4">
+                        <div class="sonata-ba-side-menu">{{ _side_menu|raw }}</div>
+                    </div>
+                    <div class="span-18 last content">
                 {% endif %}
 
                     {% if _content is not empty %}
@@ -166,10 +93,7 @@ file that was distributed with this source code.
 
             </div>
 
-            <!-- footer -->
-            <div class="span-24 last">
-                {% block footer %}{% endblock %}
-            </div>
+            {% include 'SonataAdminBundle:Core:footer.html.twig' %}
         </div>
     </body>
 </html>

+ 10 - 0
Tests/Admin/PoolTest.php

@@ -121,6 +121,16 @@ class PoolTest extends \PHPUnit_Framework_TestCase
         $this->assertInstanceOf('Symfony\Component\DependencyInjection\ContainerInterface', $this->pool->getContainer());
     }
 
+    public function testTemplates()
+    {
+        $this->assertInternalType('array', $this->pool->getTemplates());
+
+        $this->pool->setTemplates(array('ajax' => 'Foo.html.twig'));
+
+        $this->assertNull($this->pool->getTemplate('bar'));
+        $this->assertEquals('Foo.html.twig', $this->pool->getTemplate('ajax'));
+    }
+
     /**
      * @return Symfony\Component\DependencyInjection\ContainerInterface - the mock of container interface
      */