Parliamo del progetto
PHP symfony Sonata

Symfony 4 / Sonata: Installare il CMS Sonata Page

Sonata è una suite di bundle per Symfony 4. L’un d’tra loro permette di gégenerare contenuto à le manière di WordPress.Troverete abbastanza poca documentazione su internet, e a buon motivo, l’l'installazione è bloccata...

Symfony 4 / Sonata: Installare il CMS Sonata Page

Sonata è una suite di bundle per Symfony 4. L’un d’tra loro permette di gégenerare contenuto à le manière di WordPress.
Troverete abbastanza poca documentazione su internet, e a buon motivo, l’l'installazione è bloccataé, e le rare persone che si sono strofinateé sul bugtracker su GitHub, si sono vistiéscrivere un RTFM ben fatto in règle.

Rimanere su questo genere di’échec n’non è proprio il mio stile.
Ecco quindi come installare e configurare Sonata-Page-Bundle, con l’installazione ufficiale, poi le procedureédifficile da aggirare questi maledetti bug.

1ª énastro, su rétazzaèriguardo al nostro skeleton di Symfony 4 che comprende la nostra base funzionale del framework agrémenteé di Sonata + FosUser + Media.
Déjà acceso érisparmia una buona giornataée ^^

In sostanza, bisogna seguire la documentazione : https://sonata-project.org/bundles/page/3-x/doc/reference/installation.html

Installer tutti i Bundles e seguire scrupolosamente la documentazione.

La premiaèmolto difficileé c’è il’installazione tramite composer. Io non’non ho réussi à installare tutto per php 7.1. Né per php 7.2 d’altrove. C'è sempre un pacchetto in conflitto.

L’trucco in composer, c’è di uscire dalla stalla tramite l’istruzione minimum-stability nel vostro composer.json e là, dopo 3 o 4 ore à testare le versioni, stiamo arrivando à installare tutto.

Ecco il mio composer.json

{
    "type": "project",
    "license": "proprietary",
    "require": {
        "php": "^7.1.3",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "doctrine/doctrine-migrations-bundle": "^3.0",
        "jms/serializer-bundle": "^3.7",
        "liip/imagine-bundle": "^2.3",
        "nelmio/api-doc-bundle": "^3.6",
        "phpoffice/phpspreadsheet": "^1.14",
        "pixassociates/sortable-behavior-bundle": "^1.5",
        "prodigious/sonata-menu-bundle": "^3.0",
        "sensio/framework-extra-bundle": "^5.5",
        "sonata-project/block-bundle": "^3.20",
        "sonata-project/cache-bundle": "^2.4",
        "sonata-project/core-bundle": "^3.20",
        "sonata-project/doctrine-orm-admin-bundle": "^3.20",
        "sonata-project/formatter-bundle": "^4.2",
        "sonata-project/intl-bundle": "^2.7",
        "sonata-project/media-bundle": "^3.25",
        "sonata-project/notification-bundle": "^3.8",
        "sonata-project/page-bundle": "^3.17",
        "sonata-project/seo-bundle": "^2.11",
        "sonata-project/user-bundle": "^4.6",
        "symfony/apache-pack": "^1.0",
        "symfony/console": "4.*",
        "symfony/debug-pack": "^1.0",
        "symfony/dotenv": "4.4.*",
        "symfony/flex": "^1.3.1",
        "symfony/framework-bundle": "4.4.*",
        "symfony/serializer-pack": "^1.0",
        "symfony/swiftmailer-bundle": "^3.4",
        "symfony/templating": "4.4.*",
        "symfony/translation": "4.4.*",
        "symfony/var-dumper": "4.4.*",
        "symfony/yaml": "4.*",
        "twig/twig": "^2.9.0"
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.3",
        "symfony/maker-bundle": "^1.19"
    },
    "config": {
        "preferred-install": {
            "*": "dist"
        },
        "sort-packages": true
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "App\\Tests\\": "tests/"
        }
    },
    "replace": {
        "paragonie/random_compat": "2.*",
        "symfony/polyfill-ctype": "*",
        "symfony/polyfill-iconv": "*",
        "symfony/polyfill-php71": "*",
        "symfony/polyfill-php70": "*",
        "symfony/polyfill-php56": "*"
    },
    "scripts": {
        "auto-scripts": {
            "cache:clear": "symfony-cmd",
            "assets:install %PUBLIC_DIR%": "symfony-cmd"
        },
        "post-install-cmd": [
            "@auto-scripts"
        ],
        "post-update-cmd": [
            "@auto-scripts"
        ]
    },
    "conflict": {
        "symfony/symfony": "*"
    },
    "extra": {
        "symfony": {
            "allow-contrib": false,
            "require": "4.4.*"
        }
    }
    ,    
    "minimum-stability": "dev",
    "prefer-stable": true
}

