BG MVC Model View Controller eğitim serisi yayında...

Ana sayfa > Programlama > Symfony Framework > Symfony controller

Symfony controller

İşlem görmemiş (Raw) yanıtları geri döndürme

Symfony kendisini İstek (Request)- Yanıt (Response) çerçevesi olarak tanımlar. Kullanıcı, uygulamanız için bir istekte bulunursa, Symfony, bu istekle ilgili tüm bilgileri kapsüllemek için bir İstek nesnesi oluşturur. Benzer şekilde, herhangi bir denetleyicinin herhangi bir eylemini gerçekleştirmenin sonucunda, Symfony'nin kullanıcıya döndürülen HTML içeriğini üretmek için kullandığı bir Response nesnesi oluşturulur

Şimdiye kadar, gösterilen tüm eylemler, sonuç olarak bir şablon döndürmek için $this->render() denetleyici kısayol metodunu kullandık. İhtiyacınız olduğu takdirde, herhangi bir metin içeriğini geri döndürmek için de, bir işlem görmemiş Response nesnesi oluşturabilirsiniz:


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

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

class DefaultController extends Controller
{
    /**
    * @Route("/", name="homepage")
    */
    public function indexAction()
    {
        return new Response('Welcome to Symfony!');
    }
}

Route parametreleri

Çoğu zaman, uygulama URL'leri içinde değişkenler içerir. Örneğin, bir blog uygulaması oluşturuyorsanız, makaleleri görüntüleyecek olan URL, uygulamanın tam olarak hangi makaleyi göstereceğini bilmesini sağlamak için, makalenin başlığını veya başka bir benzersiz tanımlayıcısını içermelidir.

Symfony uygulamalarında, route'ların değişken kısımları yaylı parantezler içinde yer alır (ör. /blog/read/{article_title}/). Her bir değişken bölümüne, denetleyicide her bir değeri almak için daha sonra kullanılabilecek benzersiz bir ad verilir.

Bu özelliği görmek için route değişkenleri ile yeni bir eylem oluşturalım. src/AppBundle/Controller/DefaultController.php dosyasını açın ve aşağıdaki içeriğe sahip helloAction() adlı yeni bir metod ekleyin:


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

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

class DefaultController extends Controller
{
    /// ...
	
    /**
    * @Route("/hello/{name}", name="hello")
    */
    public function helloAction($name)
    {
        return $this->render('default/hello.html.twig', array(
            'name' => $name
        ));
    }
}

Bu yeni işlemin sonucunu görmek için tarayıcınızı açın ve http://localhost:8000/hello/Ahmet URL'sine erişin. İşlem sonucunun yerine bir hata sayfası görürsünüz. Tahmin ettiğiniz gibi, bu hatanın nedeni henüz mevcut olmayan bir şablon (default/hello.html.twig) göstermeye çalışmamızdan kaynaklanmaktadır.

Yeni app/Resources/views/default/hello.html.twig şablonunu aşağıdaki içerikle oluşturun:


