Dynamic Routing in cakephp issue - php

I want to use Dynamic Routing for the static pages of my site.
I have used the following code in my Routes file
$arr = ClassRegistry::init('Page');
and
$this->loadModel('Page');
$arr = $this->Page->find('all');
foreach($arr as $value)
{
//my code
}
But it doesn't work, and shows an error like below:
ClassRegistry is not defined

Don't do that
you've tried to put controller code in your routes file and are intending to make your site so needlessly dependent on the database. Of course, your whole site is likely dependent on the database, but by making your routes db-dependent all requests that make it to cakephp (which means, all requests that are not a static file in the webroot) need to talk to the db at least slowing things down, and if anything goes wrong with the db, your site is white page of fatal error awesomeness for all requests. This is because the routes file is loaded very early in the request handling process. The routes file is not supposed to contain any real logic - just Router::connect statements.
Alternative: Use a catchall route
If you have any pattern that you can use for your static pages, use it so that you have only one route definition. i.e.:
Router::connect('/x/*', array('controller' => 'some', 'action' => 'thing')); //eerily similar to the default static pages route
Alternative: Write a static routes file
Build, however you like, your routes logic whenever the rules for your routes change and write them to a static file. Therefore your routes.php file becomes:
<?php
... routes that don't change ...
require 'path/to/dynamic_routes_file.php';
You can use the afterSave handler for a relevant model to trigger rebuilding this dynamic routes file.
More alternatives
There are many other ways to handle this kind of thing e.g. override the error handling process to first check if there's one of these db-dependent routes to process - Or simply create a custom route class which implements literally whatever you want.
Whatever you do though - aim for the logic at run time to be as simple/cached/static as possible - don't build a system which makes all requests need to talk to the db all the time.

Related

Laravel Forwarding Route To Another Route File

