Yii, controllers in different subfolders - php

I have folder hierarchy
---protected
------...
------controller
---------admin
------------OneController.php
------------TwoController.php
---------user
------------ThreeController.php
------------FourController.php
also i add them in main.php as
'import' => array(
'application.models.*',
'application.forms.*',
'application.components.*',
'application.fetcher.*',
'application.controllers.admin.*',
'application.controllers.user.*', ...
add route for admin
'urlManager' => array(
'showScriptName' => false,
'urlFormat' => 'path',
'rules' => array(
// ...
'admin' => 'admin/one/index',
but this doesn't work, can you help to deal with it? I want do simply routes to subfoldered controllers.

I think your syntax of rule is wrong. Try to use
'rules' => array(
'admin' => 'admin/one/index'
)

I Found solution. My mistake was on controller, I have default (old) OneController in /protected/controllers that's why routes give me 'old' data, when I change name of (old) OneController, trouble gone. And after that route give me new one from /protected/controllers/admin/OneController.
it was like this one
---protected
------...
------controller
---------OneController.php <-- this gives wrong data even error because of routes
---------admin
------------OneController.php
------------TwoController.php
---------user
------------ThreeController.php
------------FourController.php

Related

Yii routing - how to put that controller

I need to perform routing for the following url schemas:
website.com/some-category-name
website.com/some-category-name/entryName
some-category-name will be variable - some name of category
How to configure routing for this? I need to enter previous controllers, for example:
website.com/account
website.com/regiter
and want to everything that does not have controller name (so will be category name) going to controller Category.
I can't work it out.
use
'urlManager' => array(
'urlFormat' => 'path',
'showScriptName' => false,
'rules' => array(
'categoryName/<categoryName:\w+>' => array('site/category'),
'register' => array('site/register'),
'account' => array('site/account')
),
),
At first you must declare all rules for "non Category" actions, and after that dynamic rules (associated with category and antry):
'urlManager' => array(
'urlFormat' => 'path',
'showScriptName' => false,
'rules' => array(
// for example if your account and register actions in user controller
// ... you can write
'account' => 'user/account',
'register' => 'user/register',
// or with one rule
'<action(account|register)>' => 'user/<action>',
// and for all other 'static actions', such as login, logout ...
// after yhat you can declire dynamic rules
'<categoryName:\w+>' => 'category/index',
'<categoryName:\w+>/<entryName:\w+>' => 'category/entry'
),
),
So the code Yii::app()->createUrl('user/register') will generate url website.com/register, and accordingly the url website.com/register "goes to" register action of user controller (all other static rules like this way).
Now dynamic rules: code
Yii::app()->createUrl('category/index', array(
'categoryName' => 'first-category-name'
))
will generate url website.com/first-category-name, and vice versa: the url website.com/first-category-name "goes to" category/index action and in it will be available $_GET['categoryName'] parameter, which will be equal to "second-category-name"․
Accordingly code
Yii::app()->createUrl('category/index', array(
'categoryName' => 'some-category-name',
'entryName' => 'some-entry-name'
))
will generate url website.com/some-category-name/some-entry-name, and in category/entry action you can get $_GET['categoryName'] equal to "some-category-name" and $_GET['entryName'] equal to some-entry-name.
I hope this help you to understand how works rules in Yii.
Thanks!

YII friendly SEO url

I am struggling with this problem and not found any suitable answer.
I want my_site/user/1 to become my_site/user/user_name
My urlManager looks like this:
'urlManager' => array(
'urlFormat' => 'path',
'rules' => array(
'user/<username:\w+>'=>'user/view',
'<controller:\w+>/<id:\d+>'=>'<controller>/view',
'<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
'<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
),
'showScriptName' => false,
),
User Controller:
public function actionView($username)
{
$this->render('view', array(
'model' => $this->loadModel($username),
));
}
When i hit /user/admin it redirects me to actionView not to the actionAdmin from my controller and i have multiple such actions like create, delete and so on.
How can i avoid this? Is there an alternative?
Thanks.
The urlManager try's to match the url to a controller and action.
the 1st part of
'user/<username:\w+>'=>'user/view',
has matched to the user controller and the next part it looking for any string that consists of words, then sent the user to user/view
I recommend changing user/<username> to manage-user/<username> or my-account/<username>, something like that.

Allowing only clean URLs in Yii

I have configured the CUrlManager in the config/main.php to use clean URL:
'urlManager' => array(
'showScriptName' => FALSE,
'urlFormat' => 'path',
'rules' => require(dirname(__FILE__) . '/routes.php'),
),
The clean URL function works perfectly, but I would like to prevent the default <controller>/<action> pattern match to occur.
This is my config/route.php:
<?php
return array(
'books' => 'book/index'
);
Now people can go to the same book page by 2 different URLs:
http://www.mysite.com/books
http://www.mysite.com/book/index
I want to disable the second URL pattern. Is this possible?
You can enable useStrictParsing in your url manager component.

Zend Framework 2 - Why i can't override MvcEvent's MatchRoute?

i would like to match all requests where user is unlogged to controller Admin\Controller\Sign and action in. I wrote this code in onBootstrap() method in Module.php file :
if (!$authService->hasIdentity()) {
$routeMatch = new RouteMatch(
array(
'controller' => 'Admin\Controller\Sign',
'action' => 'in'
)
);
$event->setRouteMatch($routeMatch);
}
I don't get any errors, but code doesn't work, why?
The problem here is that the application route event (MvcEvent::EVENT_ROUTE) is triggered after the (MvcEvent::EVENT_BOOTSTRAP).
Which means even if you're setting the route match at the bootstrap level, the application is going to override it with the route match of the request after the MvcEvent::EVENT_ROUTE.
If you want to avoid this overriding you need to add a listener for the route event with a very low priority to make sure it will not be overridden:
$e->getApplication()->getEventManager()->attach(MvcEvent::EVENT_ROUTE, array($this, 'onRouteEvent'), -1000000);
Note : the onRouteEvent would be the method of your Module class that handles the route event (similar to your code).
If you want to short-circuit your application running at the bootstrap level, what you can do is to send the headers with redirection code to the client:
//get the url of the login page (assuming it has route name 'login')
$url = $e->getRouter()->assemble(array(), array('name' => 'login'));
$response=$e->getResponse();
$response->getHeaders()->addHeaderLine('Location', $url);
$response->setStatusCode(302);
$response->sendHeaders();
add a route entry sign_in as below in the routes section of the module.config.php under admin module
'sign_in' => array(
'type' => 'Segment',
'options' => array(
'route' => '/admin/sign/in',
'defaults' => array(
'controller' => 'sign',
'action' => 'in',
),
),
),
and call the route in the controller like this
$this->redirect()->toRoute('sign_in');

Autoloading custom Zend_Form_Element

I can't get Zend to autoload a custom form element class. I did things exactly as Marcin describes here (except that my classes start with 'Zend' and not 'my' but I'm getting this error:
Warning: include_once(Zend\Form\Element\Div.php) [function.include-once]: failed to open stream: No such file or directory
I have Zend_Form_Element_Div inside forms\elements\ and Zend_View_Helper_FormDiv inside views\helpers\
Basically, every folder in the error message is missng an 's', the right path is Zend\Forms\Elements\Div.php
I also have this in my bootstrap, though I'm not sure if it's necessary, but I'm also using this for my forms and models folder (and some others, but I don't think there's need to post them all):
<?php
$resourceLoader->addResourceTypes(array(
'model' => array(
'namespace' => 'Model',
'path' => 'models'
),
'element' => array(
'namespace' => 'Element',
'path' => 'elements'
),
'form' => array(
'namespace' => 'Form',
'path' => 'forms'
)
));
?>
(Is there actually any other way of doing this autoloading? Instead of declaring every single folder?)
Update:
Element_Div in application/forms/elements/Div.php
In my forms init() method: $this->addElementPrefixPath('Element_', APPLICATION_PATH . '/forms/elements');
Error I'm getting: Fatal error: Class 'Element_Div' not found in C:\xampplite\htdocs\code\application\forms\PostForm.php on line 63
You essentially have to tell the form where to find custom elements by using:
$form->addElementPrefixPath()
In your case, you would use - either within the form's init() or __construct() method - something like:
$this->addElementPrefixPath('Zend_Form_Element_', APPLICATION_PATH . '/elements);;
However, I have agree with #Marcin. Naming your own classes with the Zend_ pseudo-namespace is ill-advised. Either:
Decide on an application namespace and declare it in your Bootstrap when you create your $resourceLoader
Create an custom library that resides on your include path - probably at the same level as the Zend library - and put your custom stuff out there.
Let me know if you need more details on either of these suggestions and I'll fatten up the explanations a bit.
Update based on comments
Using an empty appnamespace, your call to addElementPrefixPath() now changes to:
$this->addElementPrefixPath('Element_', APPLICATION_PATH . '/elements);
And I guess you could remove the elements entry from the $resourceLoader definition in your Bootstrap since it's really not doing anything.
Update 2
I assumed that you were adding the element to the form using the shortname, something like:
$form->addElement('div', 'my_div');
In this circumstance, we need to tell the $form and its plugin registry where to find an element of type 'div'. That's why we dealt with $form->addElementPrefixPath().
However, from the error message you are reporting, it appears that you are adding your custom element to the form using something like:
$div = new Element_Div();
$form->addElement($div, 'my_div');
In this case, it is not the $form and its plugin registry that has to worry about finding/loading/instantiating the custom element; it is the $autoloader via its $resourceLoader. In that case, there is no need for the $form->addElementPrefixPath(), which is essentially a hint to the form on how to find custom elements invoked by shortname.
What we need is to configure the $resourceLoader back in Bootstrap so it knows where to find the class. Assuming you stick with empty appnamespace (so your class is named Element_Div) and you place the file in application/forms/elements/Div.php, then the $resourceLoader call is as follows:
$resourceLoader->addResourceTypes(array(
'model' => array(
'namespace' => 'Model_',
'path' => 'models'
),
'element' => array(
'namespace' => 'Element_',
'path' => 'forms/elements'
),
'form' => array(
'namespace' => 'Form_',
'path' => 'forms'
)
));
That should do it. [Famous last words, eh?]
I prefer creating forms like this:
$form->addElement(new My_Form_Element_Whatever(array(
'name' => 'my_element',
'label' => 'My element',
)));
or
$form->addElement($whatever = new My_Form_Element_Whatever(array(
'name' => 'my_element',
'label' => 'My element',
)));
$whatever->removeDecorator('Errors');
when I need to further modify the element.

Categories