CakePHP 3.8 changing urls generated by Paginator numbers to relative - cakephp

The app has some prefixed routes like so:
Router::scope('/ru', function (RouteBuilder $routes) {
$lang = 2;
$routes->setRouteClass(DashedRoute::class);
$routes->connect('/:slug', ['controller' => 'Pages', 'action' => 'pages', 'lang' => $lang])->setPass(['slug']);
$routes->fallbacks(DashedRoute::class);
});
Page in question: http://localhost:8765/ru/smi-o-nas where there are some pagination links using this method:
<?= $this->Paginator->numbers() ?>
It generates links including matched controller and action:
http://localhost:8765/ru/pages/pages/smi-o-nas?page=2
So is it that routes are not set up correctly, or there is an option to make Paginator generate relative links like this:
http://localhost:8765/ru/smi-o-nas?page=2
Looked at the docs, paginator helper code, but all I came up with is setting Paginator config url, which still does no good.
Using this:
$this->Paginator->setConfig('options.url', ['controller' => 'ru', 'action' => 'smi-o-nas']);
Simply sticks /ro/smi-o-nas/ in the middle for the link:
http://localhost:8765/ru/ru/smi-o-nas/smi-o-nas?page=2
So do I need to set up routes in a different way, or is there an option for relative urls?
Update
I figured out that a relative url would not work for paginator as it will result in urls like "localhost:8765/ru/ru/smi-o-nas/smi-o-nas?page=2?page=3"
Dodgy solution
<?php for($page_number = 1; $page_number <= $this->Paginator->counter("{{pages}}"); $page_number ++):?>
<?php if ($page_number == $this->Paginator->counter("{{page}}")): ?>
<span><?= $page_number ?></span>
<?php else : ?>
<?= $page_number ?>
<?php endif ; ?>
<?php endfor; ?>

Related

How to get CakePHP 2 to keep 'index' in URL when using HTML Helper

In CakePHP 2.x there is a HTML Helper which allows for creating hyperlinks within Views.
If I use this...
<?php
echo $this->Html->link('Navigation',
array('controller' => 'navigations', 'action' => 'foo')
);
?>
... it will generate a URL to /navigations/foo (NavigationsController::foo).
However if I use index as the action
<?php
echo $this->Html->link('Navigation',
array('controller' => 'navigations', 'action' => 'index')
);
?>
The URL becomes /navigations.
I understand about "index" being a default when it comes to webpages. However, I actually need the URL to be /navigations/index, or at the very least have a trailing slash (/navigations/).
Is this possible?
Fix the AJAX URLs instead
With regards to the explanation in your comment, I would argue that the "correct" way of fixing this problem is to use proper root relative URLs for the AJAX calls, as changing the URL structure only cloakes the underlying problem, that is targeting non-unique resources.
Personally I alwas use Router::url() to generate the URLs, either in the specific script files when serving them via PHP, or by writing out configuration in for example the layout, being it globally so that the scripts can access it when needed:
<script>
var config = {
navigationDataUrl: <?php echo json_encode(
Router::url(array('controller' => 'Navigations', 'action' => 'get_data'))
) ?>
};
</script>
or by configuring possibly existing JS objects.
<script>
navigation.dataUrl = <?php echo json_encode(
Router::url(array('controller' => 'Navigations', 'action' => 'get_data'))
) ?>;
</script>
Connect routes with an explicit index part
That being said, for the sake of completion, it is possible to force the index part to not be dropped, by connecting routes that explicitly define that part, as opposed to using the :action route element, like:
Router::connect('/:controller/index', array('action' => 'index'));
which would match/catch URL arrays like yours before they are being handled by CakePHPs default controller index catchall route, which looks like:
Router::connect('/:controller', array('action' => 'index'), array('defaultRoute' => true));
https://github.com/cakephp/cakephp/blob/2.10.6/lib/Cake/Config/routes.php#L72

Cakephp ajax form won't load the right view

