Takip et

Symfony2 ile VPS Üzerinde CRUD İşlemleri Gerçekleştirme: Derinlemesine İnceleme (Bölüm 2)

Symfony2 ile VPS Üzerinde CRUD İşlemleri Gerçekleştirme: Derinlemesine İnceleme (Bölüm 2) Bu makale serisinin ilk bölümünde, Symfony2 proj

Symfony2 ile VPS Üzerinde CRUD İşlemleri Gerçekleştirme: Derinlemesine İnceleme (Bölüm 2)

Bu makale serisinin ilk bölümünde, Symfony2 projesi oluşturma, veritabanı bağlantısını yapılandırma ve Doctrine ORM kullanarak basit bir Entity tanımlama gibi temel konulara değinmiştik. Bir Sanal Özel Sunucu (VPS) üzerinde Symfony2 uygulamasını çalıştırmanın ilk adımlarını atmış, web sunucusu yapılandırmasına (genellikle Nginx veya Apache) genel bir bakış sunmuştuk. Şimdi, bu sağlam temel üzerine inşa ederek, Symfony2’nin CRUD (Create, Read, Update, Delete) operasyonları için sunduğu güçlü ve esnek araçları daha derinlemesine inceleyeceğiz. Özellikle, form yönetimi, veri doğrulama, kullanıcı geri bildirimleri ve güvenlik gibi önemli konulara odaklanarak, bir web uygulamasının belkemiğini oluşturan bu işlemleri nasıl etkin bir şekilde gerçekleştirebileceğinizi adım adım göstereceğiz.

CRUD Operasyonlarına Derinlemesine Bakış

CRUD operasyonları, hemen hemen her veri odaklı uygulamanın temelini oluşturur. Symfony2, bu işlemleri kolaylaştırmak için Doctrine ORM, Form Bileşeni ve Validasyon Bileşeni gibi güçlü araçlar sunar. Bu bölümde, her bir CRUD operasyonunu ayrı ayrı ele alacak ve en iyi uygulamaları sergileyeceğiz.

Yeni Kayıt Oluşturma (Create)

Yeni bir veri kaydı oluşturmak, genellikle bir HTML formu aracılığıyla kullanıcıdan bilgi almayı ve bu bilgileri veritabanına kaydetmeyi içerir. Symfony’de bu süreç, Form Bileşeni sayesinde oldukça basittir ve birçok güvenlik ve doğrulama özelliğini beraberinde getirir.

Form Oluşturma ve Yapılandırma

Öncelikle, Part 1’de oluşturduğumuz Product entity’si için bir form tipi oluşturmalıyız. Bu, src/AppBundle/Form/ProductType.php gibi bir dosyada yapılabilir:

// src/AppBundle/Form/ProductType.php
namespace AppBundle\Form;

use AppBundle\Entity\Product;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;

class ProductType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name', TextType::class, ['label' => 'Ürün Adı'])
            ->add('price', NumberType::class, ['label' => 'Fiyat'])
            ->add('description', TextareaType::class, ['label' => 'Açıklama', 'required' => false])
            ->add('save', SubmitType::class, ['label' => 'Kaydet']);
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults([
            'data_class' => Product::class,
        ]);
    }

    public function getName()
    {
        return 'product';
    }
}

Bu form tipi, Product entity’mizin alanlarına karşılık gelen form alanlarını tanımlar. data_class seçeneği, formun hangi entity ile ilişkilendirileceğini Symfony’ye bildirir.

Controller Tarafında Form İşleme

Şimdi, bu formu bir Controller içinde nasıl kullanacağımıza bakalım. Yeni bir ürün eklemek için bir eylem (Action) tanımlayalım:

// src/AppBundle/Controller/ProductController.php
namespace AppBundle\Controller;

use AppBundle\Entity\Product;
use AppBundle\Form\ProductType;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;

class ProductController extends Controller
{
    /
     * @Route("/product/new", name="product_new")
     */
    public function newAction(Request $request)
    {
        $product = new Product();
        $form = $this->createForm(ProductType::class, $product);

        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($product); // Entity'yi kalıcı hale getir
            $em->flush(); // Veritabanına kaydet

            $this->addFlash(
                'notice',
                'Ürün başarıyla eklendi!'
            );

            return $this->redirectToRoute('product_list'); // Başarılıysa ürün listesine yönlendir
        }

