PHP Çerçeveleri: Symfony ve Laravel Arasında Seçim Yapmak
Yayınlanan: 2022-03-11Günümüzde yeni bir projeye başlarken en önemli kararlardan biri doğru çerçeveyi seçmektir. Bugünlerde sıfırdan karmaşık bir web uygulaması oluşturmayı hayal etmek zorlaştı.
Web geliştirme için birçok popüler dilin “varsayılan” çerçevesi vardır, örneğin Ruby için Ruby on Rails veya Python için Django. Ancak, PHP'nin böyle tek bir varsayılanı yoktur ve aralarından seçim yapabileceğiniz birden çok popüler seçeneğe sahiptir.
Google trendlerine ve GitHub'a göre, en popüler PHP çerçeveleri 13.7k yıldızlı Symfony ve 29k yıldızlı Laravel'dir (bu makaleyi yazarken).
Bu makalede, bu iki çerçeveyi karşılaştıracağım ve size basit, günlük özelliklerin her biriyle nasıl uygulanacağını göstereceğim. Bu sayede gerçek hayattan örneklerin kodlarını yan yana karşılaştırabilirsiniz.
Bu makale, güçlü PHP becerilerini ve MVC mimari paradigmasını anladığını varsaymaktadır, ancak Symfony veya Laravel ile daha önce deneyim gerekli değildir.
yarışmacılar
laravel
Laravel'den bahsederken, Laravel sürüm 4 ve sonrasından bahsediyoruz. Laravel 4, 2013'te piyasaya sürüldü ve çerçevenin tamamen yeniden yazılmasını temsil etti. Çerçevenin işlevselliği, her şeyin tek bir büyük kod deposunda olması yerine, Composer ile yönetilen ayrı bileşenlere ayrıldı.
Laravel, öğrenmesi, okuması ve bakımı kolay, basit ve güzel bir sözdizimi ile kendini hızlı geliştirme için bir çerçeve olarak ilan eder. 2016'nın en popüler çerçevesidir. Google trendlerine göre diğer çerçevelere göre üç kat daha popülerdir ve GitHub'da rakiplerine göre iki kat daha fazla yıldıza sahiptir.
senfoni
Symfony 2 2011'de piyasaya sürüldü, ancak farklı temel ilkelere sahip tamamen farklı bir çerçeve olan Symfony 1 ile karıştırılmamalıdır. Fabien Potencier, Symfony 2'yi yarattı ve mevcut sürüm, Symfony 2'nin artımlı bir sürümü olan 3.2'dir. Bu nedenle, genellikle basitçe Symfony2/3 olarak adlandırılırlar.
Laravel 4 gibi, Symfony 2 de bir dizi ayrıştırılmış bileşen olarak tasarlanmıştır. Burada iki fayda vardır: Bir Symfony projesindeki herhangi bir bileşeni değiştirebiliriz ve herhangi bir Symfony bileşenini Symfony olmayan bir projede alabilir ve kullanabiliriz. Symfony bileşenleri harika kod örnekleri olarak hizmet edebilir ve Drupal, phpBB ve Codeception gibi birçok açık kaynak projesinde kullanılırlar. Aslında, Laravel'in kendisi en az 14 Symfony bileşeni kullanır. Symfony'yi anlamak, diğer projelerle çalışırken size birçok fayda sağlar.
Çerçeve Kurulumları
Her iki çerçeve de PHP yerleşik web sunucusu aracılığıyla sağlanan yükleyiciler ve paketleyicilerle birlikte gelir.
Symfony Kurulumu
Symfony kurulumu aşağıdaki kadar basittir:
# 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
Bu kadar! Symfony kurulumunuz URL http://localhost:8000
mevcuttur.
Laravel Kurulumu
Laravel kurulum süreci Symfony ile neredeyse aynı ve basit; tek fark, Laravel'in yükleyicisini Composer aracılığıyla yüklemenizdir:
# 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
Artık http://localhost:8000
adresini ziyaret edebilir ve Laravel kurulumunuzu kontrol edebilirsiniz.
Not: Hem Laravel hem de Symfony, varsayılan olarak aynı yerel ana bilgisayar bağlantı noktasını (8000) çalıştırır, bu nedenle bu varsayılan örneklerin aynı anda çalışmasını sağlayamazsınız. Laravel sunucusunu başlatmadan önce php bin/console server:stop
komutunu çalıştırarak Symfony sunucusunu durdurmayı unutmayın.
Çerçeve Kurulumu Hakkında
Bunlar temel kurulum örnekleridir. Projeleri yerel etki alanlarıyla yapılandırabilme veya aynı anda birden fazla proje çalıştırabilme gibi daha gelişmiş kullanım örnekleri için her iki çerçeve de Vagrant kutuları sağlar:
- laravel Çiftlik Evi,
- Symfony Homestead.
Temel Çerçeve Yapılandırmaları
Symfony Temel Yapılandırma
Symfony, yapılandırmasını belirtmek için sözdizimi olarak YAML'yi kullanır. Varsayılan yapılandırma, app/config/config.yml
dosyasında bulunur ve aşağıdaki örneğe benzer:
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%' # ...
Ortama özel bir yapılandırma oluşturmak için, temel yapılandırma parametrelerini içeren app/config/config_ENV.yml
dosyasını oluşturun. Geliştirme ortamı için bir config_dev.yml
dosyası örneği:
imports: - { resource: config.yml } # ... web_profiler: toolbar: true # ...
Bu örnek, web_profiler
Symfony aracını yalnızca geliştirme ortamı için açar. Bu araç, doğrudan tarayıcı penceresinde uygulamanızın hatalarını ayıklamanıza ve profil oluşturmanıza yardımcı olur.
Konfigürasyon dosyalarında ayrıca %secret%
yapıları da görebilirsiniz. Ortama özgü değişkenleri ayrı parameters.yml
dosyasına koymamıza izin verirler. Bu dosya her makinede benzersiz olabilir ve sürüm kontrolü altında saklanmaz. Versiyon kontrolü için, parameters.yml
dosyasının şablonu olan özel bir parameters.yml.dist
dosyamız var.
parameters.yml
dosyasına bir örnek:
parameters: database_host: 127.0.0.1 database_port: null database_name: symfony database_user: root database_password: null secret: f6b16aea89dc8e4bec811dea7c22d9f0e55593af
Laravel Temel Yapılandırma
Laravel konfigürasyonu Symfony'den çok farklı görünüyor. Tek ortak noktaları, her ikisinin de sürüm kontrolü altında saklanmayan dosyalar ( .env
durumunda .env) ve bu dosyayı oluşturmak için bir şablon ( .env.example
) kullanmasıdır. Bu dosya, aşağıdaki örnekte olduğu gibi bir anahtar ve değer listesine sahiptir:
APP_ENV=local APP_KEY=base64:Qm8mIaur5AygPDoOrU+IKecMLWgmcfOjKJItb7Im3Jk= APP_DEBUG=true APP_LOG_LEVEL=debug APP_URL=http://localhost
Symfony YAML dosyası gibi, Laravel için olan bu dosya da insan tarafından okunabilir ve temiz görünüyor. Ayrıca PHPUnit testleri çalıştırılırken kullanılacak .env.testing
dosyası oluşturabilirsiniz.
Uygulama yapılandırması, config
dizinindeki .php
dosyalarında saklanır. Temel yapılandırma, app.php
dosyasında saklanır ve bileşene özel yapılandırma, <component>.php
dosyalarında (örneğin, cache.php
veya mail.php
) saklanır. İşte bir config/app.php
dosyası örneği:
<?php return [ 'name' => 'Laravel', 'env' => env('APP_ENV', 'production'), 'debug' => env('APP_DEBUG', false), 'url' => env('APP_URL', 'http://localhost'), 'timezone' => 'UTC', 'locale' => 'en', // ... ];
Çerçeve Yapılandırması: Symfony ve Laravel
Symfony'nin uygulama yapılandırma mekanizmaları, farklı ortamlar için farklı dosyalar oluşturmanıza olanak tanır. Ayrıca, YAML yapılandırmasına karmaşık PHP mantığı eklemenizi de engeller.
Ancak, Laravel'in kullandığı varsayılan PHP yapılandırma sözdizimi ile daha rahat hissedebilirsiniz ve YAML sözdizimini öğrenmeniz gerekmez.
Yönlendirme ve Denetleyici
Genel olarak, bir arka uç web uygulamasının bir birincil sorumluluğu vardır: her isteği okumak ve isteğin içeriğine bağlı olarak bir yanıt oluşturmak. Denetleyici, uygulama yöntemlerini çağırarak isteği yanıta dönüştürmekten sorumlu bir sınıfken yönlendirici, belirli bir istek için hangi denetleyici sınıfını ve yöntemini yürütmeniz gerektiğini belirlemenize yardımcı olan bir mekanizmadır.
/posts/{id}
yolundan istenen bir blog yazısı sayfasını gösterecek bir controller oluşturalım.
Laravel'de Yönlendirme ve Denetleyici
kontrolör
<?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)]); } }
yönlendirici
Route::get('/posts/{id}', 'BlogController@show');
GET
istekleri için rotayı tanımladık. /posts/{id}
ile eşleşen URI'ye sahip tüm istekler, BlogController
denetleyicisinin yöntemi show
işlemini yürütecek ve parametre id
bu yönteme iletecektir. Denetleyicide, id
geçirilen POST
modelinin nesnesini bulmaya çalışıyoruz ve sayfayı oluşturmak için Laravel helper view()
'i çağırıyoruz.
Symfony'de Yönlendirme ve Denetleyici
Symfony'de exampleController
biraz daha büyüktür:
<?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]); } }
Ek açıklamaya zaten @Route("/posts/{id}”)
eklediğimizi görebilirsiniz, bu nedenle denetleyiciyi routing.yml
yapılandırma dosyasına eklememiz yeterlidir:
blog: resource: "@BlogBundle/Controller/" type: annotation prefix: /
Adım adım mantık, Laravel durumundakiyle aynıdır.
Yönlendirme ve Denetleyici: Symfony vs. Laravel
Bu aşamada Laravel'in Symfony'den çok daha güzel olduğunu düşünebilirsiniz. Bu, başlangıçta doğrudur. Başlaması çok daha iyi ve daha kolay görünüyor. Ancak gerçek hayattaki uygulamalarda Doctrine'ı controller'dan aramamalısınız. Bunun yerine, gönderiyi bulmaya çalışacak veya HTTP 404 İstisnası atacak bir hizmeti aramalısınız.
şablonlar
Laravel, Blade adlı bir şablon motoruyla birlikte gelir ve Symfony, Twig ile birlikte gelir. Her iki şablon motoru da iki ana özelliği uygular:
- Şablon devralma
- Bloklar veya bölümler
Her iki özellik de geçersiz kılınabilir bölümlere sahip temel bir şablon ve bu bölümlerin değerlerini dolduran alt şablonlar tanımlamanıza olanak tanır.
Yine bir blog yazısı sayfası örneğini ele alalım.
Laravel Blade Şablon Motoru
// 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
Artık Kontrolörünüzde post.blade.php
şablonunu oluşturmasını söyleyebilirsiniz. Önceki Controller örneğindeki view('post', …)
çağrımızı hatırlıyor musunuz? Başka bir şablondan miras alındığını kodunuzda bilmenize gerek yoktur. Hepsi yalnızca şablonlarınızda, görünüm düzeyinde tanımlanır.
Symfony Twig Şablon Motoru
// 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 %}
Şablonlar: Symfony ve Laravel
Yapısal olarak Blade ve Twig şablonları oldukça benzerdir. Her ikisi de PHP kodunda şablon oluşturur ve hızlı çalışır ve her ikisi de if
ifadeleri ve döngüler gibi kontrol yapılarını uygular. Her iki motorun da sahip olduğu en önemli özellik, varsayılan olarak çıktıdan kaçmalarıdır, bu da XSS saldırılarını önlemeye yardımcı olur.
Sözdiziminin yanı sıra, temel fark, Blade'in PHP kodunu doğrudan şablonlarınıza enjekte etmenize izin vermesi ve Twig'in vermemesidir. Bunun yerine Twig, filtreleri kullanmanıza izin verir.
Örneğin, bir dizeyi büyük harf yapmak istiyorsanız, Blade'de aşağıdakileri belirtirsiniz:
{{ ucfirst('welcome friend') }}
Twig'de ise aşağıdakileri yaparsınız:
{{ 'welcome friend'|capitalize }}
Blade'de bazı işlevleri genişletmek daha kolaydır, ancak Twig şablonlarda herhangi bir doğrudan PHP koduna izin vermez.
Bağımlılık Enjeksiyonu
Uygulamalar, çeşitli karşılıklı bağımlılıklarla birlikte birçok farklı hizmete ve bileşene sahiptir. Oluşturulan nesneler ve bağımlılıkları hakkındaki tüm bilgileri bir şekilde saklamanız gerekir.
Sıradaki bileşenimiz geliyor - Servis Konteyneri. İstenen hizmetleri oluşturan ve oluşturulan nesneler ve bunların bağımlılıkları hakkında bilgi depolayan bir PHP nesnesidir.
Aşağıdaki örneği ele alalım: Yeni bir blog gönderisi oluşturmaktan sorumlu bir yöntemi uygulamak için bir PostService
sınıfı oluşturuyorsunuz. Bu sınıf, diğer iki hizmete bağlıdır: Veritabanında bilgi depolamaktan sorumlu olan PostRepository
ve SubscriberNotifier
olan kullanıcılara yeni gönderi hakkında bilgi vermekten sorumlu olanSuberNotifier. Çalışması için bu iki hizmeti PostService
yapıcı argümanları olarak geçirmeniz veya başka bir deyişle bu bağımlılıkları enjekte etmeniz gerekir.
Symfony Bağımlılık Enjeksiyon Örneği
Öncelikle örnek hizmetlerimizi tanımlayalım:
<?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); } }
Sonraki bağımlılık enjeksiyon yapılandırmasıdır:
# 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
Artık, Service Container nesnenizden kodun herhangi bir yerinde posta hizmeti talep edebilirsiniz. Örneğin, denetleyicide şöyle bir şey olabilir:
// Controller file. $post variable defined below $this->get('blog.post_service')->create($post);
Service Container harika bir bileşendir ve SOLID tasarım ilkelerini izleyerek uygulamanızı oluşturmanıza yardımcı olur.
Laravel Bağımlılık Enjeksiyonu Örneği
Laravel'de bağımlılıkları yönetmek çok daha kolaydır. Aynı örneği ele alalım:
<?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); } }
İşte Laravel'in güzelliği burada geliyor - bağımlılık konfigürasyonları oluşturmanıza gerek yok . Laravel, yapıcı argüman türlerinde PostService
bağımlılıklarını otomatik olarak tarar ve bunları otomatik olarak çözer.

