CakePHP
XML Views in CakePHP
In this article, we are going to discuss about how to return XML response to views in CakePHP. CakePHP is an open source web application framework. It follows the Model-View-Controller (MVC) approach and is written in PHP, modeled after the concepts of Ruby on Rails, and distributed under the MIT License.CakePHP uses well-known software engineering concepts and software design patterns, such as Convention over configuration, Model-View-Controller, Active Record, Association Data Mapping, and Front Controller.
Step 1:
Open the file "app\Config\routes.php" and added the following line:
/**
* Parse XML Routes
*/
Router::parseExtensions('xml');
This enables your Controller actions to start accepting the .xml postfix e.g. http://cakephp_app/controller/action.xml
Step 2:
Enable the RequestHandler component in your Controller like this:
public $components = array('RequestHandler');
Step 3:
Once that's done, you have a few more methods at your disposal to start dealing with XML requests. First create a beforeFilter method in your Controller and add the following:
public function beforeFilter() {
parent::beforeFilter();
// Set XML
if ($this->RequestHandler->isXml()) {
$this->RequestHandler->setContent('xml');
}
}
Step 4:
Once that's done, create the action that you want to use and be sure to add in the respondAs & renderAs methods as the official documentation is a bit flakey with their use:
public function related() {
// Only allow XML requests
if (!$this->RequestHandler->isXml()) {
throw new MethodNotAllowedException();
}
// Set response as XML
$this->RequestHandler->respondAs('xml');
$this->RequestHandler->renderAs($this, 'xml');
}
Step 5:
Using those 2 methods as I was then able to create an xml folder in the corresponding View folder and inside that create my view file e.g. app\View\Uploads\xml\related.ctp
<?xml version="1.0"?>
<people>
<person>
<name>James</name>
</person>
</people>
Now if you visited the page in your browser you should see your XML output as per your View e.g. http://cakephp_app/uploads/related.xml
Wrapping Up
Further to this if you wanted to pass in some parameters to make the Controller action dynamic you can do by using the following e.g. http://cakephp_app/uploads/related/videos/1.xml
The "videos" parameter and the "1" ID will be available in the Controller like this:
// Get passed params
$uploadType = $this->request->params['pass'][0];
$uploadId = $this->request->params['pass'][1];
Step 1:
Open the file "app\Config\routes.php" and added the following line:
/**
* Parse XML Routes
*/
Router::parseExtensions('xml');
This enables your Controller actions to start accepting the .xml postfix e.g. http://cakephp_app/controller/action.xml
Step 2:
Enable the RequestHandler component in your Controller like this:
public $components = array('RequestHandler');
Step 3:
Once that's done, you have a few more methods at your disposal to start dealing with XML requests. First create a beforeFilter method in your Controller and add the following:
public function beforeFilter() {
parent::beforeFilter();
// Set XML
if ($this->RequestHandler->isXml()) {
$this->RequestHandler->setContent('xml');
}
}
Step 4:
Once that's done, create the action that you want to use and be sure to add in the respondAs & renderAs methods as the official documentation is a bit flakey with their use:
public function related() {
// Only allow XML requests
if (!$this->RequestHandler->isXml()) {
throw new MethodNotAllowedException();
}
// Set response as XML
$this->RequestHandler->respondAs('xml');
$this->RequestHandler->renderAs($this, 'xml');
}
Step 5:
Using those 2 methods as I was then able to create an xml folder in the corresponding View folder and inside that create my view file e.g. app\View\Uploads\xml\related.ctp
<?xml version="1.0"?>
<people>
<person>
<name>James</name>
</person>
</people>
Now if you visited the page in your browser you should see your XML output as per your View e.g. http://cakephp_app/uploads/related.xml
Wrapping Up
Further to this if you wanted to pass in some parameters to make the Controller action dynamic you can do by using the following e.g. http://cakephp_app/uploads/related/videos/1.xml
The "videos" parameter and the "1" ID will be available in the Controller like this:
// Get passed params
$uploadType = $this->request->params['pass'][0];
$uploadId = $this->request->params['pass'][1];
PHP CMS Frameworks
October 14, 2015
Read more →
CakePHP
Populate dropdown values in Cakephp using AJAX
In this article, we are going to discuss about How to populate the dropdown values in Cakephp using AJAX. CakePHP is an open source web application framework. It follows the Model-View-Controller (MVC) approach and is written in PHP. CakePHP uses well-known software engineering concepts and software design patterns, such as Convention over configuration, Model-View-Controller, Active Record, Association Data Mapping, and Front Controller.
Step 1 :
Add the below code in your View File where you want to apply the Ajax Dropdown
<div id="zoneDiv"></div>
<script>
$(document).ready(function(){
$('#HotelCountryId').change(function(){
var countryID = $(this).val();
$.ajax({
dataType: "html",
type: "POST",
evalScripts: true,
url: '<?php echo Router::url(array('controller'=>'zones','action'=>'ajaxzone'));?>',
data: ({countryid:countryID}),
success: function (data, textStatus){
$("#zoneDiv").html(data);
}
});
});
});
</script>
Step 2 :
Add the below code in your Controller function from where you want to populate data
public function ajaxzone($id = null) {
// debug($this->request->data['countryid']);exit;
$this->layout = 'ajax';
$id = $this->request->data['countryid'];
if (!$this->Zone->exists($id)) {
throw new NotFoundException(__('Invalid zone'));
}
$options = array('conditions' => array('Zone.country_id' => $id));
$this->set('zones', $this->Zone->find('list', $options));
}
Step 3:
The view file of this function ajaxzone.ctp
<?php
echo $this->Form->input('zone_id', array('class'=>'form-control','placeholder'=>'State'));
?>
Step 1 :
Add the below code in your View File where you want to apply the Ajax Dropdown
<div id="zoneDiv"></div>
<script>
$(document).ready(function(){
$('#HotelCountryId').change(function(){
var countryID = $(this).val();
$.ajax({
dataType: "html",
type: "POST",
evalScripts: true,
url: '<?php echo Router::url(array('controller'=>'zones','action'=>'ajaxzone'));?>',
data: ({countryid:countryID}),
success: function (data, textStatus){
$("#zoneDiv").html(data);
}
});
});
});
</script>
Step 2 :
Add the below code in your Controller function from where you want to populate data
public function ajaxzone($id = null) {
// debug($this->request->data['countryid']);exit;
$this->layout = 'ajax';
$id = $this->request->data['countryid'];
if (!$this->Zone->exists($id)) {
throw new NotFoundException(__('Invalid zone'));
}
$options = array('conditions' => array('Zone.country_id' => $id));
$this->set('zones', $this->Zone->find('list', $options));
}
Step 3:
The view file of this function ajaxzone.ctp
<?php
echo $this->Form->input('zone_id', array('class'=>'form-control','placeholder'=>'State'));
?>
PHP CMS Frameworks
May 17, 2015
Read more →
CakePHP
Create Authentication and Authorization Application in CakePHP
In this article, we are going to discuss about How to create an authentication and authorization application in cakePHP. imagine we wanted to secure the access to certain URLs, based on the logged in user. We also have another requirement, to allow our blog to have multiple authors so each one of them can create their own posts, edit and delete them at will disallowing other authors to make any changes on one's posts.
Creating all users' related code
First, let's create a new table in our blog database to hold our users' data:
CREATE TABLE users (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50),
password VARCHAR(255),
role VARCHAR(20),
created DATETIME DEFAULT NULL,
modified DATETIME DEFAULT NULL
);
We have adhered to the CakePHP conventions in naming tables, but we're also taking advantage of another convention: by using the username and password columns in a users table, CakePHP will be able to auto configure most things for us when implementing the user login.
Next step is to create our User model, responsible for finding, saving and validating any user data:
// app/Model/User.php
App::uses('AppModel', 'Model');
class User extends AppModel {
public $validate = array(
'username' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'A username is required'
)
),
'password' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'A password is required'
)
),
'role' => array(
'valid' => array(
'rule' => array('inList', array('admin', 'author')),
'message' => 'Please enter a valid role',
'allowEmpty' => false
)
)
);
}
Let's also create our UsersController, the following contents correspond to a basic baked UsersController class using the code generation utilities bundled with CakePHP:
// app/Controller/UsersController.php
App::uses('AppController', 'Controller');
class UsersController extends AppController {
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('add');
}
public function index() {
$this->User->recursive = 0;
$this->set('users', $this->paginate());
}
public function view($id = null) {
$this->User->id = $id;
if (!$this->User->exists()) {
throw new NotFoundException(__('Invalid user'));
}
$this->set('user', $this->User->read(null, $id));
}
public function add() {
if ($this->request->is('post')) {
$this->User->create();
if ($this->User->save($this->request->data)) {
$this->Session->setFlash(__('The user has been saved'));
return $this->redirect(array('action' => 'index'));
}
$this->Session->setFlash(
__('The user could not be saved. Please, try again.')
);
}
}
public function edit($id = null) {
$this->User->id = $id;
if (!$this->User->exists()) {
throw new NotFoundException(__('Invalid user'));
}
if ($this->request->is('post') || $this->request->is('put')) {
if ($this->User->save($this->request->data)) {
$this->Session->setFlash(__('The user has been saved'));
return $this->redirect(array('action' => 'index'));
}
$this->Session->setFlash(
__('The user could not be saved. Please, try again.')
);
} else {
$this->request->data = $this->User->read(null, $id);
unset($this->request->data['User']['password']);
}
}
public function delete($id = null) {
// Prior to 2.5 use
// $this->request->onlyAllow('post');
$this->request->allowMethod('post');
$this->User->id = $id;
if (!$this->User->exists()) {
throw new NotFoundException(__('Invalid user'));
}
if ($this->User->delete()) {
$this->Session->setFlash(__('User deleted'));
return $this->redirect(array('action' => 'index'));
}
$this->Session->setFlash(__('User was not deleted'));
return $this->redirect(array('action' => 'index'));
}
}
In the same way we created the views for our blog posts or by using the code generation tool, we implement the views. For the purpose of this tutorial, we will show just the add.ctp:
<!-- app/View/Users/add.ctp -->
<div class="users form">
<?php echo $this->Form->create('User'); ?>
<fieldset>
<legend><?php echo __('Add User'); ?></legend>
<?php echo $this->Form->input('username');
echo $this->Form->input('password');
echo $this->Form->input('role', array(
'options' => array('admin' => 'Admin', 'author' => 'Author')
));
?>
</fieldset>
<?php echo $this->Form->end(__('Submit')); ?>
</div>
Authentication (login and logout)
We're now ready to add our authentication layer. In CakePHP this is handled by the AuthComponent, a class responsible for requiring login for certain actions, handling user sign-in and sign-out, and also authorizing logged in users to the actions they are allowed to reach.
To add this component to your application open your app/Controller/AppController.php file and add the following lines:
// app/Controller/AppController.php
class AppController extends Controller {
//...
public $components = array(
'Session',
'Auth' => array(
'loginRedirect' => array(
'controller' => 'posts',
'action' => 'index'
),
'logoutRedirect' => array(
'controller' => 'pages',
'action' => 'display',
'home'
),
'authenticate' => array(
'Form' => array(
'passwordHasher' => 'Blowfish'
)
)
)
);
public function beforeFilter() {
$this->Auth->allow('index', 'view');
}
//...
}
There is not much to configure, as we used the conventions for the users table. We just set up the URLs that will be loaded after the login and logout actions is performed, in our case to /posts/ and / respectively.
What we did in the beforeFilter function was to tell the AuthComponent to not require a login for all index and view actions, in every controller. We want our visitors to be able to read and list the entries without registering in the site.
Now, we need to be able to register new users, save their username and password, and, more importantly, hash their password so it is not stored as plain text in our database. Let's tell the AuthComponent to let un-authenticated users access the users add function and implement the login and logout action:
// app/Controller/UsersController.php
public function beforeFilter() {
parent::beforeFilter();
// Allow users to register and logout.
$this->Auth->allow('add', 'logout');
}
public function login() {
if ($this->request->is('post')) {
if ($this->Auth->login()) {
return $this->redirect($this->Auth->redirectUrl());
}
$this->Session->setFlash(__('Invalid username or password, try again'));
}
}
public function logout() {
return $this->redirect($this->Auth->logout());
}
Password hashing is not done yet, open your app/Model/User.php model file and add the following:
// app/Model/User.php
App::uses('AppModel', 'Model');
App::uses('BlowfishPasswordHasher', 'Controller/Component/Auth');
class User extends AppModel {
// ...
public function beforeSave($options = array()) {
if (isset($this->data[$this->alias]['password'])) {
$passwordHasher = new BlowfishPasswordHasher();
$this->data[$this->alias]['password'] = $passwordHasher->hash(
$this->data[$this->alias]['password']
);
}
return true;
}
// ...
So, now every time a user is saved, the password is hashed using the BlowfishPasswordHasher class. We're just missing a template view file for the login function. Open up your app/View/Users/login.ctp file and add the following lines:
//app/View/Users/login.ctp
<div class="users form">
<?php echo $this->Session->flash('auth'); ?>
<?php echo $this->Form->create('User'); ?>
<fieldset>
<legend>
<?php echo __('Please enter your username and password'); ?>
</legend>
<?php echo $this->Form->input('username');
echo $this->Form->input('password');
?>
</fieldset>
<?php echo $this->Form->end(__('Login')); ?>
</div>
You can now register a new user by accessing the /users/add URL and log-in with the newly created credentials by going to /users/login URL. Also try to access any other URL that was not explicitly allowed such as /posts/add, you will see that the application automatically redirects you to the login page.
And that's it! It looks too simple to be truth. Let's go back a bit to explain what happened. The beforeFilter function is telling the AuthComponent to not require a login for the add action in addition to the index and view actions that were already allowed in the AppController's beforeFilter function.
The login action calls the $this->Auth->login() function in the AuthComponent, and it works without any further config because we are following conventions as mentioned earlier. That is, having a User model with a username and a password column, and use a form posted to a controller with the user data. This function returns whether the login was successful or not, and in the case it succeeds, then we redirect the user to the configured redirection URL that we used when adding the AuthComponent to our application.
The logout works by just accessing the /users/logout URL and will redirect the user to the configured logoutUrl formerly described. This URL is the result of the AuthComponent::logout() function on success.
Authorization (who's allowed to access what)
As stated before, we are converting this blog into a multi-user authoring tool, and in order to do this, we need to modify the posts table a bit to add the reference to the User model:
ALTER TABLE posts ADD COLUMN user_id INT(11);
Also, a small change in the PostsController is required to store the currently logged in user as a reference for the created post:
// app/Controller/PostsController.php
public function add() {
if ($this->request->is('post')) {
//Added this line
$this->request->data['Post']['user_id'] = $this->Auth->user('id');
if ($this->Post->save($this->request->data)) {
$this->Session->setFlash(__('Your post has been saved.'));
return $this->redirect(array('action' => 'index'));
}
}
}
The user() function provided by the component returns any column from the currently logged in user. We used this method to add the data into the request info that is saved.
Let's secure our app to prevent some authors from editing or deleting the others' posts. Basic rules for our app are that admin users can access every URL, while normal users (the author role) can only access the permitted actions. Open again the AppController class and add a few more options to the Auth config:
// app/Controller/AppController.php
public $components = array(
'Session',
'Auth' => array(
'loginRedirect' => array('controller' => 'posts', 'action' => 'index'),
'logoutRedirect' => array(
'controller' => 'pages',
'action' => 'display',
'home'
),
'authenticate' => array(
'Form' => array(
'passwordHasher' => 'Blowfish'
)
),
'authorize' => array('Controller') // Added this line
)
);
public function isAuthorized($user) {
// Admin can access every action
if (isset($user['role']) && $user['role'] === 'admin') {
return true;
}
// Default deny
return false;
}
We just created a very simple authorization mechanism. In this case the users with role admin will be able to access any URL in the site when logged in, but the rest of them (i.e the role author) can't do anything different from not logged in users.
This is not exactly what we wanted, so we need to supply more rules to our isAuthorized() method. But instead of doing it in AppController, let's delegate each controller to supply those extra rules. The rules we're going to add to PostsController should allow authors to create posts but prevent the edition of posts if the author does not match. Open the file PostsController.php and add the following content:
// app/Controller/PostsController.php
public function isAuthorized($user) {
// All registered users can add posts
if ($this->action === 'add') {
return true;
}
// The owner of a post can edit and delete it
if (in_array($this->action, array('edit', 'delete'))) {
$postId = (int) $this->request->params['pass'][0];
if ($this->Post->isOwnedBy($postId, $user['id'])) {
return true;
}
}
return parent::isAuthorized($user);
}
We're now overriding the AppController's isAuthorized() call and internally checking if the parent class is already authorizing the user. If he isn't, then just allow him to access the add action, and conditionally access edit and delete. A final thing is left to be implemented, to tell whether the user is authorized to edit the post or not, we're calling a isOwnedBy() function in the Post model. It is in general a good practice to move as much logic as possible into models. Let's then implement the function:
// app/Model/Post.php
public function isOwnedBy($post, $user) {
return $this->field('id', array('id' => $post, 'user_id' => $user)) !== false;
}
This concludes our simple authentication and authorization tutorial. For securing the UsersController you can follow the same technique we did for PostsController. You could also be more creative and code something more general in AppController based on your own rules.
Creating all users' related code
First, let's create a new table in our blog database to hold our users' data:
CREATE TABLE users (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50),
password VARCHAR(255),
role VARCHAR(20),
created DATETIME DEFAULT NULL,
modified DATETIME DEFAULT NULL
);
We have adhered to the CakePHP conventions in naming tables, but we're also taking advantage of another convention: by using the username and password columns in a users table, CakePHP will be able to auto configure most things for us when implementing the user login.
Next step is to create our User model, responsible for finding, saving and validating any user data:
// app/Model/User.php
App::uses('AppModel', 'Model');
class User extends AppModel {
public $validate = array(
'username' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'A username is required'
)
),
'password' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'A password is required'
)
),
'role' => array(
'valid' => array(
'rule' => array('inList', array('admin', 'author')),
'message' => 'Please enter a valid role',
'allowEmpty' => false
)
)
);
}
Let's also create our UsersController, the following contents correspond to a basic baked UsersController class using the code generation utilities bundled with CakePHP:
// app/Controller/UsersController.php
App::uses('AppController', 'Controller');
class UsersController extends AppController {
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('add');
}
public function index() {
$this->User->recursive = 0;
$this->set('users', $this->paginate());
}
public function view($id = null) {
$this->User->id = $id;
if (!$this->User->exists()) {
throw new NotFoundException(__('Invalid user'));
}
$this->set('user', $this->User->read(null, $id));
}
public function add() {
if ($this->request->is('post')) {
$this->User->create();
if ($this->User->save($this->request->data)) {
$this->Session->setFlash(__('The user has been saved'));
return $this->redirect(array('action' => 'index'));
}
$this->Session->setFlash(
__('The user could not be saved. Please, try again.')
);
}
}
public function edit($id = null) {
$this->User->id = $id;
if (!$this->User->exists()) {
throw new NotFoundException(__('Invalid user'));
}
if ($this->request->is('post') || $this->request->is('put')) {
if ($this->User->save($this->request->data)) {
$this->Session->setFlash(__('The user has been saved'));
return $this->redirect(array('action' => 'index'));
}
$this->Session->setFlash(
__('The user could not be saved. Please, try again.')
);
} else {
$this->request->data = $this->User->read(null, $id);
unset($this->request->data['User']['password']);
}
}
public function delete($id = null) {
// Prior to 2.5 use
// $this->request->onlyAllow('post');
$this->request->allowMethod('post');
$this->User->id = $id;
if (!$this->User->exists()) {
throw new NotFoundException(__('Invalid user'));
}
if ($this->User->delete()) {
$this->Session->setFlash(__('User deleted'));
return $this->redirect(array('action' => 'index'));
}
$this->Session->setFlash(__('User was not deleted'));
return $this->redirect(array('action' => 'index'));
}
}
In the same way we created the views for our blog posts or by using the code generation tool, we implement the views. For the purpose of this tutorial, we will show just the add.ctp:
<!-- app/View/Users/add.ctp -->
<div class="users form">
<?php echo $this->Form->create('User'); ?>
<fieldset>
<legend><?php echo __('Add User'); ?></legend>
<?php echo $this->Form->input('username');
echo $this->Form->input('password');
echo $this->Form->input('role', array(
'options' => array('admin' => 'Admin', 'author' => 'Author')
));
?>
</fieldset>
<?php echo $this->Form->end(__('Submit')); ?>
</div>
Authentication (login and logout)
We're now ready to add our authentication layer. In CakePHP this is handled by the AuthComponent, a class responsible for requiring login for certain actions, handling user sign-in and sign-out, and also authorizing logged in users to the actions they are allowed to reach.
To add this component to your application open your app/Controller/AppController.php file and add the following lines:
// app/Controller/AppController.php
class AppController extends Controller {
//...
public $components = array(
'Session',
'Auth' => array(
'loginRedirect' => array(
'controller' => 'posts',
'action' => 'index'
),
'logoutRedirect' => array(
'controller' => 'pages',
'action' => 'display',
'home'
),
'authenticate' => array(
'Form' => array(
'passwordHasher' => 'Blowfish'
)
)
)
);
public function beforeFilter() {
$this->Auth->allow('index', 'view');
}
//...
}
There is not much to configure, as we used the conventions for the users table. We just set up the URLs that will be loaded after the login and logout actions is performed, in our case to /posts/ and / respectively.
What we did in the beforeFilter function was to tell the AuthComponent to not require a login for all index and view actions, in every controller. We want our visitors to be able to read and list the entries without registering in the site.
Now, we need to be able to register new users, save their username and password, and, more importantly, hash their password so it is not stored as plain text in our database. Let's tell the AuthComponent to let un-authenticated users access the users add function and implement the login and logout action:
// app/Controller/UsersController.php
public function beforeFilter() {
parent::beforeFilter();
// Allow users to register and logout.
$this->Auth->allow('add', 'logout');
}
public function login() {
if ($this->request->is('post')) {
if ($this->Auth->login()) {
return $this->redirect($this->Auth->redirectUrl());
}
$this->Session->setFlash(__('Invalid username or password, try again'));
}
}
public function logout() {
return $this->redirect($this->Auth->logout());
}
Password hashing is not done yet, open your app/Model/User.php model file and add the following:
// app/Model/User.php
App::uses('AppModel', 'Model');
App::uses('BlowfishPasswordHasher', 'Controller/Component/Auth');
class User extends AppModel {
// ...
public function beforeSave($options = array()) {
if (isset($this->data[$this->alias]['password'])) {
$passwordHasher = new BlowfishPasswordHasher();
$this->data[$this->alias]['password'] = $passwordHasher->hash(
$this->data[$this->alias]['password']
);
}
return true;
}
// ...
So, now every time a user is saved, the password is hashed using the BlowfishPasswordHasher class. We're just missing a template view file for the login function. Open up your app/View/Users/login.ctp file and add the following lines:
//app/View/Users/login.ctp
<div class="users form">
<?php echo $this->Session->flash('auth'); ?>
<?php echo $this->Form->create('User'); ?>
<fieldset>
<legend>
<?php echo __('Please enter your username and password'); ?>
</legend>
<?php echo $this->Form->input('username');
echo $this->Form->input('password');
?>
</fieldset>
<?php echo $this->Form->end(__('Login')); ?>
</div>
You can now register a new user by accessing the /users/add URL and log-in with the newly created credentials by going to /users/login URL. Also try to access any other URL that was not explicitly allowed such as /posts/add, you will see that the application automatically redirects you to the login page.
And that's it! It looks too simple to be truth. Let's go back a bit to explain what happened. The beforeFilter function is telling the AuthComponent to not require a login for the add action in addition to the index and view actions that were already allowed in the AppController's beforeFilter function.
The login action calls the $this->Auth->login() function in the AuthComponent, and it works without any further config because we are following conventions as mentioned earlier. That is, having a User model with a username and a password column, and use a form posted to a controller with the user data. This function returns whether the login was successful or not, and in the case it succeeds, then we redirect the user to the configured redirection URL that we used when adding the AuthComponent to our application.
The logout works by just accessing the /users/logout URL and will redirect the user to the configured logoutUrl formerly described. This URL is the result of the AuthComponent::logout() function on success.
Authorization (who's allowed to access what)
As stated before, we are converting this blog into a multi-user authoring tool, and in order to do this, we need to modify the posts table a bit to add the reference to the User model:
ALTER TABLE posts ADD COLUMN user_id INT(11);
Also, a small change in the PostsController is required to store the currently logged in user as a reference for the created post:
// app/Controller/PostsController.php
public function add() {
if ($this->request->is('post')) {
//Added this line
$this->request->data['Post']['user_id'] = $this->Auth->user('id');
if ($this->Post->save($this->request->data)) {
$this->Session->setFlash(__('Your post has been saved.'));
return $this->redirect(array('action' => 'index'));
}
}
}
The user() function provided by the component returns any column from the currently logged in user. We used this method to add the data into the request info that is saved.
Let's secure our app to prevent some authors from editing or deleting the others' posts. Basic rules for our app are that admin users can access every URL, while normal users (the author role) can only access the permitted actions. Open again the AppController class and add a few more options to the Auth config:
// app/Controller/AppController.php
public $components = array(
'Session',
'Auth' => array(
'loginRedirect' => array('controller' => 'posts', 'action' => 'index'),
'logoutRedirect' => array(
'controller' => 'pages',
'action' => 'display',
'home'
),
'authenticate' => array(
'Form' => array(
'passwordHasher' => 'Blowfish'
)
),
'authorize' => array('Controller') // Added this line
)
);
public function isAuthorized($user) {
// Admin can access every action
if (isset($user['role']) && $user['role'] === 'admin') {
return true;
}
// Default deny
return false;
}
We just created a very simple authorization mechanism. In this case the users with role admin will be able to access any URL in the site when logged in, but the rest of them (i.e the role author) can't do anything different from not logged in users.
This is not exactly what we wanted, so we need to supply more rules to our isAuthorized() method. But instead of doing it in AppController, let's delegate each controller to supply those extra rules. The rules we're going to add to PostsController should allow authors to create posts but prevent the edition of posts if the author does not match. Open the file PostsController.php and add the following content:
// app/Controller/PostsController.php
public function isAuthorized($user) {
// All registered users can add posts
if ($this->action === 'add') {
return true;
}
// The owner of a post can edit and delete it
if (in_array($this->action, array('edit', 'delete'))) {
$postId = (int) $this->request->params['pass'][0];
if ($this->Post->isOwnedBy($postId, $user['id'])) {
return true;
}
}
return parent::isAuthorized($user);
}
We're now overriding the AppController's isAuthorized() call and internally checking if the parent class is already authorizing the user. If he isn't, then just allow him to access the add action, and conditionally access edit and delete. A final thing is left to be implemented, to tell whether the user is authorized to edit the post or not, we're calling a isOwnedBy() function in the Post model. It is in general a good practice to move as much logic as possible into models. Let's then implement the function:
// app/Model/Post.php
public function isOwnedBy($post, $user) {
return $this->field('id', array('id' => $post, 'user_id' => $user)) !== false;
}
This concludes our simple authentication and authorization tutorial. For securing the UsersController you can follow the same technique we did for PostsController. You could also be more creative and code something more general in AppController based on your own rules.
PHP CMS Frameworks
February 25, 2015
Read more →
CakePHP
Cakephp - load view in iFrame
In this article, we are going to discuss about How to load the views in iframe in CakePHP. CakePHP is an open source web application framework. It follows the Model-View-Controller (MVC) approach and is written in PHP. CakePHP uses well-known software engineering concepts and software design patterns, as Convention over configuration, Model-View-Controller, Active Record, Association Data Mapping, and Front Controller.
To use iFrame in cakephp we can set the iFrame tag in layout file. And to change source of iFrame dynamically we use $page variable which load parameters.
Example:
<iframe src="<?=$this->Html->url("/users/$page")?>" width="100%" height="500"> </iframe>
To use iFrame in cakephp we can set the iFrame tag in layout file. And to change source of iFrame dynamically we use $page variable which load parameters.
Example:
<iframe src="<?=$this->Html->url("/users/$page")?>" width="100%" height="500"> </iframe>
PHP CMS Frameworks
January 14, 2015
Read more →
CakePHP
Steps to install DebugKit in CakePHP on Ubuntu 14.04
In this article, we are going to discuss about How to install DebugKit in CakePHP on ubuntu 14.04. CakePHP is an open source web application framework. It follows the Model-View-Controller (MVC) approach and is written in PHP, modeled after the concepts of Ruby on Rails, and distributed under the MIT License.
CakePHP uses well-known software engineering concepts and software design patterns, as Convention over configuration, Model-View-Controller, Active Record, Association Data Mapping, and Front Controller.
Requirements to install DebugKit:
Follow the below steps to install DebugKit in CakePHP on Ubuntu.
Step 1:
Open terminal and first of all install git if not installed already.
$ sudo apt-get install git
Step 2:
Go to app/Plugin folder where DebugKit will be installed.
$ cd /var/www/html/cake/app/Plugin
Now initialize git repository here so that we can clone the DebugKit through GitHub using git.
$ sudo git init
Step 3:
To clone DebugKit type this command:
$ sudo git submodule add https://github.com/cakephp/debug_kit.git
or use this command:
$ sudo git clone https://github.com/cakephp/debug_kit.git
When this process is done then a folder will be created named as debug_kit in Plugin folder. Rename this folder as DebugKit. Type following command to do this:
$ sudo mv debug_kit/ DebugKit
[Note: Make sure you are in the Plugin folder.]
Step 4:
Go to app/Config folder
$ cd /var/www/html/cake/app/Config
$ sudo nano bootstrap.php
Add this line in the file CakePlugin::load('DebugKit'); if not already present.
Press ctrl+x, press y and enter to save file. Refresh localhost/cake page. Now DebugKit is detected.
Step 5:
After this check whether this line is present in core.php file or not Configure::write('debug',2); If it's not present then add this line and save file. Core.php file is present in app/Config. To edit this file type this:
$ sudo nano core.php
Step 6:
Now add DebugKit toolbar. Go to app/Controller folder.
$ cd app/Controller
$ sudo nano AppController.php
Add the red text color line in the empty class AppController which is present at the end of the file.
class AppController extends Controller {
public $components = array('DebugKit.Toolbar');
}
Press ctrl+x, press y and enter to save file. Refresh localhost/cake page. DebugKit toolbar is added at the top right end of the page.
Step 7:
After this go to app/View/Layouts folder to remove sql_dump.
$ cd app/View/Layouts
$ sudo nano default.ctp
Comment the following line present at the end of file embedded in php tags i.e. in between these tags <?php ?>
<?php //echo $this->element('sql_dump'); ?>
Press ctrl+x, press y and enter to save file. Refresh localhost/cake page.
Installation is DONE!!! Hope you get the points and this post is helpful for you. If you have any query then comment on the post. i'll get back to you as soon as possible. All The Best.
CakePHP uses well-known software engineering concepts and software design patterns, as Convention over configuration, Model-View-Controller, Active Record, Association Data Mapping, and Front Controller.
Requirements to install DebugKit:
- CakePHP 2.2.0 or greater.
- PHP 5.3.0 or greater.
Follow the below steps to install DebugKit in CakePHP on Ubuntu.
Step 1:
Open terminal and first of all install git if not installed already.
$ sudo apt-get install git
Step 2:
Go to app/Plugin folder where DebugKit will be installed.
$ cd /var/www/html/cake/app/Plugin
Now initialize git repository here so that we can clone the DebugKit through GitHub using git.
$ sudo git init
Step 3:
To clone DebugKit type this command:
$ sudo git submodule add https://github.com/cakephp/debug_kit.git
or use this command:
$ sudo git clone https://github.com/cakephp/debug_kit.git
When this process is done then a folder will be created named as debug_kit in Plugin folder. Rename this folder as DebugKit. Type following command to do this:
$ sudo mv debug_kit/ DebugKit
[Note: Make sure you are in the Plugin folder.]
Step 4:
Go to app/Config folder
$ cd /var/www/html/cake/app/Config
$ sudo nano bootstrap.php
Add this line in the file CakePlugin::load('DebugKit'); if not already present.
Press ctrl+x, press y and enter to save file. Refresh localhost/cake page. Now DebugKit is detected.
Step 5:
After this check whether this line is present in core.php file or not Configure::write('debug',2); If it's not present then add this line and save file. Core.php file is present in app/Config. To edit this file type this:
$ sudo nano core.php
Step 6:
Now add DebugKit toolbar. Go to app/Controller folder.
$ cd app/Controller
$ sudo nano AppController.php
Add the red text color line in the empty class AppController which is present at the end of the file.
class AppController extends Controller {
public $components = array('DebugKit.Toolbar');
}
Press ctrl+x, press y and enter to save file. Refresh localhost/cake page. DebugKit toolbar is added at the top right end of the page.
Step 7:
After this go to app/View/Layouts folder to remove sql_dump.
$ cd app/View/Layouts
$ sudo nano default.ctp
Comment the following line present at the end of file embedded in php tags i.e. in between these tags <?php ?>
<?php //echo $this->element('sql_dump'); ?>
Press ctrl+x, press y and enter to save file. Refresh localhost/cake page.
Installation is DONE!!! Hope you get the points and this post is helpful for you. If you have any query then comment on the post. i'll get back to you as soon as possible. All The Best.
PHP CMS Frameworks
December 17, 2014
Read more →
CakePHP
Steps to Install CakePHP on Ubuntu 14.04
In thia article, we are going to discuss about How to install CakePHP on Ubuntu 14.04. CakePHP uses well-known software engineering concepts and software design patterns, as Convention over configuration, Model-View-Controller, Active Record, Association Data Mapping, and Front Controller.
Steps are almost same but in Windows we did that using GUI or in Windows Explorer and in Ubuntu we'll do it through terminal or you can say using commands.
Step 1:
Open the command prompt (terminal) and type the following command
cd /var/www/html
Step 2:
Type the below command to download the cakephp.
$ sudo wget https://codeload.github.com/cakephp/cakephp/legacy.zip/2.5.2
where 2.5.2 is the latest stable version of CakePHP.
Step 3:
Use the following command to unzip the downloaded zip file.
$ sudo unzip 2.5.2
Step 4:
Rename extracted folder.
$ mv cakephp-cakephp-736e999/ cake
where cakephp-cakephp-736e999 is the name of extracted folder.
To run CakePHP on browser use this path localhost/cake.
Step 5:
Go to cake folder.
$ cd cake
And change permissions to app/tmp folder.
$ sudo chown -R root:www-data app/tmp
$ sudo chmod -R 775 app/tmp
Step 6:
To make script writable perform these steps:
$ apache2clt -M
If you see mod_rewrite in the list shown then script is writable. If not then to enable it type this command:
$ a2enmod rewrite
Step 7:
Type cd /etc/apache2
$ sudo nano apache2.conf
Set these lines in the file:
<Directory /var/www>
Option Indexes FollowSymlinks
AllowOverride All
Required all granted
</Directory>
Press ctrl+x, then press y and enter to save the file.
Restart apache:
$ sudo service apache2 restart
Step 8:
Now go to app/Config
$ cd /var/www/html/cake/app/Config
$ sudo mv database.php.default default.php
Refresh localhost/cake page. Now database file is detected but still we have to create a database as it will show could not connect to database.
Step 9:
Open localhost/phpmyadmin on browser. Login using your username and password and create a database named as cake. After this edit database.php file.
$ sudo nano database.php
Set host as localhost, username is your phpmyadmin username, password is your phpmyadmin password and database name.
Refresh localhost/cake page. Now database is detected.
Step 10:
To remove the salt and seed error shown on top of the localhost/cake page we have to edit core.php file.
$ sudo nano core.php
Find this section and replace both the strings with any random strings or you can use these strings also.
/* A random string used in security hashing methods. */
Configure::write('Security.salt', 'fvjhdj8fvn85grg73fbrvfn9fjFGfnhvt758nADG');
/* A random numeric string (digits only) used to encrypt/decrypt strings. */
Configure::write('Security.cipherSeed', '55857485748594575784348784787475');
Then press ctrl+x, press y and enter to save file.
Refresh localhost/cake page. And its done.
Steps are almost same but in Windows we did that using GUI or in Windows Explorer and in Ubuntu we'll do it through terminal or you can say using commands.
Step 1:
Open the command prompt (terminal) and type the following command
cd /var/www/html
Step 2:
Type the below command to download the cakephp.
$ sudo wget https://codeload.github.com/cakephp/cakephp/legacy.zip/2.5.2
where 2.5.2 is the latest stable version of CakePHP.
Step 3:
Use the following command to unzip the downloaded zip file.
$ sudo unzip 2.5.2
Step 4:
Rename extracted folder.
$ mv cakephp-cakephp-736e999/ cake
where cakephp-cakephp-736e999 is the name of extracted folder.
To run CakePHP on browser use this path localhost/cake.
Step 5:
Go to cake folder.
$ cd cake
And change permissions to app/tmp folder.
$ sudo chown -R root:www-data app/tmp
$ sudo chmod -R 775 app/tmp
Step 6:
To make script writable perform these steps:
$ apache2clt -M
If you see mod_rewrite in the list shown then script is writable. If not then to enable it type this command:
$ a2enmod rewrite
Step 7:
Type cd /etc/apache2
$ sudo nano apache2.conf
Set these lines in the file:
<Directory /var/www>
Option Indexes FollowSymlinks
AllowOverride All
Required all granted
</Directory>
Press ctrl+x, then press y and enter to save the file.
Restart apache:
$ sudo service apache2 restart
Step 8:
Now go to app/Config
$ cd /var/www/html/cake/app/Config
$ sudo mv database.php.default default.php
Refresh localhost/cake page. Now database file is detected but still we have to create a database as it will show could not connect to database.
Step 9:
Open localhost/phpmyadmin on browser. Login using your username and password and create a database named as cake. After this edit database.php file.
$ sudo nano database.php
Set host as localhost, username is your phpmyadmin username, password is your phpmyadmin password and database name.
Refresh localhost/cake page. Now database is detected.
Step 10:
To remove the salt and seed error shown on top of the localhost/cake page we have to edit core.php file.
$ sudo nano core.php
Find this section and replace both the strings with any random strings or you can use these strings also.
/* A random string used in security hashing methods. */
Configure::write('Security.salt', 'fvjhdj8fvn85grg73fbrvfn9fjFGfnhvt758nADG');
/* A random numeric string (digits only) used to encrypt/decrypt strings. */
Configure::write('Security.cipherSeed', '55857485748594575784348784787475');
Then press ctrl+x, press y and enter to save file.
Refresh localhost/cake page. And its done.
PHP CMS Frameworks
November 20, 2014
Read more →
CakePHP
Simple Cakephp 2.x AuthComponent example
In this article, we are going to discuss about How to create a simple AuthComponent in CakePHP 2.x. To make restricted access level site in cakephp we need to implement AuthComponent in cakephp. To apply AuthComponent in cakephp 2.x is similar like to apply AuthComponent in Cakephp 1.x. I think you know cakephp.
Here I described the Authcomponent implementation system for Cakephp 2.x
Step 1 :
Create a users table like bellow
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL,
`password` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`firstname` varchar(255) NOT NULL,
`lastname` varchar(255) DEFAULT NULL,
`address` text,
`mobile` varchar(255) DEFAULT NULL,
`status` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=utf8
Step 2 :
Create respective UserController, UserModel and view files.
Step 3:
For User Password hashing you need to add the SimplePasswordHasher component in your model table:
// app/Model/User.php
App::uses('AppModel', 'Model');
App::uses('SimplePasswordHasher', 'Controller/Component/Auth');
class User extends AppModel {
// ...
public function beforeSave($options = array()) {
if (isset($this->data[$this->alias]['password'])) {
$passwordHasher = new SimplePasswordHasher();
$this->data[$this->alias]['password'] = $passwordHasher->hash(
$this->data[$this->alias]['password']
);
}
return true;
}
Step 4:
Open your AppController and write the bellow code
// app/Controller/AppController.php
class AppController extends Controller {
public $components = array(
'Session',
'Auth' => array(
'loginRedirect' => array(
'controller' => 'members',
'action' => 'index'
),
'logoutRedirect' => array(
'controller' => 'pages',
'action' => 'display',
'home'
),
'authorize' => array('Controller')
)
);
public function isAuthorized() {
$userDetails = AuthComponent::user();
if($userDetails['group_id'] == 1) return true;
if(!empty($this->permissions[$this->action]))
{
if($this->permissions[$this->action] == '*') return true;
if(in_array($userDetails['group_id'], $this->permissions[$this->action]))
{
return true;
}
}else{
$this->Session->setFlash(__('You are not authorize to access that location.'));
return false;
}
}
}
Step 5:
Go to your user controller and add the following methods:
// app/Controller/UsersController.php
public function beforeFilter() {
parent::beforeFilter();
// Allow all users to register and logout.
$this->Auth->allow('add', 'logout');
}
public function login() {
if ($this->request->is('post')) {
$this->User->set($this->request->data);
if ($this->Auth->login()) {
return $this->redirect($this->Auth->redirect());
}else
{
$this->Session->setFlash('Data Validation Failure', 'default', array('class' => 'cake-error'));
}
}
public function logout() {
return $this->redirect($this->Auth->logout());
}
Step 6:
Create login.ctp file with bellow code:
//app/View/Users/login.ctp
<div class="users form">
<?php echo $this->Session->flash('auth'); ?>
<?php echo $this->Form->create('User'); ?>
<fieldset>
<legend>
<?php echo __('Please enter your username and password'); ?>
</legend>
<?php echo $this->Form->input('username');
echo $this->Form->input('password');
?>
</fieldset>
<?php echo $this->Form->end(__('Login')); ?>
</div>
All done now you can check the AuthComponent action by accessing your application:
Here I described the Authcomponent implementation system for Cakephp 2.x
Step 1 :
Create a users table like bellow
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL,
`password` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`firstname` varchar(255) NOT NULL,
`lastname` varchar(255) DEFAULT NULL,
`address` text,
`mobile` varchar(255) DEFAULT NULL,
`status` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=utf8
Step 2 :
Create respective UserController, UserModel and view files.
Step 3:
For User Password hashing you need to add the SimplePasswordHasher component in your model table:
// app/Model/User.php
App::uses('AppModel', 'Model');
App::uses('SimplePasswordHasher', 'Controller/Component/Auth');
class User extends AppModel {
// ...
public function beforeSave($options = array()) {
if (isset($this->data[$this->alias]['password'])) {
$passwordHasher = new SimplePasswordHasher();
$this->data[$this->alias]['password'] = $passwordHasher->hash(
$this->data[$this->alias]['password']
);
}
return true;
}
Step 4:
Open your AppController and write the bellow code
// app/Controller/AppController.php
class AppController extends Controller {
public $components = array(
'Session',
'Auth' => array(
'loginRedirect' => array(
'controller' => 'members',
'action' => 'index'
),
'logoutRedirect' => array(
'controller' => 'pages',
'action' => 'display',
'home'
),
'authorize' => array('Controller')
)
);
public function isAuthorized() {
$userDetails = AuthComponent::user();
if($userDetails['group_id'] == 1) return true;
if(!empty($this->permissions[$this->action]))
{
if($this->permissions[$this->action] == '*') return true;
if(in_array($userDetails['group_id'], $this->permissions[$this->action]))
{
return true;
}
}else{
$this->Session->setFlash(__('You are not authorize to access that location.'));
return false;
}
}
}
Step 5:
Go to your user controller and add the following methods:
// app/Controller/UsersController.php
public function beforeFilter() {
parent::beforeFilter();
// Allow all users to register and logout.
$this->Auth->allow('add', 'logout');
}
public function login() {
if ($this->request->is('post')) {
$this->User->set($this->request->data);
if ($this->Auth->login()) {
return $this->redirect($this->Auth->redirect());
}else
{
$this->Session->setFlash('Data Validation Failure', 'default', array('class' => 'cake-error'));
}
}
public function logout() {
return $this->redirect($this->Auth->logout());
}
Step 6:
Create login.ctp file with bellow code:
//app/View/Users/login.ctp
<div class="users form">
<?php echo $this->Session->flash('auth'); ?>
<?php echo $this->Form->create('User'); ?>
<fieldset>
<legend>
<?php echo __('Please enter your username and password'); ?>
</legend>
<?php echo $this->Form->input('username');
echo $this->Form->input('password');
?>
</fieldset>
<?php echo $this->Form->end(__('Login')); ?>
</div>
All done now you can check the AuthComponent action by accessing your application:
PHP CMS Frameworks
October 09, 2014
Read more →
CakePHP
Steps to add file download option in Cakephp
In this article, we are going to discuss about How to add file download option in CakePHP. CakePHP is an open source web application framework. It follows the Model-View-Controller (MVC) approach and is written in PHP, modeled after the concepts of Ruby on Rails, and distributed under the MIT License. CakePHP uses well-known software engineering concepts and software design patterns, as Convention over configuration, Model-View-Controller, Active Record, Association Data Mapping, and Front Controller.
To add the file download option in CakePHP, include the below action in your controller, from which controller you want to execute the download
function file_download($file_name = null) {
$this->autoRender = false;
$this->set('fileName', $file_name);
header('Content-Type: application/download');
$url = WWW_ROOT.DS.'fileFolderName'.DS.$file_name;
header("Content-Disposition: attachment; filename=".basename($url));
header("Content-Length: " . filesize($url));
$fp = fopen($url, "r");
fpassthru($fp);
fclose($fp);
}
Now add the following link in your View file from where you want to download the file
echo $this->Html->link(__('Download', true), array('controller' => 'mycontroller','action' => 'pdf_download', $file['file_name']));
/* Here $file['file_name'] is the name of your file. */
To add the file download option in CakePHP, include the below action in your controller, from which controller you want to execute the download
function file_download($file_name = null) {
$this->autoRender = false;
$this->set('fileName', $file_name);
header('Content-Type: application/download');
$url = WWW_ROOT.DS.'fileFolderName'.DS.$file_name;
header("Content-Disposition: attachment; filename=".basename($url));
header("Content-Length: " . filesize($url));
$fp = fopen($url, "r");
fpassthru($fp);
fclose($fp);
}
Now add the following link in your View file from where you want to download the file
echo $this->Html->link(__('Download', true), array('controller' => 'mycontroller','action' => 'pdf_download', $file['file_name']));
/* Here $file['file_name'] is the name of your file. */
PHP CMS Frameworks
September 24, 2014
Read more →
CakePHP
Using the Database for Sessions in CakePHP 1.3.3
In this article, we are going to discuss about How to use database for session in CakePHP version 1.3.3. In CakePHP 1.3.3, I had difficulty in finding the schema for the sessions table without using the command line to generate the table.
Below is the raw SQL, that can be used to create the table. I'm sure it will be useful in future for me so I thought I'd share.
CREATE TABLE `cake_sessions` (
`id` varchar(255) NOT NULL DEFAULT '',
`data` text,
`expires` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
);
Now you just need to modify the core.php file so that the database is used for Sessions instead of the default:
Configure::write('Session.save', 'database');
Update
To create the Sessions table from the console simply navigate to the /cake/console directory in the command line and run:
php cake.php schema create Sessions
Below is the raw SQL, that can be used to create the table. I'm sure it will be useful in future for me so I thought I'd share.
CREATE TABLE `cake_sessions` (
`id` varchar(255) NOT NULL DEFAULT '',
`data` text,
`expires` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
);
Now you just need to modify the core.php file so that the database is used for Sessions instead of the default:
Configure::write('Session.save', 'database');
Update
To create the Sessions table from the console simply navigate to the /cake/console directory in the command line and run:
php cake.php schema create Sessions
PHP CMS Frameworks
August 10, 2014
Read more →
CakePHP
Set Conditions in CakePHP pagination
In this article, we are going to discuss about How to set conditions in CakePHP pagination. CakePHP is an open source web application framework. It follows the Model-View-Controller (MVC) approach and is written in PHP, modeled after the concepts of Ruby on Rails, and distributed under the MIT License. CakePHP uses well-known software engineering concepts and software design patterns, as Convention over configuration, Model-View-Controller, Active Record, Association Data Mapping, and Front Controller.
Pagination is the process of dividing (content) into discrete pages, either electronic pages or printed pages. To get custom result in CakePHP pagination, we can set conditions. To set condition in pagination we can pass it by 'conditions' tag.
Example of set conditions in pagination:
//Ready the conditions array()
$conditions = array();
if(isset($districtID)){
$conditions[] = array('Subscriberpost.district_id' => $districtID);
}
if(isset($categoryID)){
$conditions[] = array('Subscriberpost.service_category_id' => $categoryID);
}
$this->Subscriberpost->recursive = 1;
//Set the conditions for pagination
$this->paginate = array('conditions' => $conditions);
//Pass the pagination value to view file
$this->set('subscriberposts', $this->paginate());
Pagination is the process of dividing (content) into discrete pages, either electronic pages or printed pages. To get custom result in CakePHP pagination, we can set conditions. To set condition in pagination we can pass it by 'conditions' tag.
Example of set conditions in pagination:
//Ready the conditions array()
$conditions = array();
if(isset($districtID)){
$conditions[] = array('Subscriberpost.district_id' => $districtID);
}
if(isset($categoryID)){
$conditions[] = array('Subscriberpost.service_category_id' => $categoryID);
}
$this->Subscriberpost->recursive = 1;
//Set the conditions for pagination
$this->paginate = array('conditions' => $conditions);
//Pass the pagination value to view file
$this->set('subscriberposts', $this->paginate());
PHP CMS Frameworks
June 30, 2014
Read more →
CakePHP
Create an API for TV Show Tracker app in cakephp
In this article, we are going to discuss about How to create an API for TV Show tracker app in cakephp. There is 2 parts to the API, one is the server part on my app and the other is the client which requests information and displays it. As the TV Show Tracker app is built using CakePHP I created an ApiController which deals with all the requests for information.
I have got an episodes method, which processes all the requests for episode information, currently the only action available is last_watched which gets the recently watched episodes for that user.
Below is some sample code so that you know what I'm talking about
<?php
class ApiController extends AppController {
/**
* Get Episode information
* $params[0] = api key
* $params[1] = action (last_watched)
* $params[2] = options (last_watched = limit)
*/
function episodes() {
// get params
$params = $this->params['pass'];
// switch based on action
switch($params[1])
{
/**
* Last Watched
* @param int limit
*/
case 'last_watched':
// get episodes
break;
}
echo json_encode($json);
}
}
For authentication I have created an API key for each user, this is a salted hash and is unique to that User so we know we are only going to return their information. This was easier than I thought and works quite well. All calls are logged so that I know who is using it and if it is being abused.
Using the API
To use the API you will need to query the following URL:
http://www.tvshowtracker.co.uk/api/episodes/API_KEY/last_watched
This will bring back a JSON encoded string with all the Episode & Show information which can then be used in you application. I'm using it on the blog by sending a ajax request to one of my Controller actions, this is then using cURL to request the API URL and bring back any results. This is then passed back to the Javascript file where I loop through the Episodes and display the Show Posters and info.
The PHP code
/**
* Ajax call to TV Show Tracker
*/
public function ajax_tv_show_tracker() {
if(!$this->request->is('ajax')) {
throw new NotFoundException('Action not allowed');
}
if (function_exists('curl_init')) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://www.tvshowtracker.co.uk/api/episodes/API_KEY/last_watched/8");
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$output = curl_exec($ch);
curl_close($ch);
echo $output;
exit;
}
echo json_encode(array('success'=>FALSE));
exit;
}
The Javascript code
(function ($) {
$.ajax({
type: "GET",
url: "/posts/ajax_tv_show_tracker",
dataType: "json",
success: function(episodes){
// call was successful
if(episodes.success) {
// build up HTML
var html = '<h3>Recently Watched Shows <span style="font-size:14px;">(tracked with <a href="http://www.tvshowtracker.co.uk" target="_blank">TV Show Tracker</a>)</span></h3><div id="tv_show_tracker" class="row">';
// loop through episodes
$(episodes.episodes).each(function(k,v){
// deal with first & last in row
var class_name = '';
if(k==0) {
class_name = ' alpha';
} else if(episodes.episodes.length==8 && k==3) {
class_name = ' omega';
} else if(k==7) {
class_name = ' omega';
}
// build up episode image & link
html += '<div class="two columns show'+class_name+'">';
html += '<a href="'+v.Show.link+'" target="_blank">';
html += '<img src="'+v.Show.poster.small+'" alt="'+v.Show.name+' Poster" style="width:100%; display:block;"/>';
html += '</a>';
html += '<small>Episode '+v.Episode.season_number+'x'+v.Episode.episode_number+'</small>';
html += '</div>';
});
html += '</div>';
// inject into page
$('.site_images').after(html);
}
}
});
})(jQuery);
I have got an episodes method, which processes all the requests for episode information, currently the only action available is last_watched which gets the recently watched episodes for that user.
Below is some sample code so that you know what I'm talking about
<?php
class ApiController extends AppController {
/**
* Get Episode information
* $params[0] = api key
* $params[1] = action (last_watched)
* $params[2] = options (last_watched = limit)
*/
function episodes() {
// get params
$params = $this->params['pass'];
// switch based on action
switch($params[1])
{
/**
* Last Watched
* @param int limit
*/
case 'last_watched':
// get episodes
break;
}
echo json_encode($json);
}
}
For authentication I have created an API key for each user, this is a salted hash and is unique to that User so we know we are only going to return their information. This was easier than I thought and works quite well. All calls are logged so that I know who is using it and if it is being abused.
Using the API
To use the API you will need to query the following URL:
http://www.tvshowtracker.co.uk/api/episodes/API_KEY/last_watched
This will bring back a JSON encoded string with all the Episode & Show information which can then be used in you application. I'm using it on the blog by sending a ajax request to one of my Controller actions, this is then using cURL to request the API URL and bring back any results. This is then passed back to the Javascript file where I loop through the Episodes and display the Show Posters and info.
The PHP code
/**
* Ajax call to TV Show Tracker
*/
public function ajax_tv_show_tracker() {
if(!$this->request->is('ajax')) {
throw new NotFoundException('Action not allowed');
}
if (function_exists('curl_init')) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://www.tvshowtracker.co.uk/api/episodes/API_KEY/last_watched/8");
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$output = curl_exec($ch);
curl_close($ch);
echo $output;
exit;
}
echo json_encode(array('success'=>FALSE));
exit;
}
The Javascript code
(function ($) {
$.ajax({
type: "GET",
url: "/posts/ajax_tv_show_tracker",
dataType: "json",
success: function(episodes){
// call was successful
if(episodes.success) {
// build up HTML
var html = '<h3>Recently Watched Shows <span style="font-size:14px;">(tracked with <a href="http://www.tvshowtracker.co.uk" target="_blank">TV Show Tracker</a>)</span></h3><div id="tv_show_tracker" class="row">';
// loop through episodes
$(episodes.episodes).each(function(k,v){
// deal with first & last in row
var class_name = '';
if(k==0) {
class_name = ' alpha';
} else if(episodes.episodes.length==8 && k==3) {
class_name = ' omega';
} else if(k==7) {
class_name = ' omega';
}
// build up episode image & link
html += '<div class="two columns show'+class_name+'">';
html += '<a href="'+v.Show.link+'" target="_blank">';
html += '<img src="'+v.Show.poster.small+'" alt="'+v.Show.name+' Poster" style="width:100%; display:block;"/>';
html += '</a>';
html += '<small>Episode '+v.Episode.season_number+'x'+v.Episode.episode_number+'</small>';
html += '</div>';
});
html += '</div>';
// inject into page
$('.site_images').after(html);
}
}
});
})(jQuery);
PHP CMS Frameworks
June 15, 2014
Read more →
CakePHP
Using unBindModel() in CakePHP
In this article, we are going to discuss about How to use unBindModel() in CakePHP and the purpose of using unBindModel() in CakePHP. If you have a lot of associations in your model then it take a lot of time to return result. So to remove the unnecessary model in cakephp. we can use unBindModel(). By using unBindModel we can easily load a page more faster.
Sometimes you don't want all that information to be returned in a query which are associated in a model. The answer to this is to use the unBinModel() function. Using this you can unbind certain parts of your associations. The easiest way to demonstrate this is with an example.
If you have a user model with the following associations:
var $hasMany = array(
'Worksheet' => array('className' => 'Worksheet'
),
'Login' => array('className' => 'Login'
),
'Expense' => array('className' => 'Expense'
)
);
var $belongsTo = array(
'Level' =>
array('className' => 'Level'),
'County' =>
array('className' => 'County'),
'Province' =>
array('className' => 'Province')
);
That is potentially a lot of information with array of [Worksheet,Login,Expense,Level,Country,Province] each time you query the User.
So if we want to unbind Model (Login and Expense) we will write
$this->User->unBindModel(array(hasMany => array('Login', 'Expense')));
and we now call the findAll() function.
$this->User->findAll();
Now the result array will contain the of [User,Worksheet,Level,Country,Province] data.
we no longer return information from the Login and Expenses tables. This can be used for any of the associations and can cut down query times dramatically.
Sometimes you don't want all that information to be returned in a query which are associated in a model. The answer to this is to use the unBinModel() function. Using this you can unbind certain parts of your associations. The easiest way to demonstrate this is with an example.
If you have a user model with the following associations:
var $hasMany = array(
'Worksheet' => array('className' => 'Worksheet'
),
'Login' => array('className' => 'Login'
),
'Expense' => array('className' => 'Expense'
)
);
var $belongsTo = array(
'Level' =>
array('className' => 'Level'),
'County' =>
array('className' => 'County'),
'Province' =>
array('className' => 'Province')
);
That is potentially a lot of information with array of [Worksheet,Login,Expense,Level,Country,Province] each time you query the User.
So if we want to unbind Model (Login and Expense) we will write
$this->User->unBindModel(array(hasMany => array('Login', 'Expense')));
and we now call the findAll() function.
$this->User->findAll();
Now the result array will contain the of [User,Worksheet,Level,Country,Province] data.
we no longer return information from the Login and Expenses tables. This can be used for any of the associations and can cut down query times dramatically.
PHP CMS Frameworks
May 28, 2014
Read more →
CakePHP
CakePHP - Loading Models Inside Other Models
In this article, we are going to discuss about How to load the models inside the another models. A model notifies its associated views and controllers when there has been a change in its state. This notification allows the views to produce updated output, and the controllers to change the available set of commands. In some cases an MVC implementation might instead be "passive," so that other components must poll the model for updates rather than being notified.
This is a really quick help that I'm always looking up is how to load CakePHP Models from within another Model, this is currently using version 2.x.
<?php
// the other model to load & use
App::uses('AnotherModel', 'Model');
class MyModel extends AppModel {
public $name = 'MyModel';
public function test() {
// load the Model
$anotherModel = new AnotherModel();
// use the Model
$anotherModel->save($data);
}
}
Instead of declaring uses at the top you can also import the Model class when you want to use it:
App::import('Model','AnotherModel');
$anotherModel = new AnotherModel();
$anotherModel->save($data);
This is a really quick help that I'm always looking up is how to load CakePHP Models from within another Model, this is currently using version 2.x.
<?php
// the other model to load & use
App::uses('AnotherModel', 'Model');
class MyModel extends AppModel {
public $name = 'MyModel';
public function test() {
// load the Model
$anotherModel = new AnotherModel();
// use the Model
$anotherModel->save($data);
}
}
Instead of declaring uses at the top you can also import the Model class when you want to use it:
App::import('Model','AnotherModel');
$anotherModel = new AnotherModel();
$anotherModel->save($data);
PHP CMS Frameworks
May 14, 2014
Read more →
CakePHP
Create custom Route classes and Pagination in CakePHP
In this article, we are going to discuss about How to create a custom Route classes and pagination in CakePHP. Recently I have faces some issues with the buit-in Paginator Helper when combined with custom routes. I have the site setup so that admins can create Category pages with unique URL slugs so that they can edit pages and also get nice URLs like so:
http://local.example.co.uk/category
http://local.example.co.uk/category/sub-category
I've set this up in CakePHP using a custom Route class as per the docs and this works great. Below I've got the routes.php code to check for a Category slug and use the view action of the ProductCategories Controller.
// app\Config\routes.php file
Router::connect('/:slug/*', array('controller' => 'product_categories', 'action' => 'view'), array('routeClass' => 'CategorySlugRoute'));
This is the Route class code, which is pretty straight forward just in case you need to do anything similar. I've added caching to speed things up and the only caveat are the sub-categories; as these are separated with a forward slash we have to rebuild them to ensure we're checking the slugs for sub categories as well as top level categories.
<?php
/**
* Deal with Category Slugs
*/
App::uses('ProductCategory', 'Model');
class CategorySlugRoute extends CakeRoute {
/**
* Parse the URL
* @param string $url
* @return boolean
*/
function parse($url) {
$params = parent::parse($url);
if (empty($params)) {
return false;
}
// See if slugs are cached
$slugs = Cache::read('slugs_categories');
if (!$slugs) {
// Get all slugs
$ProductCategory = new ProductCategory();
$slugs = $ProductCategory->find('list', array(
'fields' => array('ProductCategory.slug'),
'recursive' => -1
));
Cache::write('slugs_categories', $slugs);
}
// Reverse slugs for easy comparison
$slugs = array_flip($slugs);
// See if sub categories have been passed
if (!empty($params['pass'])) {
$params['slug'] .= '/' . implode('/', $params['pass']);
}
// Match passed slug with Category slugs
if (isset($slugs[$params['slug']])) {
return $params;
}
return FALSE;
}
}
When it came to paginating those result it wasn't clear how to take advantage of the custom slug I was using. I tried a few different solutions however all the generated pagination links all included the /product_categories/view in the URL which is incorrect.
To fix the links I had to pass in the slug as a url Paginator option before the calls to generate the links. After this CakePHP knew what was going on and correctly built the correct URL.
<?php
// app\View\ProductCategories\index.ctp
$this->Paginator->options(array('url' => array('slug' => $category['ProductCategory']['slug'])));
echo $this->Paginator->prev('Prev');
echo $this->Paginator->numbers();
echo $this->Paginator->next('Next');
?>
http://local.example.co.uk/category
http://local.example.co.uk/category/sub-category
I've set this up in CakePHP using a custom Route class as per the docs and this works great. Below I've got the routes.php code to check for a Category slug and use the view action of the ProductCategories Controller.
// app\Config\routes.php file
Router::connect('/:slug/*', array('controller' => 'product_categories', 'action' => 'view'), array('routeClass' => 'CategorySlugRoute'));
This is the Route class code, which is pretty straight forward just in case you need to do anything similar. I've added caching to speed things up and the only caveat are the sub-categories; as these are separated with a forward slash we have to rebuild them to ensure we're checking the slugs for sub categories as well as top level categories.
<?php
/**
* Deal with Category Slugs
*/
App::uses('ProductCategory', 'Model');
class CategorySlugRoute extends CakeRoute {
/**
* Parse the URL
* @param string $url
* @return boolean
*/
function parse($url) {
$params = parent::parse($url);
if (empty($params)) {
return false;
}
// See if slugs are cached
$slugs = Cache::read('slugs_categories');
if (!$slugs) {
// Get all slugs
$ProductCategory = new ProductCategory();
$slugs = $ProductCategory->find('list', array(
'fields' => array('ProductCategory.slug'),
'recursive' => -1
));
Cache::write('slugs_categories', $slugs);
}
// Reverse slugs for easy comparison
$slugs = array_flip($slugs);
// See if sub categories have been passed
if (!empty($params['pass'])) {
$params['slug'] .= '/' . implode('/', $params['pass']);
}
// Match passed slug with Category slugs
if (isset($slugs[$params['slug']])) {
return $params;
}
return FALSE;
}
}
When it came to paginating those result it wasn't clear how to take advantage of the custom slug I was using. I tried a few different solutions however all the generated pagination links all included the /product_categories/view in the URL which is incorrect.
To fix the links I had to pass in the slug as a url Paginator option before the calls to generate the links. After this CakePHP knew what was going on and correctly built the correct URL.
<?php
// app\View\ProductCategories\index.ctp
$this->Paginator->options(array('url' => array('slug' => $category['ProductCategory']['slug'])));
echo $this->Paginator->prev('Prev');
echo $this->Paginator->numbers();
echo $this->Paginator->next('Next');
?>
PHP CMS Frameworks
May 11, 2014
Read more →
CakePHP
Step to use media view in cakephp controller
In this article, we are going to discuss about How to use the Media view in the cakephp controller. In cakephp Media views allow you to send binary files to the user. For example, you may wish to have a directory of files outside of the webroot to prevent users from direct linking them.
You can use the Media view to pull the file from a special folder within /app/, allowing you to perform authentication before delivering the file to the user.
To use the Media view, you need to tell your controller to use the MediaView class instead of the default View class. After that, just pass in additional parameters to specify where your file is located.
class ExampleController extends AppController {
function download () {
$this->view = 'Media';
$params = array(
'id' => 'example.zip',
'name' => 'example',
'download' => true,
'extension' => 'zip', // must be lower case
'path' => APP . 'files' . DS // don't forget terminal 'DS'
);
$this->set($params);
}
}
You can use the Media view to pull the file from a special folder within /app/, allowing you to perform authentication before delivering the file to the user.
To use the Media view, you need to tell your controller to use the MediaView class instead of the default View class. After that, just pass in additional parameters to specify where your file is located.
class ExampleController extends AppController {
function download () {
$this->view = 'Media';
$params = array(
'id' => 'example.zip',
'name' => 'example',
'download' => true,
'extension' => 'zip', // must be lower case
'path' => APP . 'files' . DS // don't forget terminal 'DS'
);
$this->set($params);
}
}
PHP CMS Frameworks
May 04, 2014
Read more →
CakePHP
Easy way to use ajax in cakephp controller action
AJAX is about updating parts of a web page, without reloading the whole page. We need ajax many times to create a dynamic web application. In this article, we are going to discuss about easiest way to use the Ajax in Cakephp controller action. AJAX allows web pages to be updated asynchronously by exchanging small amounts of data with the server behind the scenes. This means that it is possible to update parts of a web page, without reloading the whole page.
In cakephp, to manipulate data by ajax we need to call some controller's action with some parameters, by the following ajax call we can easily pass the parameters to that action.
Example of ajax implementation in cakephp
<script>
$(document).ready(function(){
$.ajax({
dataType: "html",
type: "POST",
evalScripts: true,
url: '<?php echo Router::url(array('controller'=>'admin_employees','action'=>'emp_return'));?>',
data: ({dutylocation:dloc,dutytype:dtype}),
success: function (data, textStatus){
$(".UserInfoDiv").html(data);
}
});
});
</script>
<html>
<div class='UserInfoDiv'></div>
</html>
In cakephp, to manipulate data by ajax we need to call some controller's action with some parameters, by the following ajax call we can easily pass the parameters to that action.
Example of ajax implementation in cakephp
<script>
$(document).ready(function(){
$.ajax({
dataType: "html",
type: "POST",
evalScripts: true,
url: '<?php echo Router::url(array('controller'=>'admin_employees','action'=>'emp_return'));?>',
data: ({dutylocation:dloc,dutytype:dtype}),
success: function (data, textStatus){
$(".UserInfoDiv").html(data);
}
});
});
</script>
<html>
<div class='UserInfoDiv'></div>
</html>
PHP CMS Frameworks
March 05, 2014
Read more →
CakePHP
Steps to check the request type in Cakephp
In this article, we are going to discuss about How to check the request type in Cakephp. In Cakephp, we have many number of request objects. The default request object in Cakephp is "CakeRequest". By default CakeRequest is assigned to $this->request, and is available in Controller, Views and Helpers. By getting the request type, we can do the operations accordingly.
CakeRequest provide many interfaces to access the request parameters.
// Passed arguments
$this->request->pass;
$this->request['pass'];
$this->request->params['pass'];
// named parameters
$this->request->named;
$this->request['named'];
$this->request->params['named'];
CakeRequest provide many interfaces to access the request parameters.
- The first is as object properties,
- Second is array indexes,
- Third is through $this->request->params:
// Passed arguments
$this->request->pass;
$this->request['pass'];
$this->request->params['pass'];
// named parameters
$this->request->named;
$this->request['named'];
$this->request->params['named'];
PHP CMS Frameworks
February 23, 2014
Read more →
CakePHP
Steps to create File Upload Component Cakephp
In this article, we are going to discuss about How to create a file upload component in Cakephp. File upload is a most used component in each and every application. Here we are going to create our own file upload component in Cakephp.
To create a file upload in a form, we need to change the following in our .ctp file.
Step 1 : Create a form
Create a form in Cakephp by using the below code.
echo $this->Form->create('Company',array('type'=>'file'));
Step 2 : Create a file upload field
Use the below code to create file upload field in the form.
echo $this->Form->input('company_logo',array('type'=>'file'));
Changes in the .ctp file is completed. Now open the controller file and add the Resizer component.
App::import('Component', 'Resizer');
Step 3 : Initialize the resizer component
Open the Resizer component file and the below code to initialize the resizer component.
$this->Thumbcontent = new ImageComponent();
Step 4 : Call the resizer function
After initialize the resizer component, call the resizer function, which at a time upload the file to the given folder location and resize the image also.
$this->Thumbcontent->resize($this->data['Company']['company_logo']['tmp_name'], WWW_ROOT.'img'.DS.'company'.DS.$time.'_'.$this->data['Company']['company_logo']['name'],550,550,false,70);
Here,
To create a file upload in a form, we need to change the following in our .ctp file.
Step 1 : Create a form
Create a form in Cakephp by using the below code.
echo $this->Form->create('Company',array('type'=>'file'));
Step 2 : Create a file upload field
Use the below code to create file upload field in the form.
echo $this->Form->input('company_logo',array('type'=>'file'));
Changes in the .ctp file is completed. Now open the controller file and add the Resizer component.
App::import('Component', 'Resizer');
Step 3 : Initialize the resizer component
Open the Resizer component file and the below code to initialize the resizer component.
$this->Thumbcontent = new ImageComponent();
Step 4 : Call the resizer function
After initialize the resizer component, call the resizer function, which at a time upload the file to the given folder location and resize the image also.
$this->Thumbcontent->resize($this->data['Company']['company_logo']['tmp_name'], WWW_ROOT.'img'.DS.'company'.DS.$time.'_'.$this->data['Company']['company_logo']['name'],550,550,false,70);
Here,
- First argument is the file tmp_name which you want to upload,
- Second argument is the location where you want to keep the file,
- Third and forth are the upload image resize with and height,
- Sixth is the water mark true or false and
- Seventh is image quality.
PHP CMS Frameworks
February 09, 2014
Read more →
No more posts to load.
About this blog
PHPCMSFramework.com
Tutorials for WordPress, Laravel, Drupal, Joomla, Symfony & more — including AI-powered PHP guides. Publishing since 2012.
Trending posts
- Building a RAG System in Laravel from Scratch
- Steps to create a Contact Form in Symfony With SwiftMailer
- Build a WhatsApp AI Assistant Using Laravel, Twilio and OpenAI
- CIBB - Basic Forum With Codeigniter and Twitter Bootstrap
- Laravel and Prism PHP: The Modern Way to Work with AI Models
- Build an AI Code Review Bot with Laravel — Real-World Use Case
- Drupal 7 - Create your custom Hello World module
- Symfony Framework - Introduction
- A step by step procedure to develop wordpress plugin
- Create Front End Component in Joomla - Step by step procedure