Using slug in CakePHP v3 - cakephp

I plan to upgrade my CakePHP v2 to v3 website. So I start to learn by looking at the Blog tutorial & it work fine.
Next, I start to customize base on my CakePHP v2 site.
The first thing I would like to do is using slug in URL instead of id. I add slug column in database.
But I always get an error when I click the url with the slug. The error is
Notice (8): Undefined property: Cake\ORM\Query::$created [APP/Template/Articles/view.ctp, line 3]
Help on this is greatly appreciated.
This is my routes
$routes->connect('/', ['controller' => 'Articles', 'action' => 'index']);
$routes->connect('/articles/:slug', ['controller' => 'Articles', 'action' => 'view'], ['pass' => ['slug']]);
This is my controller
public function index()
{
$this->set('articles', $this->Articles->find('all'));
}
public function view($slug = null)
{
$article = $this->Articles->findBySlug($slug);
$this->set(compact('article'));
}
This is my index.ctp
<h1>Blog articles</h1>
<table>
<tr>
<th>Id</th>
<th>Title</th>
<th>Created</th>
<th>Slug</th>
</tr>
<?php foreach ($articles as $article): ?>
<tr>
<td><?= $article->id ?></td>
<td>
<?= $this->Html->link($article->title, ['action' => 'view', $article->slug]) ?>
</td>
<td>
<?= $article->created ?>
</td>
<td>
<?= $article->slug ?>
</td>
</tr>
<?php endforeach; ?>

find() method returns a query object. Since you want the single entity that matches that slug, call first() on the query object:
$article = $this->Articles->findBySlug($slug)->first();

Related

Order by in find() cakephp

Table Unit(id, unitNo, summary).
id | unitNo
1 | 23
2 | 25
3 | 22
In UnitsController:
public function index() {
$this->set('units', $this->Unit->find('all'), array(
'order' => array('Unit.unitNo ASC'),
'fields' => array('Unit.id', 'Unit.unitNo'))
);
}
index.ctp
<table>
<tr>
<th>Unit</th>
<th>Summary</th>
</tr>
<!-- Here is where we loop through our $posts array, printing out post info -->
<?php foreach ($units as $unit): ?>
<tr>
<td>
<?php echo $this->Html->link($unit['Unit']['unitNo'], array('controller' => 'units', 'action' => 'view', $unit['Unit']['id']));
?>
</td>
<td><?php echo $unit['Unit']['summary']; ?></td>
</tr>
<?php endforeach; ?>
<?php unset($unit); ?>
</table>
I want to use order unitNo but the result is still ordering by id.
http://s1104.photobucket.com/user/thai92hp/media/Untitled.png.html
Can anyone help me to fix this problem?
Please give this a try:
public function index() {
$this->set('units', $this->Unit->find('all',
array(
'order' => array('Unit.unitNo ASC'),
'fields' => array('Unit.id', 'Unit.unitNo')
)
));
}
It seems to me that you've given your order settings to $this->set() as the third parameter but what you may want to do is to give it to $this->Unit->find() as the second parameter.

how working with view and controller

I'm trying to learn how CakePHP works but i'm stuck, i just want to display the user names . I'm working in the good controller and the good view... I don't understand .
View => Users => index.ctp
<h1>Users List</h1> <table>
<tr>
<th>Username</th>
</tr>
<?php foreach ($users as $k): ?>
<tr>
<td><?php echo $k['username']; ?></td>
</tr>
<?php endforeach; ?>
</table>
Controller => UsersController
<?php
class UsersController extends AppController{
public function index() {
$users = $this->User->find('all',array('fields' => array('id','username','created')));
debug($users);
}
}
?>
With debug, i have what i want but i can't display the result in my table with foreach .
array(
(int) 0 => array(
'User' => array(
'id' => '2',
'username' => 'CREAZ',
'created' => '2014-06-17 23:39:52'
)
),
(int) 1 => array(
'User' => array(
'id' => '3',
'username' => 'test2',
'created' => '2014-06-18 16:57:37'
)
)
)
The errors i get in my view :
Notice (8): Undefined variable: users [APP\View\Users\index.ctp, line 9]
Warning (2): Invalid argument supplied for foreach() [APP\View\Users\index.ctp, line 9]
Notice (8): Undefined variable: users [APP\View\Users\index.ctp, line 13]
Warning (2): Invalid argument supplied for foreach() [APP\View\Users\index.ctp, line 13]
You should set the users variable in the controller first as shown below:
<?php
class UsersController extends AppController{
public function index() {
$users = $this->User->find('all',array('fields' => array('id','username','created')));
debug($users);
$this->set('users', $users);
}
}
?>
and in the view index.ctp, do it like below:
<h1>Users List</h1>
<table>
<tr>
<th>Username</th>
</tr>
<?php foreach ($users as $k): ?>
<tr>
<td><?php echo $k['User']['username']; ?></td>
</tr>
<?php endforeach; ?>
</table>

