Framework PHP: scegliere tra Symfony e Laravel

Pubblicato: 2022-03-11

Oggi, quando si inizia un nuovo progetto, una delle decisioni chiave è scegliere la struttura giusta. Al giorno d'oggi è diventato difficile immaginare di creare un'applicazione Web complessa da zero senza una.

Molti linguaggi popolari per lo sviluppo web hanno il loro framework "predefinito", come Ruby on Rails per Ruby o Django per Python. Tuttavia, PHP non ha un unico valore predefinito e ha più opzioni popolari tra cui scegliere.

Secondo le tendenze di Google e GitHub, i framework PHP più popolari sono Symfony con 13.7k stelle e Laravel con 29k stelle (al momento della stesura di questo articolo).

In questo articolo, confronterò questi due framework e ti mostrerò come implementare funzionalità semplici e quotidiane con ciascuno. In questo modo, puoi confrontare il codice di esempi di vita reale fianco a fianco.

Questo articolo presuppone forti competenze in PHP e una comprensione del paradigma dell'architettura MVC, ma non è richiesta alcuna esperienza precedente con Symfony o Laravel.

I contendenti

Laravel

Quando parliamo di Laravel, ci riferiamo a Laravel versione 4 e successive. Laravel 4 è stato rilasciato nel 2013 e ha rappresentato una riscrittura completa del framework. La funzionalità del framework è stata disaccoppiata in componenti separati, che sono stati gestiti con Composer, invece di essere tutto in un unico enorme repository di codice.

Laravel si dichiara come un framework per uno sviluppo rapido con una sintassi semplice e bella che è facile da imparare, leggere e mantenere. È il framework più popolare nel 2016. Secondo le tendenze di Google, è tre volte più popolare di altri framework e su GitHub ha il doppio delle stelle rispetto ai concorrenti.

Symfony

Symfony 2 è stato rilasciato nel 2011, ma non deve essere confuso con Symfony 1, che era un framework completamente diverso con diversi principi di base. Fabien Potencier ha creato Symfony 2, e l'attuale versione è 3.2, che è una versione incrementale di Symfony 2. Pertanto, sono spesso chiamati semplicemente Symfony2/3.

Come Laravel 4, Symfony 2 è progettato come un insieme di componenti disaccoppiati. Ci sono due vantaggi qui: possiamo sostituire qualsiasi componente in un progetto Symfony e possiamo prendere e usare qualsiasi componente Symfony in un progetto non Symfony. I componenti di Symfony possono servire come ottimi esempi di codice e sono usati in molti progetti open source come Drupal, phpBB e Codeception. In effetti, Laravel stesso utilizza non meno di 14 componenti Symfony. Comprendere Symfony ti dà quindi molti vantaggi quando lavori con altri progetti.

Installazioni quadro

Entrambi i framework sono dotati di programmi di installazione e wrapper disponibili tramite il server Web integrato in PHP.

Installazione di Symfony

L'installazione di Symfony è semplice come la seguente:

 # Downloading Symfony installer sudo curl -LsS https://symfony.com/installer -o /usr/local/bin/symfony # Granting permissions to execute installer sudo chmod a+x /usr/local/bin/symfony # Creating new Symfony project symfony new symfony_project # Launching built-in server cd symfony_project/ && php bin/console server:start

Questo è tutto! La tua installazione di Symfony è disponibile sull'URL http://localhost:8000 .

Installazione Laravel

Il processo di installazione di Laravel è quasi lo stesso e semplice di quello di Symfony; l'unica differenza è che installi il programma di installazione di Laravel tramite Composer:

 # Downloading Laravel installer using Composer composer global require "laravel/installer" # Creating new Laravel project laravel new laravel_project # Launching built-in server cd laravel_project/ && php artisan serve

Ora puoi visitare http://localhost:8000 e controllare la tua installazione di Laravel.

Nota: Sia Laravel che Symfony utilizzano la stessa porta localhost (8000) per impostazione predefinita, quindi non è possibile eseguire queste istanze predefinite contemporaneamente. Non dimenticare di fermare il server Symfony eseguendo php bin/console server:stop prima di avviare il server Laravel.