PostService
yöntem bağımsız değişkenlerinde "tip ipucu vererek" kullanmak için denetleyici yönteminizde enjeksiyonu da kullanabilirsiniz:
<?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); } }
Bağımlılık Enjeksiyonu: Symfony vs. Laravel
Laravel'in otomatik algılaması harika çalışıyor. Symfony, varsayılan olarak kapalı olan ve bağımlılık yapılandırmanıza autowire: true
eklenerek açılabilen "autowire" adlı benzer bir yeteneğe sahiptir, ancak bazı yapılandırmalar gerektirir. Laravel yolu daha basittir.
Nesne İlişkisel Eşleme (ORM)
Veritabanlarıyla çalışmak için her iki çerçeve de Nesne İlişkisel Eşleme (ORM) özellikleriyle birlikte gelir. ORM, veritabanındaki kayıtları koddaki nesnelere eşler. Bunu yapmak için, veritabanınızdaki her kayıt türü (veya her tablo) için modeller oluşturmanız gerekir.
Symfony, veritabanıyla etkileşim kurmak için üçüncü taraf bir proje olan Doctrine'ı kullanırken, Laravel kendi Eloquent kitaplığını kullanıyor.
Eloquent ORM, veritabanıyla çalışmak için ActiveRecord modelini uygular. Bu modelde, her model veritabanına olan bağlantının farkındadır ve onunla etkileşime girebilir. Örneğin veri tabanına veri kaydedebilir, bir kaydı güncelleyebilir veya silebilir.
Doctrine, modellerin veritabanı hakkında hiçbir şey bilmediği Veri Eşleyici modelini uygular; sadece verinin kendisinin farkındadırlar. Özel bir ayrı katman olan EntityManager
, modeller ve veritabanları arasındaki etkileşim hakkındaki tüm bilgileri depolar ve tüm işlemleri yönetir.
Farkı anlamak için bir örnek verelim. Modelinizin birincil id
anahtarı, başlığı, içeriği ve yazarı olduğunu varsayalım. Gönderiler tablosu yalnızca yazar id
saklar, bu nedenle Kullanıcılar tablosuyla bir ilişki oluşturmanız gerekir.
doktrin
Modelleri tanımlayarak başlayalım:
<?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;
Burada, model eşleme bilgilerini oluşturduk ve artık yöntem taslaklarını oluşturmak için bir yardımcı kullanabiliriz:
php bin/console doctrine:generate:entities BlogBundle
Ardından, depo sonrası yöntemleri tanımlarız:
<?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(); } }
Artık bu yöntemleri hizmetten veya örneğin 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);
anlamlı
User modeli Laravel ile birlikte gelir ve varsayılan olarak tanımlanır, bu nedenle Post için yalnızca bir model tanımlamanız gerekir.
<?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'); } }
Modeller için bu kadar. Eloquent'te, model özelliklerini veritabanı tablosu yapısına dayalı olarak dinamik olarak oluşturduğundan, model özelliklerini tanımlamanız gerekmez. Yeni bir gönderiyi $post
veritabanına kaydetmek için, bu aramayı yapmanız gerekir (örneğin, denetleyiciden):
$post->save();
Belirli bir ada sahip bir yazarın tüm gönderilerini bulmak için en iyi yaklaşım, adıyla bir kullanıcı bulmak ve tüm kullanıcıların gönderilerini istemek olacaktır:
$posts = Post::whereHas('author', function ($q) { $q->where('name', 'Karim'); })->get();
ORM: Symfony ve Laravel
ORM ile ilgili olarak, Eloquent PHP geliştiricileri için Doctrine'dan çok daha kolay ve öğrenmesi daha kolay görünüyor.
Olay Dağıtıcısı ve Ara Katman Yazılımı
Bir çerçeve hakkında anlaşılması gereken en önemli şeylerden biri, yaşam döngüsüdür.
Symfony ve Olay Dağıtıcı
Symfony, bir isteği yanıta dönüştürmek için EventDispatcher'ı kullanır. Sonuç olarak, bu olayları işlemek için farklı yaşam döngüsü olaylarını ve özel olay dinleyicilerini harekete geçirir. Başlangıçta, istek bilgilerini içeren kernel.request
olayını gönderir. Bu olayın ana varsayılan dinleyicisi, mevcut istek için uygun bir rota kuralı bulmak için yönlendirici bileşenini çağıran RouterListener
. Bundan sonra, diğer olaylar adım adım yürütülür. Tipik olay dinleyicileri, bir Güvenlik denetimi, CSRF belirteci doğrulaması ve bir günlük kaydı işlemidir. İstek yaşam döngüsüne bazı işlevler eklemek istiyorsanız, özel bir EventListener
oluşturmanız ve gerekli olaya abone olmanız gerekir.
Laravel ve Ara Katman Yazılımı
Laravel farklı bir çözüm kullanır: ara katman yazılımı. Ara yazılımı bir soğanla karşılaştırmayı seviyorum: Uygulamanızın belirli katmanları var ve denetleyiciye giderken bu katmanlardan bir istek geçiyor ve geri dönüyor. Bu nedenle, uygulama mantığınızı genişletmek ve istek yaşam döngüsüne bazı işlevler eklemek istiyorsanız, ara katman yazılımı listenize ek bir katman eklemeniz gerekir ve Laravel bunu yürütecektir.
REST API'si
Bir blog gönderisini yönetmek için temel bir CRUD örneği oluşturmaya çalışalım:
- Oluştur -
POST /posts/
- Oku -
GET /posts/{id}
- Güncelleme -
PATCH /posts/{id}
- Sil -
DELETE /posts/{id}
Symfony'de REST API
Symfony, hızlı REST API oluşturma için kullanıma hazır kolay bir çözüme sahip değildir, ancak harika üçüncü taraf paketleri FOSRestBundle
ve JMSSerializerBundle
.
FOSRestBundle
ve JMSSerializerBundle
ile minimal çalışma örneğini ele alalım. Bunları AppKernel
yükledikten ve açtıktan sonra, paket yapılandırmasında JSON biçimini kullanacağınızı ve bunun URL isteklerine dahil edilmesi gerekmediğini ayarlayabilirsiniz:
#app/config/config.yml fos_rest: routing_loader: default_format: json include_format: false
Yönlendirme yapılandırmasında, bu denetleyicinin bir REST kaynağı uygulayacağını belirtmelisiniz:
#app/config/routing.yml blog: resource: BlogBundle\Controller\PostController type: rest
Önceki örnekte depoda bir kalıcı yöntemi uyguladınız; şimdi bir silme yöntemi eklemeniz gerekiyor:
// src/BlogBundle/Repository/PostRepository.php public function delete(Post $post) { $this->getEntityManager()->remove($post); $this->getEntityManager()->flush(); }
Ardından, girdi isteklerini kabul etmek ve bunları modele eşlemek için bir form sınıfı oluşturmanız gerekir. Bunu bir CLI yardımcısı kullanarak yapabilirsiniz:
php bin/console doctrine:generate:form BlogBundle:Post
Aşağıdaki kodla oluşturulmuş bir form türü alacaksınız:
<?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'; } }
Şimdi kontrolörümüzü uygulayalım.
Not: Size göstereceğim kod mükemmel değil. Bazı tasarım ilkelerini ihlal ediyor ancak kolayca yeniden düzenlenebilir. Ana amaç, her bir yöntemi adım adım nasıl uygulayacağınızı size göstermektir.
<?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); } }
FOSRestBundle
ile her yöntem için bir yol bildirmeniz gerekmez; sadece denetleyici yöntem adlarıyla kuralı izleyin ve JMSSerializerBundle
modellerinizi otomatik olarak JSON'a dönüştürecektir.
Laravel'de REST API
İlk olarak, rotaları tanımlamanız gerekir. Bunu, bazı varsayılan ara yazılım bileşenlerini kapatmak ve diğerlerini açmak için rota kurallarının API
bölümünde yapabilirsiniz. API
bölümü, routes/api.php
dosyasında bulunur.
<?php // routes/api.php Route::resource('/posts', 'BlogController');
Modelde, modelin oluşturma ve güncelleme yöntemlerinde değişkenleri iletmek için $fillable
özelliğini tanımlamanız gerekir:
<?php // app/Post.php namespace App; use Illuminate\Database\Eloquent\Model; class Post extends Model { protected $fillable = ['title', 'content']; // …
Şimdi denetleyiciyi tanımlayalım:
<?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); } }
Symfony'de, hataları JSON'da saran FosRestBundle
kullanıyorsunuz. Laravel'de bunu kendin yapmalısın. JSON isteklerini beklemek için JSON hatalarını döndürmek için İstisna işleyicisindeki oluşturma yöntemini güncellemeniz gerekir:
<?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); } // ... }
REST API: Symfony vs. Laravel
Gördüğünüz gibi, tipik bir REST API için Laravel, Symfony'den çok daha basittir.
Kazananı Seçmek: Symfony veya Laravel?
Her şey nihai hedefinize bağlı olduğundan, Laravel ve Symfony arasında net bir kazanan yok.
Aşağıdaki durumlarda laravel daha iyi bir seçimdir:
- Bu, öğrenmesi kolay olduğu ve daha basit bir sözdizimine ve daha iyi öğrenme materyallerine sahip olduğu için çerçeveyle ilgili ilk deneyiminizdir.
- Hızlı uygulama geliştirme için iyi olduğundan ve Laravel geliştiricilerinin bulunması kolay olduğundan, bir başlangıç ürünü oluşturuyorsunuz ve hipotezinizi kontrol ediyorsunuz.
Symfony şu durumlarda en iyi seçenektir:
- Çok ölçeklenebilir, bakımı yapılabilir ve iyi yapılandırılmış olduğu için karmaşık bir kurumsal uygulama oluşturuyorsunuz.
- Symfony'nin önümüzdeki altı yıl için öngörülebilir yayın planları olduğundan, uzun vadeli büyük bir projenin geçişini oluşturuyorsunuz, bu nedenle herhangi bir sürpriz olması daha az olasıdır.