How to add posts to homepage cakephp?

I'm new to cakephp. So I want to ask you, how to add posts to homepage.
I created posts by this tutorial http://book.cakephp.org/2.0/en/getting-started.html#blog-tutorial
What should I do next?
I tried to google it, but nothing works.
Thanks.
home.ctp
<h1>Blog posts</h1>
<table>
<tr>
<th>Id</th>
<th>Title</th>
<th>Created</th>
</tr>
<!-- Here is where we loop through our $posts array, printing out post info -->
<?php foreach ($posts as $post): ?>
<tr>
<td><?php echo $post['Post']['id']; ?></td>
<td>
<?php echo $this->Html->link($post['Post']['title'],
array('controller' => 'posts', 'action' => 'view', $post['Post']['id'])); ?>
</td>
<td><?php echo $post['Post']['created']; ?></td>
</tr>
<?php endforeach; ?>
<?php unset($post); ?>
</table>
You have to redirect your homepage to the index() of PostsController.
Go to your routes.php file and change this line:
Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
for this one:
Router::connect('/', array('controller' => 'posts', 'action' => 'index'));
(assuming that your index() actually contain a list of all your posts)
Router::connect will catch when an user attempt to go to the url on the first parameter, and will redirect it to the action in the controller on the second parameter

How I can paginate custom array in CakePHP

I want to paginate in view for a custom array. My controller and view code is given below.
Controller Code:
public function admin_detail(){
$totalByDate = $this->Pbscodemetric->find('all',array('fields'=>array('created')));
$createdDate = Set::extract('/Pbscodemetric/created', $totalByDate);
$uniqueCreatedDate = array_unique($createdDate);
$finalArray = array();
foreach($uniqueCreatedDate as $created){
$downloadsArr = $this->Pbscodemetric->find('all',array('fields'=>array('downloads_iphone','downloads_ipad','downloads_android'),'conditions'=>array('created'=>$created)));
$download_iphone = array_sum(Set::extract('/Pbscodemetric/downloads_iphone',$downloadsArr));
$download_ipad = array_sum(Set::extract('/Pbscodemetric/downloads_ipad',$downloadsArr));
$downloads_android = array_sum(Set::extract('/Pbscodemetric/downloads_android',$downloadsArr));
$finalArray[$created] = array(
'downloads_iphone' => $download_iphone,
'downloads_ipad' => $download_ipad,
'downloads_android' => $downloads_android
);
}
$this->set('finalArray',$finalArray);
}
View Code:
<div class="pbscodemetrics index">
<h2><?php echo __('Pbscodemetrics List Detail'); ?></h2>
<table cellpadding="0" cellspacing="0">
<tr>
<th>Date</th>
<th>iPhone</th>
<th>iPad</th>
<th>Android</th>
</tr>
<?php
foreach($finalArray as $key => $final){?>
<tr>
<td><?php echo $key;?></td>
<td><?php echo $final['downloads_iphone'];?></td>
<td><?php echo $final['downloads_ipad'];?></td>
<td><?php echo $final['downloads_android'];?></td>
</tr>
<?php }?>
</table>
</div>
<div class="actions">
<?php echo $this->element('nav');?>
</div>
Now I want to set pagination. I know in CakePHP default pagination needs Model name. But How can I do that for the above code?
Can anyone help me please..
You could implement a custom pagination, see Custom Query Pagination in the Cookbook. However, it looks like what you're doing there could be done using grouping and the SQL SUM function, that way you could then simply use the built-in pagination. Example:
$alias = $this->Pbscodemetric->alias;
$this->Pbscodemetric->virtualFields = array
(
'downloads_iphone_sum' => sprintf('SUM(`%s.downloads_iphone`)', $alias),
'downloads_ipad_sum' => sprintf('SUM(`%s.downloads_ipad`)', $alias),
'downloads_android_sum' => sprintf('SUM(`%s.downloads_android`)', $alias)
);
$this->paginate = array
(
'fields' => array
(
'downloads_iphone_sum',
'downloads_ipad_sum',
'downloads_android_sum',
'created'
),
'group' => 'created',
'order' => array
(
'created' => 'desc'
),
'limit' => 10
);
$data = $this->paginate($alias);
This will give you Paginator helper compatible results with summed downloads_iphone, downloads_ipad and downloads_android columns, grouped by the created column. It uses virtual fields in order to retreive results in the default CakePHP style, ie they will be accessible like this:
<?php foreach($results as $result): ?>
<tr>
<td><?php echo $result['Pbscodemetric']['created'];?></td>
<td><?php echo $result['Pbscodemetric']['downloads_iphone_sum'];?></td>
<td><?php echo $result['Pbscodemetric']['downloads_ipad_sum'];?></td>
<td><?php echo $result['Pbscodemetric']['downloads_android_sum'];?></td>
</tr>
<?php endforeach; ?>