Informazioni sull'installazione del framework

Questi sono esempi di installazione di base. Per esempi di utilizzo più avanzati, come la possibilità di configurare progetti con domini locali o eseguire più progetti contemporaneamente, entrambi i framework forniscono scatole Vagrant:

  • Fattoria Laravel,
  • Fattoria Symfony.

Configurazioni del quadro di base

Configurazione di base di Symfony

Symfony usa YAML come sintassi per specificare la sua configurazione. La configurazione predefinita si trova nel file app/config/config.yml e si presenta come il seguente esempio:

 imports: - { resource: parameters.yml } - { resource: security.yml } - { resource: services.yml } framework: secret: '%secret%' router: { resource: '%kernel.root_dir%/config/routing.yml' } # ... # Twig Configuration twig: debug: '%kernel.debug%' strict_variables: '%kernel.debug%' # ...

Per creare una configurazione specifica per l'ambiente, creare il file app/config/config_ENV.yml contenente i parametri di configurazione di base. Ecco un esempio di un file config_dev.yml per l'ambiente di sviluppo:

 imports: - { resource: config.yml } # ... web_profiler: toolbar: true # ...

Questo esempio attiva lo strumento web_profiler Symfony solo per l'ambiente di sviluppo. Questo strumento ti aiuta a eseguire il debug e il profilo della tua applicazione direttamente nella finestra del browser.

Nei file di configurazione, puoi anche notare %secret% costruzioni. Ci consentono di inserire variabili specifiche dell'ambiente nel file parameters.yml separato. Questo file potrebbe essere univoco su ogni macchina e non è archiviato sotto il controllo della versione. Per il controllo della versione, abbiamo uno speciale file parameters.yml.dist che è il modello per il file parameters.yml .

Ecco un esempio del file parameters.yml :

 parameters: database_host: 127.0.0.1 database_port: null database_name: symfony database_user: root database_password: null secret: f6b16aea89dc8e4bec811dea7c22d9f0e55593af

Configurazione di base di Laravel

La configurazione di Laravel sembra molto diversa da quella di Symfony. L'unica cosa che hanno in comune è che entrambi usano file che non sono archiviati sotto il controllo della versione ( .env nel caso Laravel) e un modello per generare questo file ( .env.example ). Questo file ha un elenco di chiavi e valori, come il seguente esempio:

 APP_ENV=local APP_KEY=base64:Qm8mIaur5AygPDoOrU+IKecMLWgmcfOjKJItb7Im3Jk= APP_DEBUG=true APP_LOG_LEVEL=debug APP_URL=http://localhost

Come il file YAML di Symfony, anche questo per Laravel è leggibile dall'uomo e sembra pulito. È inoltre possibile creare un file .env.testing che verrà utilizzato durante l'esecuzione dei test PHPUnit.

