{"id":30519,"date":"2025-09-28T21:41:04","date_gmt":"2025-09-28T18:41:04","guid":{"rendered":"https:\/\/fatihsoysal.com\/blog\/?p=30519"},"modified":"2025-09-28T21:41:04","modified_gmt":"2025-09-28T18:41:04","slug":"symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2","status":"publish","type":"post","link":"https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/","title":{"rendered":"Symfony2 ile VPS \u00dczerinde CRUD \u0130\u015flemleri Ger\u00e7ekle\u015ftirme: Derinlemesine \u0130nceleme (B\u00f6l\u00fcm 2)"},"content":{"rendered":"<p><body><\/p>\n<h2>Symfony2 ile VPS \u00dczerinde CRUD \u0130\u015flemleri Ger\u00e7ekle\u015ftirme: Derinlemesine \u0130nceleme (B\u00f6l\u00fcm 2)<\/h2>\n<p>Bu makale serisinin ilk b\u00f6l\u00fcm\u00fcnde, Symfony2 projesi olu\u015fturma, veritaban\u0131 ba\u011flant\u0131s\u0131n\u0131 yap\u0131land\u0131rma ve Doctrine ORM kullanarak basit bir Entity tan\u0131mlama gibi temel konulara de\u011finmi\u015ftik. Bir Sanal \u00d6zel Sunucu (VPS) \u00fczerinde Symfony2 uygulamas\u0131n\u0131 \u00e7al\u0131\u015ft\u0131rman\u0131n ilk ad\u0131mlar\u0131n\u0131 atm\u0131\u015f, web sunucusu yap\u0131land\u0131rmas\u0131na (genellikle Nginx veya Apache) genel bir bak\u0131\u015f sunmu\u015ftuk. \u015eimdi, bu sa\u011flam temel \u00fczerine in\u015fa ederek, Symfony2&#8217;nin CRUD (Create, Read, Update, Delete) operasyonlar\u0131 i\u00e7in sundu\u011fu g\u00fc\u00e7l\u00fc ve esnek ara\u00e7lar\u0131 daha derinlemesine inceleyece\u011fiz. \u00d6zellikle, form y\u00f6netimi, veri do\u011frulama, kullan\u0131c\u0131 geri bildirimleri ve g\u00fcvenlik gibi \u00f6nemli konulara odaklanarak, bir web uygulamas\u0131n\u0131n belkemi\u011fini olu\u015fturan bu i\u015flemleri nas\u0131l etkin bir \u015fekilde ger\u00e7ekle\u015ftirebilece\u011finizi ad\u0131m ad\u0131m g\u00f6sterece\u011fiz.<\/p>\n<h3>CRUD Operasyonlar\u0131na Derinlemesine Bak\u0131\u015f<\/h3>\n<p>CRUD operasyonlar\u0131, hemen hemen her veri odakl\u0131 uygulaman\u0131n temelini olu\u015fturur. Symfony2, bu i\u015flemleri kolayla\u015ft\u0131rmak i\u00e7in Doctrine ORM, Form Bile\u015feni ve Validasyon Bile\u015feni gibi g\u00fc\u00e7l\u00fc ara\u00e7lar sunar. Bu b\u00f6l\u00fcmde, her bir CRUD operasyonunu ayr\u0131 ayr\u0131 ele alacak ve en iyi uygulamalar\u0131 sergileyece\u011fiz.<\/p>\n<h4>Yeni Kay\u0131t Olu\u015fturma (Create)<\/h4>\n<p>Yeni bir veri kayd\u0131 olu\u015fturmak, genellikle bir HTML formu arac\u0131l\u0131\u011f\u0131yla kullan\u0131c\u0131dan bilgi almay\u0131 ve bu bilgileri veritaban\u0131na kaydetmeyi i\u00e7erir. Symfony&#8217;de bu s\u00fcre\u00e7, Form Bile\u015feni sayesinde olduk\u00e7a basittir ve bir\u00e7ok g\u00fcvenlik ve do\u011frulama \u00f6zelli\u011fini beraberinde getirir.<\/p>\n<h5>Form Olu\u015fturma ve Yap\u0131land\u0131rma<\/h5>\n<p>\u00d6ncelikle, Part 1&#8217;de olu\u015fturdu\u011fumuz <code>Product<\/code> entity&#8217;si i\u00e7in bir form tipi olu\u015fturmal\u0131y\u0131z. Bu, <code>src\/AppBundle\/Form\/ProductType.php<\/code> gibi bir dosyada yap\u0131labilir:<\/p>\n<pre><code class=\"language-php\">\/\/ src\/AppBundle\/Form\/ProductType.php\nnamespace AppBundle\\Form;\n\nuse AppBundle\\Entity\\Product;\nuse Symfony\\Component\\Form\\AbstractType;\nuse Symfony\\Component\\Form\\FormBuilderInterface;\nuse Symfony\\Component\\OptionsResolver\\OptionsResolverInterface;\nuse Symfony\\Component\\Form\\Extension\\Core\\Type\\TextType;\nuse Symfony\\Component\\Form\\Extension\\Core\\Type\\NumberType;\nuse Symfony\\Component\\Form\\Extension\\Core\\Type\\TextareaType;\nuse Symfony\\Component\\Form\\Extension\\Core\\Type\\SubmitType;\n\nclass ProductType extends AbstractType\n{\n    public function buildForm(FormBuilderInterface $builder, array $options)\n    {\n        $builder\n            ->add('name', TextType::class, ['label' => '\u00dcr\u00fcn Ad\u0131'])\n            ->add('price', NumberType::class, ['label' => 'Fiyat'])\n            ->add('description', TextareaType::class, ['label' => 'A\u00e7\u0131klama', 'required' => false])\n            ->add('save', SubmitType::class, ['label' => 'Kaydet']);\n    }\n\n    public function setDefaultOptions(OptionsResolverInterface $resolver)\n    {\n        $resolver->setDefaults([\n            'data_class' => Product::class,\n        ]);\n    }\n\n    public function getName()\n    {\n        return 'product';\n    }\n}<\/code><\/pre>\n<p>Bu form tipi, <code>Product<\/code> entity&#8217;mizin alanlar\u0131na kar\u015f\u0131l\u0131k gelen form alanlar\u0131n\u0131 tan\u0131mlar. <code>data_class<\/code> se\u00e7ene\u011fi, formun hangi entity ile ili\u015fkilendirilece\u011fini Symfony&#8217;ye bildirir.<\/p>\n<h5>Controller Taraf\u0131nda Form \u0130\u015fleme<\/h5>\n<p>\u015eimdi, bu formu bir Controller i\u00e7inde nas\u0131l kullanaca\u011f\u0131m\u0131za bakal\u0131m. Yeni bir \u00fcr\u00fcn eklemek i\u00e7in bir eylem (<code>Action<\/code>) tan\u0131mlayal\u0131m:<\/p>\n<pre><code class=\"language-php\">\/\/ src\/AppBundle\/Controller\/ProductController.php\nnamespace AppBundle\\Controller;\n\nuse AppBundle\\Entity\\Product;\nuse AppBundle\\Form\\ProductType;\nuse Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\Routing\\Annotation\\Route;\n\nclass ProductController extends Controller\n{\n    \/<em><\/em>\n     * @Route(\"\/product\/new\", name=\"product_new\")\n     *\/\n    public function newAction(Request $request)\n    {\n        $product = new Product();\n        $form = $this->createForm(ProductType::class, $product);\n\n        $form->handleRequest($request);\n\n        if ($form->isSubmitted() && $form->isValid()) {\n            $em = $this->getDoctrine()->getManager();\n            $em->persist($product); \/\/ Entity'yi kal\u0131c\u0131 hale getir\n            $em->flush(); \/\/ Veritaban\u0131na kaydet\n\n            $this->addFlash(\n                'notice',\n                '\u00dcr\u00fcn ba\u015far\u0131yla eklendi!'\n            );\n\n            return $this->redirectToRoute('product_list'); \/\/ Ba\u015far\u0131l\u0131ysa \u00fcr\u00fcn listesine y\u00f6nlendir\n        }\n\n        return $this->render('product\/new.html.twig', [\n            'form' => $form->createView(),\n        ]);\n    }\n}<\/code><\/pre>\n<p>Bu kodda:<br \/>\n*   Yeni bir <code>Product<\/code> nesnesi olu\u015fturulur.<br \/>\n*   <code>ProductType<\/code> kullan\u0131larak bir form olu\u015fturulur ve <code>Product<\/code> nesnesi ile ili\u015fkilendirilir.<br \/>\n*   <code>handleRequest($request)<\/code> metodu, gelen HTTP iste\u011findeki verileri forma ba\u011flar.<br \/>\n*   <code>isSubmitted()<\/code> ve <code>isValid()<\/code> metotlar\u0131, formun g\u00f6nderilip g\u00f6nderilmedi\u011fini ve verilerin ge\u00e7erli olup olmad\u0131\u011f\u0131n\u0131 kontrol eder.<br \/>\n*   Veriler ge\u00e7erliyse, <code>persist()<\/code> ile entity Doctrine taraf\u0131ndan izlenmeye ba\u015flan\u0131r ve <code>flush()<\/code> ile veritaban\u0131na kaydedilir.<br \/>\n*   <code>addFlash()<\/code> metodu, kullan\u0131c\u0131ya geri bildirim sa\u011flamak i\u00e7in bir &#8220;flash mesaj\u0131&#8221; ekler. Bu mesajlar, bir sonraki HTTP iste\u011fi i\u00e7in saklan\u0131r ve genellikle Twig \u015fablonunda g\u00f6r\u00fcnt\u00fclenir.<br \/>\n*   \u0130\u015flem ba\u015far\u0131l\u0131 olursa, kullan\u0131c\u0131 \u00fcr\u00fcn listesi sayfas\u0131na y\u00f6nlendirilir.<\/p>\n<h5>Twig \u015eablonunda Formu G\u00f6r\u00fcnt\u00fcleme<\/h5>\n<p>Son olarak, formu g\u00f6r\u00fcnt\u00fclemek i\u00e7in <code>app\/Resources\/views\/product\/new.html.twig<\/code> dosyas\u0131n\u0131 olu\u015ftural\u0131m:<\/p>\n<pre><code class=\"language-twig\">{# app\/Resources\/views\/product\/new.html.twig #}\n{% extends 'base.html.twig' %}\n\n{% block body %}\n    <h2>Yeni \u00dcr\u00fcn Ekle<\/h2>\n\n    {% for message in app.flashes('notice') %}\n        <div class=\"alert alert-success\">\n            {{ message }}\n        <\/div>\n    {% endfor %}\n\n    {{ form_start(form) }}\n        {{ form_row(form.name) }}\n        {{ form_row(form.price) }}\n        {{ form_row(form.description) }}\n        {{ form_row(form.save) }}\n    {{ form_end(form) }}\n{% endblock %}<\/code><\/pre>\n<p>Bu \u015fablonda <code>form_start()<\/code>, <code>form_row()<\/code> ve <code>form_end()<\/code> gibi Twig fonksiyonlar\u0131, formun HTML \u00e7\u0131kt\u0131s\u0131n\u0131 kolayca olu\u015fturmak i\u00e7in kullan\u0131l\u0131r. <code>app.flashes('notice')<\/code> ile daha \u00f6nce ekledi\u011fimiz flash mesajlar\u0131 g\u00f6r\u00fcnt\u00fclenir.<\/p>\n<h4>Kay\u0131tlar\u0131 Listeleme (Read &#8211; All)<\/h4>\n<p>Veritaban\u0131ndaki t\u00fcm \u00fcr\u00fcnleri listelemek, genellikle bir Controller&#8217;dan Repository arac\u0131l\u0131\u011f\u0131yla veri \u00e7ekmeyi ve bu verileri bir Twig \u015fablonunda g\u00f6r\u00fcnt\u00fclemeyi i\u00e7erir.<\/p>\n<h5>Controller Taraf\u0131nda Veri \u00c7ekme<\/h5>\n<pre><code class=\"language-php\">\/\/ src\/AppBundle\/Controller\/ProductController.php\n\/\/ ...\nclass ProductController extends Controller\n{\n    \/<em><\/em>\n     * @Route(\"\/product\", name=\"product_list\")\n     *\/\n    public function listAction()\n    {\n        $products = $this->getDoctrine()\n            ->getRepository(Product::class)\n            ->findAll(); \/\/ T\u00fcm \u00fcr\u00fcnleri getir\n\n        return $this->render('product\/list.html.twig', [\n            'products' => $products,\n        ]);\n    }\n}<\/code><\/pre>\n<p>Burada, <code>getRepository(Product::class)<\/code> ile <code>Product<\/code> entity&#8217;mizin Repository&#8217;sine eri\u015firiz. <code>findAll()<\/code> metodu, veritaban\u0131ndaki t\u00fcm <code>Product<\/code> kay\u0131tlar\u0131n\u0131 d\u00f6nd\u00fcr\u00fcr.<\/p>\n<h5>Twig \u015eablonunda Listeyi G\u00f6r\u00fcnt\u00fcleme<\/h5>\n<p><code>app\/Resources\/views\/product\/list.html.twig<\/code> dosyas\u0131n\u0131 olu\u015ftural\u0131m:<\/p>\n<pre><code class=\"language-twig\">{# app\/Resources\/views\/product\/list.html.twig #}\n{% extends 'base.html.twig' %}\n\n{% block body %}\n    <h2>\u00dcr\u00fcn Listesi<\/h2>\n\n    <p><a href=\"{{ path('product_new') }}\" class=\"btn btn-primary\">Yeni \u00dcr\u00fcn Ekle<\/a><\/p>\n\n    {% for message in app.flashes('notice') %}\n        <div class=\"alert alert-success\">\n            {{ message }}\n        <\/div>\n    {% endfor %}\n\n    {% if products is not empty %}\n        <table class=\"table table-striped\">\n            <thead>\n                <tr>\n                    <th>ID<\/th>\n                    <th>Ad\u0131<\/th>\n                    <th>Fiyat<\/th>\n                    <th>A\u00e7\u0131klama<\/th>\n                    <th>\u0130\u015flemler<\/th>\n                <\/tr>\n            <\/thead>\n            <tbody>\n                {% for product in products %}\n                    <tr>\n                        <td>{{ product.id }}<\/td>\n                        <td>{{ product.name }}<\/td>\n                        <td>{{ product.price|number_format(2, ',', '.') }} TL<\/td>\n                        <td>{{ product.description|length > 50 ? product.description|slice(0, 50) ~ '...' : product.description }}<\/td>\n                        <td>\n                            <a href=\"{{ path('product_show', {'id': product.id}) }}\" class=\"btn btn-info btn-sm\">G\u00f6r\u00fcnt\u00fcle<\/a>\n                            <a href=\"{{ path('product_edit', {'id': product.id}) }}\" class=\"btn btn-warning btn-sm\">D\u00fczenle<\/a>\n                            <a href=\"{{ path('product_delete', {'id': product.id}) }}\" class=\"btn btn-danger btn-sm\" onclick=\"return confirm('Bu \u00fcr\u00fcn\u00fc silmek istedi\u011finizden emin misiniz?');\">Sil<\/a>\n                        <\/td>\n                    <\/tr>\n                {% endfor %}\n            <\/tbody>\n        <\/table>\n    {% else %}\n        <p>Hen\u00fcz hi\u00e7 \u00fcr\u00fcn eklenmemi\u015f.<\/p>\n    {% endif %}\n{% endblock %}<\/code><\/pre>\n<p>Bu \u015fablon, \u00fcr\u00fcnleri bir tablo i\u00e7inde listeler ve her \u00fcr\u00fcn i\u00e7in g\u00f6r\u00fcnt\u00fcleme, d\u00fczenleme ve silme ba\u011flant\u0131lar\u0131 sunar.<\/p>\n<h4>Tek Kay\u0131t G\u00f6r\u00fcnt\u00fcleme (Read &#8211; One)<\/h4>\n<p>Belirli bir \u00fcr\u00fcn\u00fcn detaylar\u0131n\u0131 g\u00f6r\u00fcnt\u00fclemek i\u00e7in, genellikle URL&#8217;den bir ID parametresi al\u0131n\u0131r ve bu ID&#8217;ye g\u00f6re veritaban\u0131ndan tek bir kay\u0131t \u00e7ekilir.<\/p>\n<h5>Controller Taraf\u0131nda Tek Kay\u0131t \u00c7ekme<\/h5>\n<pre><code class=\"language-php\">\/\/ src\/AppBundle\/Controller\/ProductController.php\n\/\/ ...\nclass ProductController extends Controller\n{\n    \/<em><\/em>\n     * @Route(\"\/product\/{id}\", name=\"product_show\")\n     *\/\n    public function showAction($id)\n    {\n        $product = $this->getDoctrine()\n            ->getRepository(Product::class)\n            ->find($id); \/\/ ID'ye g\u00f6re \u00fcr\u00fcn\u00fc bul\n\n        if (!$product) {\n            throw $this->createNotFoundException('\u00dcr\u00fcn bulunamad\u0131: ' . $id);\n        }\n\n        return $this->render('product\/show.html.twig', [\n            'product' => $product,\n        ]);\n    }\n}<\/code><\/pre>\n<p><code>find($id)<\/code> metodu, belirtilen ID&#8217;ye sahip entity&#8217;yi d\u00f6nd\u00fcr\u00fcr. E\u011fer \u00fcr\u00fcn bulunamazsa, <code>createNotFoundException()<\/code> ile bir 404 hatas\u0131 f\u0131rlat\u0131l\u0131r.<\/p>\n<h5>Twig \u015eablonunda Detaylar\u0131 G\u00f6r\u00fcnt\u00fcleme<\/h5>\n<p><code>app\/Resources\/views\/product\/show.html.twig<\/code> dosyas\u0131n\u0131 olu\u015ftural\u0131m:<\/p>\n<pre><code class=\"language-twig\">{# app\/Resources\/views\/product\/show.html.twig #}\n{% extends 'base.html.twig' %}\n\n{% block body %}\n    <h2>\u00dcr\u00fcn Detay\u0131: {{ product.name }}<\/h2>\n\n    <table class=\"table table-bordered\">\n        <tbody>\n            <tr>\n                <th>ID<\/th>\n                <td>{{ product.id }}<\/td>\n            <\/tr>\n            <tr>\n                <th>Ad\u0131<\/th>\n                <td>{{ product.name }}<\/td>\n            <\/tr>\n            <tr>\n                <th>Fiyat<\/th>\n                <td>{{ product.price|number_format(2, ',', '.') }} TL<\/td>\n            <\/tr>\n            <tr>\n                <th>A\u00e7\u0131klama<\/th>\n                <td>{{ product.description|default('A\u00e7\u0131klama yok.')|nl2br }}<\/td>\n            <\/tr>\n        <\/tbody>\n    <\/table>\n\n    <p>\n        <a href=\"{{ path('product_list') }}\" class=\"btn btn-secondary\">Listeye Geri D\u00f6n<\/a>\n        <a href=\"{{ path('product_edit', {'id': product.id}) }}\" class=\"btn btn-warning\">D\u00fczenle<\/a>\n    <\/p>\n{% endblock %}<\/code><\/pre>\n<h4>Kay\u0131t G\u00fcncelleme (Update)<\/h4>\n<p>Mevcut bir kayd\u0131 g\u00fcncellemek, yeni kay\u0131t olu\u015fturmaya benzer, ancak formun mevcut veri ile doldurulmas\u0131 ve veritaban\u0131nda sadece <code>flush()<\/code> \u00e7a\u011fr\u0131lmas\u0131 yeterlidir.<\/p>\n<h5>Controller Taraf\u0131nda Kay\u0131t G\u00fcncelleme<\/h5>\n<pre><code class=\"language-php\">\/\/ src\/AppBundle\/Controller\/ProductController.php\n\/\/ ...\nclass ProductController extends Controller\n{\n    \/<em><\/em>\n     * @Route(\"\/product\/{id}\/edit\", name=\"product_edit\")\n     *\/\n    public function editAction(Request $request, $id)\n    {\n        $em = $this->getDoctrine()->getManager();\n        $product = $em->getRepository(Product::class)->find($id);\n\n        if (!$product) {\n            throw $this->createNotFoundException('G\u00fcncellenecek \u00fcr\u00fcn bulunamad\u0131: ' . $id);\n        }\n\n        $form = $this->createForm(ProductType::class, $product);\n        $form->handleRequest($request);\n\n        if ($form->isSubmitted() && $form->isValid()) {\n            $em->flush(); \/\/ Sadece flush yeterli, persist zaten yap\u0131ld\u0131\n\n            $this->addFlash(\n                'notice',\n                '\u00dcr\u00fcn ba\u015far\u0131yla g\u00fcncellendi!'\n            );\n\n            return $this->redirectToRoute('product_show', ['id' => $product->getId()]);\n        }\n\n        return $this->render('product\/edit.html.twig', [\n            'form' => $form->createView(),\n            'product' => $product,\n        ]);\n    }\n}<\/code><\/pre>\n<p>Burada dikkat edilmesi gereken nokta, form olu\u015fturulurken mevcut <code>$product<\/code> nesnesinin ikinci parametre olarak ge\u00e7irilmesidir. Bu, formun mevcut verilerle doldurulmas\u0131n\u0131 sa\u011flar. <code>flush()<\/code> \u00e7a\u011fr\u0131ld\u0131\u011f\u0131nda, Doctrine, izledi\u011fi <code>$product<\/code> nesnesindeki de\u011fi\u015fiklikleri otomatik olarak veritaban\u0131na yans\u0131t\u0131r.<\/p>\n<h5>Twig \u015eablonunda G\u00fcncelleme Formu<\/h5>\n<p><code>app\/Resources\/views\/product\/edit.html.twig<\/code> dosyas\u0131n\u0131 olu\u015ftural\u0131m:<\/p>\n<pre><code class=\"language-twig\">{# app\/Resources\/views\/product\/edit.html.twig #}\n{% extends 'base.html.twig' %}\n\n{% block body %}\n    <h2>\u00dcr\u00fcn D\u00fczenle: {{ product.name }}<\/h2>\n\n    {% for message in app.flashes('notice') %}\n        <div class=\"alert alert-success\">\n            {{ message }}\n        <\/div>\n    {% endfor %}\n\n    {{ form_start(form) }}\n        {{ form_row(form.name) }}\n        {{ form_row(form.price) }}\n        {{ form_row(form.description) }}\n        {{ form_row(form.save, {'label': 'G\u00fcncelle'}) }}\n    {{ form_end(form) }}\n\n    <p><a href=\"{{ path('product_show', {'id': product.id}) }}\" class=\"btn btn-secondary\">\u0130ptal<\/a><\/p>\n{% endblock %}<\/code><\/pre>\n<h4>Kay\u0131t Silme (Delete)<\/h4>\n<p>Bir kayd\u0131 silmek, di\u011fer operasyonlara g\u00f6re daha basit g\u00f6r\u00fcnse de, g\u00fcvenlik ve kullan\u0131c\u0131 onay\u0131 a\u00e7\u0131s\u0131ndan dikkatli olunmas\u0131 gereken bir i\u015flemdir.<\/p>\n<h5>Controller Taraf\u0131nda Kay\u0131t Silme<\/h5>\n<pre><code class=\"language-php\">\/\/ src\/AppBundle\/Controller\/ProductController.php\n\/\/ ...\nclass ProductController extends Controller\n{\n    \/<em><\/em>\n     * @Route(\"\/product\/{id}\/delete\", name=\"product_delete\", methods={\"POST\"})\n     *\/\n    public function deleteAction(Request $request, $id)\n    {\n        $em = $this->getDoctrine()->getManager();\n        $product = $em->getRepository(Product::class)->find($id);\n\n        if (!$product) {\n            throw $this->createNotFoundException('Silinecek \u00fcr\u00fcn bulunamad\u0131: ' . $id);\n        }\n\n        \/\/ G\u00fcvenlik i\u00e7in CSRF token kontrol\u00fc \u00f6nerilir.\n        \/\/ Symfony 2'de bunu manuel yapman\u0131z gerekebilir veya bir form kullanarak.\n        \/\/ Basit bir \u00f6rnek i\u00e7in \u015fimdilik atl\u0131yoruz, ancak \u00fcretimde kullanmay\u0131n.\n        \/\/ Daha g\u00fcvenli bir yakla\u015f\u0131m i\u00e7in a\u015fa\u011f\u0131daki \"G\u00fcvenlik\" b\u00f6l\u00fcm\u00fcne bak\u0131n.\n\n        $em->remove($product); \/\/ Entity'yi silme i\u00e7in i\u015faretle\n        $em->flush(); \/\/ Veritaban\u0131ndan sil\n\n        $this->addFlash(\n            'notice',\n            '\u00dcr\u00fcn ba\u015far\u0131yla silindi!'\n        );\n\n        return $this->redirectToRoute('product_list');\n    }\n}<\/code><\/pre>\n<p><code>remove($product)<\/code> metodu, entity&#8217;yi silinmek \u00fczere i\u015faretler. <code>flush()<\/code> \u00e7a\u011fr\u0131ld\u0131\u011f\u0131nda, Doctrine bu entity&#8217;yi veritaban\u0131ndan siler. <code>methods={\"POST\"}<\/code> ile bu rotan\u0131n sadece POST istekleriyle eri\u015filebilir oldu\u011funu belirtmek, yanl\u0131\u015fl\u0131kla silme i\u015flemlerini \u00f6nlemeye yard\u0131mc\u0131 olur. Ancak bu yeterli de\u011fildir, CSRF korumas\u0131 kesinlikle gereklidir.<\/p>\n<h5>G\u00fcvenli Silme \u0130\u015flemleri (CSRF Korumas\u0131)<\/h5>\n<p>Bir <code>GET<\/code> iste\u011fi ile silme i\u015flemi yapmak, CSRF (Cross-Site Request Forgery) sald\u0131r\u0131lar\u0131na a\u00e7\u0131k kap\u0131 b\u0131rak\u0131r. Bu nedenle, silme i\u015flemleri i\u00e7in her zaman <code>POST<\/code> istekleri ve CSRF token&#8217;\u0131 kullan\u0131lmal\u0131d\u0131r. Bunun i\u00e7in, silme linki yerine k\u00fc\u00e7\u00fck bir form kullanmak en iyi yoldur:<\/p>\n<pre><code class=\"language-twig\">{# product\/list.html.twig veya product\/show.html.twig i\u00e7inde #}\n<form action=\"{{ path('product_delete', {'id': product.id}) }}\" method=\"post\" style=\"display:inline-block;\">\n    <input type=\"hidden\" name=\"_method\" value=\"DELETE\"> {# Symfony'nin MethodOverrideListener'\u0131 i\u00e7in #}\n    <input type=\"hidden\" name=\"_token\" value=\"{{ csrf_token('delete' ~ product.id) }}\"> {# CSRF token #}\n    <button type=\"submit\" class=\"btn btn-danger btn-sm\" onclick=\"return confirm('Bu \u00fcr\u00fcn\u00fc silmek istedi\u011finizden emin misiniz?');\">Sil<\/button>\n<\/form><\/code><\/pre>\n<p>Controller&#8217;da ise CSRF token&#8217;\u0131 do\u011frulamak i\u00e7in:<\/p>\n<pre><code class=\"language-php\">\/\/ src\/AppBundle\/Controller\/ProductController.php\n\/\/ ...\nclass ProductController extends Controller\n{\n    \/<em><\/em>\n     * @Route(\"\/product\/{id}\/delete\", name=\"product_delete\", methods={\"POST\", \"DELETE\"}) \/\/ DELETE metodunu da ekleyelim\n     *\/\n    public function deleteAction(Request $request, $id)\n    {\n        \/\/ CSRF token kontrol\u00fc\n        if (!$this->isCsrfTokenValid('delete' . $id, $request->request->get('_token'))) {\n            throw $this->createAccessDeniedException('Ge\u00e7ersiz CSRF token.');\n        }\n\n        $em = $this->getDoctrine()->getManager();\n        $product = $em->getRepository(Product::class)->find($id);\n\n        if (!$product) {\n            throw $this->createNotFoundException('Silinecek \u00fcr\u00fcn bulunamad\u0131: ' . $id);\n        }\n\n        $em->remove($product);\n        $em->flush();\n\n        $this->addFlash(\n            'notice',\n            '\u00dcr\u00fcn ba\u015far\u0131yla silindi!'\n        );\n\n        return $this->redirectToRoute('product_list');\n    }\n}<\/code><\/pre>\n<p><code>isCsrfTokenValid()<\/code> metodu, sa\u011flanan token&#8217;\u0131n ge\u00e7erli olup olmad\u0131\u011f\u0131n\u0131 kontrol eder. <code>delete<\/code> metodu i\u00e7in <code>methods={\"POST\"}<\/code> yerine <code>methods={\"POST\", \"DELETE\"}<\/code> kullanmak, RESTful yakla\u015f\u0131ma daha uygun olacakt\u0131r. Symfony&#8217;nin <code>MethodOverrideListener<\/code>&#8216;\u0131, <code>_method<\/code> hidden input alan\u0131 sayesinde POST isteklerini DELETE olarak yorumlayabilir.<\/p>\n<h3>Geli\u015fmi\u015f Form \u00d6zellikleri ve Do\u011frulama<\/h3>\n<p>Symfony Form Bile\u015feni, temel alanlar\u0131n \u00f6tesinde bir\u00e7ok geli\u015fmi\u015f \u00f6zellik sunar.<\/p>\n<h4>Veri Do\u011frulama (Validation)<\/h4>\n<p>Symfony&#8217;nin Validasyon Bile\u015feni, form verilerinin do\u011frulu\u011funu sa\u011flamak i\u00e7in g\u00fc\u00e7l\u00fc bir mekanizma sunar. Do\u011frulama kurallar\u0131 (constraints) genellikle entity s\u0131n\u0131f\u0131nda tan\u0131mlan\u0131r.<\/p>\n<pre><code class=\"language-php\">\/\/ src\/AppBundle\/Entity\/Product.php\nnamespace AppBundle\\Entity;\n\nuse Doctrine\\ORM\\Mapping as ORM;\nuse Symfony\\Component\\Validator\\Constraints as Assert;\n\n\/<em><\/em>\n * @ORM\\Entity(repositoryClass=\"AppBundle\\Repository\\ProductRepository\")\n * @ORM\\Table(name=\"product\")\n *\/\nclass Product\n{\n    \/<em><\/em>\n     * @ORM\\Column(type=\"integer\")\n     * @ORM\\Id\n     * @ORM\\GeneratedValue(strategy=\"AUTO\")\n     *\/\n    private $id;\n\n    \/<em><\/em>\n     * @ORM\\Column(type=\"string\", length=255)\n     * @Assert\\NotBlank(message=\"\u00dcr\u00fcn ad\u0131 bo\u015f b\u0131rak\u0131lamaz.\")\n     * @Assert\\Length(\n     *      min = 3,\n     *      max = 255,\n     *      minMessage = \"\u00dcr\u00fcn ad\u0131 en az {{ limit }} karakter olmal\u0131.\",\n     *      maxMessage = \"\u00dcr\u00fcn ad\u0131 en fazla {{ limit }} karakter olmal\u0131.\"\n     * )\n     *\/\n    private $name;\n\n    \/<em><\/em>\n     * @ORM\\Column(type=\"decimal\", precision=10, scale=2)\n     * @Assert\\NotBlank(message=\"Fiyat bo\u015f b\u0131rak\u0131lamaz.\")\n     * @Assert\\Type(type=\"numeric\", message=\"Fiyat say\u0131sal bir de\u011fer olmal\u0131d\u0131r.\")\n     * @Assert\\GreaterThan(value=0, message=\"Fiyat s\u0131f\u0131rdan b\u00fcy\u00fck olmal\u0131d\u0131r.\")\n     *\/\n    private $price;\n\n    \/<em><\/em>\n     * @ORM\\Column(type=\"text\", nullable=true)\n     *\/\n    private $description;\n\n    \/\/ ... getter ve setter metotlar\u0131\n}<\/code><\/pre>\n<p>Bu \u00f6rnekte, <code>@Assert\\NotBlank<\/code>, <code>@Assert\\Length<\/code>, <code>@Assert\\Type<\/code> ve <code>@Assert\\GreaterThan<\/code> gibi constraint&#8217;ler kullan\u0131larak <code>name<\/code> ve <code>price<\/code> alanlar\u0131 i\u00e7in do\u011frulama kurallar\u0131 tan\u0131mlanm\u0131\u015ft\u0131r. Form g\u00f6nderildi\u011finde <code>form->isValid()<\/code> \u00e7a\u011fr\u0131ld\u0131\u011f\u0131nda bu kurallar otomatik olarak kontrol edilir ve ihlal durumunda hata mesajlar\u0131 olu\u015fturulur. Twig \u015fablonunda <code>form_row()<\/code> kulland\u0131\u011f\u0131m\u0131zda, bu hata mesajlar\u0131 ilgili form alan\u0131n\u0131n alt\u0131nda otomatik olarak g\u00f6r\u00fcnt\u00fclenir.<\/p>\n<h4>\u00d6zel Do\u011frulama Kurallar\u0131 (Custom Validators)<\/h4>\n<p>Bazen standart constraint&#8217;ler yeterli olmayabilir ve kendi \u00f6zel do\u011frulama mant\u0131\u011f\u0131n\u0131z\u0131 yazman\u0131z gerekebilir. \u00d6rne\u011fin, bir \u00fcr\u00fcn ad\u0131n\u0131n veritaban\u0131nda benzersiz olmas\u0131n\u0131 sa\u011flamak isteyebilirsiniz. Bunun i\u00e7in \u00f6zel bir validator olu\u015fturulabilir veya Entity Repository i\u00e7inde benzersizlik kontrol\u00fc yap\u0131labilir.<\/p>\n<pre><code class=\"language-php\">\/\/ src\/AppBundle\/Validator\/Constraints\/UniqueProductName.php\nnamespace AppBundle\\Validator\\Constraints;\n\nuse Symfony\\Component\\Validator\\Constraint;\n\n\/<em><\/em>\n * @Annotation\n *\/\nclass UniqueProductName extends Constraint\n{\n    public $message = 'Bu isimde bir \u00fcr\u00fcn zaten mevcut.';\n\n    public function getTargets()\n    {\n        return self::CLASS_CONSTRAINT; \/\/ Entity seviyesinde do\u011frulama\n    }\n}\n\n\/\/ src\/AppBundle\/Validator\/Constraints\/UniqueProductNameValidator.php\nnamespace AppBundle\\Validator\\Constraints;\n\nuse AppBundle\\Entity\\Product;\nuse Doctrine\\ORM\\EntityManagerInterface;\nuse Symfony\\Component\\Validator\\Constraint;\nuse Symfony\\Component\\Validator\\ConstraintValidator;\n\nclass UniqueProductNameValidator extends ConstraintValidator\n{\n    private $em;\n\n    public function __construct(EntityManagerInterface $em)\n    {\n        $this->em = $em;\n    }\n\n    public function validate($product, Constraint $constraint)\n    {\n        \/<em> @var $constraint UniqueProductName <\/em>\/\n        if (!$product instanceof Product) {\n            return;\n        }\n\n        $existingProduct = $this->em->getRepository(Product::class)\n            ->findOneBy(['name' => $product->getName()]);\n\n        \/\/ E\u011fer ayn\u0131 isimde ba\u015fka bir \u00fcr\u00fcn varsa ve bu \u00fcr\u00fcn mevcut \u00fcr\u00fcn de\u011filse hata ver.\n        if ($existingProduct && $existingProduct->getId() !== $product->getId()) {\n            $this->context->buildViolation($constraint->message)\n                ->atPath('name') \/\/ Hata mesaj\u0131n\u0131 'name' alan\u0131na ba\u011fla\n                ->addViolation();\n        }\n    }\n}<\/code><\/pre>\n<p>Bu validator&#8217;\u0131 kullanmak i\u00e7in <code>services.yml<\/code> i\u00e7inde tan\u0131mlaman\u0131z ve <code>Product<\/code> entity&#8217;nizin ba\u015f\u0131na <code>@UniqueProductName<\/code> annotation&#8217;\u0131n\u0131 eklemeniz gerekir.<\/p>\n<pre><code class=\"language-yaml\"># app\/config\/services.yml\nservices:\n    app.validator.unique_product_name:\n        class: AppBundle\\Validator\\Constraints\\UniqueProductNameValidator\n        arguments: ['@doctrine.orm.entity_manager']\n        tags:\n            - { name: validator.constraint_validator, alias: app_unique_product_name_validator }<\/code><\/pre>\n<pre><code class=\"language-php\">\/\/ src\/AppBundle\/Entity\/Product.php\n\/\/ ...\nuse AppBundle\\Validator\\Constraints as AppAssert;\n\n\/<em><\/em>\n * @ORM\\Entity(repositoryClass=\"AppBundle\\Repository\\ProductRepository\")\n * @ORM\\Table(name=\"product\")\n * @AppAssert\\UniqueProductName() \/\/ Entity seviyesinde \u00f6zel do\u011frulama\n *\/\nclass Product\n{\n    \/\/ ...\n}<\/code><\/pre>\n<h3>G\u00fcvenlik ve Yetkilendirme (Temel Seviye)<\/h3>\n<p>Bir web uygulamas\u0131nda CRUD operasyonlar\u0131n\u0131 ger\u00e7ekle\u015ftirirken g\u00fcvenlik ve yetkilendirme hayati \u00f6neme sahiptir. Symfony&#8217;nin G\u00fcvenlik Bile\u015feni, kullan\u0131c\u0131 do\u011frulama (authentication) ve yetkilendirme (authorization) i\u00e7in kapsaml\u0131 bir \u00e7er\u00e7eve sunar.<\/p>\n<h4>Kullan\u0131c\u0131 Do\u011frulama (Authentication)<\/h4>\n<p>Kullan\u0131c\u0131 do\u011frulama, bir kullan\u0131c\u0131n\u0131n kim oldu\u011funu belirleme s\u00fcrecidir (\u00f6rn: giri\u015f yapma). Symfony&#8217;de bu, genellikle bir g\u00fcvenlik duvar\u0131 (firewall) ve kullan\u0131c\u0131 sa\u011flay\u0131c\u0131s\u0131 (user provider) tan\u0131mlanarak yap\u0131l\u0131r. <code>security.yml<\/code> dosyas\u0131 bu yap\u0131land\u0131rman\u0131n merkezidir.<\/p>\n<pre><code class=\"language-yaml\"># app\/config\/security.yml\nsecurity:\n    providers:\n        our_db_provider:\n            entity:\n                class: AppBundle:User # Kendi User entity'nizi kullan\u0131n\n                property: username\n\n    firewalls:\n        dev:\n            pattern: ^\/(_(profiler|wdt)|css|images|js)\/\n            security: false\n        main:\n            anonymous: ~\n            form_login:\n                login_path: login\n                check_path: login_check\n            logout:\n                path: logout\n                target: \/\n\n    access_control:\n        - { path: ^\/admin, roles: ROLE_ADMIN } # \/admin ile ba\u015flayan t\u00fcm URL'ler i\u00e7in ROLE_ADMIN gerekli\n        - { path: ^\/product\/new, roles: ROLE_USER } # Yeni \u00fcr\u00fcn eklemek i\u00e7in ROLE_USER gerekli\n        - { path: ^\/product\/\\d+\/edit, roles: ROLE_USER }\n        - { path: ^\/product\/\\d+\/delete, roles: ROLE_USER }<\/code><\/pre>\n<p>Bu \u00f6rnekte, <code>form_login<\/code> yap\u0131land\u0131rmas\u0131 ile basit bir kullan\u0131c\u0131 giri\u015fi mekanizmas\u0131 olu\u015fturulmu\u015ftur. <code>access_control<\/code> b\u00f6l\u00fcm\u00fc ise belirli URL yollar\u0131na eri\u015fim i\u00e7in gereken rolleri tan\u0131mlar.<\/p>\n<h4>Rol Tabanl\u0131 Yetkilendirme (Authorization)<\/h4>\n<p>Yetkilendirme, bir kullan\u0131c\u0131n\u0131n belirli bir kayna\u011fa veya eyleme eri\u015fim izni olup olmad\u0131\u011f\u0131n\u0131 belirleme s\u00fcrecidir. Symfony&#8217;de bu, roller (roles) ve eri\u015fim delegeleri (access decision managers) arac\u0131l\u0131\u011f\u0131yla yap\u0131l\u0131r.<\/p>\n<p>Controller i\u00e7inde veya Twig \u015fablonunda <code>is_granted()<\/code> fonksiyonunu kullanarak yetkilendirme kontrol\u00fc yapabilirsiniz:<\/p>\n<pre><code class=\"language-php\">\/\/ Controller i\u00e7inde\nif (!$this->isGranted('ROLE_ADMIN')) {\n    throw $this->createAccessDeniedException('Bu i\u015flemi yapmaya yetkiniz yok.');\n}\n\n\/\/ Belirli bir nesne \u00fczerinde yetkilendirme (Voter kullanarak)\n\/\/ if (!$this->isGranted('EDIT', $product)) { ... }<\/code><\/pre>\n<pre><code class=\"language-twig\">{# Twig \u015fablonunda #}\n{% if is_granted('ROLE_ADMIN') %}\n    <a href=\"{{ path('admin_dashboard') }}\">Y\u00f6netici Paneli<\/a>\n{% endif %}\n\n{% if is_granted('EDIT', product) %} {# E\u011fer bir Voter tan\u0131ml\u0131ysa #}\n    <a href=\"{{ path('product_edit', {'id': product.id}) }}\">D\u00fczenle<\/a>\n{% endif %}<\/code><\/pre>\n<p>CRUD operasyonlar\u0131 i\u00e7in, <code>new<\/code>, <code>edit<\/code>, <code>delete<\/code> gibi eylemlerin sadece belirli rollere sahip kullan\u0131c\u0131lar taraf\u0131ndan ger\u00e7ekle\u015ftirilmesini sa\u011flamak \u00e7ok \u00f6nemlidir. Yukar\u0131daki <code>security.yml<\/code> i\u00e7indeki <code>access_control<\/code> b\u00f6l\u00fcm\u00fc bunun temel bir \u00f6rne\u011fidir.<\/p>\n<h3>VPS Ortam\u0131nda Da\u011f\u0131t\u0131m ve Optimizasyon<\/h3>\n<p>Symfony uygulaman\u0131z\u0131 bir VPS&#8217;e da\u011f\u0131t\u0131rken, sadece kodun \u00e7al\u0131\u015fmas\u0131n\u0131 sa\u011flamakla kalmay\u0131p, ayn\u0131 zamanda performans ve g\u00fcvenlik i\u00e7in optimizasyonlar yapmak da \u00f6nemlidir.<\/p>\n<h4>Ortam De\u011fi\u015fkenleri ve Konfig\u00fcrasyon<\/h4>\n<p>Symfony, farkl\u0131 ortamlar (development, production, test) i\u00e7in farkl\u0131 konfig\u00fcrasyonlar kullanman\u0131za olanak tan\u0131r. <code>app\/config\/parameters.yml<\/code> ve <code>app\/config\/parameters_prod.yml<\/code> (veya <code>parameters_dev.yml<\/code>) dosyalar\u0131 bu ama\u00e7la kullan\u0131l\u0131r. VPS&#8217;te <code>APP_ENV=prod<\/code> ve <code>APP_DEBUG=0<\/code> olarak ayarlamak esast\u0131r. Bu, uygulaman\u0131z\u0131n \u00fcretim modunda \u00e7al\u0131\u015fmas\u0131n\u0131 ve hata ay\u0131klama bilgilerini g\u00f6stermemesini sa\u011flar.<\/p>\n<p>Ortam de\u011fi\u015fkenlerini sunucu seviyesinde (\u00f6rne\u011fin Nginx veya Apache yap\u0131land\u0131rmas\u0131nda <code>fastcgi_param APP_ENV prod;<\/code> veya <code>.env<\/code> dosyas\u0131 ile) ayarlamak, hassas bilgileri (veritaban\u0131 \u015fifreleri gibi) versiyon kontrol\u00fcnden uzak tutmak i\u00e7in iyi bir y\u00f6ntemdir.<\/p>\n<h4>\u00d6nbellekleme (Caching) Stratejileri<\/h4>\n<p>Performans i\u00e7in \u00f6nbellekleme hayati \u00f6neme sahiptir. Symfony ve Doctrine \u00e7e\u015fitli \u00f6nbellekleme katmanlar\u0131 sunar:<\/p>\n<p>*   <strong>Doctrine Metaveri \u00d6nbelle\u011fi:<\/strong> Entity metaverilerini \u00f6nbelle\u011fe al\u0131r.<br \/>\n*   <strong>Doctrine Sorgu \u00d6nbelle\u011fi:<\/strong> Veritaban\u0131na g\u00f6nderilen sorgular\u0131n sonu\u00e7lar\u0131n\u0131 \u00f6nbelle\u011fe al\u0131r.<br \/>\n*   <strong>Doctrine Sonu\u00e7 \u00d6nbelle\u011fi:<\/strong> Sorgu sonu\u00e7lar\u0131n\u0131 do\u011frudan \u00f6nbelle\u011fe al\u0131r.<br \/>\n*   <strong>Twig \u00d6nbelle\u011fi:<\/strong> Twig \u015fablonlar\u0131n\u0131n derlenmi\u015f hallerini \u00f6nbelle\u011fe al\u0131r.<\/p>\n<p>\u00dcretim ortam\u0131nda \u00f6nbellekleri etkinle\u015ftirmek i\u00e7in genellikle <code>app\/AppKernel.php<\/code> dosyas\u0131nda <code>registerContainerConfiguration()<\/code> metodunda ortam kontrol\u00fc yap\u0131l\u0131r ve <code>config_prod.yml<\/code> i\u00e7inde Doctrine ve Twig i\u00e7in \u00f6nbellek servisleri tan\u0131mlan\u0131r.<\/p>\n<p>\u00d6nbellekleri temizlemek i\u00e7in:<br \/>\n<code>php app\/console cache:clear --env=prod<\/code><br \/>\n<code>php app\/console doctrine:cache:clear-metadata --env=prod<\/code><br \/>\n<code>php app\/console doctrine:cache:clear-query --env=prod<\/code><br \/>\n<code>php app\/console doctrine:cache:clear-result --env=prod<\/code><\/p>\n<h4>Composer Optimizasyonu<\/h4>\n<p>Uygulaman\u0131z\u0131 VPS&#8217;e da\u011f\u0131tt\u0131ktan sonra ba\u011f\u0131ml\u0131l\u0131klar\u0131 y\u00fcklerken <code>composer install --no-dev --optimize-autoloader<\/code> komutunu kullanmak \u00f6nemlidir. <code>--no-dev<\/code> geli\u015ftirme ba\u011f\u0131ml\u0131l\u0131klar\u0131n\u0131 y\u00fcklemezken, <code>--optimize-autoloader<\/code> Composer&#8217;\u0131n otomatik y\u00fckleme haritas\u0131n\u0131 optimize ederek daha h\u0131zl\u0131 s\u0131n\u0131f y\u00fcklemesi sa\u011flar.<\/p>\n<h4>Web Sunucusu Yap\u0131land\u0131rmas\u0131 (K\u0131sa Tekrar)<\/h4>\n<p>\u0130lk b\u00f6l\u00fcmde Nginx veya Apache yap\u0131land\u0131rmas\u0131na de\u011finmi\u015ftik. \u00d6nemli noktalar:<br \/>\n*   <code>web\/app.php<\/code> (veya <code>app_dev.php<\/code> yerine <code>app.php<\/code>) dosyas\u0131n\u0131 k\u00f6k dizin olarak ayarlay\u0131n.<br \/>\n*   <code>index.php<\/code>&#8216;yi varsay\u0131lan dosya olarak belirtin.<br \/>\n*   <code>try_files<\/code> (Nginx) veya <code>mod_rewrite<\/code> (Apache) kullanarak t\u00fcm istekleri <code>app.php<\/code>&#8216;ye y\u00f6nlendirin.<br \/>\n*   PHP-FPM kullan\u0131yorsan\u0131z, do\u011fru soket veya port \u00fczerinden PHP-FPM ile ileti\u015fim kurdu\u011funuzdan emin olun.<br \/>\n*   Statik dosyalar i\u00e7in \u00f6nbellekleme ba\u015fl\u0131klar\u0131 ekleyin.<\/p>\n<h4>G\u00fcnl\u00fckleme (Logging) ve Hata Ay\u0131klama<\/h4>\n<p>\u00dcretim ortam\u0131nda hatalar\u0131 izlemek i\u00e7in g\u00fcnl\u00fckleme (logging) \u00e7ok \u00f6nemlidir. Symfony, MonologBundle arac\u0131l\u0131\u011f\u0131yla g\u00fc\u00e7l\u00fc bir g\u00fcnl\u00fckleme sistemi sunar. <code>app\/config\/config_prod.yml<\/code> dosyas\u0131nda g\u00fcnl\u00fckleme seviyesini <code>error<\/code> veya <code>critical<\/code> gibi daha k\u0131s\u0131tl\u0131 bir seviyeye ayarlayarak log dosyalar\u0131n\u0131n a\u015f\u0131r\u0131 b\u00fcy\u00fcmesini engelleyebilirsiniz.<\/p>\n<p>VPS \u00fczerinde hatalar\u0131 izlemek i\u00e7in genellikle <code>tail -f var\/logs\/prod.log<\/code> komutu kullan\u0131l\u0131r.<\/p>\n<h3>Sonu\u00e7<\/h3>\n<p>Bu makalede, Symfony2 ile CRUD operasyonlar\u0131n\u0131 ger\u00e7ekle\u015ftirmenin inceliklerine derinlemesine dald\u0131k. Form Bile\u015feni kullanarak g\u00fcvenli ve do\u011frulanm\u0131\u015f formlar olu\u015fturmay\u0131, Doctrine ORM ile veritaban\u0131 i\u015flemlerini y\u00f6netmeyi ve flash mesajlar\u0131 ile kullan\u0131c\u0131ya geri bildirim sa\u011flamay\u0131 \u00f6\u011frendik. Ayr\u0131ca, CSRF korumas\u0131 gibi temel g\u00fcvenlik \u00f6nlemlerinin \u00f6nemini vurgulad\u0131k ve \u00f6zel do\u011frulay\u0131c\u0131lar arac\u0131l\u0131\u011f\u0131yla i\u015f mant\u0131\u011f\u0131n\u0131 formlara entegre etme yollar\u0131n\u0131 g\u00f6sterdik. Son olarak, VPS ortam\u0131nda bir Symfony uygulamas\u0131n\u0131 da\u011f\u0131t\u0131rken dikkat edilmesi gereken performans optimizasyonlar\u0131 ve g\u00fcvenlik ayarlar\u0131na genel bir bak\u0131\u015f sunduk.<\/p>\n<p>Symfony2, web uygulamalar\u0131 geli\u015ftirmek i\u00e7in kapsaml\u0131 ve mod\u00fcler bir \u00e7er\u00e7eve sunar. Bu makale serisi, temelden ba\u015flayarak CRUD operasyonlar\u0131n\u0131 ba\u015far\u0131yla uygulaman\u0131z i\u00e7in gerekli bilgi ve ara\u00e7lar\u0131 sa\u011flam\u0131\u015ft\u0131r. Art\u0131k kendi Symfony2 tabanl\u0131 uygulamalar\u0131n\u0131z\u0131 geli\u015ftirirken bu bilgileri kullanarak daha sa\u011flam, g\u00fcvenli ve performansl\u0131 \u00e7\u00f6z\u00fcmler \u00fcretebilirsiniz. Uygulaman\u0131z\u0131n karma\u015f\u0131kl\u0131\u011f\u0131 artt\u0131k\u00e7a, Symfony&#8217;nin di\u011fer g\u00fc\u00e7l\u00fc bile\u015fenlerini (\u00f6rne\u011fin, kullan\u0131c\u0131 y\u00f6netimi i\u00e7in FOSUserBundle, API geli\u015ftirme i\u00e7in FOSRestBundle) ke\u015ffetmeye devam etmeniz, yeteneklerinizi daha da geni\u015fletecektir. Unutmay\u0131n, pratik yapmak ve Symfony dok\u00fcmantasyonunu d\u00fczenli olarak incelemek, bu g\u00fc\u00e7l\u00fc \u00e7er\u00e7evede ustala\u015fman\u0131n anahtar\u0131d\u0131r.<\/body><\/p>\n","protected":false},"excerpt":{"rendered":"Symfony2 ile VPS \u00dczerinde CRUD \u0130\u015flemleri Ger\u00e7ekle\u015ftirme: Derinlemesine \u0130nceleme (B\u00f6l\u00fcm 2)\nBu makale serisinin ilk b\u00f6l\u00fcm\u00fcnde, Symfony2 proj","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"csco_page_header_type":"","csco_page_load_nextpost":"","csco_page_subscribe_form":"","csco_page_contact_form":"","footnotes":""},"categories":[133],"tags":[],"class_list":{"0":"post-30519","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-php","7":"cs-entry","8":"cs-video-wrap"},"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.5 (Yoast SEO v25.3.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Symfony2 ile VPS \u00dczerinde CRUD \u0130\u015flemleri Ger\u00e7ekle\u015ftirme: Derinlemesine \u0130nceleme (B\u00f6l\u00fcm 2) - Kodlar\u0131n Gizemli D\u00fcnyas\u0131<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Symfony2 ile VPS \u00dczerinde CRUD \u0130\u015flemleri Ger\u00e7ekle\u015ftirme: Derinlemesine \u0130nceleme (B\u00f6l\u00fcm 2)\" \/>\n<meta property=\"og:description\" content=\"Symfony2 ile VPS \u00dczerinde CRUD \u0130\u015flemleri Ger\u00e7ekle\u015ftirme: Derinlemesine \u0130nceleme (B\u00f6l\u00fcm 2) Bu makale serisinin ilk b\u00f6l\u00fcm\u00fcnde, Symfony2 proj\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/\" \/>\n<meta property=\"og:site_name\" content=\"Kodlar\u0131n Gizemli D\u00fcnyas\u0131\" \/>\n<meta property=\"article:published_time\" content=\"2025-09-28T18:41:04+00:00\" \/>\n<meta name=\"author\" content=\"Fatih Soysal\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Yazan:\" \/>\n\t<meta name=\"twitter:data1\" content=\"Fatih Soysal\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tahmini okuma s\u00fcresi\" \/>\n\t<meta name=\"twitter:data2\" content=\"18 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/\"},\"author\":{\"name\":\"Fatih Soysal\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"headline\":\"Symfony2 ile VPS \u00dczerinde CRUD \u0130\u015flemleri Ger\u00e7ekle\u015ftirme: Derinlemesine \u0130nceleme (B\u00f6l\u00fcm 2)\",\"datePublished\":\"2025-09-28T18:41:04+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/\"},\"wordCount\":2047,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"articleSection\":[\"PHP\"],\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/#respond\"]}],\"copyrightYear\":\"2025\",\"copyrightHolder\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/\",\"name\":\"Symfony2 ile VPS \u00dczerinde CRUD \u0130\u015flemleri Ger\u00e7ekle\u015ftirme: Derinlemesine \u0130nceleme (B\u00f6l\u00fcm 2) - Kodlar\u0131n Gizemli D\u00fcnyas\u0131\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\"},\"datePublished\":\"2025-09-28T18:41:04+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Anasayfa\",\"item\":\"https:\/\/fatihsoysal.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Symfony2 ile VPS \u00dczerinde CRUD \u0130\u015flemleri Ger\u00e7ekle\u015ftirme: Derinlemesine \u0130nceleme (B\u00f6l\u00fcm 2)\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/\",\"name\":\"Fatihsoysal.com\",\"description\":\"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim\",\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"tr\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\",\"name\":\"Fatih Soysal\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"contentUrl\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"width\":512,\"height\":512,\"caption\":\"Fatih Soysal\"},\"logo\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\"},\"description\":\"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Symfony2 ile VPS \u00dczerinde CRUD \u0130\u015flemleri Ger\u00e7ekle\u015ftirme: Derinlemesine \u0130nceleme (B\u00f6l\u00fcm 2) - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/","og_locale":"tr_TR","og_type":"article","og_title":"Symfony2 ile VPS \u00dczerinde CRUD \u0130\u015flemleri Ger\u00e7ekle\u015ftirme: Derinlemesine \u0130nceleme (B\u00f6l\u00fcm 2)","og_description":"Symfony2 ile VPS \u00dczerinde CRUD \u0130\u015flemleri Ger\u00e7ekle\u015ftirme: Derinlemesine \u0130nceleme (B\u00f6l\u00fcm 2) Bu makale serisinin ilk b\u00f6l\u00fcm\u00fcnde, Symfony2 proj","og_url":"https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/","og_site_name":"Kodlar\u0131n Gizemli D\u00fcnyas\u0131","article_published_time":"2025-09-28T18:41:04+00:00","author":"Fatih Soysal","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"Fatih Soysal","Tahmini okuma s\u00fcresi":"18 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/#article","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/"},"author":{"name":"Fatih Soysal","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"headline":"Symfony2 ile VPS \u00dczerinde CRUD \u0130\u015flemleri Ger\u00e7ekle\u015ftirme: Derinlemesine \u0130nceleme (B\u00f6l\u00fcm 2)","datePublished":"2025-09-28T18:41:04+00:00","mainEntityOfPage":{"@id":"https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/"},"wordCount":2047,"commentCount":0,"publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"articleSection":["PHP"],"inLanguage":"tr","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/#respond"]}],"copyrightYear":"2025","copyrightHolder":{"@id":"https:\/\/fatihsoysal.com\/blog\/#organization"}},{"@type":"WebPage","@id":"https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/","url":"https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/","name":"Symfony2 ile VPS \u00dczerinde CRUD \u0130\u015flemleri Ger\u00e7ekle\u015ftirme: Derinlemesine \u0130nceleme (B\u00f6l\u00fcm 2) - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/#website"},"datePublished":"2025-09-28T18:41:04+00:00","breadcrumb":{"@id":"https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/fatihsoysal.com\/blog\/symfony2-ile-vps-uzerinde-crud-islemleri-gerceklestirme-derinlemesine-inceleme-bolum-2\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Anasayfa","item":"https:\/\/fatihsoysal.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Symfony2 ile VPS \u00dczerinde CRUD \u0130\u015flemleri Ger\u00e7ekle\u015ftirme: Derinlemesine \u0130nceleme (B\u00f6l\u00fcm 2)"}]},{"@type":"WebSite","@id":"https:\/\/fatihsoysal.com\/blog\/#website","url":"https:\/\/fatihsoysal.com\/blog\/","name":"Fatihsoysal.com","description":"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim","publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"tr"},{"@type":["Person","Organization"],"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1","name":"Fatih Soysal","image":{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","contentUrl":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","width":512,"height":512,"caption":"Fatih Soysal"},"logo":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/"},"description":"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.","url":"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/"}]}},"yoast_meta":{"yoast_wpseo_title":"","yoast_wpseo_metadesc":"","yoast_wpseo_canonical":""},"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/30519","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/comments?post=30519"}],"version-history":[{"count":1,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/30519\/revisions"}],"predecessor-version":[{"id":30520,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/30519\/revisions\/30520"}],"wp:attachment":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/media?parent=30519"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/categories?post=30519"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/tags?post=30519"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}