{# app/Resources/views/default/hello.html.twig #}
{% extends 'base.html.twig' %}

{% block body %}
    <h1>Hi {{ name }}! Welcome to Symfony!</h1>
{% endblock %}

http://localhost:8000/hello/Ahmet URL'sine yeniden giriş yaptığınızda, denetleyicinin ilettiği bilgilerle oluşturulmuş bu yeni şablonu görürsünüz. URL'nin son bölümünü değiştirir (ör. http://localhost:8000/hello/Mehmet) ve tarayıcınızı yeniden yüklerseniz, sayfada farklı bir mesaj görüntülenir. Ve URL'nin son kısmını kaldırırsanız (örn. http://localhost:8000/hello), route'un beklediği ismi sağlamadığınız için Symfony bir hata mesajı görüntüler.

Farklı veri formatlarının kullanımı

Günümüzde bir web uygulaması HTML sayfalarından daha fazlasını sunabilmelidir. RSS yayınları veya Web Hizmetleri için kullanılan XML'den tutun, Ajax istekleri için kullanılan JSON'a kadar, seçim yapabileceğiniz çok sayıda farklı format bulunmaktadır.

Symfony'de, kullanıcı tarafından istenen formatı yükleyen _format adlı özel bir değişkeni kullanarak istediğiniz işlemleri gerçekleştirebilirsiniz.

Varsayılan değer olarak html değerine sahip yeni bir _format değişkenini hello route'una ekleyeniz:


// src/AppBundle/Controller/DefaultController.php
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
// ...

/**
* @Route("/hello/{name}.{_format}", defaults={"_format"="html"}, name="hello")
*/
public function helloAction($name, $_format)
{
    return $this->render('default/hello.'.$_format.'.twig', array(
        'name' => $name
    ));
}

Açıkçası, birkaç istek formatını desteklediğinizde, desteklenen her format için bir şablon sağlamanız gerekir. Bu durumda, yeni bir hello.xml.twigşablonu oluşturmalısınız:


<!-- app/Resources/views/default/hello.xml.twig -->
<hello>
    <name>{{ name }}</name>
</hello>

Şimdi, http://localhost:8000/hello/Ahmet adresine ulaşmaya çalıştığınızda, normal bir HTML sayfası görürsünüz, çünkü html varsayılan biçimdir. http://localhost:8000/hello/Ahmet.html adresine ulaşmaya çalıştığınızda tekrar bir HTML sayfası elde edersiniz, ancak bu defa açıkça html biçimini istediniz. Son olarak, http://localhost:8000/hello/Ahmet.xml adresini ziyaret ederseniz, yeni XML şablonunun tarayıcınızda görürsünüz.

Standart formatlar için, Symfony yanıt için otomatik olarak en iyi Content-Type başlığını seçecektir. Belirli bir eylem tarafından desteklenen biçimleri kısıtlamak için @Route() ifadesinin requirements seçeneğini kullanabilirsiniz:


// src/AppBundle/Controller/DefaultController.php
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
// ...

/**
* @Route("/hello/{name}.{_format}",
* defaults = {"_format"="html"},
* requirements = { "_format" = "html|xml|json" },
* name = "hello"
* )
*/
public function helloAction($name, $_format)
{
    return $this->render('default/hello.'.$_format.'.twig', array(
        'name' => $name
    ));
}

hello eylemi şimdi /hello/Ahmet.xml veya /hello/Ahmet.json gibi URL'lerle eşleşecek, ancak /hello/Ahmet.js gibi URL'ler elde etmeye çalışırsanız 404 hatası gösterilecektir, çünkü _format değişkeni js formatını içermemektedir.

Yeniden yönlendirme

Kullanıcıyı başka bir sayfaya yönlendirmek istediğinizde, redirectToRoute() metodunu kullanabilirsiniz:


// src/AppBundle/Controller/DefaultController.php
class DefaultController extends Controller
{
    /**
     * @Route("/", name="homepage")
     */
    public function indexAction()
    {
        return $this->redirectToRoute('hello', array('name' => 'Ahmet'));
    }
}

redirectToRoute() yöntemi, argüman olarak route adını ve isteğe bağlı bir parametre dizisi alır ve kullanıcıyı bu bağımsız değişkenlerle oluşturulan URL'ye yönlendirir.

Hata sayfalarını gösterme

Web uygulamalarının çalıştırılmasında hatalarla karşılaşmak kaçınılmazdır. 404 hataları ile karşılaşıldığında, Symfony, denetleyicilerinizde kullanabileceğiniz kullanışlı bir kısayol içerir:


// src/AppBundle/Controller/DefaultController.php
// ...

class DefaultController extends Controller
{
    /**
     * @Route("/", name="homepage")
     */
    public function indexAction()
    {
        // ...
        throw $this->createNotFoundException();
    }
}

500 hataları için, denetleyici içinde normal bir PHP istisnası atamanız yeterlidir. Symfony bunu uygun bir 500 hata sayfasına çevirir:


// src/AppBundle/Controller/DefaultController.php
// ...

class DefaultController extends Controller
{
    /**
     * @Route("/", name="homepage")
     */
    public function indexAction()
    {
        // ...
        throw new \Exception('Something went horribly wrong!');
    }
}

İsteklerden (Request) bilgi alma

Bazen denetleyicileriniz tercih edilen dil, IP adresi veya URL sorgu parametreleri gibi kullanıcı istekleri ile ilgili bilgilere erişmesi gerekir. Bu bilgilere erişmek için, eyleme Request cinsinden yeni bir değişken parametre ekleyin. Bu yeni parametreye farklı isimler verebilirsiniz, ancak işlem görebilmesi için Request türünde tanımlanmalıdır:


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

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

class DefaultController extends Controller
{
    /**
     * @Route("/", name="homepage")
     */
    public function indexAction(Request $request)
    {	
	// Bir Ajax isteği mi?
	$isAjax = $request->isXmlHttpRequest();
	
	// Kullanıcının tercih ettiği dil hangisi?
	$language = $request->getPreferredLanguage(array('en', 'fr'));
	
	// $_GET parametresinin değerini al
	$pageName = $request->query->get('page');
	
	// $_POST parametresinin değerini al
	$pageName = $request->request->get('page');
    }
}

Bir şablonda, Symfony tarafından otomatik olarak sağlanan özel app.request değişkeniyle de Request nesnesine erişebilirsiniz:


{{ app.request.query.get('page') }}

{{ app.request.request.get('page') }}

Oturumda verilerin kalıcılığını sağlamak

Symfony, istemciyi temsil eden güzel bir oturum nesnesi sağlar (gerçek anlamda bir tarayıcı, bot veya web servisi kullanan biri olabilir). İki istek arasında, Symfony yerel PHP oturumlarını kullanarak özellikleri bir çerezde saklar.

Oturumda bilgi depolama ve alma işlemi herhangi bir denetleyiciden kolaylıkla gerçekleştirilebilir:


use  Symfony\Component\HttpFoundation\Request;

public function indexAction(Request $request)
{
    $session = $request->getSession();

    // Daha sonraki kullanıcı isteğinde tekrar kullanmak üzere bir özelliği depolama
    $session->set('foo', 'bar');

    // Bir oturum özelliğinin değerini alma
    $foo = $session->get('foo');

    // Eğer özellik mevcut değilse, varsayılan değeri kullanma
    $foo = $session->get('foo', 'default_value');
}

Bir sonraki istekten sonra otomatik olarak silenecek "flash mesajları" da saklayabilirsiniz. Kullanıcıyı başka bir sayfaya yönlendirmeden önce bir başarı mesajı göstermeniz gerektiğinde fayda sağlar:


public function indexAction(Request $request)
{
    // ...

    // Sonraki istekler için bir mesaj saklama
    $this->addFlash('notice', 'Tebrikler, eyleminiz başarıyla sonuçlandı!');
}

Flash mesajı şablonda aşağıdaki şekilde gösterebilirsiniz:


{% for flashMessage in app.session.flashBag.get('notice') %}
    <div class="flash-notice">
        {{ flashMessage }}
    </div>
{% endfor %}