Өөрийн фраймворкоо Symfony2 -ын компонент дээр үүсгэе (хэсэг 4)

За уншигч, хөгжүүлэгч нартаа энэ өдрийн мэнд хүргэе.

Тэмдэглэл:
Энэхүү нийтлэл нь “Өөрийн фраймворкоо Symfony2 -ын компонент дээр үүсгэе” цувралын нэг хэсэг юм.

Өнөөдрийн хичээлээ эхлэхээсээ өмнө цөмөөрөө одооныхоо байгаа кодоо бага зэрэг өөрчлөөд тэмплэйтээ илүү уншигдахуйц болгоцгооё.


'hello',
'/bye' => 'bye',
);

$path = $request->getPathInfo();
if (isset($map[$path])) {
ob_start();
extract($request->query->all(), EXTR_SKIP);
include sprintf(__DIR__.’/../src/pages/%s.php’, $map[$path]);
$response = new Response(ob_get_clean());
} else {
$response = new Response(‘Not Found’, 404);
}

$response->send();

Хүсэлтийн шаардлагатай өгөгдлүүдийг ялган авч, `hello.php` тэмтлэйтыг дараах байдлаар хялбарчилъя.


<!-- example.com/src/pages/hello.php -->

Hello <?php echo htmlspecialchars($name, ENT_QUOTES, ‘UTF-8’) ?>

Одоо бид шинэ зүйл нэмэхэд ямарч асуудалгүй боллоо.

Ямар ч вэб сайтад хамгийн нэг чухал зүйл нь тэдгээрийн URL-үүдын бүтэц, бүрэлдэхүүн юм. URL зурагчлалын (map) ачаар бид URL-үүдээ буцах хүсэлтийн хариуны кодоос тусгаарлаж чадсан билээ. Гэсэн ч энэ нь тийм ч хангалттай биш л байна. Тухайлбал бид динамик хүсэлтийн утгуудыг текстэн хүсэлтийн утгаас (query string) хамаарахгүйгээр шууд хүсэлтийн зам дээр тусд нь хавсаргаж өгөх шаардалагатай учирч болох юм.

# Өмнө нь
/hello?name=Fabien

# Дараа нь
/hello/Fabien

Энэ шаардлагыг дэмждэг болохын тулд бид Symfony2-ын Routing компонентыг ашиглая.
Суулгахын тулд `composer.json` файлдаа нэмээд `php composer.phar update` коммандыг ажиллуулъя:


{
"require": {
"symfony/class-loader": "2.1.*",
"symfony/http-foundation": "2.1.*",
"symfony/routing": "2.1.*"
}
}

Одооноос эхлээд, бид өөрсдийн `autoload.php`-ын оронд бий болсон Composer-ын `autoloader`-ыг ашиглана. `autoload.php` -ыг устгаад, түүнтэй харгалзах утгыг `front.php`-д дараах байдлаар өөрчлөе:

<?php

// example.com/web/front.php

require_once __DIR__.’/../vendor/.composer/autoload.php’;

// …

URL- зураглалын(map) array-г ашиглахын оронд, `RouteCollection`-аас хамаарах `Routing` компонентыг ашиглая:


use Symfony\Component\Routing\RouteCollection;

$routes = new RouteCollection();

За цөмөөрөө `/hello/SOMETHING` гэсэн URL болон өөр дахин нэгэн `/bye` гэсэн замуудыг нэмж өгцгөөе:


use Symfony\Component\Routing\Route;

$routes->add(‘hello’, new Route(‘/hello/{name}’, array(‘name’ => ‘World’)));
$routes->add(‘bye’, new Route(‘/bye’));

Дээрх бүрэлдэхүүний оролт бүр нь:
– нэр (`hello`),
– замын хэрхэн бүрдэхийг тодорхойлох `Route`-н объект (`/hello/{name}`) болон
– `route`-ын хувьсагчдын анхдагч утгуудыг тодорхойлох `array` (`array(‘name’ => ‘World’)`) -аас бүрдэж байна.

Тэмдэглэл:
URL-ыг бэлтгэн бий болгох, хувьсагчдын шаардлагууд, HTTP аргуудын хэрэгжилт,
YAML, XML файлуудыг дуудаж ашиглах, PHP класс файл бэлдэх болон сайжруулсан гүйцэтгэлд зориулсан Apache-ын rewrite дүрмүүд гэх мэт илүү боломжуудыг өөрийнх нь энэ тайлбараас үзнэ үү.

`UrlMatcher` -ын объект дуудагдах URL-ын замыг `RouteCollection`-ын объектд орших өгөгдлүүдээс адилтган, тохирсныг олно:

use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Matcher\UrlMatcher;

$context = new RequestContext();
$context->fromRequest($request);
$matcher = new UrlMatcher($routes, $context);

$attributes = $matcher->match($request->getPathInfo());

`match()` функц хүсэлтийн замыг оролтоор авч, хувьсагчдын array-ыг (тохирсон зам (route) нь автоматаар `_route` гэсэн тусгайлсан хувьсагчид хадгалагдаж байгааг анзаараарай) буцаана:


print_r($matcher->match('/bye'));
array (
'_route' => 'bye',
);

print_r($matcher->match(‘/hello/Fabien’));
array (
‘name’ => ‘Fabien’,
‘_route’ => ‘hello’,
);

