On the documentation for Slim Framework, it says
In this example application, all the routes are in index.php but in
practice this can make for a rather long and unwieldy file! It’s fine
to refactor your application to put routes into a different file or
files, or just register a set of routes with callbacks that are
actually declared elsewhere.
It doesn't say how to actually do this though. My only thought is that you could split code into multiple PHP files and then use include or require in index.php to reference these.
I'm also not sure what it means by "register a set of routes with callbacks that are actually declared elsewhere"
Does anyone have any thoughts on this, since the application I'm wanting to build might have quite a few routes?
Being a micro-framework, Slim does not enforce any specific method. You can either find a ready-to-use structure (Slim Skeleton Application comes to my mind) or write your own; unlike other frameworks, Slim does not try to protect you from PHP.
Route definitions can be something as simple as an array of strings:
<?php // routes.php
return [
'/' => ['Foo\\Home', 'index'],
'/about' => ['Foo\\Home', 'about'],
'/contact' => ['Foo\\Contact', 'form' ],
];
... which you then load and process in your index.php entry point:
$routes = require('/path/to/routes.php');
foreach ($routes as list($path, $handler)) {
$app->get($route, $handler);
}
And you can leverage the existing Composer set up to auto-load your classes by adding the appropriate directories to composer.json:
{
"require": {
"slim/slim": "^3.3",
"monolog/monolog": "^1.19"
},
"autoload": {
"psr-4": {"Foo\\": "./Foo/"}
}
}
From here, it can get as complex as required: define routes in a YAML file, auto-load from defined classes, etc.
(Code samples are shown for illustration purposes and might not even be valid.)
There're some thoughts on it in Slim documentation
Instead of require's you can use composer autoloading
"register a set of routes with callbacks that are actually declared elsewhere"
From docs:
Each routing method described above accepts a callback routine as its final argument. This argument can be any PHP callable...
So you can do:
$routeHandler = function ($request, $response) { echo 'My very cool handler'; };
$app->get('/my-very-cool-path', $routeHandler);
But usually people use classes instead of functions:
http://www.slimframework.com/docs/objects/router.html#container-resolution
I think you almost get the basic idea right. I recommend reading chapter on routing a couple of times. It covers everything pretty good.
Happy coding and let me know if you need any other help!
Related
I have some php lines which will be used very often in my application. So I would like to build a function and call it every where in my app. My function could be :
static function array_matiere($id_ecole) {
return $something;
}
I tried to put this code in a controller and then call it like that :
$liste_matieres = MatieresController::array_matieres(Session::get('id_ecole'));
It works, but where to put this kind of function ? in the controller ? in a method file ? what is the best practice ?
Thanks for your responses.
Dominique
There are multiple ways to implement this. look here
Method 1 This method is highly suggested by Laravel Expert ( JeffreyWay)
If your helper functions are similar to the way laravel 5 ones work, i.e Illuminate/Support/helpers.php you could just create a helpers.php and have composer do the autoloading for you.
Edit your composer.json file and add the file to the autoloading key. In my example my app is called Tasky so just add the files key and reference helpers.php.
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"Tasky\\": "app/"
},
"files": [
"app/Support/helpers.php"
]
},
That way you just create your file inside app/Support/helpers.php and all your common function based view helpers or other helpers can go here. If you take the class based approach then the above is great.
Also then remember to just run the following once.
$ composer dumpautoload
Source
Method 2
Please Follow the link and read answer & Its comments
Whenever u need to include a piece of code providing some functionality through out your application then the best way in Laravel is to make Service class inside app/Services and then you can use that class anywhere in your application using
use App\Services\YourServiceName;
I am trying to use Symfony to replicate behavior in an existing Framework (zikula). This framework is extensible using modules which are basically extended symphony bundles. The old framework had urls like so
index.php?module=foo&type=bar&func=zip
which in symfony speak roughly translates to
index.php?bundle=foo&controller=bar&method=zip
The framework has an AbstractController which has a magic method like:
public function __call($method, $args)
{
$event = new \Zikula\Core\Event\GenericEvent($this, array('method' => $method, 'args' => $args));
$this->eventManager->dispatch('controller.method_not_found', $event);
if ($event->isPropagationStopped()) {
return $event->getData();
}
}
so, if you created a url with a method that didn't exist in the bundle, you could create a listener to capture it and send a response that looks like and behaves like it came from the specified bundle. We use this to call module services that are available to all modules and provided in a separate module but look like they are served by the 'host' module.
Now I am trying to replicates this using symfony and routing.
the first problem is generating a route that doesn't technically exist. Is this possible?
The second problem is capturing the RouteNotFoundException (which I know how to do, we already have listeners for other exceptions).
The last problem is making it appear that the bundle is serving up the response when it is actually being served by an event listener (or something else). This last part is important because other content in the response needs to come from the module/bundle.
I have tried changing the current listener to a controller, and also tried adding a method to our extension of symfony's AbstractController, but haven't yet achieved what I am hoping to achieve. I'm hoping for some suggestions on new ideas or methods to try.
I gave up trying to replicate the exact behavior as it seems impossible (it is also pretty difficult to describe). So I have resorted to a normal controller with standard route, but I found a way to make it appear to belong to the original 'host' module. Thanks to Gerry, ggioffreda and DerStoffel for offering ideas.
I have the following association between a route and a callback in my application:
$api->slim->post('/:accountId/Phone-Numbers/', function($accountId) use ($api) {
$api->createPhoneNumber($accountId);
});
What I want to avoid is having the route myhost/a7b81cf/phone-numbers/ return a 404 response because Slim understands the route myhost/a7b81cf/Phone-Numbers/ as being different, due to the usage of uppercase letters.
How can I avoid setting up two separate routes that trigger the same callback function?
This is an old question, but I wanted to provide a clear answer for this problem.
There is a 'routes.case_sensitive' configuration that allows you to do that. I don't know exactly why this is not in the docs (http://docs.slimframework.com/#Application-Settings), but if you look at the framework's source code (specifically, in getDefaultSettings() at Slim.php) you can see that is there.
I just tested it and it works fine.
Summarizing, the solution is to apply the 'routes.case_sensitive' configuration like this:
$configurations = [
// ... other settings ...
'routes.case_sensitive' => false
];
$app->config($configurations);
You could try with route validation/conditions:
$api->slim->post('/:accountId/:phoneNumbers/', function ($accountId) {
$api->createPhoneNumber($accountId);
})->conditions(array('phoneNumbers' => '(p|P)hone\-(n|N)umbers'));
Or if you want more global change you could override Route->matches method in Route class to be case insensitive but it will affect whole application.
You can mimic case-insensitive routing in Slim by registering a hook and modifying the incoming routes to match the case of your defined routes.
In the example, all of your defined routes should be lowercase and strtolower is called on all incoming paths:
$app->hook('slim.before.router', function () use ($app) {
$app->environment['PATH_INFO'] = strtolower($app->environment['PATH_INFO']);
});
I'm using Slim. In the documentation they only show examples working with only one index.php file, which has really little functionality for every route. For example:
$app = new \Slim\Slim();
$app->get('/books/:id', function ($id) {
//Show book identified by $id
});
But in my case, my index.php file is getting bigger and bigger, now I have a lot of code for most routes, what is the best practice in this case? to include files inside the routes closures? What happens with the scope of global variables, like DB connection or app config? Thank you
Brian Nesbitt made a nice post about this: http://nesbot.com/2012/11/5/lazy-loading-slim-controllers-using-pimple.
If you don't want to use pimple, than you can get some idea from the section "Common first attempt", on how to separate you files.
update:
Since version 2.4.0 you can use the inbuilt "Class controller": Version 2.4.0
I've trying to expand my knowledge on separation of concerns in php. I've been practicing for over a year I think and trying to write my own mvc framework for practice. Now I am stuck again in routing and on how to initiate MVC triad.
I have this uri that I want to map so I can identify which controller and which view to use
$uri = filter_var(rtrim(filter_input(INPUT_GET, 'url', FILTER_SANITIZE_STRING), '/'), FILTER_SANITIZE_URL);
lets say this piece of code resides in my bootstrap.php file that acts as the entry point.
While reading Tom Butler's Blog I realize many things, like views should have access to models, but not quite, using a viewmodel is better, or just a model.
I've come across his IOC or his Dependency Injection Container and fell interested on trying it.
What lacks in that article is the dispatching part, which I am very interested to learn, I've tried a couple things to make it work but with no avail.
I wanted to implement this because I want a single call of controller can have shared dependency across its views, something like
$route = $router->getRoutes(); // maybe something that return a Route object with Controller, and View object that has already shared dependecies.
I do not know if my understanding on the above paragraphs where correct and if really can be of use on my routing. Correct me if I am wrong.
The real question is how would the dispatcher looks like? and if I were to use the convention over configuration stuff of mr. tom, should I declare the routes individually in my bootstrap? Like these
$dice->addRule('$route_user/edit', $rule);
$dice->addRule('$route_user/delete', $rule);
...
I wonder if I could just do:
$controller->method($params)
After I have settled on what view and controller I needed.
I'm not sure that this answer will be what you want, but if I where you I'll do it this way, it will be more restFull, and more "convention over configuration":
Use http verbs for edit , delete...
Use a standard way to handle your urls: "article/", "article/2"
Where article is your controller name AND your view name
Use a simple array tree for simple routes:
$bootstrap=[
...
"routes"=>[
"myFirstCategory"=>[
"art"=>"article",
...
],
"mySecondCategory"=>[
...
This way, myFirstCategory/art can be redirected to article controller and view, with a recursive function that handle the routes tree
In this tree you can use a callback rule for complex rules (that callback have to be handeled by your recursive function for the routes tree:
... "art"=>function($myContainer){...return ['view'=>$view,'controller'=>$controller,'id'=>$id...];}...
It's just some ideas to make it more easy to use...