From 97743fb879f1868965228cd3823a48175e5a5fec Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 15 Jan 2012 10:50:03 +0100 Subject: [PATCH] added part 7 --- book/part7.rst | 188 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 book/part7.rst diff --git a/book/part7.rst b/book/part7.rst new file mode 100644 index 00000000000..7679675e9eb --- /dev/null +++ b/book/part7.rst @@ -0,0 +1,188 @@ +Create your own framework... on top of the Symfony2 Components (part 7) +======================================================================= + +One down-side of our framework right now is that we need to copy and paste the +code in ``front.php`` each time we create a new website. 40 lines of code is +not that much, but it would be nice if we could wrap this code into a proper +class. It would bring us better *reusability* and easier testing to name just +a few benefits. + +If you have a closer look at the code, ``front.php`` has one input, the +Request, and one output, the Response. Our framework class will follow this +simple principle: the logic is about creating the Response associated with a +Request. + +As the Symfony2 components requires PHP 5.3, let's create our very own +namespace for our framework: ``Simplex``. + +Move the request handling logic into its own ``Simple\\Framework`` class:: + + matcher = $matcher; + $this->resolver = $resolver; + } + + public function handle(Request $request) + { + try { + $request->attributes->add($this->matcher->match($request->getPathInfo())); + + $controller = $this->resolver->getController($request); + $arguments = $this->resolver->getArguments($request, $controller); + + return call_user_func_array($controller, $arguments); + } catch (Routing\Exception\ResourceNotFoundException $e) { + return new Response('Not Found', 404); + } catch (Exception $e) { + return new Response('An error occurred', 500); + } + } + } + +And update ``example.com/web/front.php`` accordingly:: + + fromRequest($request); + $matcher = new Routing\Matcher\UrlMatcher($routes, $context); + $resolver = new HttpKernel\Controller\ControllerResolver(); + + $framework = new Simplex\Framework($matcher, $resolver); + $response = $framework->handle($request); + + $response->send(); + +To wrap up the refactoring, let's move everything but routes definition from +``example.com/src/app.php`` into yet another namespace: ``Calendar``. + +For the classes defined under the ``Simplex`` and ``Calendar`` namespaces to +be autoloaded, update the ``composer.json`` file: + +.. code-block:: json + + { + "require": { + "symfony/class-loader": "2.1.*", + "symfony/http-foundation": "2.1.*", + "symfony/routing": "2.1.*", + "symfony/http-kernel": "2.1.*" + }, + "autoload": { + "psr-0": { "Simplex": "src/", "Calendar": "src/" } + } + } + +.. note:: + + For the autoloader to be updated, run ``php composer.phar update``. + +Move the controller to ``Calendar\\Controller\\LeapYearController``:: + + isLeapYear($year)) { + return new Response('Yep, this is a leap year!'); + } + + return new Response('Nope, this is not a leap year.'); + } + } + +And move the ``is_leap_year()`` function to its own class too:: + + add('leap_year', new Routing\Route('/is_leap_year/{year}', array( + 'year' => null, + '_controller' => 'Calendar\\Controller\\LeapYearController::indexAction', + ))); + +To sum up, here is the new file layout: + + example.com + ├── composer.json + │ src + │ ├── app.php + │ └── Simplex + │ └── Framework.php + │ └── Calendar + │ └── Controller + │ │ └── LeapYearController.php + │ └── Model + │ └── LeapYear.php + ├── vendor + └── web + └── front.php + +That's it! Our application has now four different layers and each of them has +a well defined goal: + +* ``web/front.php``: The front controller; the only exposed PHP code that + makes the interface with the client (it gets the Request and sends the + Response) and provides the boiler-plate code to initialize the framework and + our application; + +* ``src/Simplex``: The reusable framework code that abstracts the handling of + incoming Requests (by the way, it makes your controllers/templates easily + testable -- more about that later on); + +* ``src/Calendar``: Our application specific code (the controllers and the + model); + +* ``src/app.php``: The application configuration/framework customization.