I'm building enterprise modular Laravel web application but I'm having a small problem.
I would like to have it so that if someone goes to the /api/*/ route (/api/ is a route group) that it will go to an InputController. the first variable next to /api/ will be the module name that the api is requesting info from. So lets say for example: /api/phonefinder/find
In this case, when someone hit's this route, it will go to InputController, verifiy if the module 'phonefinder' exists, then sends anything after the /api/phonefinder to the correct routes file in that module's folder (In this case the '/find' Route..)
So:
/api/phonefinder/find - Go to input controller and verify if phonefinder module exists (Always go to InputController even if its another module instead of phonefinder)
/find - Then call the /find route inside folder Modules/phonefinder/routes.php
Any idea's on how to achieve this?
Middlewares are designed for this purpose. You can create a middleware by typing
php artisan make:middleware MiddlewareName
It will create a middleware named 'MiddlewareName' under namespace App\Http\Middleware; path.
In this middleware, write your controls in the handle function. It should return $next($request); Dont change this part.
In your Http\Kernel.php file, go to $routeMiddleware variable and add this line:
'middleware_name' => \App\Http\Middleware\MiddlewareName::class,
And finally, go to your web.php file and set the middleware. An example can be given as:
Route::middleware(['middleware_name'])->group(function () {
Route::prefix('api')->group(function () {
Route::get('/phonefinder', 'SomeController#someMethod');
});
});
Whenever you call api/phonefinder endpoint, it will go to the Middleware first.
What you are looking for is HMVC, where you can send internal route requests, but Laravel doesn't support it.
If you want to have one access point for your modular application then you should declare it like this (for example):
Route::any('api/{module}/{action}', 'InputController#moduleAction');
Then in your moduleAction($module, $action) you can process it accordingly, initialize needed module and call it's action with all attached data. Implement your own Module class the way you need and work from there.
Laravel doesn't support HMVC, you can't have one general route using other internal routes. And if those routes (/find in your case) are not internal and can be publicly accessed then also having one general route makes no sense.

Dealing with Views in Phalcon Controllers

I am working on a newly created Phalcon project, and I don't really know how to actually use multiples views.
What is the entry point? I don't really know when each method in the controller is called, under which conditions, etc.
Where is the control flow defined? is it based in the name of the view? or is there a place where you can register them?
Phalcon is a bit different than other well-known PHP frameworks, in that not much is pre-configured or pre-built by default. It's quite loosely-coupled. So you have to decide where and how your control flow will work. This means that you will need to dig deeper in the documentation and also that there could be different way to achieve the same thing.
I'm going to walk you through a simple example and provide references, so you can understand it more.
1) You would start by defining a bootstrap file (or files) that will define the routes, or entry points, and will setup and create the application. This bootstrap file could be called by an index.php file that is the default file served by the web server. Here is an example of how such bootstrap file will define the routes or entry points (note: these are just fragments and do not represent all the things that a bootstrap file should do):
use Phalcon\Di\FactoryDefault;
// initializes the dependency injector of Phalcon framework
$injector = new FactoryDefault();
// defines the routes
$injector->setShared('router', function () {
return require_once('some/path/routes.php');
});
Then it the routes.php file:
use Phalcon\Mvc\Router;
use Phalcon\Mvc\Router\Group as RouterGroup;
// instantiates the router
$router = new Router(false);
// defines routes for the 'users' controller
$user_routes = new RouterGroup(['controller' => 'users']);
$user_routes->setPrefix('/users');
$user_routes->addGet('/show/{id:[0-9]{1,9}}', ['action' => 'show']);
$router->mount($user_routes);
return $router;
Im defining routes in an alternate way, by defining routes groups. I find it to be more easy to organize routes by resource or controller.
2) When you enter the url example.com/users/show/123, the routes above will match this to the controller users and action show. This is specified by the chunks of code ['controller' => 'users'], setPrefix('/users') and '/show/{id:[0-9]{1,9}}', ['action' => 'show']
3) So now you create the controller. You create a file in, let's say, controllers/UsersController.php. And then you create its action; note the name that you used in the route (show) and the suffix of Action:
public function showAction(int $id) {
// ... do all you need to do...
// fetch data
$user = UserModel::findFirst(blah blah);
// pass data to view
$this->view->setVar('user', $user);
// Phalcon automatically calls the view; from the manual:
/*
Phalcon automatically passes the execution to the view component as soon as a particular
controller has completed its cycle. The view component will look in the views folder for
a folder named as the same name of the last controller executed and then for a file named
as the last action executed.
*/
// but in case you would need to specify a different one
$this->view->render('users', 'another_view');
}
There is much more stuff related to views; consult the manual.
Note that you will need to register such controller in the bootstrap file like (Im also including examples on how to register other things):
use Phalcon\Loader;
// registers namespaces and other classes
$loader = new Loader();
$loader->registerNamespaces([
'MyNameSpace\Controllers' => 'path/controllers/',
'MyNameSpace\Models' => 'path/models/',
'MyNameSpace\Views' => 'path/views/'
]);
$loader->register();
4) You will also need to register a few things for the views. In the bootstrap file
use Phalcon\Mvc\View;
$injector->setShared('view', function () {
$view = new View();
$view->setViewsDir('path/views/');
return $view;
});
And this, together with other things you will need to do, particularly in the bootstrap process, will get you started in sending requests to the controller and action/view defined in the routes.
Those were basic examples. There is much more that you will need to learn, because I only gave you a few pieces to get you started. So here are some links that can explain more. Remember, there are several different ways to achieve the same thing in Phalcon.
Bootstrapping:
https://docs.phalconphp.com/en/3.2/di
https://docs.phalconphp.com/en/3.2/loader
https://docs.phalconphp.com/en/3.2/dispatcher
Routing: https://docs.phalconphp.com/en/3.2/routing
Controllers: https://docs.phalconphp.com/en/3.2/controllers
More on Views (from registering to passing data to them, to templating and more): https://docs.phalconphp.com/en/3.2/views
And a simple tutorial to teach you some basic things: https://docs.phalconphp.com/en/3.2/tutorial-rest
The application begins with the routing stage. From there you grab the controller and action from the router, and feed it to the dispatcher. You set the view then call the execute the dispatcher so it access your controller's action. From there you create a new response object and set its contents equal to the view requests, and finally send the response to the client's browser -- both the content and the headers. It's a good idea to do this through Phalcon rather than echoing directly or using PHP's header(), so it's only done at the moment you call $response->send(); This is best practice because it allows you to create tests, such as in phpunit, so you can test for the existence of headers, or content, while moving off to the next response and header without actually sending anything so you can test stuff. Same idea with exit; in code, is best to avoid so you can write tests and move on to the next test without your tests aborting on the first test due to the existence of exit.
As far as how the Phalcon application works, and in what steps, it's much easier to follow the flow by looking at manual bootstrapping:
https://docs.phalconphp.com/en/3.2/application#manual-bootstrapping
At the heart of Phalcon is the DI, the Dependency Injection container. This allows you to create services, and store them on the DI so services can access each other. You can create your own services and store them under your own name on the DI, there's nothing special about the names used. However depending on the areas of Phalcon you used, certain services on the DI are assumed like "db" for interacting with your database. Note services can be set as either shared or not shared on the DI. Shared means it implements singleton and keeps the object alive for all calls afterwards. If you use getShared, it does a similar thing even if it wasn't initially a shared service. The getShared method is considered bad practice and the Phalcon team is talking about removing the method in future Phalcon versions. Please rely on setShared instead.
Regarding multiple views, you can start with $this->view->disable(); from within the controller. This allows you to disable a view so you don't get any content generated to begin with from within a controller so you can follow how views work from within controllers.
Phalcon assumes every controller has a matching view under /someController/someView followed by whatever extension you registered on the view, which defaults to .volt but can also be set to use .phtml or .php.
These two correspond to:
Phalcon\Mvc\View\Engine\Php and Phalcon\Mvc\View\Engine\Volt
Note that you DON'T specify the extension when looking for a template to render, Phalcon adds this for you
Phalcon also uses a root view template index.volt, if it exists, for all interactions with the view so you can use things like the same doctype for all responses, making your life easier.
Phalcon also offers you partials, so from within a view you can render a partial like breadcrumbs, or a header or footer which you'd otherwise be copy-pasting into each template. This allows you to manage all pages from the same template so you're not repeating yourself.
As far as which view class you use within Phalcon, there's two main choices:
Phalcon\Mvc\View and Phalcon\Mvc\View\Simple
While similar, Phalcon\Mvc\View gives you a multiple level hierarchy as described before with a main template, and a controller-action based template as well as some other fancy features. As far as Phalcon\Mvc\View\Simple, it's much more lightweight and is a single level.
You should be familiar with hierarchical rendering:
https://docs.phalconphp.com/en/3.2/views#hierarchical-rendering
The idea is with Phalcon\Mvc\View that you have a Main Layout (if this template exists) usually stored in /views/index.volt, which is used on every page so you can toss in your doctypes, the title (which you would set with a variable the view passed in), etc. You'd have a Controller Layout, which would be stored under /views/layouts.myController.volt and used for every action within a controller (if this template exists), finally you'd have the Action Layout which is used for the specific action of the controller in /views/myController/myAction.volt.
There are all types of ways you can break from Phalcon's default behavior. You can do the earlier stated $this->view->disable(); so you can do everything manually yourself so Phalcon doesn't assume anything about the view template. You can also use ->pick to pick which template to use if it's going to be different than the controller and action it's ran in.
You can also return a response object from within a controller and Phalcon will not try to render the templates and use the response object instead.
For example you might want to do:
return $this->response->redirect('index/index');
This would redirect the user's browser to said page. You could also do a forward instead which would be used internally within Phalcon to access a different controller and/or action.
You can config the directory the views are stored with setViewsDir. You can also do this from within the controller itself, or even within the view as late as you want, if you have some exceptions due to a goofy directory structure.
You can do things like use $this->view->setTemplateBefore('common') or $this->view->setTemplateAfter('common'); so you can have intermediate templates.
At the heart of the view hierarchy is <?php echo $this->getContent(); ?> or {{ content() }} if you're using Volt. Even if you're using Volt, it gets parsed by Phalcon and generates the PHP version with $this->getContent(), storing it in your /cache/ directory, before it is executed.
The idea with "template before" is that it's optional if you need another layer of hierarchy between your main template and your controller template. Same idea with "template after" etc. I would advise against using template before and after as they are confusing and partials are better suited for the task.
It all depends on how you want to organize your application structure.
Note you can also swap between your main template to another main template if you need to swap anything major. You could also just toss in an "if" statement into your main template to decide what to do based on some condition, etc.
With all that said, you should be able to read the documentation and make better sense of how to utilize it:
https://docs.phalconphp.com/en/3.2/api/Phalcon_Mvc_View

