Parliamo del progetto
PHP symfony Sonata

Symfony 4 / Sonata : Creare un'interfaccia di configurazione.

Uno dei bisogni récorrente d’un progetto web, è di’avere bisogno di paramèmolto globali per la vostra applicazione. Généraramente, in magazzinoça in un file yml e il gioco è fattoé. Ma la situazione si c...

Symfony 4 / Sonata : Creare un'interfaccia di configurazione.

Uno dei bisogni récorrente d’un progetto web, è di’avere bisogno di paramèmolto globali per la vostra applicazione. Généraramente, in magazzinoça in un file yml e il gioco è fattoé. Ma la situazione si complica quando il cliente chiedeàpoter mettere le mani sopra.
Lui dare gli accès FTP/SSH per modificarli? No, certamente no. Soprattutto se c’è per rifilare questo compito al tirocinante.

Bisognerà metterglieloàdisposizione di un'interfaccia di’admin con un modulo per poterli modificare.

Nel nostro caso, abbiamo bisogno solo di alcuni paramèmolto, ma questa interfaccia permetterà di gérer tanto di paramèpiù di quanto desideriamo.

Créazione della nostra tavola

Su crééun tavolo tutto bête con MySQL Workbench, o con make:entity. A scelta.
Nel nostro esempio, useremo solo 2 campi data per un déscopo e fine di’un'offerta.
Abbiamo bisogno di’un campo chiave, che conterrà la parola chiave che permetterà di puntarvi sopra. E un campo valore, che conterrà una stringaînato con il valore sérialée.
E un ultimo campo con l'ultimaère data di messaàgiorno.

Sélection_219

Créazione della nostra interfaccia di’amministratore

Una volta che il nostro tavolo è créécon MysqlWorkbench o PhpMyAdmin, si creaée la nostra entitàé e repository

php bin/console doctrine:mapping:import "App\Entity" annotation --path=src/Entity

E affinché il nostro repository sia créé, dovremo aggiungere l’annotazione seguente e régénémescolare tutto

@ORM\Entity(repositoryClass="App\Repository\parametresRepository")

Per dare questo :

/**
 * Parametres
 *
 * @ORM\Table(name="parametres", indexes={@ORM\Index(name="clef", columns={"clef"})})
 * @ORM\Entity(repositoryClass="App\Repository\parametresRepository")
 */
class Parametres
{

Su régénèi file

php bin/console make:entity --regenerate App

Su crééil nostro admin :

php bin/console make:sonata:admin
image-4

Ed eccoàa questo stadio abbiamo crééla nostra interfaccia di’admin dei paramétrage, con un CRUD semplice.

image-5


Tranne, che non’non è ciò che’vogliamo, même stessoça funzionerei quando mêio.
Quindi andiamo créaprire una pagina di’admin où l’l'utente non potrà creareéer e modificare ciò che’lui vuole, ma solo i nostri 2 paramètre.

Par déserve, la nostra interfaccia punta sulla vista elenco. c’è questa azione che useremo.
E per sovraccaricarla dovrà créper un controller.

Sélection_216

Poi l’aggiungere nella configurazione il nostro servizio admin aggiungendo il controller (App\Controller\ParametresController) negli argomenti :

    admin.parametres:
        class: App\Admin\ParametresAdmin
        arguments: [~, App\Entity\Parametres, App\Controller\ParametresController]
        tags:
            - { name: sonata.admin, manager_type: orm, group: admin, label: Parametres }
        public: true

Poi, dobbiamo cambiare l’estendere il nostro controller per che’utilizza CRUDController invece di AbstractController. Dobbiamo anche aggiungere il nostro mémetodo listAction che punta al proprio template.

<?php

namespace App\Controller;

#use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Sonata\AdminBundle\Controller\CRUDController;

class ParametresController extends CRUDController
{
    
    public function listAction()
    {
        
        
        if (false === $this->admin->isGranted('LIST')) {
            throw new AccessDeniedException();
        }
        
        return $this->render('Admin/parametres/listAction.html.twig', [
            'controller_name' => 'ParametresController',
        ]);
    }
}

Installare un selettore di data

Come il nostro parametroètre è una data. Dovremo installare un datepicker. La documentazione parla di eonasdan bootstrap-datetimepicker

composer require eonasdan/bootstrap-datetimepicker
php bin/console assets:install

Si aggiunge un thèmeàrametto

# config/packages/twig.yaml.yml

twig:
    form_themes:
        - '@SonataCore/Form/datepicker.html.twig'

E si aggiunge la référiferimento ai nostri asset in sonata_admin.yaml

    assets:
        extra_stylesheets:
            - bundles/sonataformatter/markitup/skins/sonata/style.css
            - bundles/sonataformatter/markitup/sets/markdown/style.css
            - bundles/sonataformatter/markitup/sets/html/style.css
            - bundles/sonataformatter/markitup/sets/textile/style.css
            - css/admin.css
            - build/admin.css
            - css/fontawesome/css/all.css
            - bundles/sonatacore/vendor/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css