Una volta installati i pacchettiés, e configurés, n’non dimenticate di’installare Ckeditor e gli asset. E accessoriamente, il vostro utente super admin.

php bin/console assets:install
php bin/console ckeditor:install
mkdir -p public/uploads/media
php bin/console cache:clear
php bin/console fos:user:create admin contact@partitech.com admin --super-admin

Rimane à créper il primo sito:

php app/console sonata:page:create-site

Please define a value for Site.name : Skeletton CMS
Please define a value for Site.host : www.skeleton-cms.test
Please define a value for Site.relativePath : /
Please define a value for Site.enabled : true
Please define a value for Site.locale : -
Please define a value for Site.enabledFrom : now
Please define a value for Site.enabledTo : +10 years
Please define a value for Site.default : true

Creating website with the following information :
  name : www.skeleton-cms.test
  site : http(s)://www.skeleton-cms.test
  enabled :  Tue, 10 Jul 2030 16:12:08 +0100 => Mon, 10 Jan 2022 16:12:08 +0100

Confirm site creation ?y

Site created !

You can now create the related pages and snapshots by running the followings commands:
  php app/console sonata:page:update-core-routes --site=1
  php app/console sonata:page:create-snapshots --site=1

Il primo sito è ora operativoérazionale. Infine quasi.

Nel’interfaccia della pagina, bisogna créessere nostro primoère pagina

image

La configurazione per dénon deve contenere nulla. Bisogna poi organizzare il contenuto di questa pagina tramite un éeditore, che permette di’organizzare la nostra pagina sotto forma di blocchi, assegnareés à delle aree dei nostri modelli.

Nella nostra configurazione del bundle, abbiamo déchiaroé un template per déserve. E c’è questa configurazione, che ci permette di modéleggere l’interfaccia di gestione dei blocchi

   default_template: default
    templates:
        default:
            path: '@SonataPage/layout.html.twig'
            name: 'default'
            containers:
                header:
                    name: Header
                content_top:
                    name: Top content
                content:
                    name: Main content
                content_bottom:
                    name: Bottom content
                footer:
                    name: Footer
            matrix:
                layout: |
                    HHHHHHHH
                    HHHHHHHH
                    TTTTTTTT
                    TTTTTTTT
                    CCCCCCCC
                    CCCCCCCC
                    BBBBBBBB
                    BBBBBBBB
                    FFFFFFFF
                    FFFFFFFF

                mapping:
                    H: header
                    T: content_top
                    C: content
                    B: content_bottom
                    F: footer
image-2

Nel nostro esempio sopra, abbiamo inséré 2 blocchi nella nostra zona.
Il primo è un testo semplice, il secondo è un menu (un classico menu footer).
Per inséPer creare un blocco ci si posiziona su un'area a sinistra, e si clicca sul pulsante + à destra per séselezionare il tipo di blocco après l’avere sélezioneé nella lista.

Tutta la gestione delle pagine si fa in questo modoère.
Il che vuol dire che dovremo créer a série di blocchi secondo le necessità della nostra applicazione.
E per créper un blocco, c’è super semplice. Prenderemo l’esempio del nostro blocco menu.

I menu sono géré via il pacchetto Sonata-Menu-Bundle che è compatibile con Sonata-Page-Bundle. Ma non’non fornito con un blocco per déserve. C’è stupido, perché’un menu, c’è un po' la cosa di base.

Quindi andiamo a créer notre block dans /src/Block/SonataMenuBlockService.php

<?php
namespace App\Block;

use Sonata\AdminBundle\Form\FormMapper;
use Sonata\BlockBundle\Block\BlockContextInterface;

use Sonata\BlockBundle\Block\Service\AbstractAdminBlockService;
use Sonata\BlockBundle\Meta\Metadata;
use Sonata\BlockBundle\Model\BlockInterface;
use Sonata\Form\Type\ImmutableArrayType;
use Sonata\PageBundle\Model\Page;
use Sonata\PageBundle\Model\PageManagerInterface;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\OptionsResolver\OptionsResolver;






use Sonata\AdminBundle\Admin\Pool;

use Sonata\BlockBundle\Block\BaseBlockService;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Doctrine\ORM\EntityManager;


use Sonata\CoreBundle\Validator\ErrorElement;

class SonataMenuBlockService extends AbstractAdminBlockService
{
    /**
     * @var PageManagerInterface
     */
    protected $pageManager;