La configurazione dell'applicazione è memorizzata in file .php nella directory config . La configurazione di base è memorizzata nel file app.php e la configurazione specifica del componente è memorizzata nei file <component>.php (ad esempio, cache.php o mail.php ). Ecco un esempio di un file config/app.php :

 <?php return [ 'name' => 'Laravel', 'env' => env('APP_ENV', 'production'), 'debug' => env('APP_DEBUG', false), 'url' => env('APP_URL', 'http://localhost'), 'timezone' => 'UTC', 'locale' => 'en', // ... ];

Configurazione del framework: Symfony vs. Laravel

I meccanismi di configurazione dell'applicazione di Symfony consentono di creare file diversi per ambienti diversi. Inoltre, ti impedisce di inserire una logica PHP complessa nella configurazione YAML.

Tuttavia, potresti sentirti più a tuo agio con la sintassi di configurazione PHP predefinita utilizzata da Laravel e non devi imparare la sintassi YAML.

Instradamento e controllore

In generale, un'applicazione web back-end ha una responsabilità primaria: leggere ogni richiesta e creare una risposta a seconda del contenuto della richiesta. Il controller è una classe responsabile della trasformazione della richiesta in risposta chiamando i metodi dell'applicazione, mentre il router è un meccanismo che ti aiuta a rilevare quale classe e metodo di controller dovresti eseguire per una particolare richiesta.

Creiamo un controller che mostrerà una pagina di post del blog richiesta dal percorso /posts/{id} .

Routing e Controller in Laravel

Controllore

 <?php namespace App\Http\Controllers; use App\Post; class BlogController extends Controller { /** * Show the blog post * @param int $id * @return \Illuminate\Http\Response */ public function show($id) { return view('post', ['post' => Post::findOrFail($id)]); } }

Router

 Route::get('/posts/{id}', 'BlogController@show');

Abbiamo definito il percorso per le richieste GET . Tutte le richieste con l'URI corrispondente a /posts/{id} eseguiranno il metodo show del controller BlogController e passeranno l' id del parametro a quel metodo. Nel controller, stiamo cercando di trovare l'oggetto del modello POST con l' id passato e chiamare Laravel helper view() per eseguire il rendering della pagina.

Routing e controller in Symfony

In Symfony, exampleController è un po' più grande:

 <?php namespace BlogBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; class PostController extends Controller { /** * @Route("/posts/{id}") * @param int $id * @return \Symfony\Component\HttpFoundation\Response */ public function indexAction($id) { $repository = $this->getDoctrine()->getRepository('BlogBundle:Post'); $post = $repository->find($id); if ($post === null) { throw $this->createNotFoundException(); } return $this->render('BlogBundle:Post:show.html.twig', ['post'=>$post]); } }

Puoi vedere che abbiamo già incluso @Route("/posts/{id}”) nell'annotazione, quindi dobbiamo solo includere il controller nel file di configurazione routing.yml :

 blog: resource: "@BlogBundle/Controller/" type: annotation prefix: /

La logica passo passo è la stessa del caso Laravel.

Routing e controller: Symfony vs. Laravel

A questo punto, potresti pensare che Laravel sia molto più carino di Symfony. Questo è vero, all'inizio. Sembra molto migliore e più facile per iniziare. Tuttavia, nelle applicazioni reali, non dovresti chiamare Doctrine dal controller. Invece, dovresti chiamare un servizio che proverà a trovare il post o a lanciare HTTP 404 Exception .

Modelli

Laravel viene fornito con un motore modello chiamato Blade e Symfony viene fornito con Twig. Entrambi i motori di template implementano due caratteristiche principali:

  1. Ereditarietà del modello
  2. Blocchi o sezioni

Entrambe le funzionalità consentono di definire un modello di base con sezioni sovrascrivibili e modelli figlio che riempiono i valori di tali sezioni.

Consideriamo di nuovo l'esempio di una pagina di post di un blog.

Laravel Blade Template Engine

 // base.blade.php <html> <head> <style></style> <title>@section('page-title') Welcome to blog! @show </title> </head> <body> <div class="container"> <h1>@yield('title')</h1> <div class="row"> @yield('content') </div> </div> </body> </html> // post.blade.php @extends('base') @section('page-title')Post {{ $post->title }} - read this and more in our blog.@endsection @section('title'){{ $post->title }}@endsection @section('content') {{ $post->content }} @endsection

Ora puoi dire a Laravel nel tuo Controller di rendere il modello post.blade.php . Ricordi la nostra chiamata view('post', …) nel precedente esempio di Controller? Non è necessario sapere nel codice che è ereditato da qualche altro modello. È tutto definito solo nei tuoi modelli, a livello di visualizzazione.

Symfony Twig Template Engine

 // base.html.twig <html> <head> <style></style> <title>{% block page_title %} Welcome to blog! {% endblock %} </title> </head> <body> <div class="container"> <h1>{% block title %}{% endblock %}</h1> <div class="row"> {% block content %}{% endblock %} </div> </div> </body> </html> // show.html.twig {% extends '@Blog/base.html.twig' %} {% block page_title %}Post {{ post.title }} - read this and more in our blog.{% endblock %} {% block title %}{{ post.title }}{% endblock %} {% block content %} {{ post.content }} {% endblock %}

Modelli: Symfony contro Laravel

Strutturalmente, i modelli Blade e Twig sono abbastanza simili. Entrambi generano modelli in codice PHP e funzionano velocemente, ed entrambi implementano strutture di controllo, come istruzioni if ​​e loop. La caratteristica più importante di entrambi i motori è che sfuggono all'output per impostazione predefinita, il che aiuta a prevenire gli attacchi XSS.

A parte la sintassi, la differenza principale è che Blade ti consente di iniettare codice PHP direttamente nei tuoi modelli e Twig no. Invece, Twig ti consente di utilizzare i filtri.

Ad esempio, se vuoi mettere in maiuscolo una stringa, in Blade devi specificare quanto segue:

 {{ ucfirst('welcome friend') }}

In Twig, d'altra parte, dovresti fare quanto segue:

 {{ 'welcome friend'|capitalize }}

In Blade è più facile estendere alcune funzionalità, ma Twig non consente alcun codice PHP diretto nei modelli.

Iniezione di dipendenza

Le applicazioni hanno molti servizi e componenti diversi, con varie interdipendenze. È necessario archiviare in qualche modo tutte le informazioni sugli oggetti creati e le loro dipendenze.

Ecco che arriva il nostro prossimo componente: Service Container. È un oggetto PHP che crea i servizi richiesti e memorizza le informazioni sugli oggetti creati e le loro dipendenze.

Consideriamo il seguente esempio: stai creando una classe PostService per implementare un metodo responsabile della creazione di un nuovo post di blog. Questa classe dipende da altri due servizi: PostRepository , che è responsabile della memorizzazione delle informazioni nel database, e SubscriberNotifier , che è responsabile della notifica agli utenti iscritti del nuovo post. Per farlo funzionare, devi passare questi due servizi come argomenti del costruttore di PostService o, in altre parole, devi inserire queste dipendenze.

Esempio di iniezione di dipendenza di Symfony

Per prima cosa, definiamo i nostri servizi di esempio:

 <?php // src/BlogBundle/Repository/PostRepository.php namespace BlogBundle\Repository; use BlogBundle\Entity\Post; use Doctrine\ORM\EntityRepository; class PostRepository extends EntityRepository { public function persist(Post $post) { // Perform save to db } }
 <?php // src/BlogBundle/Service/SubscriberNotifier.php namespace BlogBundle\Service; use BlogBundle\Entity\Post; class SubscriberNotifier { public function notifyCreate(Post $post) { // Notify subscribers } }
 <?php // src/BlogBundle/Service/PostService namespace BlogBundle\Service; use BlogBundle\Entity\Post; use BlogBundle\Repository\PostRepository; class PostService { /** @var PostRepository */ private $repository; /** @var SubscriberNotifier */ private $notifier; function __construct(PostRepository $repository, SubscriberNotifier $notifier) { $this->repository = $repository; $this->notifier = $notifier; } public function create(Post $post) { $this->repository->persist($post); $this->notifier->notifyCreate($post); } }

La prossima è la configurazione dell'iniezione delle dipendenze:

 # src/BlogBundle/Resources/config/services.yml services: # Our main service blog.post_service: class: BlogBundle\Service\PostService arguments: ['@blog.post_repository', '@blog.subscriber_notifier'] # SubscriberNotifier service. It could also have its own dependencies, for example, mailer class. blog.subscriber_notifier: class: BlogBundle\Service\SubscriberNotifier # Repository. Don't dive deep into it's configuration, it is not a subject now blog.post_repository: class: BlogBundle\Repository\PostRepository factory: 'doctrine.orm.default_entity_manager:getRepository' arguments: - BlogBundle\Entity\Post

Ora puoi richiedere il tuo servizio postale in qualsiasi punto del codice dal tuo oggetto Service Container. Ad esempio, nel controller potrebbe essere qualcosa del genere:

 // Controller file. $post variable defined below $this->get('blog.post_service')->create($post);

Service Container è un ottimo componente e aiuta a creare la tua applicazione seguendo i principi di progettazione SOLID.

Correlati: Iniezione di vera dipendenza con i componenti di Symfony

Esempio di iniezione di dipendenza di Laravel

È molto più semplice gestire le dipendenze in Laravel. Consideriamo lo stesso esempio:

 <?php // app/Repository/PostRepository.php namespace App\Repository; use App\Post; class PostRepository { public function persist(Post $post) { // Perform save to db } }
 <?php // app/Service/SubscriberNotifier.php namespace App\Service; use App\Post; class SubscriberNotifier { public function notifyCreate(Post $post) { // Notify subscribers } }
 <?php // app/Service/PostService.php namespace App\Service; use App\Post; use App\Repository\PostRepository; class PostService { /** @var PostRepository */ private $repository; /** @var SubscriberNotifier */ private $notifier; public function __construct(PostRepository $repository, SubscriberNotifier $notifier) { $this->repository = $repository; $this->notifier = $notifier; } public function create(Post $post) { $this->repository->persist($post); $this->notifier->notifyCreate($post); } }

Ecco la bellezza di Laravel: non è necessario creare configurazioni di dipendenza . Laravel esegue automaticamente la scansione delle dipendenze per PostService nei tipi di argomenti del costruttore e le risolve automaticamente.

Puoi anche usare l'iniezione nel metodo del tuo controller per usare PostService "dando un suggerimento" negli argomenti del metodo:

 <?php namespace App\Http\Controllers; use App\Post; use App\Service\PostService; class BlogController extends Controller { public function create(PostService $service) { $post = new Post(['title' => 'Title', 'content' => 'Content']); $service->create($post); return redirect('/posts/'.$post->id); } }

Iniezione di dipendenza: Symfony contro Laravel

Il rilevamento automatico di Laravel funziona alla grande. Symfony ha una capacità simile chiamata "autowire" che è disattivata per impostazione predefinita e può essere attivata aggiungendo autowire: true alla configurazione delle dipendenze, ma richiede alcune configurazioni. Il modo Laravel è più semplice.

Mappatura relazionale degli oggetti (ORM)

Per lavorare con i database, entrambi i framework sono dotati di funzionalità Object-Relational Mapping (ORM). ORM mappa i record dal database agli oggetti nel codice. Per fare ciò, devi creare modelli per ogni tipo di record (o ogni tabella) nel tuo database.

Symfony usa un progetto di terze parti Doctrine per interagire con il database, mentre Laravel usa la propria libreria Eloquent.

L'ORM Eloquent implementa il modello ActiveRecord per lavorare con il database. In questo schema, ogni modello è a conoscenza della connessione al database e può interagire con esso. Ad esempio, può salvare i dati nel database, aggiornare o eliminare un record.

Doctrine implementa il modello Data Mapper, in cui i modelli non sanno nulla del database; sono a conoscenza solo dei dati stessi. Uno speciale livello separato, EntityManager , memorizza tutte le informazioni sull'interazione tra modelli e database e gestisce tutte le operazioni.

Facciamo un esempio per capire la differenza. Supponiamo che il tuo modello abbia una chiave id primaria, un titolo, un contenuto e un autore. La tabella Posts memorizza solo l' id autore, quindi è necessario creare una relazione con la tabella Users .

Dottrina

Iniziamo definendo i modelli:

 <?php // src/BlogBundle/Entity/User.php namespace BlogBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** * User * * @ORM\Table(name="user") * @ORM\Entity */ class User { /** * @var int * * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @var string * * @ORM\Column(name="name", type="string", length=255) */ private $name; }
 <?php // src/BlogBundle/Entity/Post.php namespace BlogBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** * Post * * @ORM\Table(name="post") * @ORM\Entity(repositoryClass="BlogBundle\Repository\PostRepository") */ class Post { /** * @var int * * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @var string * * @ORM\Column(name="title", type="string", length=255) */ protected $title; /** * @var string * * @ORM\Column(name="content", type="text") */ protected $content; /** * @var User * * @ORM\ManyToOne(targetEntity="BlogBundle\Entity\User") * @ORM\JoinColumn(name="author_id", referencedColumnName="id") */ protected $author;

Qui, abbiamo creato informazioni sulla mappatura del modello e ora possiamo utilizzare un helper per generare gli stub del metodo:

 php bin/console doctrine:generate:entities BlogBundle

Successivamente, definiamo i metodi di post repository:

 <?php // src/BlobBundle/Repository/PostRepository.php namespace BlogBundle\Repository; use BlogBundle\Entity\Post; use Doctrine\ORM\EntityRepository; class PostRepository extends EntityRepository { /** * Store post to database * * @param Post $post */ public function persist(Post $post) { $this->getEntityManager()->persist($post); $this->getEntityManager()->flush(); } /** * Search posts with given author's name * * @param string $name * @return array */ public function findByAuthorName($name) { return $this->createQueryBuilder('posts') ->select('posts') ->join('posts.author', 'author') ->where('author.name = :name') ->setParameter('name', $name) ->getQuery() ->getResult(); } }

Ora puoi chiamare questi metodi dal servizio o, ad esempio, da PostController :

 // To search for posts $posts = $this->getDoctrine()->getRepository('BlogBundle:Post')->findByAuthorName('Karim'); // To save new post in database $this->getDoctrine()->getRepository('BlogBundle:Post')->persist($post);

Eloquente

Il modello User viene fornito con Laravel ed è definito per impostazione predefinita, quindi è necessario definire solo un modello per Post .

 <?php // app/Post.php namespace App; use Illuminate\Database\Eloquent\Model; class Post extends Model { public function author() { return $this->belongsTo('App\User', 'author_id'); } }

Questo è tutto per i modelli. In Eloquent, non è necessario definire le proprietà del modello, poiché le crea dinamicamente in base alla struttura della tabella del database. Per memorizzare un nuovo post $post nel database, devi effettuare questa chiamata (dal controller, ad esempio):

 $post->save();

Per trovare tutti i post di un autore con un determinato nome, l'approccio migliore sarebbe trovare un utente con il suo nome e richiedere i post di tutti gli utenti:

 $posts = Post::whereHas('author', function ($q) { $q->where('name', 'Karim'); })->get();

ORM: Symfony contro Laravel

Per quanto riguarda ORM, Eloquent sembra molto più amichevole per gli sviluppatori PHP e più facile da imparare rispetto a Doctrine.

Event Dispatcher vs Middleware

Ciclo di vita di Symfony e Laravel

Una delle cose più importanti da capire su un framework è il suo ciclo di vita.

Symfony e Event Dispatcher

Per convertire una richiesta in una risposta, Symfony usa EventDispatcher. Di conseguenza, attiva diversi eventi del ciclo di vita e listener di eventi speciali per gestire questi eventi. All'inizio, invia l'evento kernel.request che include le informazioni sulla richiesta. Il principale listener predefinito di questo evento è RouterListener , che richiama il componente router per trovare una regola di instradamento adatta per la richiesta corrente. Successivamente, altri eventi vengono eseguiti passo dopo passo. I tipici listener di eventi sono un controllo di sicurezza, una verifica del token CSRF e un processo di registrazione. Se desideri aggiungere alcune funzionalità al ciclo di vita della richiesta, devi creare un EventListener personalizzato e iscriverlo all'evento necessario.

Laravel e Middleware

Laravel utilizza una soluzione diversa: il middleware. Mi piace confrontare il middleware con una cipolla: la tua applicazione ha determinati livelli e una richiesta passa attraverso questi livelli sulla strada per il controller e ritorno. Quindi, se desideri estendere la logica dell'applicazione e aggiungere alcune funzionalità nel ciclo di vita della richiesta, devi aggiungere un livello aggiuntivo all'elenco del middleware e Laravel lo eseguirà.

API REST

Proviamo a creare un esempio CRUD di base per gestire un post del blog:

  • Crea - POST /posts/
  • Leggi - GET /posts/{id}
  • Aggiornamento - PATCH /posts/{id}
  • Elimina - DELETE /posts/{id}

API REST in Symfony

Symfony non ha una soluzione pronta all'uso per la creazione rapida di API REST, ma ha ottimi bundle di terze parti FOSRestBundle e JMSSerializerBundle .

Consideriamo l'esempio di lavoro minimo con FOSRestBundle e JMSSerializerBundle . Dopo averli installati e attivati ​​in AppKernel , puoi impostare nella configurazione del bundle che utilizzerai il formato JSON e che questo non debba essere incluso nelle richieste URL:

 #app/config/config.yml fos_rest: routing_loader: default_format: json include_format: false

Nella configurazione di routing, è necessario specificare che questo controller implementerà una risorsa REST:

 #app/config/routing.yml blog: resource: BlogBundle\Controller\PostController type: rest

Hai implementato un metodo persist nel repository nell'esempio precedente; ora devi aggiungere un metodo di eliminazione:

 // src/BlogBundle/Repository/PostRepository.php public function delete(Post $post) { $this->getEntityManager()->remove($post); $this->getEntityManager()->flush(); }

Successivamente, è necessario creare una classe modulo per accettare le richieste di input e mapparle al modello. Puoi farlo usando un helper CLI:

 php bin/console doctrine:generate:form BlogBundle:Post

Riceverai un tipo di modulo generato con il seguente codice:

 <?php // src/BlogBundle/Form/PostType.php namespace BlogBundle\Form; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; class PostType extends AbstractType { /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('title')->add('content'); } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'data_class' => 'BlogBundle\Entity\Post', 'csrf_protection' => false ]); } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'post'; } }

Ora implementiamo il nostro controller.

Nota: il codice che sto per mostrarti non è perfetto. Viola alcuni principi di progettazione ma potrebbe essere facilmente rifattorizzato. Lo scopo principale è mostrarti come implementare ogni metodo, passo dopo passo.

 <?php // src/BlogBundle/Controller/PostController.php namespace BlogBundle\Controller; use BlogBundle\Entity\Post; use BlogBundle\Form\PostType; use FOS\RestBundle\Controller\FOSRestController; use FOS\RestBundle\View\View; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; class PostController extends FOSRestController { /** * @param $id * @return Response */ public function getPostAction($id) { $view = new View(); $post = $this->getDoctrine()->getRepository('BlogBundle:Post')->find($id); if ($post === null) { $view->setStatusCode(Response::HTTP_NOT_FOUND); } else { $view->setData(['post' => $post]); } return $this->handleView($view); } /** * @param Request $request * @return Response */ public function postPostAction(Request $request) { $view = new View(null, Response::HTTP_BAD_REQUEST); $post = new Post; $form = $this->createForm(PostType::class, $post, ['method' => $request->getMethod()]); $form->handleRequest($request); if ($form->isValid()) { $this->getDoctrine()->getRepository('BlogBundle:Post')->persist($post); $view->setStatusCode(Response::HTTP_CREATED); $postUrl = $this->generateUrl('get_post', ['id' => $post->getId()], UrlGeneratorInterface::ABSOLUTE_URL); $view->setHeader('Location', $postUrl); } else { $view->setData($form->getErrors()); } return $this->handleView($view); } /** * @param $id * @param Request $request * @return Response */ public function patchPostAction($id, Request $request) { $view = new View(null, Response::HTTP_BAD_REQUEST); $post = $this->getDoctrine()->getRepository('BlogBundle:Post')->find($id); if ($post === null) { $view->setStatusCode(Response::HTTP_NOT_FOUND); } else { $form = $this->createForm(PostType::class, $post, ['method' => $request->getMethod()]); $form->handleRequest($request); if ($form->isValid()) { $this->getDoctrine()->getRepository('BlogBundle:Post')->persist($post); $view->setStatusCode(Response::HTTP_NO_CONTENT); $postUrl = $this->generateUrl('get_post', ['id' => $post->getId()], UrlGeneratorInterface::ABSOLUTE_URL); $view->setHeader('Location', $postUrl); } else { $view->setData($form->getErrors()); } } return $this->handleView($view); } /** * @param $id * @return Response */ public function deletePostAction($id) { $view = new View(null, Response::HTTP_NOT_FOUND); $post = $this->getDoctrine()->getRepository('BlogBundle:Post')->find($id); if ($post !== null) { $this->getDoctrine()->getRepository('BlogBundle:Post')->delete($post); $view->setStatusCode(Response::HTTP_NO_CONTENT); } return $this->handleView($view); } }

Con FOSRestBundle , non è necessario dichiarare un percorso per ogni metodo; segui semplicemente la convenzione con i nomi dei metodi del controller e JMSSerializerBundle convertirà automaticamente i tuoi modelli in JSON.

API REST in Laravel

Innanzitutto, è necessario definire i percorsi. Puoi farlo nella sezione API delle regole del percorso per disattivare alcuni componenti del middleware predefiniti e attivarne altri. La sezione API si trova nel file routes/api.php .

 <?php // routes/api.php Route::resource('/posts', 'BlogController');

Nel modello, dovresti definire la proprietà $fillable per passare le variabili nei metodi di creazione e aggiornamento del modello:

 <?php // app/Post.php namespace App; use Illuminate\Database\Eloquent\Model; class Post extends Model { protected $fillable = ['title', 'content']; // …

Definiamo ora il controller:

 <?php // app/Http/Controllers/BlogController.php namespace App\Http\Controllers; use App\Post; use Illuminate\Http\Request; use Illuminate\Http\Response; class BlogController extends Controller { public function show(Post $post) { return $post; } public function store(Request $request) { $post = Post::create($request->get('post')); return response(null, Response::HTTP_CREATED, ['Location'=>'/posts/'.$post->id]); } public function update(Post $post, Request $request) { $post->update($request->get('post')); return response(null, Response::HTTP_NO_CONTENT, ['Location'=>'/posts/'.$post->id]); } public function destroy(Post $post) { $post->delete(); return response(null, Response::HTTP_NO_CONTENT); } }

In Symfony, stai usando FosRestBundle , che racchiude gli errori in JSON. In Laravel, devi farlo da solo. È necessario aggiornare il metodo di rendering nel gestore delle eccezioni per restituire errori JSON per le richieste JSON previste:

 <?php // app/Exceptions/Handler.php namespace App\Exceptions; use Exception; use Illuminate\Auth\AuthenticationException; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; class Handler extends ExceptionHandler { /** * Render an exception into an HTTP response. * * @param \Illuminate\Http\Request $request * @param \Exception $exception * @return \Illuminate\Http\Response */ public function render($request, Exception $exception) { if ($request->expectsJson()) { $status = 400; if ($this->isHttpException($exception)) { $status = $exception->getStatusCode(); } elseif ($exception instanceof ModelNotFoundException) { $status = 404; } $response = ['message' => $exception->getMessage(), 'code' => $exception->getCode()]; return response()->json($response, $status); } return parent::render($request, $exception); } // ... }

API REST: Symfony contro Laravel

Come puoi vedere, per una tipica API REST, Laravel è molto più semplice di Symfony.

Scegliere il vincitore: Symfony o Laravel?

Non c'è un chiaro vincitore tra Laravel e Symfony, poiché tutto dipende dal tuo obiettivo finale.

Laravel è una scelta migliore se:

  • Questa è la tua prima esperienza con il framework, poiché è facile da imparare e ha una sintassi più semplice e migliori materiali di apprendimento.
  • Stai costruendo un prodotto di avvio e verificando le tue ipotesi, poiché è utile per lo sviluppo rapido di applicazioni e gli sviluppatori Laravel sono facili da trovare.

Symfony è l'opzione migliore se:

  • Stai creando un'applicazione aziendale complessa, poiché è molto scalabile, manutenibile e ben strutturata.
  • Stai costruendo una migrazione di un grande progetto a lungo termine, dato che Symfony ha piani di rilascio prevedibili per i prossimi sei anni, quindi è meno probabile che ci siano sorprese.