Zend Framework 2 DI alias, same controller name in different modules - zend-framework2

I have an application with 3 modules and route configs like below:
admin.domain.tld/[:controller[:/action]] => Admin
rest.domain.tld/[:controller[:/id]] => Rest
domain.tld/[:controller[:/action]] => Site
and set DI alias for all controller in each modules
REST Module DI Alias:
'alias' => array(
'index' => 'Rest\Controller\IndexController',
...
),
Admin Module DI Alias:
'alias' => array(
'index' => 'Admin\Controller\IndexController',
...
),
Site Module DI Alias:
'alias' => array(
'index' => 'Site\Controller\IndexController',
...
),
As you see, some controllers has same name (eg: IndexController), but since zf2 merged config with LIFO behaviour, 'index' alias always from the last added module.
Application Config
'modules' => array('Rest','Admin', 'Site'),
when i access http://admin.domain.tld/ I expect index alias gives Admin\Controller\IndexController but since Site Module (registered last) has same alias for index it gives Site\Controller\IndexController
How to use different DI alias to match same controller name?

Before the new view layer was merged into master, it was required to have aliases for controllers to behave correctly when resolving view scripts. Now this is not required anymore, it is even not recommended anymore to use aliases for controllers. The problem with aliasing is there is one alias for one FQCN, so your problem is directly related to this.
What you need to do is to remove aliases from the DI configuration and use explicit routes instead. The "magic" route [:controller[/:action]] is a bad practice and results in more problems than it can help you. So write some explicit routes and remove the aliases.

Related

Zf2 ScnSocialAuth HybridAuth zfcuser and Routes

Using ZF2 to customise an Entity based on ZfcUser. Trying to use ScnSocialAuth and got a bit of a problem.
The problem is that I am using custom routes ('/account' instead of '/user') and when implementing ScnSocialAuth I cannot get the social code into my custom zfcuser view...?
I have \\view\zfc-user\user\register.php which overrides the zfcuser registration.
I have a customised route:
'account' => array(
'type' => 'Zend\Mvc\Router\Http\Literal',
'options' => array(
'route' => '/account',
),
),
These are my zfc config modification within \my-module\config\module.config.php
'zfcuser' => array(
// telling ZfcUser to use our own class
'user_entity_class' => 'WMember\Entity\WMember',
// telling ZfcUserDoctrineORM to skip the entities it defines
'enable_default_entities' => false,
'table_name' => 'w_member',
'login_redirect_route' => 'account',
),
My global \config\application.config.php
'ScnSocialAuth',
'MyModule1',
'ZfcBase',
'ZfcUser',
'BjyAuthorize',
'GoalioMailService',
'GoalioForgotPassword',
'my-user-module',
Therefore, after all this:
I can see my own extended User registration form by navigating to
/account/register with no Social login links visible
I can see the ScnSocialAuth when navigating to /user/register
a) I cannot create the view in my module to override \vendor\scn-social-auth\user\register.phtml as was done with zfcuser
Please help with getting ScnSocialAuth to work with my custom route setup.
If this is just wrong please let me know as I'm not ZF2 expert. Happy to take 'constructive' criticism.
Saw these posts: How to (correctly) extend ScnSocialAuth\Authentication\Adapter\HybridAuth::authenticate() method?
and this as a result of the above post:
https://github.com/SocalNick/ScnSocialAuth/issues/202
NOTE: still running ZF-2.3* due to PHP 5.3,5.4
Instead of adding a custom route to your config, you need to over-ride the zfcuser route
<?php
// #file MyUserModule/config/module.config.php
return array(
// other config ...
'router' => array(
'routes' => array(
'zfcuser' => array(
'options' => array(
// this is the only change needed to route zfcuser to /account
'route' => '/account',
),
),
),
),
// more config ...
);
The ScnSocialAuth module uses the forward() plugin to render the content from zfcusers register view (and login view iirc), which means it will only ever look at the zfcuser route and completely ignore your custom route. The only way to have it use your custom route would be to replace ScnSocialAuths UserController with your own using identical code but forwarding to your custom route (much more work there, and still the potential to break anything else that expects zfcuser to be the route used)

zf2 website with a single entry-point, no routes/paths in URL

Is it be possible to make a website that doesn't reveal any relative URL's at all?
Say for example, I have a domain name "somedomain.xyz" and I want to route everything through the default route, and I want not to reveal any paths or route structures to the end user.
The end user shall only see the domain name in the browser's address bar, like:
http://somedomain.xyz
or
https://somedomain.xyz.
Any path like
http://somedomain.xyz/index.php
or
http://somedomain.xyz/index or
http://somedomain.xyz/index/index
shall show a 404.
And I don't care about SEO stuff and static pages.
Is that possible with ZF2, and if yes, then how?
similar question: hide module and action name from zf2 routing
Just create a hostname route for subdomain.xyz like so:
'my-route' => array(
'type' => 'Hostname',
'options' => array(
'route' => 'subdomain.xyz',
'defaults' => array(
'controller' => 'MyApp\Controller\TheController',
'action' => 'whatever-action',
),
),
),
see here for a complete solution, with using HTTP POST vars for the routing:
ZF2 routing via post vars