print_r($matcher->match(‘/hello’));
array (
‘name’ => ‘World’,
‘_route’ => ‘hello’,
);

Тэмдэглэл:
Хэдийгээр бидэнд хүсэлтийн `context` зайлшгүй шаардлагатай биш боловч, бодит аппликэйшнд аргуудын (method)-уудын шаардлагуудын хэрэгжилт болон бусад зүйлүүдэд ашигладдаг.

Ирэх хүсэлтийн утга бидний замуудад (routes) байхгүй бол URL-ын адилтгагч (matcher) `exception`-ыг шиднэ:


$matcher->match('/not-found');

// throws a Symfony\Component\Routing\Exception\ResourceNotFoundException

За эдгээр мэдлэгүүдийнхээ хүрээнд, өөрсдийнхөө фраймворкоо дараах байдлаар шинээр шинчилье:

<?php

// example.com/web/front.php

require_once __DIR__.’/../vendor/.composer/autoload.php’;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing;

$request = Request::createFromGlobals();
$routes = include __DIR__.’/../src/app.php’;

$context = new Routing\RequestContext();
$context->fromRequest($request);
$matcher = new Routing\Matcher\UrlMatcher($routes, $context);

try {
extract($matcher->match($request->getPathInfo()), EXTR_SKIP);
ob_start();
include sprintf(__DIR__.’/../src/pages/%s.php’, $_route);

$response = new Response(ob_get_clean());
} catch (Routing\Exception\ResourceNotFoundException $e) {
$response = new Response(‘Not Found’, 404);
} catch (Exception $e) {
$response = new Response(‘An error occurred’, 500);
}

$response->send();

Дээрх кодонд орших зарим зүйлүүдийг дурьдвал:
– Зам (Route)-ын нэрүүд харгалзах тэмплэйтын нэрэнд ашиглагдаж байгаа
– 500 алдаа одоо зөвөөр дуудагдана
– Тэмплэйтээ хялбар хэлбэрээр нь хадгалж үлдэхийн тулд хүсэлтийн хувьсагчуудд ялгагдсан байгаа

<!-- example.com/src/pages/hello.php -->

Hello <?php echo htmlspecialchars($name, ENT_QUOTES, ‘UTF-8’) ?>

– Замуудын (Routes) тохиргоонууд өөрийн тусдаа файл руу шилжсэн:

<?php

// example.com/src/app.php

use Symfony\Component\Routing;

$routes = new Routing\RouteCollection();
$routes->add(‘hello’, new Routing\Route(‘/hello/{name}’, array(‘name’ => ‘World’)));
$routes->add(‘bye’, new Routing\Route(‘/bye’));

return $routes;

Одоо бид тохиргооны файлууд (зөвхөн бидний аппликэйшн-д зориулагдсан тохиргоонууд `app.php`-д) болон фрэймвор(аппликэйшнд маань ашиглагдах ерөнхий кодууд `front.php`-д) -ыг тус тусд нь ялгаж өгснөөр хөгжүүлэхэд ойлгомжтой, цэвэрхэн болгож чадлаа.

30 мөрнөөс ч бага кодоор бид өөрсдийн фрэймворкоо өмнөхөөсөө илүү хүчирхэг, илүү уян хатан болгож чадлаа. Enjoy!

`Routing` компонент ашиглах бас нэг том давуу тал гэвэл: `Route`-ын тодорхойлолтуудад тулгуурлан URL-ыг бэлтгэн гаргах боломж юм.
URL адилтгал (matching) болон URL бэлгэгч (generation) хоёрыг хоёуланг нь цугт нь ашигласнаар, URL-ын бүрдэлтийг өөрчлөхөд ямар ч асуудалгүй болом юм. URL бэлтгэгчийг хэрхэн ашиглагддагыг сурмаар байна уу? Мангар хялбархан:

 

use Symfony\Component\Routing;

$generator = new Routing\Generator\UrlGenerator($routes, $context);

echo $generator->generate(‘hello’, array(‘name’ => ‘Fabien’));
// outputs /hello/Fabien

 

Дээрх код өөрөө өөрөөрөө тайлбарлагдахаар бичигдсэн байгаа. `Context`-ын тусламжтайгаар та мөн бүрэн, гүйцэт URL-ыг бэлтгэн гаргах боломжтой:


echo $generator->generate('hello', array('name' => 'Fabien'), true);
// outputs something like http://example.com/somewhere/hello/Fabien

Чимэг:
Хийгдсэн гүйцэтгэл хэр болсон бол гэж гайхаж байна уу? Дараах код таны замуудын тодорхойлолтонд тулгуурлан, анхдагч (default) `UrlMatcher` -ын оронд дуудагдаж, маш оновтой болгосон классыг үүсгэнэ.


$dumper = new Routing\Matcher\Dumper\PhpMatcherDumper($routes);

echo $dumper->dump();

Өшөө илүү боломж гэж үү? Та өөрийнхөө замуудаа Apache-ын `rewrite` дүрмийн загвараар мөн гаргах боломжтой:


$dumper = new Routing\Matcher\Dumper\ApacheMatcherDumper($routes);

echo $dumper->dump();

Эх хувилбарыг эндээс үзнэ үү.

Published by

Think!

Web developer. Open source enthusiast.

Сэтгэгдэл бичих