3

I decided to make my own mini - framework for PHP that I am going to use for a real life job, creation of a Web Service for a social app.

I got started with Fabien Potencier's guide to creating your own framework on top of the Symfony's components - http://symfony.com/doc/current/create_framework/index.html. I really liked his classLoader and http-foundation libraries and decided to integrate them.

I read the whole tutorial but I decided to stop integrating Symfony's components up to part 5 of the tutorial where he gets to the Symfony http kernel, route matcher and controller resolver (excluding those).

There are the front controller and route mapper file of my framework that qre in question.

front.php(the front controller)

<?php 

        require 'config/config.php';
        require 'config/routing.php';
        require 'src/autoloader.php';

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

        $request = Request::createFromGlobals();

        $response = new Response();


        $path = $request->getPathInfo();

        if(isset($siteMap[$path])) {
            call_user_func_array('src\Controllers' .'\\' . $siteMap[$path]['controller'] . '::' . $siteMap[$path]['action'], array($siteMap[$path]['arguments']));
        } else {    
            $response->setStatusCode('404');
            $response->setContent('Page not found');
        }

    $response->send();
?>  

My routing file :

/*  
    Map of routes
*/

$siteMap = array('/' => array('controller' => 'IndexController', 'action' => 'indexAction', 'arguments' => ''),
                    '/categories' => array('controller' => 'CategoriesController', 'action' => 'indexAction', '

What I want to know now is without further using Symfony's components, how can I do something like this:

In my routing file I wanna add an URL like '/hello' with Controller - Hello Controller and arguments name,age,gender that would correspond to a request in the browser GET www.base/hello/samuel/11/male.

And in the HelloController have an indexAction($name, $age, $gender) { ... }. I have tried looking at Symfony's source but it eludes me so far(I spent a lot of time going trough the source code of the libraries). I am going to modularize and separate the functions of the front controller and controller resolving even further but I want to get this down.

Ah and also any advice on building my framework further would be welcome(I am creating a framework for a REST - like web service that needs to be scalable and fast and handle tens of thousands requests per second maybe).

4

2 回答 2

3

You must define regexes for your routes and match them against the requests, if you want to know how Symfony transforms its own route format e.g: '/path/to/{id}' to a regex, see RouteCompiler::compilePattern. That's out of the scope of this question and I will provide no code for it.

The regex for your example route will be something like ^/hello/(\w*)/(\d*)/(\w*)/$, this will match '/hello/any string/any number/any string/' e.g: /hello/samuel/11/male (don't forget the ^ and the $, they match the beginning and end of the string).

You must provide a regex for each route, and do a preg_match(rawurldecode($request->getPathInfo(), $regex /* as created earlier*/, $matches) against all of the routes (until one matches), instead of the isset($sitemap[$path]) if this returns false, the route does not match.otherwise you must get the arguments for your controller like so:

preg_match(rawurldecode($request->getPathInfo(), $regex /* as created earlier*/, $matches)
$args = array();
// we omit the first element of $matches, since it's the full string for the match
for($i = 1; $i < count($matches); $i++){
  $args[] = $matches[$i];
}

Now you can merge $args with the default arguments and call the controller.


See UrlMatcher::matchCollection() on how Symfony matches each route against the regex, and constructs the arguments.

于 2015-08-04T08:22:56.330 回答
0

I would like to add some additional information. In Symfony you can get the Arguments of your request into the method arguments:

public function fooAction($bar);

In this case it would look in the $request->attributes for a key with bar. if the value is present it will inject this value into your action. In Symfony 3.0 and lower, this is done via the ControllerResolver::getArguments(). As of Symfony 3.1 you will be able to implement or extend an ArgumentResolver.

Utilizing the ArgumentResolver means you can easily add your own functionality to the resolving. The existing value resolvers are located here.

于 2016-04-25T06:34:58.847 回答