ZF2 Route with Colon Separator

I am working with ZF2 and trying to setup Route configuration that uses a colon separator.
For example, the web address could be www.example.com/namespace:subject and I want to send it to a specific controller, action with the two variables. I am trying to use a Regex since the colon ":" is a special character for segments. Is there a nice way to do this? Here is my route configuration:
'dataReqs' => array(
'type' => 'regex',
'options' => array(
'regex' => '/(?<namespace>[^:]+).(?<subject>[a-zA-Z0-9_-]+)',
'defaults' => array(
'controller' => 'Application\Controller\Data',
'action' => 'get',
),
'spec' => '/%namespace%:%subject%',
),
),
EDIT: I want to use the colon as the prefix:resource format is commonly used in RDF syntax (http://www.w3.org/TR/2007/PR-rdf-sparql-query-20071112/#QSynIRI). For instance, a long uri like http://dbpedia.org/data/Semantic_Web with a #prefix dbp: http://dbpedia.org/resource/ may be referred in a document with dbp:Semantic_Web. So for my Linked Data server I could direct requests and include the prefix (namespace) and the resource name; eg http://myserver.com/dbp:Semantic_Web. While I am using the segment combinations /namespace/resource for now, it would be nice to handle a route with prefix:resource syntax.
Do not use colon in your route. It isn't good practice, because colon is reserved character(see https://www.rfc-editor.org/rfc/rfc3986#section-2.2)
I'm inclined to agree with kormik. Why do you want to specify URL's in that way? What is wrong with the default behavior?
www.example.com/namespace/subject
eg:
www.example.com/somenamespace/10
or even:
www.exmple.com/namespace/namespace/subject/subject
eg
www.example.com/namespace/somenamespace/subject/10
you can easily grab these parameters in the controller like so:
$ns = $this->params()->fromRoute('namespace',0);
$subject = (int) $this->params->fromRoute('subject',0);
You would need to modify the route config also.

Change default controller path in lithium

I'm writing a new version of an API and would like to support legacy versions by having distinct sets of controllers for each version. Within the default "app\controllers" path in Lithium, I would like to have for example "v1" and "v2" paths.
I have tried accomplishing this within the route itself by doing something like:
Router::connect('/{:version}/{:controller}/{:action}{:args}', array(
'controller'=> '\app\controllers\{:version}\{:controller}Controller',
), array());
Then I tried overriding the path in the libraries bootstrap module by doing something like:
if( preg_match('/^\/(v[0-9\.]+)/', $_SERVER['REQUEST_URI'], $match) ) {
Libraries::paths(array(
'controllers' => "controllers\\".$match[1].'\\{:name}Controller',
'models' => "models\\".$match[1]."\\{:name}",
));
}
I spent about a half a day at work searching google and the very sparse lithium docs. I am not sure what release of Lithium we are using as I have stepped into this pre-existing code base.
Thanks for any tips you may have!
In your routes.php file, you should re-configure the Dispatcher default rules with
Dispatcher::config(array('rules' => array(
'v1' => array('controller' => 'app\controllers\v1\{:controller}Controller')
)));
and a continuation route to match /v1/... requests
Router::connect('/v1/{:args}', array('v1' => true), array(
'continue' => true, 'persist' => array('controller', 'v1')
));
You can easily use :version instead of a predefined version number if you need so.

Rails static page routes vs :constraints => { :url => /.+/ } -- pros and cons

I'm creating Page admin setup. Pages may include sub pages and I have a bunch of functionality to create the trailing url strings. Anyways, just wondering what the pros and cons here is. Speed-wise or anything I didn't really consider (aside maybe a bit more/less flexibility with other route matching):
Option 1 -- Match everything to pages:
get ':url' => 'pages#show', :constraints => { :url => /.+/ }
# with #page = Page.find_by_url("/"+params[:url]) in my controller
Option 2 -- Statically map routes to pages, and reload routes after each save
if Page.table_exists? # Otherwise on rake db:migrate this file will be called and throw an error
Page.all.each do |page|
match page.url, :controller => 'pages', :action => 'show', :page_id => page.id
end
end
# Then after pages save it calls MyApp::Application.reload_routes!
Either way may work just as well.. just curious.
Option-1 is superior and will actually work properly regardless of your deployment environment, Option-2 will fail in any non-trivial deployment.
Suppose you have two web server processes, P1 and P2; they may be on the same machine, separate machines, or perhaps in separate VMs on the same machine. Suppose some saves a new page that just happens to go to P1; then P1 will update the database (a shared resource between P1 and P2) and rebuild its routing table. But now P1 has the correct routing information but P2 is stuck with the old one because no one told it that something had changed.
You could set up some polling or broadcast system but that would just be a bunch of pointless complexity when Option-1 will work just fine as-is.
You can use routes constraints:
get ':url' => 'pages#show', :constraints => lambda {|request| Page.all.map(&:url).include?(request.path[1..-1]) }
Can yet to use a "catch all" to "page not found"
get '*not_found' => 'page#not_found'
http://guides.rubyonrails.org/routing.html#advanced-constraints

Resources