        extra_javascripts:
            - bundles/fosckeditor/ckeditor.js
            - bundles/sonataformatter/vendor/markitup-markitup/markitup/jquery.markitup.js
            - bundles/sonataformatter/markitup/sets/markdown/set.js
            - bundles/sonataformatter/markitup/sets/html/set.js
            - bundles/sonataformatter/markitup/sets/textile/set.js
            - bundles/pixsortablebehavior/js/jquery-ui.min.js
            - bundles/pixsortablebehavior/js/init.js
            - bundles/sonatacore/vendor/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js
            - js/admin.js

Créazione del nostro modulo

In primo luogo noi andiamo créessere una mémetodo per mettereàgiorno i nostri valori secondo le nostre chiavi del nostro parametroètre. Questa méthode sarà collocatoée nel nostro repository.

<?php

namespace App\Repository;

use App\Entity\Parametres;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;


class ParametresRepository extends ServiceEntityRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        $this->registry=$registry;
        $this->connection=$this->registry->getManager()->getConnection();

        parent::__construct($registry, Parametres::class);
    }

    public function updateConfig($clef,$valeur){
        $em = $this->registry->getManager();
        $item = $this->createQueryBuilder('p')
        ->andWhere('p.clef = :val')
        ->setParameter('val', $clef)
        ->getQuery()
        ->getOneOrNullResult();
        if (!$item) {
            $item = new Parametres();
            $item->setValeur($valeur);
            $item->setClef($clef);
            $item->setUpdatedAt(date("Y-m-d H:i:s",strtotime('now')));
            $em->persist($item);
        }else{
            $item->setValeur($valeur);
            $item->setUpdatedAt(date("Y-m-d H:i:s",strtotime('now')));
        }
       $em->flush();
    }
}

Poi, vogliamo memorizzare dei valori. Possonoêtre di tutte le nature. Quindi andremo a conservare dei élémenti sérialés.
Dobbiamo quindi modificare il nostro getter e il nostro setter della nostra entity Parametres. E mettere il nostro campo data in tipo stringa per maggiore facilitàés.

    public function getValeur(): ?string
    {
        return unserialize($this->valeur);
    }

    public function setValeur(?string $valeur): self
    {
        $this->valeur = serialize($valeur);

        return $this;
    }

    public function getUpdatedAt(): ?string
    {
        return $this->updatedAt;
    }

    public function setUpdatedAt(?string $updatedAt): self
    {
        $this->updatedAt = $updatedAt;

        return $this;
    }

Si può quindi créper il nostro modulo, con la sua véverifica nel nostro controller. Aggiungiamo tutto di mêmi alcune funzioni per gévedere le nostre date.

<?php

namespace App\Controller;

use Symfony\Component\Routing\Annotation\Route;
use Sonata\AdminBundle\Controller\CRUDController;
use App\Entity\Parametres;

use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\HttpFoundation\Request;
use Sonata\CoreBundle\Form\Type\DatePickerType;
use Sonata\CoreBundle\Form\Type\DateTimePickerType;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Validator\Context\ExecutionContextInterface;

class ParametresController extends CRUDController
{
    
    private function getConfigData() {
        $em = $this->container->get('doctrine.orm.entity_manager');
        $config = $em->getRepository(Parametres::class)->findAll();
        $data=[];
        foreach($config as $c){
            $data[$c->getClef()]=$c->getValeur();
        }
        return $data;
    }
    