Laravel :: Routes Vs. Controller

As I am new to the laravel 4 after spending some few months in Codeigniter, I went through the lots of tutorials about laravel and one thing I want to be clear is what is the actual difference between Routes and Controller in laravel, because we can create and generate view in both controller and routes too. Will anyone explain me in brief when to use routes and Controller in laravel? Because in other Framework we need routes to specify some particular URL's within the apps and Controller were used to do some real tasks but in laravel I didnt get the main concept of Routes except the routing mechanism?
In Laravel, you can totally skip controllers and do the task of performing business logic and generating the view in the routes.
E.g I have a link b2.com/getUsers so in routes.php I can write:
Route::get('/getUsers',function()
{
$users=User::all(); //select * from users
return View::make('allUsers')->with('users',$users);
}
So, here to serve the request b2.com/getUsers, we didn't use controller at all and you can very well do this for handling all requests in your application, both get and post.
But then, if your application is large and have 500+ url's with complex business logic then imagine putting everything in one routes.php. It will totally make it criminally messy and whole purpose of architecture will be defeated. Hence what we usually do is, reserve routes.php for routing only and write all business logic (along with generation of views inside controllers)
So the same example can be solved as:
To handle link: b2.com/getUsers, in routes.php
Route::get('/getUsers', array('before' => 'auth', 'uses' => 'MyController#getUsers'));
MyController has the method getUsers defined like this:
public function getUsers()
{
$users=User::all(); //select * from users
return View::make('allUsers')->with('users',$users);
}
I usually create a controller for related activities e.g for login/signup/logout. I create AuthController and all the links related to those activities are routed to AuthController through routes.php.
The fact that you can get views or do a lot of things in Routes::any() is against MVC and separation of logic.
In Route::get("admin", function(){}), you indeed have a fast access to your route callback, which otherwise in a standard fashion must just be bound to controller. But Laravel allows you to do your job there in a closure (function(){}), instead of binding it to a controller. Anyway, it lets you, but you'd better avoid it. In Route::get() you only should go with your 'routing' and nothing more.
There is no reason for you to use callbacks in Route unless for testing or some trivial requests. So, better to avoid this:
Route::get("admin", function(){
return View::make("admin_index");
});
And rather go with this:
Route::controller("admin", "AdminController");
And in your AdminController.php :
// I mean create a file named AdminController.php in controllers directory under app.
class AdminController extends Controller
{
function getIndex()
{
return View::make("admin_index");
}
}
Read more about Route::controller and restful controllers.
Some Notes:
Having the ability to add closures in your Routes allows you to make
complex decisions on Routes and have a powerful routing system.
These callbacks let you add conditions to your route.
Having Controller separated from you Routes makes you application
more extensible, less confusing and makes other coders more
comfortable in future.
It allows you to focus better on your problem and finding solution,
this physical separation is very important. Having View::make()
inside your Route stirs all problems into each other and makes up a
confusion for the coder.
Let's see what we have in both cases:
In CodeIgniter, a route is just pointing your request to a specific method of your controller:
$route['blog/joe'] = "blogs/users/34";
Here when you visit application.com/blog/joe, you will invoke the controller BlogsController, call the method users() and pass 34 as the first parameter. Nothing else. As they put it, a route in CI is just a one-to-one relationship between a URL string and its corresponding controller class/method.
Now, in Laravel, you have a lot of possibilities:
You can directly return a simple response
You can return a view
You can point the request to a specific controller and a method
You can write some logic in a closure and then decide what you want to do
You can add some additional functionality to them, like attaching filters, checking parameters upon a regex, give them separate names, etc., but this is the main functionality.
What's the reason for being able to do so much stuff? It gives you the power to use them in any way you need. Examples:
Need a small website, rendering static HTML? Use them like this:
Route::get('/', function()
{
return View::make('greeting');
});
Need a bigger application using the traditional MVC pattern? Use like this:
Route::get('user/{id}', 'UserController#showProfile');
Need a RESTful approach? No problem. This will generate routes for all the CRUD methods:
Route::resource('photo', 'PhotoController');
Need something quick and dirty to handle a specific Ajax request? Keep it simple:
Route::post('foo/bar', function()
{
return 'Hello World';
});
TL;DR: For very simple things without or with very little logic, use them instead of controllers. Otherwise, always stick to the MVC principles and route to your controllers, so that they're the ones who do the actual work.

ZEND - Conflicting route patterns

I'm using Zend framework 1.12, trying to come up with custom routes.
I'm trying to create something that looks like facebook's profile URL (http://facebook.com/username). So, at first I tried something like that:
$router->addRoute(
'eventName',
new Zend_Controller_Router_Route(
'/:eventName',
array(
'module' => 'default',
'controller' => 'event',
'action' => 'detail'
)
)
);
I kept getting the following error anytime I tried running mydomain.com/something:
Fatal error: Uncaught exception 'Zend_Controller_Router_Exception'
with message 'eventName is not specified' in
/var/desenvolvimento/padroes/zf/ZendFramework-1.12.0/library/Zend/Controller/Plugin/Broker.php
on line 336
Not only I was unable to make that piece of code work, all my default routes were (obviously) overwritten. So I have, for example, stuff like "mydomain.com/admin" that should send me to the "admin" module, on the Index controller, but was now returning the same error (as it fell in the same pattern as /:eventName).
What I need to do is to create this custom route, without overwriting the default ones and actually working (dûh).
I have already checked the online docs and a lot (A LOT) of stuff on google, but I didn't find anything related to the error I'm getting or how to not overwrite the default routes. I'd appreciate anything that could point me the right direction.
Thanks.
EDIT¹:
I managed to get it working, but I didn't use any routing at all. I just made a plugin with the following:
public function preDispatch(\Zend_Controller_Request_Abstract $request) {
if (!\Zend_Controller_Front::getInstance()->getDispatcher()->isDispatchable($request)) {
$request->setModuleName($this->_eventRouter["module"]);
$request->setControllerName($this->_eventRouter["controller"]);
$request->setActionName($this->_eventRouter["action"]);
}
}
It feels like an ugly workaround, though... As Tim Fountain pointed out, my events are dynamic (I load them from a database), so I can't hardcode it. Also, my current implementation prevents me from having to hardcode every module/controller/action combination.
I'd just like to know if there's a way to avoid using a plugin.
EDIT²: I'm not doing that crappy plugin thing anymore. I figured out what was causing the router error. My routing definition did not have a valid default value for variable 'eventName'. My fix was:
$router->addRoute(
'eventName',
new Zend_Controller_Router_Route(
'/:eventName',
array(
'module' => 'default',
'controller' => 'event',
'action' => 'detail',
'eventName' => ''
)
)
);
I am still unable to create routes with "conflicting" patterns, such as /admin and /:eventName. If only there was a way to make /admin override /:eventName...
Routes are applied/matched on a LIFO basis. As the routing docs note:
Note: Reverse Matching
Routes are matched in reverse order so make sure your most generic routes are defined first.
So, in order to have your "static" routes (static, in the sense that they do not pull from the db, /admin and the like) apply over your dynamic ones (/:eventName), make sure you define the static ones later in the execution flow.
In practical terms, this means that you cannot define your static routes during bootstrap, so you'll have to do it in a plugin with a routeStartup hook. Perhaps, two plugins: one for your dynamic routes, then another for the static ones, just make sure that the priority on the plugins is set so that the static ones are added later.
The error you are getting is probably coming from a URL helper call you have in your template. You need to specify the eventName param to this since you've made it required, e.g.:
Something
The answer to your other question depends a bit on whether you have a static, unchanging list of events or non-event URLs. You need to give the router a way to determine whether /foo is an event, or a controller. You do this by either hardcoding the possible events in to your event route, hardcoding routes for your other non-event URLs, or (if your events are dynamic and based on some database content) writing a custom route class for your event route which can do a lookup to see whether a given string is an event.
Since you are using Zend Framework 1.x
Here is the solution which I have added here : How to redirect Error Page and perform Routes in Zend Framework 1.x
Also, to make life easier... here it is:
I am still unable to create routes with "conflicting" patterns, such as /admin and /:eventName. If only there was a way to make /admin override /:eventName...
Once you are on the action which calls your eventName, you can put a check if that == admin, later you can define a re-route by specifying which action needs to be loaded, in that condition itself.
Simple? :)
define the eventName, and even if it's not required, just leave it blank.

Make title string the entire URI for all pages using CodeIgniter

With CodeIgniter I'm trying to create a URL structure that uses a title string as the entire URI; so for example: www.example.com/this-is-a-title-string
I'm pretty confident I need to use the url_title() function in the URL Helper along with the routes.php config folder but I'm stuck bringing it all together.
Where do I define the URI and how is it caught by the routes folder?
Seems to be a straight forward problem but I'm getting stuck creating the URLs end-to-end. What am I missing?
I thought about a catch-all in the routes folder: $route['(.*)'] = "welcome/controller/$1"; ....but how would this work with multiple functions inside a particular controller? ...and maybe it's not even the right way to solve.
You can send all requests to a driver with something like this:
$route['(:any)'] = "welcome/function";
Then use the _remap function to route requests inside the controller.
However, using URL's as you suggest limits the CI functionality. Try something better like www.example.com/article/this-is-a-title-string
$route['article/(:any)'] = "articles/index";
and in article (controller), use _remap...
If you're going to re-route every request, you should extend CI_Router.
The actual implementation depends on what you're doing. If you customize CI_Router, you can do it AFTER the code that checks routes.php, so that you can keep routes.php available for future customization.
If the URI contains the controller, function, and parameters, you can parse it within your extended CI_Router and then continue with the request like normal.
If the URI is arbitrary, then you'll need something (file, db, etc) that maps the URI to the correct controller/function/parameters. Using blog posts as an example, you can search for the URI (aka post-slug in WordPress) in the db and grab the corresponding record. Then forward the request to something like "articles/view/ID".

Categories