I'm just trying to call a function from a form submision (which is also call from ajax).
I want to call the add method but it's the index which always called.
My ajax view with the ajax submission form :
<?php $count = count($files); ?>
<div id="message"></div>
<i><?= __('Nombre de fichiers liés : ') . $count ?></i>
<?= $this->Form->create('FilesManager', array('enctype' => 'multipart/form-data', 'url' => array('action' => 'add'))); ?>
<?= $this->Form->input('file', array('type' => 'file', 'label' => false, 'class' => 'form-control')); ?>
<?= $this->Js->submit('Envoyer', array('update' => '#message', 'div' => false, 'type' => 'json', 'async' => false)); ?>
<?= $this->Js->writeBuffer(); ?>
i've also tried :
<?= $this->Form->create(null, array('enctype' => 'multipart/form-data', 'url' => array('controller' => 'FilesManagers', 'action' => 'add'))); ?>
<?= $this->Form->create('FilesManager/add', array('enctype' => 'multipart/form-data')); ?>
EDIT
$this->Form->create('FilesManager', array('action' => 'add'))
Don't work for me but the form generated look like :
<form action="/agralis/files_managers/add" enctype="multipart/form-data" id="FilesManagerIndexForm" method="post" accept-charset="utf-8">...<input id="submit-838644811" type="submit" value="Envoyer"><script type="text/javascript">
//<![CDATA[
$("#submit-838644811").bind("click", function (event) {$.ajax({async:false, data:$("#submit-838644811").closest("form").serialize(), dataType:"html", success:function (data, textStatus) {$("#message").html(data);}, type:"post", url:"\/agralis\/FilesManagers"});
return false;});
//]]>
</script></form>
I can see that form action look good (when i copy/paste the action in the browser url he found the method) but the url called from the ajax submit button is wrong ! How can I change that ?
The helpers are working independently
The Js helper is not aware of the Form helper, they don't interact with each other, and so the form URL is unknown to the Js helper.
The solution for that problem is rather simple, just look at the docs:
http://book.cakephp.org/2.0/en/core-libraries/helpers/js.html#JsHelper::submit
The submit() method accepts a url option where you can specify a URL in case the default one that is based on the current request doesn't fit you.
$this->Js->submit('Envoyer', array(
'url' => array('action' => 'add')
// ...
));
File uploads are not supported
The next problem that you'll encounter is that the file upload doesn't work. That's not part of the question, but I'll broach the subject.
The Js helper doesn't support generating the required JavaScript to handle file uploads, it would need to make use of the XMLHttpRequest Level 2 (xhr2) functionalities that older browsers are lacking.
You'll have to write custom JavaScript to handle that. Explanations and tutorials regarding that can be found all over the web.

CakePHP pagination custom url

I am trying to implement pagination with custom url, when i try to paginate to the next page i am getting the following error.
The requested address '/adminuser/userlist/page:2' was not found on this server.
Here adminuser is the name of the admin user and userlist is the method to get all the users under this adminuser.
The url will look like this http://domain.com/adminuser/userlist
Here is my code
In view:
<?php $this->paginator->options(array('url' =>
array('path'=>$this->params['path']))); ?>
<div class="pagination">
<ul>
<li class="prevnext disablelink">
<?php echo str_replace('/users/','',$this->paginator->prev('« Prev'));?>
<li>
<?php echo str_replace('/users/','',$this->paginator->numbers());?>
</li>
<li class="prevnext">
<?php echo str_replace('/users/','',$this->paginator->next('Next »'));?>
</ul>
</div>
routes.php
Router::connect('/:sluguser/:action', array('controller' => 'users', 'action' => 'userlist'),array('pass' => array('sluguser')));
For pagination, using the default 'paramType' => 'named' you will need to extend your route to accept also the page parameter (as well as sort and direction). In your routes.php, you can add following:
// Parse only default parameters used for CakePHP's pagination:
Router::connectNamed(false, array('default' => true));
// the route to your controller action and wildcard (*) for the possible named parameter
Router::connect('/:sluguser/:action/*', array('controller' => 'users', 'action' => 'userlist'),array('pass' => array('sluguser')));
Btw. As I have found out recently named parameters are deprecated and totally removed in CakePHP 3.x, so consider using $this->paginate['paramType'] = 'querystring'; instead. Then it will work without those additional routes above.

