getting controller route parameter - kohana

Using Kohana 3.3, I created a tabbed interface and I'm trying to detect which tab is active based on a route parameter.
Testing with 2 urls which look like this: mysite.com/p/mycontroll
and: mysite.com/p/Francis-Lewis/mycontroll
My route looks like this:
Route::set('profile', 'p(/<name>)(/<controller>(/<action>))', array(
'name' => '[\w\-]+',
'controller' => '[a-z]+',
'action' => '(view|edit|save|delete|create|cancel)',
))->defaults(array(
'name' => null,
'directory' => 'profile',
'controller' => 'main',
'action' => 'index',
));
The route itself is working fine, selecting the mycontroll controller.
Here's where the problem comes in.
In the controller:
$this->request->param('controller'); // returns NULL
In the view
<?= Request::current()->param('controller') ?> // returns NULL
After banging my head around for a while, I added a function to the Kohana Request class to return the $_params array to see what was in there.
Here's all it returns:
name => 'Francis Lewis'
Any ideas how to get the current controller?

There is a function for that in in the request object:
$this->request->controller(); // Returns the current controller as a String

If you are absolutely sure that you want the initial controller then you can use the next method:
Request::initial()->controller();
otherwise use this method:
Request::current()->controller();

Related

Yii2 CRUD and Pagination

I am using Yii2 with Pjax for index/gridview listing. using pjax pagination , search all working fine without postback to server.
My problem starts now,
suppose i am on page number 2, i have clicked on edit record of that 2nd page list, i reach to update view, i have done changes and saved, now i am redirected to view , now i clicked on index link from breadcrumbs.
i want to reach to page number 2 of index rather then 1st page.
Traditional process for this is get refereeing page params an append that in breadcrumbs.
But is there any simple approach to this problem where i can write few lines of code and its applied to every where in backend?
Thanks for reading.
For remembering grid filter, pages i use yii2-grid-view-state
If you need to store page only, isn't it quite easy to pass page param into your view url (<model/view>) like <model>/view?id=<id>&page=<page>?
in your index.php view, edit your ActionColumn as follow:
[
'class' => 'yii\grid\ActionColumn',
'urlCreator' => function ($action, $model, $key, $index) {
return \yii\helpers\Url::to([$action, 'id' => $model->id, 'page' => Yii::$app->request->getQueryParam('page', null)]);
},
],
As you can see, I'm getting page param from request url and pass it to models' action buttons (to all buttons, but in your question it would be enough for view button of course)
And when you click to view model, in our Controller we need to get that page value and pass it to our view.php view (in order to place it in breadcrumbs).
Our ModelController:
public function actionView($id, $page = null)
{
return $this->render('view', [
'model' => $this->findModel($id),
'page' => $page,
]);
}
And finally view.php view will get the page value, and populate the index url (if not null):
/* #var $page int */
$this->title = $model->name;
$this->params['breadcrumbs'][] = ['label' => 'Index', 'url' => ['index', 'page' => $page]];
So when you press the Index breadcrumb, it will open the page, where you entered from.
Some advantages againts session implementation (#user1764431 solution):
Each of your tab can return to it's own last page
Simple and stupid solution
Some disadvantages:
If you need to store some filter params, url could stretch very long
Just add following Code in every controller of actionIndex() rest all things will take care
$searchModel = new CentervideosSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
/*Code insertion block begin*/
$params = Yii::$app->request->queryParams;
if (count($params) <= 1)
{
$params = Yii::$app->session['customerparams'];
if(isset(Yii::$app->session['customerparams']['page']))
$_GET['page'] = Yii::$app->session['customerparams']['page'];
if(isset(Yii::$app->session['customerparams']['per-page']))
$_GET['per-page'] = Yii::$app->session['customerparams']['per-page'];
}
else
{
Yii::$app->session['customerparams'] = $params;
}
$dataProvider = $searchModel->search($params);
/*Code insertion block Ends*/

Removing the number of first page in Yii2 Pagination from the URL

For SEO purposes I need to remove the first page number from the URL. i.e I have the following:
example.com/pages/view/1 and example.com/pages/view the two URLs points to the same contents of the view action. I want to make the pagination free from 1 in the URL. i.e first Page link and Page Number 1 should be linked to pages/view.
I tried to deal with the $pagination object like the following:
$pages = new Pagination(['totalCount' => $books['booksCount'], 'pageParam' => 'start', 'defaultPageSize' => 10,]);
$pagingLinks = $pages->getLinks();
$pagingLinks['first'] = '/';
$pages->links = $pagingLinks;
However, the last line causing error:
Setting read-only property: yii\data\Pagination::links
So I have a problem to modify the links property. Is there any other solution to get this task done?!
According to docs you should set yii\data\Pagination::forcePageParam to false by passing it in Pagination constructor
$pages = new Pagination([
'totalCount' => $books['booksCount'],
'pageParam' => 'start',
'defaultPageSize' => 10,
'forcePageParam' => false,
]);
The above answer may works for direct use of Pagination but remain an issue if it was used from another widget such as ListView.
I found the solution from a comment on an issue report on Yii2 repository on github
The solution is just define proper route in config/web.php. Suppose here we have a controller called Suras and we use the ListView widget on its action's view called view. So placing rule array with defaults has value 'page' => 1 will prevent adding the page parameter to the link's URL of the first page. Also notice the first rule 'view/<id:\d+>/1' => 'Error404', is placed in-order to prevent any access to the first page using page=1 parameter, for example, trying to access mysite.com/view/20/1 will invoke 404 error, because there is no controller called Error404.
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
'view/<id:\d+>/1' => 'Error404',
['pattern' => 'view/<id:\d+>/<page:\d+>', 'route' => 'suras/view', 'defaults' => ['page' => 1]],
'view/<id:\d+>/<page:\d+>' => 'suras/view',
'view/<id:\d+>' => 'suras/view',
],
],
],