    /**
     * @param string $name
     */
    public function __construct($name, EngineInterface $templating, Pool $pool, EntityManager $em , PageManagerInterface $pageManager)
    {
        parent::__construct($name, $templating);


        $this->pool = $pool;
        $this->em = $em;
        $this->pageManager = $pageManager;
        
    }

    public function getName()
    {
        return 'Partitech Menu Block';
    }
    
    public function buildEditForm(FormMapper $formMapper, BlockInterface $block)
    {
        $menu_list=$this->pool->getContainer()->get('doctrine')->getManager()->getRepository('Prodigious\Sonata\MenuBundle\Entity\Menu')->findAll();
        
        if(!empty($menu_list))
        {
            $option_list=array();
            foreach($menu_list as $m)
            {
                
                $option_list[$m->getAlias()]=$m->getName();
            }
            
        }
          
        $formMapper->add('settings', ImmutableArrayType::class, [
            'keys' => [
               /* ['title', TextType::class, [
                    'label' => 'form.label_title',
                    'required' => false,
                ]],*/
                ['menu', ChoiceType::class, [
                    'label' => 'Menu',
                    'choices' => array_flip($option_list),
                ]],

                ['template', TextType::class, [
                    'label' => 'template',
                    'required' => false,
                ]],
                
            ],
            'translation_domain' => 'SonataPageBundle',
        ]);
    }

    public function execute(BlockContextInterface $blockContext, ?Response $response = null)
    {
  
        
        $settings=$blockContext->getSettings();
        
        $systemElements = $this->pageManager->findBy([
            'url' => null,
            'parent' => null,
        ]);

        
       
        $menu_list=$this->pool->getContainer()->get('doctrine')->getManager()->getRepository('Prodigious\Sonata\MenuBundle\Entity\Menu')->findOneBy(['alias'=> $settings['menu']]);
        if(!empty($menu_list)){
            $menu=$this->pool->getContainer()->get('doctrine')->getManager()->getRepository('Prodigious\Sonata\MenuBundle\Entity\MenuItem');
            $mm = $this->pool->getContainer()->get('prodigious_sonata_menu.manager');
            $menu = $mm->load($menu_list->getId());
            // $status = true (Get enabled menu items)
            // $status = false (Get disabled menu items)
            // getMenuItems($menu, $root = MenuManager::ITEM_CHILD, $status = MenuManager::STATUS_ALL)
            
            $menuItems = $mm->getMenuItems($menu, true, true);
        }else{
            $menuItems=false;
        }
                ;
        
        return $this->renderResponse($blockContext->getTemplate(), [
            'context' => $blockContext,
            'block' => $blockContext->getBlock(),
            'settings' => $blockContext->getSettings(),
            
            'systemElements' => $systemElements,
            'menuItems'=>$menuItems
        ], $response);
    }

    public function configureSettings(OptionsResolver $resolver)
    {
        
        $resolver->setDefaults([

            'menu'=>'menu',
            'template' => '/Block/Menu/menu.html.twig',
        ]);
    }

    public function getBlockMetadata($code = null)
    {
        return new Metadata($this->getName(), (null !== $code ? $code : $this->getName()), false, 'SonataPageBundle', [
            'class' => 'fa fa-list-ul',
        ]);
    }
}

Aggiungiamo i nostri template in /Block/Menu/menu.html.twig e il file macro dei menu in /Block/Menu/menu_tree_macro.html.twig.
C’è nient'altro che i file per déserve un pacchetto intornoé d’un div che contiene le informazioni del blocco per l’éedizione in fronte.