        return $this->render('product/new.html.twig', [
            'form' => $form->createView(),
        ]);
    }
}

Bu kodda:
* Yeni bir Product nesnesi oluşturulur.
* ProductType kullanılarak bir form oluşturulur ve Product nesnesi ile ilişkilendirilir.
* handleRequest($request) metodu, gelen HTTP isteğindeki verileri forma bağlar.
* isSubmitted() ve isValid() metotları, formun gönderilip gönderilmediğini ve verilerin geçerli olup olmadığını kontrol eder.
* Veriler geçerliyse, persist() ile entity Doctrine tarafından izlenmeye başlanır ve flush() ile veritabanına kaydedilir.
* addFlash() metodu, kullanıcıya geri bildirim sağlamak için bir “flash mesajı” ekler. Bu mesajlar, bir sonraki HTTP isteği için saklanır ve genellikle Twig şablonunda görüntülenir.
* İşlem başarılı olursa, kullanıcı ürün listesi sayfasına yönlendirilir.

Twig Şablonunda Formu Görüntüleme

Son olarak, formu görüntülemek için app/Resources/views/product/new.html.twig dosyasını oluşturalım:

{# app/Resources/views/product/new.html.twig #}
{% extends 'base.html.twig' %}

{% block body %}
    

Yeni Ürün Ekle

{% for message in app.flashes('notice') %}
{{ message }}
{% endfor %} {{ form_start(form) }} {{ form_row(form.name) }} {{ form_row(form.price) }} {{ form_row(form.description) }} {{ form_row(form.save) }} {{ form_end(form) }} {% endblock %}

Bu şablonda form_start(), form_row() ve form_end() gibi Twig fonksiyonları, formun HTML çıktısını kolayca oluşturmak için kullanılır. app.flashes('notice') ile daha önce eklediğimiz flash mesajları görüntülenir.

Kayıtları Listeleme (Read – All)

Veritabanındaki tüm ürünleri listelemek, genellikle bir Controller’dan Repository aracılığıyla veri çekmeyi ve bu verileri bir Twig şablonunda görüntülemeyi içerir.

Controller Tarafında Veri Çekme
// src/AppBundle/Controller/ProductController.php
// ...
class ProductController extends Controller
{
    /
     * @Route("/product", name="product_list")
     */
    public function listAction()
    {
        $products = $this->getDoctrine()
            ->getRepository(Product::class)
            ->findAll(); // Tüm ürünleri getir

        return $this->render('product/list.html.twig', [
            'products' => $products,
        ]);
    }
}

Burada, getRepository(Product::class) ile Product entity’mizin Repository’sine erişiriz. findAll() metodu, veritabanındaki tüm Product kayıtlarını döndürür.

Twig Şablonunda Listeyi Görüntüleme

app/Resources/views/product/list.html.twig dosyasını oluşturalım:

{# app/Resources/views/product/list.html.twig #}
{% extends 'base.html.twig' %}

{% block body %}
    

Ürün Listesi

Yeni Ürün Ekle

{% for message in app.flashes('notice') %}
{{ message }}
{% endfor %} {% if products is not empty %} {% for product in products %} {% endfor %}
ID Adı Fiyat Açıklama İşlemler
{{ product.id }} {{ product.name }} {{ product.price|number_format(2, ',', '.') }} TL {{ product.description|length > 50 ? product.description|slice(0, 50) ~ '...' : product.description }} Görüntüle Düzenle Sil
{% else %}

Henüz hiç ürün eklenmemiş.

{% endif %} {% endblock %}

Bu şablon, ürünleri bir tablo içinde listeler ve her ürün için görüntüleme, düzenleme ve silme bağlantıları sunar.

Tek Kayıt Görüntüleme (Read – One)

Belirli bir ürünün detaylarını görüntülemek için, genellikle URL’den bir ID parametresi alınır ve bu ID’ye göre veritabanından tek bir kayıt çekilir.

Controller Tarafında Tek Kayıt Çekme
// src/AppBundle/Controller/ProductController.php
// ...
class ProductController extends Controller
{
    /
     * @Route("/product/{id}", name="product_show")
     */
    public function showAction($id)
    {
        $product = $this->getDoctrine()
            ->getRepository(Product::class)
            ->find($id); // ID'ye göre ürünü bul

        if (!$product) {
            throw $this->createNotFoundException('Ürün bulunamadı: ' . $id);
        }

        return $this->render('product/show.html.twig', [
            'product' => $product,
        ]);
    }
}

find($id) metodu, belirtilen ID’ye sahip entity’yi döndürür. Eğer ürün bulunamazsa, createNotFoundException() ile bir 404 hatası fırlatılır.

Twig Şablonunda Detayları Görüntüleme

app/Resources/views/product/show.html.twig dosyasını oluşturalım:

{# app/Resources/views/product/show.html.twig #}
{% extends 'base.html.twig' %}

{% block body %}
    

Ürün Detayı: {{ product.name }}

ID {{ product.id }}
Adı {{ product.name }}
Fiyat {{ product.price|number_format(2, ',', '.') }} TL
Açıklama {{ product.description|default('Açıklama yok.')|nl2br }}

Listeye Geri Dön Düzenle

{% endblock %}

Kayıt Güncelleme (Update)

Mevcut bir kaydı güncellemek, yeni kayıt oluşturmaya benzer, ancak formun mevcut veri ile doldurulması ve veritabanında sadece flush() çağrılması yeterlidir.

Controller Tarafında Kayıt Güncelleme
// src/AppBundle/Controller/ProductController.php
// ...
class ProductController extends Controller
{
    /
     * @Route("/product/{id}/edit", name="product_edit")
     */
    public function editAction(Request $request, $id)
    {
        $em = $this->getDoctrine()->getManager();
        $product = $em->getRepository(Product::class)->find($id);

        if (!$product) {
            throw $this->createNotFoundException('Güncellenecek ürün bulunamadı: ' . $id);
        }

        $form = $this->createForm(ProductType::class, $product);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $em->flush(); // Sadece flush yeterli, persist zaten yapıldı

            $this->addFlash(
                'notice',
                'Ürün başarıyla güncellendi!'
            );

            return $this->redirectToRoute('product_show', ['id' => $product->getId()]);
        }

        return $this->render('product/edit.html.twig', [
            'form' => $form->createView(),
            'product' => $product,
        ]);
    }
}

Burada dikkat edilmesi gereken nokta, form oluşturulurken mevcut $product nesnesinin ikinci parametre olarak geçirilmesidir. Bu, formun mevcut verilerle doldurulmasını sağlar. flush() çağrıldığında, Doctrine, izlediği $product nesnesindeki değişiklikleri otomatik olarak veritabanına yansıtır.

Twig Şablonunda Güncelleme Formu

app/Resources/views/product/edit.html.twig dosyasını oluşturalım:

{# app/Resources/views/product/edit.html.twig #}
{% extends 'base.html.twig' %}

{% block body %}
    

Ürün Düzenle: {{ product.name }}

{% for message in app.flashes('notice') %}
{{ message }}
{% endfor %} {{ form_start(form) }} {{ form_row(form.name) }} {{ form_row(form.price) }} {{ form_row(form.description) }} {{ form_row(form.save, {'label': 'Güncelle'}) }} {{ form_end(form) }}

İptal

{% endblock %}

Kayıt Silme (Delete)

Bir kaydı silmek, diğer operasyonlara göre daha basit görünse de, güvenlik ve kullanıcı onayı açısından dikkatli olunması gereken bir işlemdir.

Controller Tarafında Kayıt Silme
// src/AppBundle/Controller/ProductController.php
// ...
class ProductController extends Controller
{
    /
     * @Route("/product/{id}/delete", name="product_delete", methods={"POST"})
     */
    public function deleteAction(Request $request, $id)
    {
        $em = $this->getDoctrine()->getManager();
        $product = $em->getRepository(Product::class)->find($id);

        if (!$product) {
            throw $this->createNotFoundException('Silinecek ürün bulunamadı: ' . $id);
        }

        // Güvenlik için CSRF token kontrolü önerilir.
        // Symfony 2'de bunu manuel yapmanız gerekebilir veya bir form kullanarak.
        // Basit bir örnek için şimdilik atlıyoruz, ancak üretimde kullanmayın.
        // Daha güvenli bir yaklaşım için aşağıdaki "Güvenlik" bölümüne bakın.

        $em->remove($product); // Entity'yi silme için işaretle
        $em->flush(); // Veritabanından sil

        $this->addFlash(
            'notice',
            'Ürün başarıyla silindi!'
        );

        return $this->redirectToRoute('product_list');
    }
}

remove($product) metodu, entity’yi silinmek üzere işaretler. flush() çağrıldığında, Doctrine bu entity’yi veritabanından siler. methods={"POST"} ile bu rotanın sadece POST istekleriyle erişilebilir olduğunu belirtmek, yanlışlıkla silme işlemlerini önlemeye yardımcı olur. Ancak bu yeterli değildir, CSRF koruması kesinlikle gereklidir.

Güvenli Silme İşlemleri (CSRF Koruması)

Bir GET isteği ile silme işlemi yapmak, CSRF (Cross-Site Request Forgery) saldırılarına açık kapı bırakır. Bu nedenle, silme işlemleri için her zaman POST istekleri ve CSRF token’ı kullanılmalıdır. Bunun için, silme linki yerine küçük bir form kullanmak en iyi yoldur:

{# product/list.html.twig veya product/show.html.twig içinde #}
{# Symfony'nin MethodOverrideListener'ı için #} {# CSRF token #}

Controller’da ise CSRF token’ı doğrulamak için:

// src/AppBundle/Controller/ProductController.php
// ...
class ProductController extends Controller
{
    /
     * @Route("/product/{id}/delete", name="product_delete", methods={"POST", "DELETE"}) // DELETE metodunu da ekleyelim
     */
    public function deleteAction(Request $request, $id)
    {
        // CSRF token kontrolü
        if (!$this->isCsrfTokenValid('delete' . $id, $request->request->get('_token'))) {
            throw $this->createAccessDeniedException('Geçersiz CSRF token.');
        }

        $em = $this->getDoctrine()->getManager();
        $product = $em->getRepository(Product::class)->find($id);

        if (!$product) {
            throw $this->createNotFoundException('Silinecek ürün bulunamadı: ' . $id);
        }

        $em->remove($product);
        $em->flush();

        $this->addFlash(
            'notice',
            'Ürün başarıyla silindi!'
        );

        return $this->redirectToRoute('product_list');
    }
}

isCsrfTokenValid() metodu, sağlanan token’ın geçerli olup olmadığını kontrol eder. delete metodu için methods={"POST"} yerine methods={"POST", "DELETE"} kullanmak, RESTful yaklaşıma daha uygun olacaktır. Symfony’nin MethodOverrideListener‘ı, _method hidden input alanı sayesinde POST isteklerini DELETE olarak yorumlayabilir.

Gelişmiş Form Özellikleri ve Doğrulama

Symfony Form Bileşeni, temel alanların ötesinde birçok gelişmiş özellik sunar.

Veri Doğrulama (Validation)

Symfony’nin Validasyon Bileşeni, form verilerinin doğruluğunu sağlamak için güçlü bir mekanizma sunar. Doğrulama kuralları (constraints) genellikle entity sınıfında tanımlanır.

// src/AppBundle/Entity/Product.php
namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/
 * @ORM\Entity(repositoryClass="AppBundle\Repository\ProductRepository")
 * @ORM\Table(name="product")
 */
class Product
{
    /
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /
     * @ORM\Column(type="string", length=255)
     * @Assert\NotBlank(message="Ürün adı boş bırakılamaz.")
     * @Assert\Length(
     *      min = 3,
     *      max = 255,
     *      minMessage = "Ürün adı en az {{ limit }} karakter olmalı.",
     *      maxMessage = "Ürün adı en fazla {{ limit }} karakter olmalı."
     * )
     */
    private $name;

    /
     * @ORM\Column(type="decimal", precision=10, scale=2)
     * @Assert\NotBlank(message="Fiyat boş bırakılamaz.")
     * @Assert\Type(type="numeric", message="Fiyat sayısal bir değer olmalıdır.")
     * @Assert\GreaterThan(value=0, message="Fiyat sıfırdan büyük olmalıdır.")
     */
    private $price;

    /
     * @ORM\Column(type="text", nullable=true)
     */
    private $description;

    // ... getter ve setter metotları
}

Bu örnekte, @Assert\NotBlank, @Assert\Length, @Assert\Type ve @Assert\GreaterThan gibi constraint’ler kullanılarak name ve price alanları için doğrulama kuralları tanımlanmıştır. Form gönderildiğinde form->isValid() çağrıldığında bu kurallar otomatik olarak kontrol edilir ve ihlal durumunda hata mesajları oluşturulur. Twig şablonunda form_row() kullandığımızda, bu hata mesajları ilgili form alanının altında otomatik olarak görüntülenir.

Özel Doğrulama Kuralları (Custom Validators)

Bazen standart constraint’ler yeterli olmayabilir ve kendi özel doğrulama mantığınızı yazmanız gerekebilir. Örneğin, bir ürün adının veritabanında benzersiz olmasını sağlamak isteyebilirsiniz. Bunun için özel bir validator oluşturulabilir veya Entity Repository içinde benzersizlik kontrolü yapılabilir.

// src/AppBundle/Validator/Constraints/UniqueProductName.php
namespace AppBundle\Validator\Constraints;

use Symfony\Component\Validator\Constraint;

/
 * @Annotation
 */
class UniqueProductName extends Constraint
{
    public $message = 'Bu isimde bir ürün zaten mevcut.';

    public function getTargets()
    {
        return self::CLASS_CONSTRAINT; // Entity seviyesinde doğrulama
    }
}

// src/AppBundle/Validator/Constraints/UniqueProductNameValidator.php
namespace AppBundle\Validator\Constraints;

use AppBundle\Entity\Product;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

class UniqueProductNameValidator extends ConstraintValidator
{
    private $em;

    public function __construct(EntityManagerInterface $em)
    {
        $this->em = $em;
    }

    public function validate($product, Constraint $constraint)
    {
        / @var $constraint UniqueProductName /
        if (!$product instanceof Product) {
            return;
        }

        $existingProduct = $this->em->getRepository(Product::class)
            ->findOneBy(['name' => $product->getName()]);

        // Eğer aynı isimde başka bir ürün varsa ve bu ürün mevcut ürün değilse hata ver.
        if ($existingProduct && $existingProduct->getId() !== $product->getId()) {
            $this->context->buildViolation($constraint->message)
                ->atPath('name') // Hata mesajını 'name' alanına bağla
                ->addViolation();
        }
    }
}

Bu validator’ı kullanmak için services.yml içinde tanımlamanız ve Product entity’nizin başına @UniqueProductName annotation’ını eklemeniz gerekir.

# app/config/services.yml
services:
    app.validator.unique_product_name:
        class: AppBundle\Validator\Constraints\UniqueProductNameValidator
        arguments: ['@doctrine.orm.entity_manager']
        tags:
            - { name: validator.constraint_validator, alias: app_unique_product_name_validator }
// src/AppBundle/Entity/Product.php
// ...
use AppBundle\Validator\Constraints as AppAssert;

/
 * @ORM\Entity(repositoryClass="AppBundle\Repository\ProductRepository")
 * @ORM\Table(name="product")
 * @AppAssert\UniqueProductName() // Entity seviyesinde özel doğrulama
 */
class Product
{
    // ...
}

Güvenlik ve Yetkilendirme (Temel Seviye)

Bir web uygulamasında CRUD operasyonlarını gerçekleştirirken güvenlik ve yetkilendirme hayati öneme sahiptir. Symfony’nin Güvenlik Bileşeni, kullanıcı doğrulama (authentication) ve yetkilendirme (authorization) için kapsamlı bir çerçeve sunar.

Kullanıcı Doğrulama (Authentication)

Kullanıcı doğrulama, bir kullanıcının kim olduğunu belirleme sürecidir (örn: giriş yapma). Symfony’de bu, genellikle bir güvenlik duvarı (firewall) ve kullanıcı sağlayıcısı (user provider) tanımlanarak yapılır. security.yml dosyası bu yapılandırmanın merkezidir.

# app/config/security.yml
security:
    providers:
        our_db_provider:
            entity:
                class: AppBundle:User # Kendi User entity'nizi kullanın
                property: username

    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: ~
            form_login:
                login_path: login
                check_path: login_check
            logout:
                path: logout
                target: /

    access_control:
        - { path: ^/admin, roles: ROLE_ADMIN } # /admin ile başlayan tüm URL'ler için ROLE_ADMIN gerekli
        - { path: ^/product/new, roles: ROLE_USER } # Yeni ürün eklemek için ROLE_USER gerekli
        - { path: ^/product/\d+/edit, roles: ROLE_USER }
        - { path: ^/product/\d+/delete, roles: ROLE_USER }

Bu örnekte, form_login yapılandırması ile basit bir kullanıcı girişi mekanizması oluşturulmuştur. access_control bölümü ise belirli URL yollarına erişim için gereken rolleri tanımlar.

Rol Tabanlı Yetkilendirme (Authorization)

Yetkilendirme, bir kullanıcının belirli bir kaynağa veya eyleme erişim izni olup olmadığını belirleme sürecidir. Symfony’de bu, roller (roles) ve erişim delegeleri (access decision managers) aracılığıyla yapılır.

Controller içinde veya Twig şablonunda is_granted() fonksiyonunu kullanarak yetkilendirme kontrolü yapabilirsiniz:

// Controller içinde
if (!$this->isGranted('ROLE_ADMIN')) {
    throw $this->createAccessDeniedException('Bu işlemi yapmaya yetkiniz yok.');
}

// Belirli bir nesne üzerinde yetkilendirme (Voter kullanarak)
// if (!$this->isGranted('EDIT', $product)) { ... }
{# Twig şablonunda #}
{% if is_granted('ROLE_ADMIN') %}
    Yönetici Paneli
{% endif %}

{% if is_granted('EDIT', product) %} {# Eğer bir Voter tanımlıysa #}
    Düzenle
{% endif %}

CRUD operasyonları için, new, edit, delete gibi eylemlerin sadece belirli rollere sahip kullanıcılar tarafından gerçekleştirilmesini sağlamak çok önemlidir. Yukarıdaki security.yml içindeki access_control bölümü bunun temel bir örneğidir.

VPS Ortamında Dağıtım ve Optimizasyon

Symfony uygulamanızı bir VPS’e dağıtırken, sadece kodun çalışmasını sağlamakla kalmayıp, aynı zamanda performans ve güvenlik için optimizasyonlar yapmak da önemlidir.

Ortam Değişkenleri ve Konfigürasyon

Symfony, farklı ortamlar (development, production, test) için farklı konfigürasyonlar kullanmanıza olanak tanır. app/config/parameters.yml ve app/config/parameters_prod.yml (veya parameters_dev.yml) dosyaları bu amaçla kullanılır. VPS’te APP_ENV=prod ve APP_DEBUG=0 olarak ayarlamak esastır. Bu, uygulamanızın üretim modunda çalışmasını ve hata ayıklama bilgilerini göstermemesini sağlar.

Ortam değişkenlerini sunucu seviyesinde (örneğin Nginx veya Apache yapılandırmasında fastcgi_param APP_ENV prod; veya .env dosyası ile) ayarlamak, hassas bilgileri (veritabanı şifreleri gibi) versiyon kontrolünden uzak tutmak için iyi bir yöntemdir.

Önbellekleme (Caching) Stratejileri

Performans için önbellekleme hayati öneme sahiptir. Symfony ve Doctrine çeşitli önbellekleme katmanları sunar:

* Doctrine Metaveri Önbelleği: Entity metaverilerini önbelleğe alır.
* Doctrine Sorgu Önbelleği: Veritabanına gönderilen sorguların sonuçlarını önbelleğe alır.
* Doctrine Sonuç Önbelleği: Sorgu sonuçlarını doğrudan önbelleğe alır.
* Twig Önbelleği: Twig şablonlarının derlenmiş hallerini önbelleğe alır.

Üretim ortamında önbellekleri etkinleştirmek için genellikle app/AppKernel.php dosyasında registerContainerConfiguration() metodunda ortam kontrolü yapılır ve config_prod.yml içinde Doctrine ve Twig için önbellek servisleri tanımlanır.

Önbellekleri temizlemek için:
php app/console cache:clear --env=prod
php app/console doctrine:cache:clear-metadata --env=prod
php app/console doctrine:cache:clear-query --env=prod
php app/console doctrine:cache:clear-result --env=prod

Composer Optimizasyonu

Uygulamanızı VPS’e dağıttıktan sonra bağımlılıkları yüklerken composer install --no-dev --optimize-autoloader komutunu kullanmak önemlidir. --no-dev geliştirme bağımlılıklarını yüklemezken, --optimize-autoloader Composer’ın otomatik yükleme haritasını optimize ederek daha hızlı sınıf yüklemesi sağlar.

Web Sunucusu Yapılandırması (Kısa Tekrar)

İlk bölümde Nginx veya Apache yapılandırmasına değinmiştik. Önemli noktalar:
* web/app.php (veya app_dev.php yerine app.php) dosyasını kök dizin olarak ayarlayın.
* index.php‘yi varsayılan dosya olarak belirtin.
* try_files (Nginx) veya mod_rewrite (Apache) kullanarak tüm istekleri app.php‘ye yönlendirin.
* PHP-FPM kullanıyorsanız, doğru soket veya port üzerinden PHP-FPM ile iletişim kurduğunuzdan emin olun.
* Statik dosyalar için önbellekleme başlıkları ekleyin.

Günlükleme (Logging) ve Hata Ayıklama

Üretim ortamında hataları izlemek için günlükleme (logging) çok önemlidir. Symfony, MonologBundle aracılığıyla güçlü bir günlükleme sistemi sunar. app/config/config_prod.yml dosyasında günlükleme seviyesini error veya critical gibi daha kısıtlı bir seviyeye ayarlayarak log dosyalarının aşırı büyümesini engelleyebilirsiniz.

VPS üzerinde hataları izlemek için genellikle tail -f var/logs/prod.log komutu kullanılır.

Sonuç

Bu makalede, Symfony2 ile CRUD operasyonlarını gerçekleştirmenin inceliklerine derinlemesine daldık. Form Bileşeni kullanarak güvenli ve doğrulanmış formlar oluşturmayı, Doctrine ORM ile veritabanı işlemlerini yönetmeyi ve flash mesajları ile kullanıcıya geri bildirim sağlamayı öğrendik. Ayrıca, CSRF koruması gibi temel güvenlik önlemlerinin önemini vurguladık ve özel doğrulayıcılar aracılığıyla iş mantığını formlara entegre etme yollarını gösterdik. Son olarak, VPS ortamında bir Symfony uygulamasını dağıtırken dikkat edilmesi gereken performans optimizasyonları ve güvenlik ayarlarına genel bir bakış sunduk.

Symfony2, web uygulamaları geliştirmek için kapsamlı ve modüler bir çerçeve sunar. Bu makale serisi, temelden başlayarak CRUD operasyonlarını başarıyla uygulamanız için gerekli bilgi ve araçları sağlamıştır. Artık kendi Symfony2 tabanlı uygulamalarınızı geliştirirken bu bilgileri kullanarak daha sağlam, güvenli ve performanslı çözümler üretebilirsiniz. Uygulamanızın karmaşıklığı arttıkça, Symfony’nin diğer güçlü bileşenlerini (örneğin, kullanıcı yönetimi için FOSUserBundle, API geliştirme için FOSRestBundle) keşfetmeye devam etmeniz, yeteneklerinizi daha da genişletecektir. Unutmayın, pratik yapmak ve Symfony dokümantasyonunu düzenli olarak incelemek, bu güçlü çerçevede ustalaşmanın anahtarıdır.

Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.