Symfony Framework

Veritabanı İşlemleri ve Doctrine ORM

Symfony Framework yapısı içinde veritabanları ile işlem yapmak üzere bir bileşen bulunmamaktadır. Veritabanı işlemleri Doctrine adlı bir üçüncü parti kitaplığı yoluyla yapılır. Doctrine kitaplığını kullanarak, veritabanı işlemlerini kolay ve esnek bir şekilde gerçekleştirebilirsiniz.

Doctrine Projesi, öncelikle veritabanı depolaması ve nesne haritalaması üzerine odaklanan birkaç PHP kütüphanesinden oluşmaktadır. Temel projeler, Object Relational Mapper (ORM) ve Database Abstraction Layer (DBAL)'dır.

Şimdi, Doctrine kütüphanesinde veritabanı işlemlerinin çalışma şeklini görmek için, veritabanı yapılandırma, bir tablo nesnesi oluşturma, tablo yapısını veritabanına aktarma ve girilen değerleri tablodan okuma işlemlerini gerçekleştireceğiz.

Veritabanını yapılandırma

Veritabanı işlemlerine başlamadan önce, app/config/parameters.yml dosyasında bulunan veritabanı bağlantı bilgilerinizi yapılandırmanız gerekir. Aşağıdaki bilgileri içeren bir parameters.yml dosyası, Ahmet adlı bir kullanıcı tarafından işlem yapılabilecek mysymfony adlı bir veritabanı dosyası oluşturulmasını sağlayacaktır:

# app/config/parameters.yml

parameters:
    database_host:     localhost
    database_name:     mysymfony
    database_user:     Ahmet
    database_password: parola

# ...

Doctrine yapılandırılırken, parameters.yml dosyasındaki değerler, temel yapılandırma dosyası olan app/config/config.yml tarafından kullanılır:

# app/config/config.yml

doctrine:
    dbal:
        driver:   pdo_mysql
        host:     '%database_host%'
        dbname:   '%database_name%'
        user:     '%database_user%'
        password: '%database_password%'

C:\wamp\bin\mysql\mysql5.7.14 klasöründe bulunan my.ini dosyasında [mysqld] ifadesinin altına aşağıdaki satırları ekleyerek, MySQL UTF8 kod düzenlemesini yapabilirsiniz:

# C:/wamp/bin/mysql/mysql5.7.14/my.ini

[mysqld]
collation-server     = utf8mb4_general_ci
character-set-server = utf8mb4

Ayrıca, veritabanını oluşturmadan önce, Doctrine için kullanılacak olan ön tanımlı SQL karakter setini belirlemek için, app/config/config.yml dosyasında aşağıda renkli olarak gösterilen değerleri değiştirebilirsiniz:

# app/config/config.yml

doctrine:
    dbal:
        charset: utf8mb4
        default_table_options:
            charset: utf8mb4
            collate: utf8mb4_unicode_ci		

Veritabanı oluşturma

Artık, Doctrine veritabanınıza bağlandığından, aşağıdaki komut otomatik olarak boş ve mysymfony adlı bir veritabanı oluşturur:

  php bin/console doctrine:database:create

Komut istemi penceresinde, yukarıdaki komutu yazıp ENTER tuşuna bastığınızda, aşağıdakine benzer bir ekran karşınıza gelecektir:

mysymfony adlı veritabanını oluşturulduğunu phpMyAdmin benzeri bir arayüzle kontrol edebilirsiniz:

Entity sınıfı oluşturma (Tablo oluşturma hazırlığı)

Symfony'de Entity verileri ve verilerle ilgili metodları (fonksiyonları) barındıran bir sınıftır. Örneğin, bir tabloyu oluşturacak verileri ve metodları Entity yoluyla oluşturabilirsiniz.

1. Aşağıdaki komut, mysymfony adlı veritabanımızda bir tablo oluşturmamızı sağlayacak bir sınıf oluşturur:

  php bin/console doctrine:generate:entity

2. Komut isteminde iken, yukarıdaki komutu yazdığınızda, Entity kısayol adı girilecek olan bir ekran görüntüsü gelir. Bu ekranda, AppBundle:Product ifadelerini girip ENTER tuşuna basarak, product adlı bir tablo oluşturabilirsiniz.

3. Bu kez, yapılandırma şeklini girmeniz gereken bir görüntü ekrana gelir. Burada, ön tanımlı değer olan annotation değerini seçmek ENTER tuşuna basınız.