CakePHP 2 How to pass variables through the URL when using pagination?

I have a project in CakePHP application and I want to add pagination to it. I have added pagination to it, but when I click on a page number or go to the next page my application breaks.
The page relies on variables being passed to the controller in order to display the correct data. Here is my code for the view:
<table class="table table-striped">
<thead>
<tr>
<th>Job ID</th>
<th>Date</th>
<th>Site</th>
<th> </th>
</tr>
</thead>
<tbody>
<?php foreach ($data as $jobsheet) { ?>
<tr>
<td>
<?php echo $jobsheet['Jobsheet']['jobnum']; ?>
</td>
<td>
<?php echo date("l, jS F Y", strtotime($jobsheet['Jobsheet']['jobdate'])); ?>
</td>
<td>
<span class="companyname"><strong><?php echo $jobsheet['Siteaddress']['sitename'] ?></strong></span><br />
<?php echo $jobsheet['Siteaddress']['addressline1']; ?>,
<?php echo $jobsheet['Siteaddress']['addressline2']; ?>,
<?php if ( $jobsheet['Siteaddress']['addressline3'] = '') { ?>
<?php echo $jobsheet['Siteaddress']['addressline3']; ?>,
<?php } else { ?>
<?php } ?>
<?php echo $jobsheet['Siteaddress']['city']; ?>,
<?php echo $jobsheet['Siteaddress']['county']; ?>,
<?php echo $jobsheet['Siteaddress']['country']; ?>,
<?php echo $jobsheet['Siteaddress']['postcode']; ?>
</td>
<td><a data-toggle="modal" href="#viewjobsheet<?php echo $jobsheet['Jobsheet']['id']; ?>" onClick="document.getElementById('jbif<?php echo $jobsheet['Jobsheet']['id']; ?>').src='/modal/customers/<?php echo $company['Company']['id']; ?>/jobs/<?php echo $jobsheet['Jobsheet']['id']; ?>/view/';" title="View" class="icon-eye-open"></a>
</td>
</tr>
<?php } ?>
</tbody>
</table>
</div>
</div>
<div class="row">
<div class="controls">
<?php echo $this->Paginator->prev('« Previous', null, null, array('class' => 'disabled')); ?>
<?php echo $this->Paginator->numbers(); ?>
<?php echo $this->Paginator->next('Next »', null, null, array('class' => 'disabled')); ?>
<br />
<br />
<?php echo $this->Paginator->counter(array(
'format' => 'Page {:page} of {:pages}, showing {:current} records out of
{:count} total, starting on record {:start}, ending on {:end}'
));
?>
</div>
</div>
This is the controller:
function index(){
$companyid = $this->params['customer'];
$this->set('companyid', $companyid);
$siteid = $this->params['site'];
$this->loadModel('Jobsheet');
// Job Sheets
$jobsheets = $this->Jobsheet->find('all', array('conditions' => array('Jobsheet.company' => $companyid), 'recursive' => 2, 'order' => 'Jobsheet.jobdate DESC', 'limit' => '10'));
$this->set('jobsheets', $jobsheets);
$this->paginate = array(
'limit' => 10
);
$data = $this->paginate('Jobsheet');
$this->set(compact('data'));
}
While the pagination does work, it ends up loosing the variable and this breaks what I'm trying to do. What am i missing?
One method is to use PaginatorHelper::options (see the API)
For example, say we want to pass the variable $pass between Paginator page changes. So first pass the variable to the View.
public function index() {
$pass = 'testString';
$this->set(compact('pass'));
$this->set('posts', $this->paginate());
}
In the View, we can then add this to the parameters that Paginator passes when changing pages using Paginator::options and the url option.
<?php
$this->Paginator->options(array(
'url' => array(
'pass' => $pass
)
));
?>
So if you moved from page 1 to page 2, the resulting url would be something similar to:
http://localhost/cake/posts/index/pass:testString/page:2
This is also how Paginator passes sort orders and sort keys. So while "pass" in pass:testString can be anything you want, be sure not to use sort, direction, and page.
As long as you are changing pages through the Paginator links, the passed variables will remain. Note that you can access the values of the passed arguments in both the View and the Controller by the property:
$this->passedArgs

Resources