validation on unbound form field

I have a form with an extra unbound field added using 'property_path' => false.
I would like to have a simple validation on this field and I've found many answers that suggest to use something like
$builder->addValidator(...);
but I've seen that in symfony 2.1 $builder->addValidator is deprecated. Does anyone know what is the correct way to put a validation on an unbound field in Symfony 2.1?
Edit :
I've just made a more complete answer on topic Symfony validate form with mapped false form fields
Original answer
Validating unbound (non mapped) field in a form is not well documented and the fast evolving form and validator components make the few examples obsoletes (for Symfony 2.1.2).
For now I succeed in validated non mapped fields with event listener.
Here is my simplified code :
namespace Dj\TestBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormEvents;
use Dj\TestBundle\Form\EventListener\NewPostListener;
class PostType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('lineNumber', 'choice', array(
'label' => 'How many lines :',
'choices' => array(
3 => '3 lines',
6 => '6 lines'
),
// 'data' => 3, // default value
'expanded' => true,
'mapped' => false
))
->add('body', 'textarea', array(
'label' => 'Your text',
'max_length' => 120));
// this listener will validate form datas
$listener = new NewPostListener;
$builder->addEventListener(FormEvents::POST_BIND, array($listener, 'postBind'));
}
// ... other methods
}
And the event listener :
namespace Dj\TestBundle\Form\EventListener;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormError;
/**
* listener used at Post creation time to validate non mapped fields
*/
class NewPostListener
{
/**
* Validates lineNumber and body length
* #param \Symfony\Component\Form\FormEvent $event
*/
public function postBind(FormEvent $event)
{
$form = $event->getForm();
$data = $event->getData();
if (!isset($data->lineNumber)) {
$msg = 'Please give a correct line number';
$form->get('lineNumber')->addError(new FormError($msg));
}
// ... other validations
}
}
This is how I validate my non mapped fields until I find out how to do this with validators.
I have the same problem from the docs we get this:
The interface FormValidatorInterface was deprecated and will be
removed in Symfony 2.3. If you implemented custom validators using
this interface, you can substitute them by event listeners listening
to the FormEvents::POST_BIND (or any other of the *BIND events). In
case you used the CallbackValidator class, you should now pass the
callback directly to addEventListener.
This suggest to use event listeners but I have not found and example.
https://github.com/symfony/symfony/blob/master/UPGRADE-2.1.md

How to validate a POST of a non standard action in Cake PHP 1.3

Using CakePHP 1.3
I have a controller with a non standard action name - say:
class WidgetsController extends AppController {
function modifyColor($id = null) {
// Some code that modifies the background color of a widget
}
}
and a companion view views/widgets/modifyColor.ctp
The modifyColor template POSTS to the action:
echo $this->Form->create('User',array('url' => array('controller' => 'widgets', 'action' => 'modifyColor')));
I get a 404 on the POST since the CakePHP Security component is trying to validate the form
and I would like to be able to validate the POST.
The only way I can get this to work seems to be to turn off POST validation
if ($this->action == 'modifyColor') {
$this->Security->validatePost = false;
}
This seems a bad solution.
How do I use the Security component on a non standard action?
allowedActions doesn't seem to work
Thanks
Danny
Answering my own question.
A. There is no problem with using any-named actions in CakePHP
B. A conceptual bug with CakePHP related to using the same function for the Form GET and Form POST
On the Form GET I had this:
if (empty($this->data)) {
$this->data = $this->Widget->read(null, $id);
}
The Form itself had some code like this:
echo $this->Form->input('id');
echo $this->formView('Current color', 'CurrentColor');
echo $this->formView('New color', 'NewColor');
echo $this->formView('New background color', 'BackgrdColor');
Which was fine, except that none of these fields appear in the Widget model - and the CakePHP Security component interprets this as a sort of XSRF attack - since it is finding fields in the form that don't belong to the model. That's why:
$this->Security->validatePost = false;
solved the "problem".
The correct solution is simply not to populate $this->data with the model in the controller action and handle the field assignments on the POST:
function modcolor () {
$this->layout = 'app_ui_listview';
if (!empty($this->data)) {
$id = $this->Session->read('Auth.User.id');
$u = $this->Widget->read(null, $id);
// Assign fields from the form to the model....
}
}
the problem is you are trying to pass url and you are trying to pass the controller stuff too.
echo $this->Form->create('Widget', array('controller' => 'widgets', 'action' => 'modifyColor'));
or
echo $this->Form->create('Widget', array('url' => '/widgets/modifyColor'));

CakePHP Searchable Plugin of Neil Crookes

I have a problem with the routing while using the Searchable Plugin of Neil Crookes. When I search for something the URL looks like this:
http://localhost/search/All/sunshine
But now all the other links have the name of the plugin in their URL.
For example this:
$html->link(__('News', true), array('controller'=>'news', 'action'=>'index'));
creates this link url: http://localhost/searchable/news correct would be http://localhost/news
I already have this in app/config/routes.php:
Router::connect('/search/:type/:term/*', array(
'plugin' => 'searchable',
'controller' => 'search_indexes',
'action' => 'index',
));
Any idea how I can get rid of "/searchable/" for my normal app links???
For your normal links created by the Cake link helper you have to add this parameter 'plugin' => null
Example:
$html->link(__('News', true), array('controller'=>'news', 'action'=>'index', 'plugin' => null));

Resources