4. Boş bir Entity oluşturmuş olduk. Artık, tablomuz için alan değerleri ekleyebiliriz.

Bu işlemleri yaparken, id adlı bir alan tablo yapısına otomatik olarak eklenecektir.

Aynı zamanda, tablo veri alanlarında kullanılabilecek tüm veri türleri ekrana gelir. Ekranda, tablonuzda yer almasını istediğiniz ilk alan adını name olarak girdiğinizde, alan veri türünü belirlemenizi sağlayan bir görüntü (Field type [string]:) ekrana gelir. Ön tanımlı değer olan ve köşeli parentezler içinde yer alan string değerini seçmek ENTER tuşuna basınız. Alan uzunluğu giriş değeri ekrana geldiğinde (Field length [255]:), 100 değerini girin ve ENTER tuşuna basınız. Veri alanına değer girişi gerekliliğini belirleyen giriş ekranı (Is nullable [false]:) geldiğinde, ön tanımlı değeri seçmek için ENTER tuşuna basınız. Veri alanı değerinin benzersiz olma özelliğini belirleyen giriş ekranı (Unique [false]:) geldiğinde, true değerini girin ve ENTER tuşuna basınız.

İkinci alan adını price olarak girdiğinizde, alan veri türünü belirlemenizi sağlayan bir görüntü ekrana gelir. Burada, decimal yazarak ENTER tuşuna basınız. Ondalıklı sayının toplam basamak sayısını belirleyen ve köşeli parentezler içinde yer alan ön tanımlı değer olan 10 değerini (Precision [10]) seçmek ENTER tuşuna basınız. Ondalıklı sayıda virgülden sonra yer alan ve ondalık kısım değeri için (Scale:) 2 değerini girin ve ENTER tuşuna basınız. Veri alanına değer girişi gerekliliğini belirleyen giriş ekranı (Is nullable [false]:) geldiğinde ve veri alanı değerinin benzersiz olma özelliğini belirleyen giriş ekranı (Unique [false]:) geldiğinde, ön tanımlı değeri seçmek için ENTER tuşuna basınız.

Üçüncü alan adını description olarak girdiğinizde, alan veri türünü belirlemenizi sağlayan bir görüntü ekrana gelir. Burada, text yazarak ENTER tuşuna basınız. Veri alanına değer girişi gerekliliğini belirleyen giriş ekranı (Is nullable [false]:) geldiğinde ve veri alanı değerinin benzersiz olma özelliğini belirleyen giriş ekranı (Unique [false]:) geldiğinde, ön tanımlı değeri seçmek için ENTER tuşuna basınız.

Tabloya veri alanı eklemeyi sona erdirmek için, yeni alan adı girmeden ENTER tuşuna basınız.

Böylece, tablomuzu oluşturmak için gerekli olan Entity sınıfını oluşturmuş olduk. Bu işlemle birlikte, aşağıdaki şekilde görülen Entity dizini ve içindeki Product.php dosyası ile Repository dizini ve içindeki ProductRepository.php dosyası otomatik olarak oluşturulur.

Oluşturulan Product.php ve ProductRepository.php dosyalarının içerikleri aşağıda yer almaktadır:

// src/AppBundle/Entity/Product.php

<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Product
 *
 * @ORM\Table(name="product")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\ProductRepository")
 */
class Product
{
    /**
     * @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=100, unique=true)
     */
    private $name;

    /**
     * @var string
     *
     * @ORM\Column(name="price", type="decimal", precision=10, scale=2)
     */
    private $price;

    /**
     * @var string
     *
     * @ORM\Column(name="description", type="text")
     */
    private $description;


    /**
     * Get id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     *
     * @return product
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set price
     *
     * @param string $price
     *
     * @return product
     */
    public function setPrice($price)
    {
        $this->price = $price;

        return $this;
    }

    /**
     * Get price
     *
     * @return string
     */
    public function getPrice()
    {
        return $this->price;
    }

    /**
     * Set description
     *
     * @param string $description
     *
     * @return product
     */
    public function setDescription($description)
    {
        $this->description = $description;

        return $this;
    }

    /**
     * Get description
     *
     * @return string
     */
    public function getDescription()
    {
        return $this->description;
    }
}
// src/AppBundle/Repository/ProductRepository.php

<?php

namespace AppBundle\Repository;

/**
 * ProductRepository
 *
 * This class was generated by the Doctrine ORM. Add your own custom
 * repository methods below.
 */