    public function listAction()
    {
        
        
        if (false === $this->admin->isGranted('LIST')) {
            throw new AccessDeniedException();
        }
        
        $request = $this->getRequest();
        $locale = $this->getRequest()->getLocale();
        
        $data = $this->getConfigData();
       
        
        $formBuilder = $this->createFormBuilder(null, [
            'constraints' => [new Callback([$this, 'formValidate'])]
        ]);
        $formBuilder->add("offre_date_debut", DatePickerType::class, [
            'required' => true,
            'dp_use_current' => false,
            'dp_min_date' => new \DateTime("2020-01-01"),
            'data' => isset($data['offre_date_debut']) ? new \DateTime('@'.$this->parseDate($data['offre_date_debut'],$locale)) : new \DateTime(),
            'mapped' => false,
        ])
        ->add("offre_date_fin", DatePickerType::class, [
            'required' => true,
            'dp_use_current' => false,
            'dp_min_date' => new \DateTime("2020-01-01"),
            'data' => isset($data['offre_date_fin']) ? new \DateTime('@'.$this->parseDate($data['offre_date_fin'],$locale)) : new \DateTime(),
            'mapped' => false,
        ])
        ->add('submit', SubmitType::class, [
            'label' => $this->get('translator')->trans('Valider')
        ]);

        $form = $formBuilder->getForm();
        $form->handleRequest($request);
        
        if ($form->isSubmitted() && $form->isValid()) {
            $formData = $this->getRequest()->request->get('form');
            $ParametresRepositoty = $this->container->get('doctrine.orm.entity_manager')->getRepository(Parametres::class);
            $ParametresRepositoty->updateConfig('offre_date_debut', date("Y-m-d", $this->parseDate($formData['offre_date_debut'],$locale)) );
            $ParametresRepositoty->updateConfig('offre_date_fin',date("Y-m-d",$this->parseDate($formData['offre_date_fin'],$locale)));
            $this->addFlash('success', $this->get('translator')->trans('Parametres sauvegardés.'));
        }
        
        
        return $this->render('Admin/parametres/listAction.html.twig', [
            'controller_name' => 'ParametresController',
            'form' => $form->createView()
        ]);
    }
    

    
    public function formValidate($data, ExecutionContextInterface $context) {
    
        $data = $this->getRequest()->request->get('form');
        $locale = $this->getRequest()->getLocale();
        
        if (isset($data['offre_date_debut'])) {
            $offre_date_debut = $this->parseDate($data['offre_date_debut'], $locale);
            $offre_date_debut = new \DateTime("@$offre_date_debut");
        }
        if (isset($data['offre_date_fin'])) {
            $offre_date_fin = $this->parseDate($data['offre_date_fin'], $locale);
            $offre_date_fin = new \DateTime("@$offre_date_fin");
        }
    }
    
    
    public function parseDate($date, $locale, $format = 'dd LLL. y') {
        $fmt = \IntlDateFormatter::create(
            $locale,
            \IntlDateFormatter::FULL,
            \IntlDateFormatter::FULL,
            'Etc/UTC',
            \IntlDateFormatter::GREGORIAN,
            $format
            );
        if (isset($date)) {
            $parse_date = $fmt->parse($date);
            return $parse_date;
        }
        return null;
    }
}

La nostra ultimaèreénastro consisteàformattare la nostra pagina nel nostro template twig che abbiamo posizionatoéin templates/Admin/parametres/listAction.html.twig

{% extends '@SonataAdmin/standard_layout.html.twig' %}

{% block notice %}
    {{ parent() }}
{% endblock %}

{% form_theme form _self %}

{# form_errors.html.twig #}
{% block form_errors %}
    {% spaceless %}
        {% if errors|length > 0 %}
            {% for error in errors %}
            <div class="alert alert-danger alert-dismissable">
            <button type="button" class="close" data-dismiss="alert" aria-hidden="true" aria-label="Fermer">×</button>
                {{ error.message }}
            </div>
            {% endfor %}
        {% endif %}
    {% endspaceless %}
{% endblock form_errors %}

{% block sonata_admin_content %}
    {% include 'SonataCoreBundle:FlashMessage:render.html.twig' %}

    <div>
        {{ form_errors(form) }}
        <h2 class="title-border">{{ 'Paramétrage'|trans }}</h2>
        <p>{{ 'Modifiaction des parametres transverse de l\'application'|trans }}</p>
        <div class="sonata-ba-form">
        {{ form_start(form, { attr: { class: 'form-setting-general form-theme' }}) }}
        <div class="box-body container-fluid">
            <div class="sonata-ba-collapsed-fields form-theme-hoz">
                <div class="row">
                    <div class="">
                        <div class="box box-primary">
                            <div class="box-header with-border">
                                <h4 class="box-title">{{ 'Dates par défaut des offres'|trans }}</h4>
                            </div>
                            <div class="box-body">
                            
                                <div class="sonata-ba-collapsed-fields">
                                    <div class="form-group">
                                        <label class="control-label required" for="form_date_manifestation">{{ 'Date de début'|trans }}</label>
                                        <div class="sonata-ba-field sonata-ba-field-standard-natural">
                                            {{ form_widget(form.offre_date_debut, { attr: { class: 'sonata-medium-date form-control' }}) }}
                                        </div>
                                    </div>
                                </div>
                                
                                <div class="sonata-ba-collapsed-fields">
                                    <div class="form-group">
                                        <label class="control-label required" for="form_date_manifestation">{{ 'Date de fin'|trans }}</label>
                                        <div class="sonata-ba-field sonata-ba-field-standard-natural">
                                            {{ form_widget(form.offre_date_fin, { attr: { class: 'sonata-medium-date form-control' }}) }}
                                        </div>
                                    </div>
                                </div>
                                
                                
                            </div>
                        </div>
                    </div>

                    <div class="sonata-ba-form-actions well well-small form-actions">
                                   {{ form_widget(form.submit, { attr: { class: 'btn btn-success' }}) }}                                                                                                                
                     </div>


                </div>
            </div>
        </div>
                                                                                         
        {{ form_end(form) }}
        </div>
    </div>
{% endblock %}

Ed ecco il rendering della nostra pagina

image-6

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