Right now I am sharing Kohana::Core between many sites on the same server based on this tutorial. I would like to go one step further and share everything (Controllers, Views, Models) except configs and content. Is it possible? I am using 'table_prefix' field in database config to distinguish tables for each sites. I would like to load dynamically database config base on url parameters - I think it should work.
I was thinking about changing routes to:
Route::set('default', '(<site>(/<controller>(/<action>(/<parametr>)))))')
->defaults(array(
'controller' => 'mainpage',
'action' => 'index',
));
But currently I have no idea in which place and how I should check and load appropriate configs.
There are some ways you can do this,
one way:
build a Controller_Base class
put there method before()
in this method grab the <site> param by use $this->request->param('site').
now you can load the config file in switch case or by the <site> param
by set the config name for each site as the <site>
now in every controller you should extends the Controller_Base
put before() method
and in this method use parent::before()
Hope i helped you
I found the best and the most elegant solution. I moved my application to modules directory. It was rather easy. It was necessary to change bootstrap.php to init.php by removing everything except routing. Now I can use all controllers, models and views many times with standard multisite configuration.
Related
I'm trying to set up a routing prefix in cakephp 3 so any URLs starting with /json/ get the prefix key set and I can change the layout accordingly in the app controller. Other than that, they should use the usual controller and action. I have added the following to routes.php
$routes->prefix('json', function($routes) {
$routes->connect(
'/:controller/:action/*',
[],
['routeClass' => 'InflectedRoute']
);
});
I want to direct all requests with json as first url segment to controller specified in second url segment. e.g. /json/users/add_account_type/ goes to users controller. However when accessing this URL I get the message:
Error: Create the class UsersController below in file:
src/Controller/Json/UsersController.php
whereas I want it to be using
src/Controller/UsersController.php
I think this should be possible but I can't quite see what I'm doing wrong when consulting the book. Have partly based my code on: CakePHP3.x controller name in url when using prefix routing
Thanks a lot in advance
That's simply how prefix routing now works in 3.x, as explained in the docs, prefixes are being mapped to subnamespaces, and thus to separate controllers in subfolders.
http://book.cakephp.org/3.0/en/development/routing.html#prefix-routing
If you'd wanted to change that behavior (I don't really see why), one way would be to implement a custom ControllerFactory dispatcher filter.
http://book.cakephp.org/3.0/en/development/dispatch-filters.html
On a side note, the RequestHandler component supports layout/template switching out of the box, so maybe you should give that a try.
http://book.cakephp.org/3.0/en/controllers/components/request-handling.html
http://book.cakephp.org/3.0/en/views/json-and-xml-views.html
Prefix routing is a way of namespacing parts of your routes to a dedicated controller. It seem that what you want is a scope and not a prefix, for what you describe:
Router::scope('/json', function($routes) {
$routes->fallbacks('InfledtedRoute')
});
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.
Starting from the skeleton application using beta3 how would you resolve the view path for a new module called Foo?
I have added below to the di config and now both modules action's render Foo's views.
'Zend\View\Resolver\TemplatePathStack' => array(
'parameters' => array(
'paths' => array(
'foo' => __DIR__ . '/../view',
),
),
),
I would expect Application\Controller\IndexController::indexAction() to render the views in Application and for Foo\Controller\IndexController::indexAction() to render Foo's views.
Note that questions like this help shape the direction of the stable framework. :)
One idea I've been toying with is to use the module as part of the view script resolution. Right now, the default used is "/"; my proposal is to use "//", as this would help prevent naming conflicts between modules; it also makes it much simpler to understand exactly what view script you are overriding if you use template maps.
You can use this approach today, but it will require manually setting the template on the view models you return from your controllers.
This doesn't currently work in ZF2 as there is no concept of taking the namespace into account when resolving view scripts. Discussions are currently ongoing on how best to tackle this.
For the time being, you have to name each controller differently. In general, we are recommending that you name the "primary" controller within a module after the module name. That is, the primary controller in the Foo module would be FooController.
You actually can do this; and it is not too bad....
Rob Allen himself had a blog post that basically makes this work... Notice you have to basically handle it as a module based loader that separates much of the work out so that we don't have controllers utilizing it: http://pastie.org/3824571
I'm currently looking into CakePHP 2.0 and wanting to convert old 1.3 projects to 2.0. I'm going to start from scratch because there's a whole lot of code in the projects that could be a lot better.
One of those things is the dynamic URLs, the projects multilingual and even the URLs change to the chosen language. Eg:
English: /pages/new-article
Dutch: /paginas/nieuw-artikel
Both would go to PagesController::display();
Note: the URLs can be way longer, pages can have subpages and those will be added to the URL too. Eg: /pages/new-article/article-subpage
Now, the way I did it before is to have a route for everything going to a specific action. Like * going to PagesController::index();
However this seems to slow the apps down and it brings a lot of problems along with it.
So my question to you is, is there a simpler way to do this?
I do not want to hardcode anything, I should be able to change /pages/article to /page/article without needing to change the code.
Note: If you know a way to do it in 1.2 or 1.3, that would also be great, 2.0 isn't that different.
Well i figured it out, apparently CakePHP 1.3 and 2.0 allow you to create custom route classes. It's in the documentation here: http://book.cakephp.org/2.0/en/development/routing.html?highlight=route#custom-route-classes
So basically what you need to do is create a file APP/Lib/Routing/Route/UrlRoute.php with the following contents:
class UrlRoute extends CakeRoute{
public function parse($url){
$params = parent::parse($url);
# Here you get the controller and action from a database.
// tmp
$params['controller'] = 'pages';
$params['action'] = 'index';
return $params;
}
}
And in your APP/Config/routes.php you put the following:
App::import('Lib', 'Routing/Route/UrlRoute');
Router::connect('/*', array('controller' => 'tests', 'action' => 'index'), array('routeClass' => 'UrlRoute'));
I think the real challenge is getting the arguments that usually get passed to the functions back to work. func_get_args() now returns everything behind the domain name. And retrieving the URL from the database if you're using extra params. Might have to cache each URL.
In zend framework I register my namespace like this (in application.php):
'autoloaderNamespaces' => array(
'Cms_'
)
And after this - I'd expect that Zend would always check that path in addition to Zend and ZendX paths if unknown class is called. But for some reason this doesn't work with for example view helpers.
I still have to register a separate path for my view helpers even though view helper scripts are named according to Zend coding standards and are located in:
Cms/View/Helper/
And this is how I register helper path in config file:
view' => array(
'charset' => 'UTF-8',
'doctype' => 'XHTML1_TRANSITIONAL',
'helperPath' => array(
'Cms_View_Helper_' => 'Cms/View/Helper'
)
),
So - I'm not sure why I have to register "Cms" namespace twice first through 'autoloaderNamespaces' and then through View "helperPath"? Shouldn't Cms namespace include Cms/View/Helper namespace?
can someone plz clarify this:)
View Helpers are considered application specific, so in the Recommended Project Directory Structure View Helpers are supposed to be placed in application/views/helpers. Which means, they usually wouldn't be found if ZF would just resolve the conventionalized class name.
When you call helpers with $this->helperName() or $this->getHelper('HelperName') from the View, the View will use the PluginLoader with the configured prefix and path to fetch that helper and inject the current View Instance. See sourcecode for all the details:
http://framework.zend.com/svn/framework/standard/trunk/library/Zend/View/Abstract.php
http://framework.zend.com/svn/framework/standard/trunk/library/Zend/Loader/PluginLoader.php
So in other words, when loading a ViewHelper, you are not using the Autoloader. See:
Loading Plugins in the Zend Framework Reference Guide
This is taken directly from one of my application.ini files.
autoloaderNamespaces.Foo = "Foo"
includePaths.library = APPLICATION_PATH "/../library"
My "Foo" libraries are in the library directory - library/Foo. All I've done up until this point is make the "Foo" library available within the include paths.
I need to add a separate helper path to the default list for my view, otherwise the view won't look in that directory for matching view helpers. I think of loading view helpers as direct discovery. The view needs explicit instructions on where to look for helpers.
I believe it is exactly as you describe, the documentation on custom view helpers is pretty explicit about it:
You may, and should, give the class name a prefix, and it is recommended that you use 'View_Helper' as part of that prefix: "My_View_Helper_SpecialPurpose". (You will need to pass in the prefix, with or without the trailing underscore, to addHelperPath() or setHelperPath()).
This does make some sense to me though. In theory you could build a library of generic view helpers that could be re-used across multiple applications, so binding them to a specific application namespace would be inconvenient, i.e. if all my helpers were prefixed 'MyApp_' I would have to rename them to be able to use them in 'MyOtherApp'.