class ProductRepository extends \Doctrine\ORM\EntityRepository
{
}

Product.php dosyasında, Product adlı bir sınıf oluşturulmuş, bu sınıf içinde ise $id, $name, $price ve $description adlı 4 adet değişken ve her bir değişken için biri değişken değerini almak diğeri ise değişken değerini belirlemek için ikişer adet fonksiyon tanımlanmıştır.

Tablo oluşturmak için bir Entity sınıfı oluşturulmuş olmasına rağmen, henüz bir tablo oluşturulmadığına dikkat ediniz!

Tablo oluşturma

Aşağıdaki komut, product.php dosyasında bulunan sınıf bilgilerini kullanarak mysymfony veritabanı altında product adlı bir tablo oluşturur:

  php bin/console doctrine:schema:update --force

Oluşturulan ve herhangi bir veri girişi yapılmamış product tablosunu, phpMyAdmin benzeri bir arayüzle kontrol edebilirsiniz:

Veritabanına veri girişi

1. Öncelikle, veritabanına giriş yapmak kullanacağımız web sayfası için menüde bir giriş oluşturalım. Bunun için, C:\wamp\www\mysym\app\Resources\views dizini altında bulunan main.html.twig dosyasını aşağıdaki hale getirerek kaydedin.

{# app/Resources/views/main.html.twig #}
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>{% block title %}Symfony Uygulaması{% endblock %}</title>
        {% block stylesheets %}{% endblock %}
        <link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" />
		
	<style>
          .ulmenu {
              margin:10px 0px 0px 0px;
              padding:5px;
              font-weight:bold;
              background:#9ee03f;
          }
		  
          .ulmenu li {
              display:inline;
              padding-right:20px;
          }
	   
          a, a:hover, a:link, a:visited , a:active, a:focus {
              border:none;
              outline:none;
              text-decoration:none; 
              color:#323232;  
          }		   
	</style>
		
    </head>
    <body>
	<ul class="ulmenu">
            <li><a href="{{ path('homepage') }}">Ana sayfa</a></li>
            <li><a href="{{ path('Ürünler') }}">Ürünler</a></li>
            <li><a href="{{ path('Ürün girişi') }}">Ürün girişi</a></li>
	</ul>	
        {% block body %}{% endblock %}
        {% block javascripts %}{% endblock %}
    </body>
</html>

2. Ürün girişini sağlayacak ve girilen ürün bilgilerini ekranda gösterecek bir sayfaya yönlendirmek amacıyla bir Route oluşturmak için MainController.php dosyasını aşağıdaki hale getirerek kaydedin.

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

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;

use AppBundle\Entity\Product;
use Symfony\Component\HttpFoundation\Response;

class MainController extends Controller
{
    /**
    * @Route("/", name="homepage")
    */
    public function mainAction(Request $request)
    {
        return $this->render('myview/index.html.twig');
    }
	
    /**
     * @Route("/urunler", name="Ürünler")
     */
    public function productsAction(Request $request)
    {
        return $this->render('myview/urunler.html.twig');
    }
	
    /**
     * @Route("/urungirisi", name="Ürün girişi")
     */
    public function newAction(Request $request)
    {
        $product = new Product();
        $product->setName('Süt');
        $product->setPrice(2.50);
        $product->setDescription('Tam yağlı pastorize süt!');

        $em = $this->getDoctrine()->getManager();

        // Sonuç olarak ürün kaydı yapmak istediğinizi Doctrine'e bildirme (Henüz bir sorgulama (query) yapılmadı)
        $em->persist($product);

        // Sorgulamayı gerçekleştirme
        $em->flush();
		
        // Kaydı girilen ürünün bilgilerini bir dizi ile urungirisi.html.twig dosyasına aktarma
        return $this->render('myview/urungirisi.html.twig', array('product' => array('name' => $product->getName(), 'price' => $product->getPrice(), 'description' => $product->getDescription())));		
    }
}

Yukarıda oluşturduğumuz newAction adlı Action (Fonksiyon) , Product sınıfından $product adlı bir nesne ouşturur ve sınıf içindeki fonksiyonları (metodlar) kullanarak sınıf içindeki değişkenlere birer değer atar.

$this->getDoctrine()->getManager() komutu ile, Doctrine'in veritabanına nesne kaydetme ve veritabanından nesne alma işlemlerini yöneten Entity Manager uygulamasını çağırır.

persist($product) komutu ile, Doctrine'e $product nesnesini yöneteceğini bildirir.

flush() komutu ile, Doctrine $product nesnesini veritabanına kaydederek, product tablosuna bir satır ekler.

En son satırda ise, kaydı girilen ürünün bilgilerini bir dizi ile urungirisi.html.twig dosyasına aktarır.

3. Verileri ekranda gösterecek olan web sayfası şablonunu oluşturmak için, daha önce, myview dizininin altında oluşturduğunuz urunler.html.twig adlı dosyanın içeriğini kopyalayarak yeni bir dosyaya yapıştırın. Dosya içeriğini aşağıdaki hale getirdikten sonra urungirisi.html.twig adı ile kaydedin:

{# app/Resources/views/myview/urungirisi.html.twig #}

{% extends 'main.html.twig' %}
{% block body %}
<h1>Ürün girişi</h1>

<p>Yeni ürün kaydedildi: {{ product.name }} {{ product.price }} {{ product.description }}</p>
{% endblock %}

Sonuç olarak, myview dizin içeriği aşağıdaki şekilde oluşacaktır:

Aşağıdaki şekilde yer alan Ürün girişi menü seçeneğine tıkladığınızda, aşağıdakine benzer bir ekran görüntüsü karşınıza gelecektir:

product adlı tabloya eklenen kaydı phpMyAdmin benzeri bir arayüzle kontrol edebilirsiniz:

Veritabanından veri alma

1. Veritabanından veri okumak C:\wamp\www\mysym\app\Resources\views dizini altında bulunan main.html.twig dosyasındaki Ürünler menü seçeneğini kullanabiliriz:

	<ul class="ulmenu">
            <li><a href="{{ path('homepage') }}">Ana sayfa</a></li>
            <li><a href="{{ path('Ürünler') }}">Ürünler</a></li>
            <li><a href="{{ path('Ürün girişi') }}">Ürün girişi</a></li>
	</ul>	

2. Veritabanında bulunan ürün bilgilerini ekranda gösterecek bir sayfaya yönlendirmek amacıyla, MainController.php dosyası içinde, /urunler Route değeri için tanımlanmış productsAction() Action (Metod)'ı içinde aşağıdaki değişiklikleri yaparak kaydedin.

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

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;

use AppBundle\Entity\Product;
use Symfony\Component\HttpFoundation\Response;

class MainController extends Controller
{
    /**
    * @Route("/", name="homepage")
    */
    public function mainAction(Request $request)
    {
        return $this->render('myview/index.html.twig');
    }
	
    /**
     * @Route("/urunler", name="Ürünler")
     */
    public function productsAction(Request $request)
    {
        $product = $this->getDoctrine()
            ->getRepository('AppBundle:Product')
            ->findAll();

        if (!$product) {
            throw $this->createNotFoundException('Ürün bulunamadı!');
        }		
		
        return $this->render('myview/urunler.html.twig', array ('products' => $product));
    }
	
    /**
     * @Route("/urungirisi", name="Ürün girişi")
     */
    public function newAction(Request $request)
    {
        $product = new Product();
        $product->setName('Süt');
        $product->setPrice(2.50);
        $product->setDescription('Tam yağlı pastorize süt!');

        $em = $this->getDoctrine()->getManager();

        // Sonuç olarak ürün kaydı yapmak istediğinizi Doctrine'e bildirme (Henüz bir sorgulama (query) yapılmadı)
        $em->persist($product);

        // Sorgulamayı gerçekleştirme
        $em->flush();
		
        // Kaydı girilen ürünün bilgilerini bir dizi ile urungirisi.html.twig dosyasına aktarma
        return $this->render('myview/urungirisi.html.twig', array('product' => array('name' => $product->getName(), 'price' => $product->getPrice(), 'description' => $product->getDescription())));		
    }
}

3. Verileri ekranda gösterecek olan web sayfası şablonunu oluşturmak için, daha önce, myview dizininin altında oluşturduğunuz urunler.html.twig adlı dosyanın içeriğini aşağıdaki şekilde değiştirdikten sonra kaydedin:

{# app/Resources/views/myview/urunler.html.twig #}

{% extends 'main.html.twig' %}
{% block body %}
<h1>Ürünler sayfası</h1>

{% for key in products %}
   <div>
      {{ key.name }}
      {{ key.price }}
      {{ key.description }}
   </div>
{% endfor %}

{% endblock %}