Disable specific divs in CakePHP based on page selected

I'm new with CakePHP and I need your assistance. I need to display a specific widget which is in the form of a div on a specific page i.e. my homepage and disable on the rest of the pages. Essentially I have been able to specifically display specific divs based on log in status as indicated below:
<?php if (!$this->Session->read('Auth.User.id')): ?>
<div class="register link right <?php if ($active == 'register') echo 'active'; ?>"><?php echo $html->link('Register', array('controller' => 'users', 'action' => 'register')); ?></div>
<div class="login link right <?php if ($active == 'login') echo 'active'; ?>"><?php echo $html->link('Login', array('controller' => 'users', 'action' => 'login')); ?></div>
<?php else: ?>
<div class="logout link right"><?php echo $html->link('Logout', array('controller' => 'users', 'action' => 'logout')); ?></div>
<div class="myaccount link right <?php if ($active == 'myaccount') echo 'active'; ?>"><?php echo $html->link('My account', array('controller' => 'account', 'action' => 'summary')); ?></div>
<?php endif; ?>
I was asking for any help with regards to displaying a specific div based on the selection of my homepage.
The pseudocode below indicates my the line of thinking I'm taking to solve this issue:
<?php if (the selected page is homepage or default.ctp)?>
// set the display property for the desired div to none
<?php else: ?>
// do not set the display property for the desired div to none
<?php endif; ?>
In cakephp you cannot use directly $this->Session->read('Auth.User.id') in your view is bettere to do this into your controller:
$this->set('authUser', $this->Auth->user());
and into your view
if (!$authUser)
{
//not logged
}
else{
//logged
}
And if you wanna check which is the page you can try something like that
echo Router::url($this->last, true);
Is what you want?
In your controller you can define something like:
$this->set('pageName', $pageName);
Then you can do in your view:
$class='';
if($pageName=='homepage') {
$class=' hide';
}
echo $this->Html->div($class, 'your content here');
Also think about why you need a structure of this in your view. Maybe you can just not supply the content if it is not needed to the view? So you make the decision in your controller. That makes most of the time more clean views and the smallest amount of data needed in your view.

CakePHP: creating a dropdown on homepge through an element problem

I try to create a search function on my homepage where the user can limit the search results by country.
It all works in my posts/index controller whereby the country list is automatically retrieved by a find('list).
However, on the homepage, the country dropdown remains empty. Below some code:
I try to retrieve the dropdown by using requestAction (please omit 'requestAction is slow from the comments, thanks)
homesearch.ctp ELEMENT:
<?php $this->requestAction('countries/getCountries');?>
<?php
echo $this->Form->create('Post', array(
'url' => array_merge(array('controller' => 'posts','action' => 'index'), $this->params['pass'])
));
echo $this->Form->input('title', array('div' => false, 'empty' => true, 'label' => false));
echo $this->Form->input('country_id');
echo $this->Form->submit(__('Search', true), array('div' => false));
echo $this->Form->end();
?>
getCountries function in countries controller:
function getCountries(){
$countries = $this->Country->find('list');
$this->set(compact('countries'));
}
Before diving into alternatives (loadmodule('Country') in PagesController etc), I think I am doing something wrong, there is no data flowing back from the requestAction function as debug taught me.
How do you guys wash this cow? Thanks!
... (please omit 'requestAction is slow from the comments, thanks)
For improved performance, replace:
<?php $this->requestAction('countries/getCountries');?>
with:
<?php $this->viewVars['countries'] = ClassRegistry::init('Country')->find('list'); ?>
This approach doesn't generate a second request.
function getCountries(){
$countries = $this->Country->find('list');
if (!empty($this->params['requested'])) {
return $countries;
} else {
$this->set(compact('countries'));
}
}
and in the element: <?php $countries = $this->requestAction('countries/getCountries');?>
man, it's right in the book: http://book.cakephp.org/view/991/requestAction

Resources