{#/Block/Menu/menu.html.twig#}
{% if block.name|length %}
    {% set name=block.name%}
{% else %}
    {% set name=block.settings.menu %}
{% endif %}
<div id="cms-block-25" class="cms-block cms-block-element ui-sortable-handle" data-id="{{ block.id }}" data-name="{{ name }}" data-role="block" data-page-id="{{ block.page.id }}">

    {% if menuItems is not null and menuItems|length > 0 %}
    
    {% import 'Block/Menu/menu_tree_macro.html.twig' as tree %}
    
    {% set currentPath = app.request.requestUri %}
    
    {{ tree.menu(menuItems, currentPath) }}
    
    {% endif %}

</div>
{#/Block/Menu/menu_tree_macro.html.twig#}
{% macro menu(items, currentPath) %}
    
    {% import _self as self %}

        <ul>
            {% for menuItem in items %}
    
            {% set url = menuItem.url %}
            {% set attributes = "menu-item" %}
            {% if menuItem.classAttribute %}
            {% set attributes = attributes ~ ' ' ~ menuItem.classAttribute %}
            {% endif %}
            {% if menuItem.hasChild() %}
            
            {% set attributes = attributes ~ ' has-child' %}
            
            {% for childItem in menuItem.children %}

            {% set childUrl = childItem.url %}

            {% if childUrl == currentPath %}
            {% set attributes = attributes ~ ' current-parent' %}
            {% endif %}
            
            {% endfor %}
            
            {% endif %}

            <li class="{{ attributes }}" role="menu-item">
                {% if menuItem.hasChild() %}
                <a href="{{ url }}" class="parent" {% if currentPath == url %} class="current"{% endif %}" {% if menuItem.target %} target="_blank"{% endif %}>{{ menuItem.name }}</a>
                {{ self.menu(menuItem.children, currentPath) }}
                {% else %}
                <a href="{{ url }}" {% if currentPath == url %} class="current"{% endif %}" {% if menuItem.target %} target="_blank"{% endif %}>{{ menuItem.name }}</a>
                {% endif %}
            </li>
            {% endfor %}
        </ul>

{% endmacro %}

Su référence il nostro blocco nei nostri servizi

services:
    sonata.block.service.sonata_menu:
        class: App\Block\SonataMenuBlockService
        arguments: 
           - "sonata.block.service.sonata_menu"
           - "@templating"
           - "@sonata.admin.pool"
           - "@doctrine.orm.entity_manager"
           - "@sonata.page.manager.page"
        tags:
            - { name: sonata.block }   

E poi abbiamo il nostro nuovo blocco che è disponibile nella nostra lista di blocchi. Possiamo fare praticamente tutto ciò che l’vogliamo in un blocco, à le manière d’un controller.

Sélection_296

Si può quindi créper il nostro menu footer

image-3

E il’usare nel blocco note

image-4

Ecco il risultato della nostra pagina

image-5

In realtà, no. Ça c’è il risultato con un modello correttoé. Altrimenti il risultato appare così:

Sélection_302

Dovremo quindi duplicare il template di base nel nostro progetto e correggere ciò che non va.

Su créé la nostra base_layout e il nostro template di test test-layout nel rérepertorio Layouts/

{#/templates/Layouts/base_layout.html.twig#}
{#

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 sonata_page_html_tag -%}
<!DOCTYPE html>
<html {{ sonata_seo_html_attributes() }}>
{% endblock %}
    {% block sonata_page_head %}
        <head {{ sonata_seo_head_attributes() }}>

            <!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
            {{ sonata_seo_title() }}
            {{ sonata_seo_metadatas() }}

            {% block sonata_page_stylesheets %}
                {% block page_stylesheets %} {# Deprecated block #}
                    {% for stylesheet in sonata_page.assets.stylesheets %}
                        <link rel="stylesheet" href="{{ asset(stylesheet) }}" media="all">
                    {% endfor %}
                {% endblock %}
            {% endblock %}

            {% block sonata_page_javascripts %}
                {% block page_javascripts %} {# Deprecated block #}
                    <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
                    <!--[if lt IE 9]>
                        <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
                    <![endif]-->

                    {% for js in sonata_page.assets.javascripts %}
                        <script src="{{ asset(js) }}"></script>
                    {% endfor %}
                {% endblock %}

            {% endblock %}
        </head>
    {% endblock %}

    {% block sonata_page_body_tag %}
        <body class="sonata-bc">
    {% endblock %}

        {% block sonata_page_top_bar %}
        
            {% block page_top_bar %} {# Deprecated block #}
                {% if sonata_page.isEditor or ( app.user and is_granted('ROLE_PREVIOUS_ADMIN') ) %}

                    {% if sonata_page.isEditor and sonata_page.isInlineEditionOn %}
                        <!-- CMS specific variables -->
                        <script>
                            jQuery(document).ready(function() {
                                Sonata.Page.init({
                                    url: {
                                        block_save_position: '{{ sonata_admin.objectUrl('sonata.page.admin.page', 'edit', page) }}',
                                        block_edit:          '{{ sonata_admin.url('sonata.page.admin.page|sonata.page.admin.block', 'edit', {'id': 'BLOCK_ID'}) }}'
                                    }
                                });
                            });
                        </script>
                    {% endif %}

                    <header class="sonata-bc sonata-page-top-bar navbar navbar-inverse navbar-fixed-top" role="banner"
                    {% if sonata_page.isEditor and sonata_page.isInlineEditionOn %}
                        data-page-editor='{{ {
                            url: {
                                block_save_position: sonata_admin.objectUrl('sonata.page.admin.page', 'edit', page),
                                block_edit:          sonata_admin.url('sonata.page.admin.page|sonata.page.admin.block', 'edit', {'id': 'BLOCK_ID'})
                            }
                        }|json_encode()|raw }}'
                    {% endif %}>
                        <div class="container">
                            <ul class="nav navbar-nav">
                                {% if app.user and is_granted('ROLE_SONATA_ADMIN') %}
                                    <li><a href="{{ path('sonata_admin_dashboard') }}">{{ "header.sonata_admin_dashboard"|trans({}, 'SonataPageBundle') }}</a></li>
                                {% endif %}

                                {% if sonata_page.isEditor %}
                                    {% set sites = sonata_page.siteavailables %}

                                    {% if sites|length > 1 and site is defined %}
                                        <li class="dropdown">
                                            <a href="#" class="dropdown-toggle" data-toggle="dropdown">{{ site.name }} <span class="caret"></span></a>
                                            <ul class="dropdown-menu">
                                                {% for site in sites %}
                                                    <li><a href="{{ site.url }}">{{ site.name }}</a></li>
                                                {% endfor %}
                                            </ul>
                                        </li>
                                    {% endif %}

                                    <li class="dropdown">
                                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">Page <span class="caret"></span></a>
                                        <ul class="dropdown-menu">
                                            {% if page is defined %}
                                                <li><a href="{{ sonata_admin.objectUrl('sonata.page.admin.page', 'edit', page) }}" target="_new">{{ "header.edit_page"|trans({}, 'SonataPageBundle') }}</a></li>
                                                <li><a href="{{ sonata_admin.objectUrl('sonata.page.admin.page|sonata.page.admin.snapshot', 'list', page) }}" target="_new">{{ "header.create_snapshot"|trans({}, 'SonataPageBundle') }}</a></li>
                                                <li class="divider"></li>
                                            {% endif %}

                                            <li><a href="{{ sonata_admin.url('sonata.page.admin.page', 'list') }}" target="_new">{{ "header.view_all_pages"|trans({}, 'SonataPageBundle') }}</a></li>

                                            {% if error_codes is defined and error_codes|length %}
                                                <li class="divider"></li>
                                                <li><a href="{{ path('sonata_page_exceptions_list') }}" target="_new">{{ "header.view_all_exceptions"|trans({}, 'SonataPageBundle') }}</a></li>
                                            {% endif %}
                                        </ul>
                                    </li>

                                    {% if page is defined %}
                                        <li>
                                            <a href="{{ sonata_admin.url('sonata.page.admin.page', 'compose', {'id': page.id}) }}">
                                                <i class="fa fa-magic"></i>
                                                {{ 'header.compose_page'|trans({}, 'SonataPageBundle')}}
                                            </a>
                                        </li>
                                    {% endif %}

                                    {% if page is defined and not page.enabled %}
                                        <li><span style="padding-left: 20px; background: red;"><strong><em>{{ 'header.page_is_disabled'|trans([], 'SonataPageBundle') }}</em></strong></span></li>
                                    {% endif %}

                                    {% if sonata_page.isInlineEditionOn and page is defined %}
                                        <li>
                                            <form class="form-inline" style="margin: 0px">
                                                <label class="checkbox inline" for="page-action-enabled-edit"><input type="checkbox" id="page-action-enabled-edit">{{ 'header.show_zone'|trans({}, 'SonataPageBundle') }}</label>
                                                <input type="submit" class="btn" value="{{ 'btn_save_position'|trans({}, 'SonataPageBundle') }}" id="page-action-save-position">
                                            </form>
                                        </li>
                                    {% endif %}
                                {% endif %}

                                {% if app.user and is_granted('ROLE_PREVIOUS_ADMIN') %}
                                    <li><a href="{{ url('homepage', {'_switch_user': '_exit'}) }}">{{ "header.switch_user_exit"|trans({}, 'SonataPageBundle')}}</a></li>
                                {% endif %}

                            </ul>
                        </div>
                    </header>

                {% endif %}
            {% endblock %}
        {% endblock %}

        {% block sonata_page_container %}
            {% block page_container %}{% endblock %} {# Deprecated block #}
        {% endblock %}

        {% block sonata_page_asset_footer %}
            {% block page_asset_footer %} {# Deprecated block #}
                {% if page is defined %}
                    {% if page.javascript is not empty %}
                        <script>
                            {{ page.javascript|raw }}
                        </script>
                    {% endif %}
                    {% if page.stylesheet is not empty %}
                        <style>
                            {{ page.stylesheet|raw }}
                        </style>
                    {% endif %}
                {% endif %}
                {#
                    These includes can be done only at this point as all blocks are loaded,
                    Limition : this does not work if a global page is loaded from an ESI tag inside a container block
                #}
                {{ sonata_block_include_stylesheets('screen', app.request.basePath) }}
                {{ sonata_block_include_javascripts('screen', app.request.basePath) }}
            {% endblock %}
        {% endblock %}

        <!-- monitoring:3e9fda56df2cdd3b039f189693ab7844fbb2d4f6 -->
    </body>
</html>

e il nostro modello

{#/templates/Layouts/test-layout.html.twig#}
{#

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.

#}
{% extends '/Layouts/base_layout.html.twig' %}

{% block sonata_page_container %}
    <div class="container">
        <div class="content">
            <div class="row page-header">
                {{ sonata_page_render_container('header', 'global') }}
            </div>

           <!---->   {% block sonata_page_breadcrumb %}
                <div class="row">
                    {{ sonata_block_render_event('breadcrumb', { 'context': 'page', 'current_uri': app.request.requestUri }) }}
                </div>
            {% endblock %}

            {% if page is defined %}
                <div class="row">
                    {% if page.name != 'global'%}
                        {{ sonata_page_render_container('content_top', 'global') }}
                    {% endif %}
                    {{ sonata_page_render_container('content_top', page) }}
                </div>
            {% endif %}

            <div class="row">
                {% block page_content %}
                    {% if content is defined %}
                        {{ content|raw }}
                    {% else %}
                        {% set content = block('content') is defined ? block('content') : '' %}
                        {% if content|length > 0 %}
                            {{ content|raw }}
                        {% elseif page is defined %}
                            {{ sonata_page_render_container('content', page) }}
                        {% endif %}
                    {% endif %}
                {% endblock %}
            </div>

            {% if page is defined %}
                <div class="row">
                    {{ sonata_page_render_container('content_bottom', page) }}

                    {% if page.name != 'global'%}
                        {{ sonata_page_render_container('content_bottom', 'global') }}
                    {% endif %}
                </div>
            {% endif %}
        </div>

        <footer class="row">
            {{ sonata_page_render_container('footer', 'global') }}
        </footer>
    </div>
{% endblock %}

Lo référiferimento successivamente nel file di configurazione del bundle

sonata_page:
       test:
            path: 'Layouts/test-layout.html.twig'
            name: 'test'
            containers:
                header:
                    name: Header
                content_top:
                    name: Top content
                content:
                    name: Main content
                content_bottom:
                    name: Bottom content
                footer:
                    name: Footer
            matrix:
                layout: |
                    HHHHHHHH
                    HHHHHHHH
                    TTTTTTTT
                    TTTTTTTT
                    CCCCCCCC
                    CCCCCCCC
                    BBBBBBBB
                    BBBBBBBB
                    FFFFFFFF
                    FFFFFFFF

                mapping:
                    H: header
                    T: content_top
                    C: content
                    B: content_bottom
                    F: footer
                    

Nostra él'edizione in frontale è quasi funzionante.
Abbiamo effettivamente una barra di navigazione nella nostra pagina. Quando l’su attivo l’éedizione delle zone, tutto s’visualizza correttamente. Se si fa doppio clic su un'area del blocco, una finestraêtre s’manifesto con l’édizione del blocco in l’admin. E quando l’si muovono i blocchi di’una zona a un'altra, çha le déposto bene. Ma se si guarda la pagina, niente n’è salvatoé.
Dovremo créessere una méthode dédié di nota coté per salvare i paramètre.

Sélection_303

Andiamo quindi créessere un contrôloro nel nostro pacchetto éteso, per géfare la messa à giorno della donazioneée.

Su créé il nostro controller UpdatePositionController con il nostro méthode sonata_page_update_position()

<?php

namespace App\Application\Sonata\PageBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpFoundation\BinaryFileResponse;





use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Sonata\MediaBundle\Entity\MediaManager; 
use Sonata\MediaBundle\Provider\FileProvider;
use Symfony\Component\HttpKernel\KernelInterface;
use Psr\Container\ContainerInterface;

class UpdatePositionController extends AbstractController
{

    
    /**
     * @Route("/sonata-page-update-position", methods={"GET","POST"}, name="sonata_page_update_position")
     *
     *
     * @return array
     */
    public function sonata_page_update_position(Request $request)
    {
        $keyword=$request->request->all();
 
        if(!empty($keyword['disposition']))
        {
            foreach($keyword['disposition'] as $i=>$v)
            {
                $id=$keyword['disposition'][$i]['id'];
                $position=$keyword['disposition'][$i]['position'];
                $parent_id=$keyword['disposition'][$i]['parent_id'];
                $page_id=$keyword['disposition'][$i]['page_id'];
                
                $connection = $this->getDoctrine()->getConnection();
                $statement = $connection->prepare("UPDATE `page__block` SET `parent_id` = :parent_id, `position` = :position, `page_id`=:page_id WHERE `page__block`.`id` = :id ");
                
                $statement->bindValue('id', $id);
                $statement->bindValue('page_id', $page_id);
                $statement->bindValue('position', $page_id);
                $statement->bindValue('parent_id', $parent_id);
                $statement->execute();
            }
        }
        return new JsonResponse( (object) [
           'result' => 'ok'
        ]);

    }
}
?>


Dobbiamo poi il réféincontrare nei nostri servizi :

services:
    App\Application\Sonata\PageBundle\Controller\:
        resource: '../src/Application/Sonata/PageBundle/Controller'
        tags: ['controller.service_arguments']

Si deve poi il référenter dans les annotazioni in modo che la route sia automaticamente géré tramite Symfony :

#config/routes/annotations.yaml
controllers:
    resource: ../../src/Controller/
    type: annotation

controllers_sonata_pages:
    resource: ../../src/Application/Sonata/PageBundle/Controller/
    type: annotation  

E per finire, dobbiamo modificare il collegamento di messa à giorno di l’ordine dei blocchi nel nostro template che deve être : block_save_position: ‘{{ path(‘sonata_page_update_position’, {}) }}’,

{#

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 sonata_page_html_tag -%}
<!DOCTYPE html>
<html {{ sonata_seo_html_attributes() }}>
{% endblock %}
    {% block sonata_page_head %}
        <head {{ sonata_seo_head_attributes() }}>

            <!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
            {{ sonata_seo_title() }}
            {{ sonata_seo_metadatas() }}

            {% block sonata_page_stylesheets %}
                {% block page_stylesheets %} {# Deprecated block #}
                    {% for stylesheet in sonata_page.assets.stylesheets %}
                        <link rel="stylesheet" href="{{ asset(stylesheet) }}" media="all">
                    {% endfor %}
                {% endblock %}
            {% endblock %}

            {% block sonata_page_javascripts %}
                {% block page_javascripts %} {# Deprecated block #}
                    <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
                    <!--[if lt IE 9]>
                        <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
                    <![endif]-->
 					
                    {% for js in sonata_page.assets.javascripts %}
                        <script src="{{ asset(js) }}"></script>
                    {% endfor %}
                    <script src="/bundles/pixsortablebehavior/js/jquery-ui.min.js"></script>
                {% endblock %}

            {% endblock %}
        </head>
    {% endblock %}

    {% block sonata_page_body_tag %}
        <body class="sonata-bc">
    {% endblock %}

        {% block sonata_page_top_bar %}
        
      
            {% block page_top_bar %} {# Deprecated block #}
                {% if sonata_page.isEditor or ( app.user and is_granted('ROLE_PREVIOUS_ADMIN') ) %}

                    {% if sonata_page.isEditor and sonata_page.isInlineEditionOn %}
                        <!-- CMS specific variables -->
                        <script>
                            jQuery(document).ready(function() {
                                Sonata.Page.init({
                                    url: {
                                    	block_save_position: '{{ path('sonata_page_update_position', {}) }}',
                                        block_edit:          '{{ sonata_admin.url('sonata.page.admin.page|sonata.page.admin.block', 'edit', {'id': page.id , 'childId': 'BLOCK_ID'}) }}'
                                    }
                                });
                            });
                        </script>
                    {% endif %}

                    <header class="sonata-bc sonata-page-top-bar navbar navbar-inverse navbar-fixed-top" role="banner"
                    {% if sonata_page.isEditor and sonata_page.isInlineEditionOn %}
                        data-page-editor='{{ {
                            url: {
                            
                                block_save_position: path('sonata_page_update_position', {}),
                                block_edit:          sonata_admin.url('sonata.page.admin.page|sonata.page.admin.block', 'edit', {'id': page.id , 'childId': 'BLOCK_ID'})
                            }
                        }|json_encode()|raw }}'
                    {% endif %}>
                        <div class="container">
                            <ul class="nav navbar-nav">
                                {% if app.user and is_granted('ROLE_SONATA_ADMIN') %}
                                    <li><a href="{{ path('sonata_admin_dashboard') }}">{{ "header.sonata_admin_dashboard"|trans({}, 'SonataPageBundle') }}</a></li>
                                {% endif %}

                                {% if sonata_page.isEditor %}
                                    {% set sites = sonata_page.siteavailables %}

                                    {% if sites|length > 1 and site is defined %}
                                        <li class="dropdown">
                                            <a href="#" class="dropdown-toggle" data-toggle="dropdown">{{ site.name }} <span class="caret"></span></a>
                                            <ul class="dropdown-menu">
                                                {% for site in sites %}
                                                    <li><a href="{{ site.url }}">{{ site.name }}</a></li>
                                                {% endfor %}
                                            </ul>
                                        </li>
                                    {% endif %}

                                    <li class="dropdown">
                                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">Page <span class="caret"></span></a>
                                        <ul class="dropdown-menu">
                                            {% if page is defined %}
                                                <li><a href="{{ sonata_admin.objectUrl('sonata.page.admin.page', 'edit', page) }}" target="_new">{{ "header.edit_page"|trans({}, 'SonataPageBundle') }}</a></li>
                                                <li><a href="{{ sonata_admin.objectUrl('sonata.page.admin.page|sonata.page.admin.snapshot', 'list', page) }}" target="_new">{{ "header.create_snapshot"|trans({}, 'SonataPageBundle') }}</a></li>
                                                <li class="divider"></li>
                                            {% endif %}

                                            <li><a href="{{ sonata_admin.url('sonata.page.admin.page', 'list') }}" target="_new">{{ "header.view_all_pages"|trans({}, 'SonataPageBundle') }}</a></li>

                                            {% if error_codes is defined and error_codes|length %}
                                                <li class="divider"></li>
                                                <li><a href="{{ path('sonata_page_exceptions_list') }}" target="_new">{{ "header.view_all_exceptions"|trans({}, 'SonataPageBundle') }}</a></li>
                                            {% endif %}
                                        </ul>
                                    </li>

                                    {% if page is defined %}
                                        <li>
                                            <a href="{{ sonata_admin.url('sonata.page.admin.page', 'compose', {'id': page.id}) }}">
                                                <i class="fa fa-magic"></i>
                                                {{ 'header.compose_page'|trans({}, 'SonataPageBundle')}}
                                            </a>
                                        </li>
                                    {% endif %}

                                    {% if page is defined and not page.enabled %}
                                        <li><span style="padding-left: 20px; background: red;"><strong><em>{{ 'header.page_is_disabled'|trans([], 'SonataPageBundle') }}</em></strong></span></li>
                                    {% endif %}

                                    {% if sonata_page.isInlineEditionOn and page is defined %}
                                        <li>
                                            <form class="form-inline" style="margin: 0px">
                                                <label class="checkbox inline" for="page-action-enabled-edit"><input type="checkbox" id="page-action-enabled-edit">{{ 'header.show_zone'|trans({}, 'SonataPageBundle') }}</label>
                                                <input type="submit" class="btn" value="{{ 'btn_save_position'|trans({}, 'SonataPageBundle') }}" id="page-action-save-position">
                                            </form>
                                        </li>
                                    {% endif %}
                                {% endif %}

                                {% if app.user and is_granted('ROLE_PREVIOUS_ADMIN') %}
                                    <li><a href="{{ url('homepage', {'_switch_user': '_exit'}) }}">{{ "header.switch_user_exit"|trans({}, 'SonataPageBundle')}}</a></li>
                                {% endif %}

                            </ul>
                        </div>
                    </header>

                {% endif %}
            {% endblock %}
        {% endblock %}

        {% block sonata_page_container %}
            {% block page_container %}{% endblock %} {# Deprecated block #}
        {% endblock %}

        {% block sonata_page_asset_footer %}
            {% block page_asset_footer %} {# Deprecated block #}
                {% if page is defined %}
                    {% if page.javascript is not empty %}
                        <script>
                            {{ page.javascript|raw }}
                        </script>
                    {% endif %}
                    {% if page.stylesheet is not empty %}
                        <style>
                            {{ page.stylesheet|raw }}
                        </style>
                    {% endif %}
                {% endif %}
                {#
                    These includes can be done only at this point as all blocks are loaded,
                    Limition : this does not work if a global page is loaded from an ESI tag inside a container block
                #}
                {{ sonata_block_include_stylesheets('screen', app.request.basePath) }}
                {{ sonata_block_include_javascripts('screen', app.request.basePath) }}
            {% endblock %}
        {% endblock %}

        <!-- monitoring:3e9fda56df2cdd3b039f189693ab7844fbb2d4f6 -->
    </body>
</html>

Ecco il résultato :

Adattare l’esempio alla versione installata

Gli esempi Symfony e Sonata rimangono legati alle versioni indicate nell’articolo. Symfony 4.x e Symfony 6.2 non sono più supportati: per un progetto attuale, utilizzate un ramo mantenuto e la documentazione corrispondente esattamente alle vostre dipendenze.

php bin/console about
composer show symfony/framework-bundle sonata-project/admin-bundle

Prima di riprendere il codice, controllate le firme, i servizi, le rotte e i template interessati. Aggiungete poi un test funzionale che copra le autorizzazioni, il codice HTTP e il risultato visibile.

Riferimento : versioni di Symfony supportate.

Condividi questo articolo