بخش 2 - سیمفونی دربرابر PHP خام
چرا استفاده از سیمفونی بهتر از بازکردن یک فایل و نوشتن کد PHP خام است؟
اگر هرگز از یک فریمورک PHP استفاده نکرده باشید، با فلسفه MVC آشنا نباشد، یا فکر میکنید که همه حرف و حدیثها درباره Symfony است، این بخش ویژه شماست. بجای اینکه به شما بگوییم سیمفونی اجازه میدهد نرمافزارها را سریعتر و بهتر از PHP خام توسعه دهید، خودتان آنرا خواهید دید.
در این بخش یک برنامه ساده با PHP خام مینویسید و سپس آنرا کمی سازماندهی میکنید. سفری در زمان خواهید داشت تا با تصمیمات پشتپردهای که موجب شدهاند توسعه وب در سالهای گذشته به جایی که اکنون قراردارد برسد، آشنا شوید.
در پایان، خواهید دید که چگونه سیمفونی میتواند شما را از وظایف پیشپاافتاده نجات دهد و بگذارد کنترل کدتان را دوباره بدست بگیرید.
یک وبلاگ ساده با PHP خام
در این بخش یک اپلیکیشن وبلاگ را با کمک PHP خام خواهید ساخت. برای شروع، اجازهدهید یک صفحه ساده بسازیم که مطالب وبلاگ را که درون دیتابیس ثبت شدهاند، نمایش میدهد. نوشتن یک فایل PHP خام، سریع و کثیف است:
<?php
// index.php
$link = new PDO('mysql:host=localhost;dbname=blog_db', 'myuser', 'mypassword');
$result = $link->query('SELECT id, title FROM post');
?>
<!DOCTYPE html>
<html>
<head>
<title>List of Posts</title>
</head>
<body>
<h1>List of Posts</h1>
<ul>
<?php while ($row = $result->fetch(PDO::FETCH_ASSOC)) : ?>
<li>
<a href="/show.php?id=<?php echo $row['id'] ?>">
<?php echo $row['title'] ?>
</a>
</li>
<?php endwhile ?>
</ul>
</body>
</html>
<?php
$link = null;
?>
نوشتن این فایل و اجرای آن سریع است و بهمرور با بزرگشدن برنامه شما، نگهداری آن غیرممکن خواهد بود. چند مشکل وجود دارد که شما باید آنها را برطرف نمایید:
- کنترلنکردن خطا: اگر اتصال به دیتابیس با موفقیت انجام نشود، چه اتفاقی میافتد؟
- سازماندهی ضعیف: اگر برنامه رشد کند، این فایل تنها بهشدت غیرقابل نگهداری خواهد شد. کد مدیریت فرمهای ارسالشده را کجا قرار میدهید؟ چگونه میتوانید دادهها را اعتبارسنجی کنید؟ کد ارسال ایمیل کجا میرود؟
- استفاده مجدد از کد سخت است: از آنجا که همهچیز در یک فایل قرار دارد، هیچ راهی برای استفاده مجدد از بخشهای برنامه برای «صفحات» دیگر بلاگ وجود ندارد.
نقل قول:مشکل دیگری که در اینجا ذکر نشدهاست، این حقیقت است که دیتابیس به MySQL گره خوردهاست. اگرچه این موضوع را در اینجا پوشش نمیدهیم، اما سیفونی بهخوبی با
Doctrine ادغام میشود که یک کتابخانه مختص چکیدهسازی و نگاشت پایگاه دادهها است.
جداسازی نمایش
کد فوق میتواند مستقیماً از جداسازی «منطق» برنامه از کد «نمایش» خروجی HTML بهرهمند شود:
// index.php
$link = new PDO('mysql:host=localhost;dbname=blog_db', 'myuser', 'mypassword');
$result = $link->query('SELECT id, title FROM post');
$posts = array();
while($row = $result->fetch(PDO::FETCH_ASSOC)) {
$posts[] = $row;
}
$link = null;
// include the HTML presentation code
require 'templates/list.php';[/shcode=php]
اکنون کد HTML در یک فایل جداگانه قرار گرفته است (templates/list.php) که یک فایل HTML و حاوی محتوایی شبیه یک سیستم قالب PHP است:
[shcode=php]<!DOCTYPE html>
<html>
<head>
<title>List of Posts</title>
</head>
<body>
<h1>List of Posts</h1>
<ul>
<?php foreach ($posts as $post): ?>
<li>
<a href="/read?id=<?php echo $post['id'] ?>">
<?php echo $post['title'] ?>
</a>
</li>
<?php endforeach ?>
</ul>
</body>
</html>
ازنظر مفهوم، فایلی که حاوی همه منطق برنامه است - index.php - بعنوان کنترلکننده (
کنترلر) شناخته میشود. اصلاح کنترلر کلمهای است که آنرا بسیار خواهید شنید، بدون توجه به اینکه از چه زبان یا فریمورکی استفاده میکنید. این کلمه بهسادگی به محدودهای از «کد شما» اشاره میکند که ورودیهای کاربر را پردازشکرده و خروجی را آماده میکند.
در این مثال، کنترلر دادهها را از پایگاه دادهها آمادهکرده و سپس یک قالب را برای نمایش آن اطلاعات ضمیمه میکند. با جداسازی کنترلر، میتوانید بهراحتی «فقط» فایل قالب را درصورت نیاز برای نمایش محتوای وبلاگ در ساختار دیگر تغییر دهید (برای مثال list.json.php برای قالب JSON).
جداسازی منطق (حوزه) برنامه
تا اینجا برنامه فقط یک صفحه داشت. اما اگر صفحه دوم نیاز به استفاده از اتصال مشابه به پایگاه دادهها یا حتی آرایه مشابعی از پستهای وبلاگ داشت چهکنیم؟ کد را بازنویسی کنید تا رفتار هسته برنامه و توابع دسترسی به دادههای برنامه در یک فایل جداگانه بنام model.php قرار گیرد:
// model.php
function open_database_connection()
{
$link = new PDO('mysql:host=localhost;dbname=blog_db', 'myuser', 'mypassword');
return $link;
}
function close_database_connection($link)
{
$link = null;
}
function get_all_posts()
{
$link = open_database_connection();
$result = $link->query('SELECT id, title FROM post');
$posts = array();
while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
$posts[] = $row;
}
close_database_connection($link);
return $posts;
}
نقل قول:نکته: نام فایل model.php به این دلیل بکار رفتهاست که منطق و دسترسی به دادههای برنامه، بطور سنتی تحت عنوان لایه «مدل» شناخته میشود. در یک برنامه که بهخوبی سازماندهی شدهاست، بخش عمده کد که معادل «منطق تجاری» شماست باید در مدل قرار گیرد (برخلاف باور عمومی که باید در کنترلر باشد). و برخلاف این مثال، فقط بخشی (یا هیچ) از مدل درحقیقت نگران دسترسی به دیتابیس است.
کنترلر (index.php) اکنون بسیار ساده است:
require_once 'model.php';
$posts = get_all_posts();
require 'templates/list.php';
اکنون تنها وظیفه کنترلر، دریافت دادهها از لایه مدل برنامه و فراخوانی یک قالب برای نمایش آن دادهها است. این یک مثال بسیار ساده از الگوی Model-View-Controller یا بهاختصار MVC است.
جداسازی چیدمان صفحه
در این نقطه، برنامه به سه بخش کاملاً مجزا بازنویسی شده است که مزایای زیادی دارد و تقریباً امکان استفاده مجدد از هر بخش آن در سایر صفحات وجود دارد. تنها بخشی که نمیتوان در سایر قسمتها مجدداً مورداستفاده قرار داد، چیدمان صفحه یا لِیاوت (Layout) است. برای حل این مشکل، یک فایل layout.php ایجاد کنید:
<!-- templates/layout.php -->
<!DOCTYPE html>
<html>
<head>
<title><?php echo $title ?></title>
</head>
<body>
<?php echo $content ?>
</body>
</html>
قالب (templates/list.php) میتواند بهسادگی برای «توسعه» چیدمان بهکار رود:
<?php $title = 'List of Posts'; ?>
<?php ob_start(); ?>
<h1>List of Posts</h1>
<ul>
<?php foreach ($posts as $post): ?>
<li>
<a href="/read?id=<?php echo $post['id'] ?>">
<?php echo $post['title'] ?>
</a>
</li>
<?php endforeach ?>
</ul>
<?php $content = ob_get_clean() ?>
<?php include 'layout.php' ?>
اکنون دارای پیکربندی خاصی هستید که به شما اجازه میدهد از چیدمان کلی صفحات، مجدداً استفادهکنید. متأسفانه برای دستیابی به این موضوع، مجبور به استفاهد از چند تابع زشت PHP (ob_start() و ob_get_clean()) درون قالب هستید. سیمفونی از یک کامپوننت قالببندی استفاده میکند که اینکار را بصورت تمیز و ساده انجام میدهد و بزودی آنرا در عمل خواهید دید.
افزودن یک صفحه «نمایش» بلاگ
صفحه «فهرست» وبلاگ باید مجدداً بازنویسی شود تا کدها بهتر سازماندهی و قابلاستفاده شوند. برای اثبات این موضوع، یک صفحه «نمایش» وبلاگ اضافهکنید که یک پست خاص را که با پارامتر id ارسالشده در آدرس صفحه، نمایش میدهد.
برای شروع، یک تابع جدید به model.php اضافهکنید که یک پست خاص را براساس id دادهشده استخراج میکند:
// model.php
function get_post_by_id($id)
{
$link = open_database_connection();
$id = intval($id);
$result = $link->query('SELECT created_at, title, body FROM post WHERE id = ' . $id);
$row = $result->fetch(PDO::FETCH_ASSOC);
close_database_connection($link);
return $row;
}
حال یک فایل دیگر به اسم show.php بسازید - کنترلر برای این صفحه جدید:
require_once 'model.php';
$post = get_post_by_id($_GET['id']);
require 'templates/show.php';
درنهایت، یک فایل قالب جدید - templates/show.php - برای نمایش پست موردنظر:
<?php $title = $post['title'] ?>
<?php ob_start(); ?>
<h1><?php echo $post['title'] ?></h1>
<div class="date"><?php echo $post['created_at'] ?></div>
<div class="body">
<?php echo $post['body'] ?>
</div>
<?php $content = ob_get_clean() ?>
<?php include 'layout.php' ?>
ساخت صفحه دوم اکنون بسیار ساده است و هیچ کدی تکرار نمیشود. هنوز هم این صفحه مشکلات زیادی را نشان میدهد که یک فریمورک میتواند برای شما حلکند. برای مثال، اگر پارامتر id در URL موجود نباشد، صفحه با خطا مواجه میشود. بهتر است چنین مواردی با یک خطای 404 نمایش داده شود، اما این موضوع فعلاً بهسادگی قابل انجام نیست. بدتر از آن، اگر فراموش کنید که پارامتر id را با دستور intval() ایمنکنید، کل پایگاه دادههای شما درمعرض خطر حمله SQL Injection قرار خواهد گرفت.
یک مشکل دیگر آن است که هر فایل کنترلر باید فایل model.php را جداگانه ضمیمهکند. حال اگر هر فایل کنترلر، ناگهان نیاز به ضمیمهکردن یک فایل اضافه یا انجام یک کار سراسری دیگر داشته باشد (برای مثال، اجرای امنیت)، چه باید بکنید؟ با وضع فعلی، آن کد باید به همه فایلهای کنترلر اضافه شود. اگر فراموشکنید که چیزی را در یک فایل ضمیمهکنید، امیدواریم که مرتبط به امنیت نباشد...
یک «کنترلر جلویی» برای نجات
راهحل مشکل فوق، استفاده از
کنترلر جلویی یا «خطمقدم» است: یک فایل PHP منفرد که «همه» درخواستها در آن پردازش میشوند. با یک کنترلر جلویی، URIهای برنامه کمی تغییر میکنند، اما اجازهدهید کمی انعطافپذیری را بیشتر کنیم:
Without a front controller
/index.php => Blog post list page (index.php executed)
/show.php => Blog post show page (show.php executed)
With index.php as the front controller
/index.php => Blog post list page (index.php executed)
/index.php/show => Blog post show page (index.php executed)
نقل قول:بخش index.php از URI میتواند درصورت استفاده از قواعد بازنویسی آدرس Apache (یا معادل آن در سایر وبسرورها) حذف شود. در این حالت، URI صفحه نمایش پست بهسادگی /show خواهد بود.
وقتی از کنترلر جلویی استفاده میکنید، یک فایل PHP مستقل (index.php در این مثال) همه درخواستها را پردازش میکند. برای صفحه نمایش پست، /index.php/show درحقیقت فایل index.php را اجرا میکند، که اکنون مسئول آدرسدهی درخواستها بصورت داخلی براساس URI کامل است. همانگونه که خواهید دید، یک کنترلر جلویی، ابزاری بسیار قدرتمند است.
ساخت کنترلر جلویی
شما میخواهید یک قدم بزرگ در برنامه بردارید. با کنترلکردن همه درخواستها در یک فایل، میتوانید مواردی مثل کنترل امنیت، بارگذاری تنظیمات، و مسیریابی را بصورت متمرکز مدیریت کنید. در این برنامه، index.php باید اکنون بهاندازه کافی هوشمند باشد تا صفحه فهرست پستها یا نمایش یک پست خاص را براساس URI درخواستشده نمایش دهد:
// index.php
// load and initialize any global libraries
require_once 'model.php';
require_once 'controllers.php';
// route the request internally
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
if ('/index.php' === $uri) {
list_action();
} elseif ('/index.php/show' === $uri && isset($_GET['id'])) {
show_action($_GET['id']);
} else {
header('Status: 404 Not Found');
echo '<html><body><h1>Page Not Found</h1></body></html>';
}
برای سازماندهی، هر دو کنترلر (قبلاً index.php و show.php) اکنون توابع PHP هستند و درون یک فایل جداگانه بنام controllers.php ذخیره شدهاند:
function list_action()
{
$posts = get_all_posts();
require 'templates/list.php';
}
function show_action($id)
{
$post = get_post_by_id($id);
require 'templates/show.php';
}
بعنوان یک کنترلر جلویی، index.php یک نقش کاملاً جدید را پذیرفته است: وظیفهای که شامل بارگذاری کتابخانههای هسته و مسیریابی برنامه است تا هرکدام از دو کنترلر (توابع list_action() و show_action()) فراخوانی شوند. در واقعیت، کنترلر جلویی نقطه شروع برای بررسی است و نقشی بسیار شبیه مکانیزم سیمفونی برای کنترل و مسیریابی درخواستها ایفا میکند.
نقل قول:یک مزیت دیگر کنترلر جلویی، URLهای انعطافپذیر است. دقتکنید که URL صفحه نمایش پست وبلاگ میتواند از /show به /read با تغییر کد فقط در یک محل، تغییریایبد. قبلاً کل یک فایل باید تغییرنام پیدا میکرد. در سیمفونی، URLها میتوانند حتی بیش از این انعطافپذیر باشند.
تا اینجا، برنامه از یک فایل تک PHP به یک ساختار سازماندهیشده تبدیل شده و اجازه استفاده مجدد از کدها را میدهد. شما باید خوشحالتر باشید، اما هنوز از رضایت کامل دور هستیم. برای مثال، سیستم «مسیریابی» بیثبات است و تشخیص نمیدهد که صفحه فهرست (/index) باید با / نیز قابل دسترسی باشد (اگر قوانین موردنیاز ماژول rewrite آپاچی اضافه شده باشند). همچنین، بجای توسعه وبلاگ، بخش عمده زمان صرف کار برروی «معماری» کد (مثل مسیریابی، فراخوانی کنترلرها، قالبها و...) میشود. زمانی بیشتری باید صرف مدیریت فرمهای ارسالی، اعتبارسنجی ورودیهای کاربر، گزارشگیری و امنیت شود. چرا باید راهکارهای موردنیاز برای تمام این مشکلات رایج و روزمره را مجدداً اختراع کنید؟
اتصال به سیمفونی
سیمفونی برای نجات شما حاضر است. قبلاز اینکه واقعاً از سیمفونی استفاده کنید، باید آنرا دانلود نمایید. اینکار را میتوانید با کمک کامپوزر انجام دهید، که روند دانلود نسخه صحیح و تمام وابستگیهای آنرا بعهده میگیرد و یک بارگذار خودکار نیز عرضه میکند. بارگذار خودکار، ابزاری است که استفاده از کلاسهای PHP را بدون اینکه صراحتاً نیاز به ضمیمهکردن فایل حاوی کلاس داشتهباشید، ممکن میسازد.
در پوشه پروژه خود، یک فایل composer.json با محتوای زیر بسازید:
{
"require": {
"symfony/symfony": "3.0.*"
},
"autoload": {
"files": ["model.php", "controllers.php"]
}
}
حال
کامپوزر را دانلود کنید و بعد دستور زیر را در خط فرمان و درحالی که در پوشه اصلی پروژه قراردارید، اجرا کنید تا سیمفونی دانلود و در پوشه
vendor/ نصب شود:
composer install
درکنار دانلود وابستگیها، کامپوزر یک فایل vendor/autoload.php نیز تولید میکند، که وظیفه بارگذاری خودکار تمام فایلهای درون فریمورک سیمفونی را درکنار فایلهایی که در بخش autoload فایل composer.json مشخص کردهاید، انجام میدهد.
قلب فلسفه سیمفونی، این ایده است که وظیفه اصلی یک برنامه، تفسیر هر درخواست و بازگرداندن یک پاسخ است. بدینمنظور، سیمفونی هر دو کلاس
Request و
Response را ارائه میکند. این کلاسها نسخههای معادل شئگرای درخواست HTTP خامِ تحتپردازش و خروجی HTTP تولیدشده هستند. از آنها برای بهبود وبلاگ استفادهکنید:
// index.php
require_once 'vendor/autoload.php';
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpFoundationResponse;
$request = Request::createFromGlobals();
$uri = $request->getPathInfo();
if ('/' === $uri) {
$response = list_action();
} elseif ('/show' === $uri && $request->query->has('id')) {
$response = show_action($request->query->get('id'));
} else {
$html = '<html><body><h1>Page Not Found</h1></body></html>';
$response = new Response($html, Response::HTTP_NOT_FOUND);
}
// echo the headers and send the response
$response->send();
کنترلرها اکنون مسئول بازگرداندن یک شئ Response هستند. برای سادهسازی اینکار میتوانید یک تابع render_template() اضافهکنید که برحسب اتفاق، کمی شبیه موتور قالب Symfony عمل میکند:
// controllers.php
use SymfonyComponentHttpFoundationResponse;
function list_action()
{
$posts = get_all_posts();
$html = render_template('templates/list.php', array('posts' => $posts));
return new Response($html);
}
function show_action($id)
{
$post = get_post_by_id($id);
$html = render_template('templates/show.php', array('post' => $post));
return new Response($html);
}
// helper function to render templates
function render_template($path, array $args)
{
extract($args);
ob_start();
require $path;
$html = ob_get_clean();
return $html;
}
با استفاده از بخش کوچکی از سیمفونی، برنامه انعطافپذیرتر و قابلاطمینانتر است. Request یک روش قابل اعتماد برای دسترسی به اطلاعات درباره درخواست HTTP ارائه میکند. متد getPathInfo() یک URI تمیزشده باز میگرداند (همیشه /show بر میگرداند و هیچوقت /index.php/show خروجی نمیدهد). بنابراین، حتی اگر کاربر وارد مسیر /index.php/show شود، برنامه هوشمندی کافی برای مسیریابی درخواست ازطریق show_action را دارد.
برنامه مشابه در سیمفونی
وبلاگ راه زیادی را آمدهاست، اما هنوز کد زیادی برای چنین برنامه سادهای دارد. درطول مسیر، شما یک سیستم مسیریابی ساده ایجاد کردید و متدی با کمک
ob_start() و
ob_get_clean() برای رندر قالبها ایجاد نمودید. اگر بههردلیلی نیاز به ادامه ساخت این «فریمورک» از پایه داشتید، میتوانید لااقل از کامپوننتهای مستقل
Routing و
Templating در سیمفونی استفادهکنید، که این مشکلات را از قبل حل کردهاند.
بجای حل مجدد مشکلات مشابه، میتوانید از سیمفونی بخواهید که مسئولیت آنها را برای شما بعهده بگیرد. در اینجا برنامه مشابهی را میبینید، که اکنون در سیمفونی ساخته شده است:
// src/AppBundle/Controller/BlogController.php
namespace AppBundleController;
use SymfonyBundleFrameworkBundleControllerController;
class BlogController extends Controller
{
public function listAction()
{
$posts = $this->get('doctrine')
->getManager()
->createQuery('SELECT p FROM AppBundle:Post p')
->execute();
return $this->render('Blog/list.html.php', array('posts' => $posts));
}
public function showAction($id)
{
$post = $this->get('doctrine')
->getManager()
->getRepository('AppBundle:Post')
->find($id);
if (!$post) {
// cause the 404 page not found to be displayed
throw $this->createNotFoundException();
}
return $this->render('Blog/show.html.php', array('post' => $post));
}
}
دو کنترلر هنوز هم سبک هستند. هرکدام از کتابخانه مدل رابطهای شئ خاصی بنام
Doctrine ORM استفاده میکنند تا اشیاء را از پایگاه دادهها استخراجکنند و از کامپوننت Templating برای رندرکردن یک قابل و بازگشت شئ Response بهره میبرند. قالب فهرست اکنون کمی سادهتر است:
<!-- app/Resources/views/Blog/list.html.php -->
<?php $view->extend('layout.html.php') ?>
<?php $view['slots']->set('title', 'List of Posts') ?>
<h1>List of Posts</h1>
<ul>
<?php foreach ($posts as $post): ?>
<li>
<a href="<?php echo $view['router']->path(
'blog_show',
array('id' => $post->getId())
) ?>">
<?php echo $post->getTitle() ?>
</a>
</li>
<?php endforeach ?>
</ul>
چیدمان صفحه تقریباً مثل گذشته است:
<!-- app/Resources/views/layout.html.php -->
<!DOCTYPE html>
<html>
<head>
<title><?php echo $view['slots']->output(
'title',
'Default title'
) ?></title>
</head>
<body>
<?php echo $view['slots']->output('_content') ?>
</body>
</html>
نقل قول:قالب نمایش یک پست بعنوان تمرین برای شما گذاشته شدهاست، زیرا ساخت آن با کمک قالب فهرست، کار بسیار سادهای است.
وقتی موتور سیمفونی (که به آن، هسته میگویند) روشن میشود، نیاز به یک نقشه دارد تا بداند کدام کنترلرها باید براساس اطلاعات درخواست اجرا شوند. یک نقشه تنظیمات مسیریابی، این اطلاعات را در یک قالب قابلخواندن ارائه میدهد:
# app/config/routing.yml
blog_list:
path: /blog
defaults: { _controller: AppBundle:Blog:list }
blog_show:
path: /blog/show/{id}
defaults: { _controller: AppBundle:Blog:show }
حالا که سیمفونی همه وظایف پایهای را مدیریت میکند، کنترلر جلویی بهشدت ساده میشود و اینقدر کوچک شدهاست، شما هرگز نیاز به دستکاری آن بعد از ایجاد، ندارید (و اگر از یک
توزیع سیمفونی استفاده کردهباشید، اصلاً حتی نیاز به ایجاد آن هم نخواهید داشت!) :
// web/app.php
require_once __DIR__ . '/../app/bootstrap.php';
require_once __DIR__ . '/../app/AppKernel.php';
use SymfonyComponentHttpFoundationRequest;
$kernel = new AppKernel('prod', false);
$kernel->handle(Request::createFromGlobals())->send();
تنها وظیفه کنترلر جلویی آمادهسازی موتور سیمفونی (هسته) و ارسال یک شئ Request به آن است. هسته سیمفونی سپس از نقشه مسیریابی برای تشخیص اینکه چه کنترلری باید صدازده شود استفاده میکند. دقیقاً مشابه قبل، متد کنترلر مسئول بازگرداندن شئ Response نهایی است. چیزی بیش از این در اینجا وجود ندارد.
برای نمایش بصری چگونگی مدیریت هر درخواست در Symfony، تصویر
چرخه درخواست را مجدداً مشاهده کنید.
آنچه که سیمفونی ارائه میدهد
در بخشهای آینده، درمورد اینکه چگونه هرکدام از اجزاء سیمفونی کار میکند و همچنین ساختار پیشنهادی پروژه، مطالب زیادی خواهید آموخت. فعلاً نگاهی به اینکه چگونه مهاجرت وبلاگ از PHP خام به سیمفونی، حیات پروژه را توسعهداد، بیاندازید:
برنامه شما یک کد واضح و با سازماندهی یکپارچه دارد (هرچند سیمفونی شما را مجبور به این کار نمیکند). این موضوع قابلیت استفاده مجدد از کد را گسترشداده و به برنامهنویسان جدید اجازه میدهد سریعتر در پروژه شما خلاقانه ظاهر شوند.
صددرصد کدی که نوشتهاید، مخصوص برنامه شماست. نیاز به توسعه یا نگهداری ابزارهای سطحپایین مثل بارگذاری خودکار،
مسیریابی، یا رندرکردن
کنترلرها ندارید.
سیمفونی به شما دسترسی به ابزارهای بازمتنی نظیر کامپوننتهای داکترین (Doctrine)، قالببندی (Templating)، امنیت (Security)، فرم (Form)، اعتبارسنجی (Validation) و ترجمه (Translation) را میدهد (صرفاً چندمورد اندک از همه ابزارهای موجود نام برده شد).
برنامه اکنون بهلطف کامپوننت مسیریابی، از URLهای کاملاً انعطافپذیر لذت میبرد.
معماری سیمفونی با محوریت HTTP به شما دسترسی به ابزارهای قدرتمندی نظیر کَش (Cache) در HTTP را با کمک کش داخلی HTTP سیمفونی یا ابزارهای قدرتمندتری نظیر
Varnish میدهد. این موضوع در بخشهای بعدی بطور کامل در مبحث
مدیریت حافظه پنهان پوشش داده میشود.
و شاید بهترین مورد اینکه با استفاده از سیمفونی، شما اکنون دسترسی به تمام مجموعه ابزارهای بازمتنی که توسعه جامعه کاربری Symfony توسعه داده میشود، دارید! یک انتخاب خوب از ابزارهای جامعه کاربران سیمفونی را میتوان در [/url]
KnpBundles.com یافت.
قالبهای بهتر
اگر تصمیم به استفاده از آن داشتهباشید، سیمفونی با یک استاندارد موتور قالب موسوم به
Twig عرضه میشود که نوشتن قالبها را سریعتر و خواندن آنها را سادهتر میکند. معنای این حرف آن است که برنامه مشابه، حتی میتواند باز هم کد کمتری داشته باشد. برای مثال، قالب فهرست که در ساختار Twig نوشته شدهاست، بصورت زیر خواهد بود:
{# app/Resources/views/blog/list.html.twig #}
{% extends "layout.html.twig" %}
{% block title %}List of Posts{% endblock %}
{% block body %}
<h1>List of Posts</h1>
<ul>
{% for post in posts %}
<li>
<a href="{{ path('blog_show', {'id': post.id}) }}">
{{ post.title }}
</a>
</li>
{% endfor %}
</ul>
{% endblock %}
چیدمان layout.html.twig نیز سادهتر است:
{# app/Resources/views/layout.html.twig #}
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}Default title{% endblock %}</title>
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
Twig بهخوبی در سیمفونی پشتیبانی میشود و درحالیکه همیشه امکان استفاده از قالبهای PHP در سیمفونی وجود دارد، مزایای زیاد Twig همچنان مورد بحث خواهد بود. برای اطلاعات بیشتر، بخش
قالببندی را مطالعهکنید.
از کتاب آشپزی سیمفونی بیشتر بیاموزید