Change CakePHP settings for tests - cakephp

The Code
AppController.php
<?php
App::uses('Controller', 'Controller');
class AppController extends Controller {
public $components = array(
'Auth' => array(
'authorize' => array('Controller')
),
'Session'
);
}
PostsController.php
<?php
App::uses('AppController', 'Controller');
class PostsController extends AppController {
public function isAuthorized() {
return $this->Auth->user('role') == 'admin';
}
public function add() {
$this->set('some_var', true);
}
}
PostsControllerTest.php
<?php
App::uses('PostsController', 'Controller');
class PostsControllerTest extends ControllerTestCase {
public function setUp() {
parent::setUp();
CakeSession::write('Auth.User', array(
'id' => 2,
'username' => 'joe_bloggs',
'role' => 'user',
'created' => '2013-05-17 10:00:00',
'modified' => '2013-05-17 10:00:00'
));
}
public function testAddWhileLoggedInAsNonAdminFails() {
$this->testAction('/posts/add/', array('method' => 'get'));
$this->assertTrue($this->vars['some_var']);
}
public function tearDown() {
parent::tearDown();
CakeSession::destroy();
}
}
The Problem
Right now, the "testAddWhileLoggedInAsNonAdminFails" test passes. It should fail. The issue is that redirects do not exit/halt the simulated request.
Partial Solution
I can fix the problem by modifying "AppController.php" and "PostsControllerTest.php" like so:
Modified AppController.php
<?php
App::uses('Controller', 'Controller');
class AppController extends Controller {
public $components = array(
'Auth' => array(
'authorize' => array('Controller'),
// ***** THE FOLLOWING LINE IS NEW *****
'unauthorizedRedirect' => false
),
'Session'
);
}
Modified PostsControllerTest.php
<?php
App::uses('PostsController', 'Controller');
class PostsControllerTest extends ControllerTestCase {
public function setUp() {
parent::setUp();
CakeSession::write('Auth.User', array(
'id' => 2,
'username' => 'joe_bloggs',
'role' => 'user',
'created' => '2013-05-17 10:00:00',
'modified' => '2013-05-17 10:00:00'
));
}
// ***** THE FOLLOWING 3 LINES ARE NEW *****
/**
* #expectedException ForbiddenException
*/
public function testAddWhileLoggedInAsNonAdminFails() {
$this->testAction('/posts/add/', array('method' => 'get'));
}
public function tearDown() {
parent::tearDown();
CakeSession::destroy();
}
}
The problem with this solution is it modifies the behavior of the real website too. I'm looking for a way to set the Auth component's unauthorizedRedirect property to false only when tests are being run. How can I do this?

Changing the behavior of your code to make tests work right is not really a good idea.
The correct answer to this question is that it's not a very good question, and what you really should do is test each function separately.
For the isAuthorized function, you should do:
<?php
class PostsControllerTest extends ControllerTestCase {
public function testIsAuthorized() {
$Posts = $this->generate('Posts');
$user = array('role' => 'admin');
$this->assertTrue($Posts->isAuthorized($user));
$anotherUser = array('role' => 'saboteur');
$this->assertFalse($Posts->isAuthorized($user));
}
public function testAdd() {
$this->testAction('/posts/add/', array('method' => 'get'));
$this->assertTrue($this->vars['some_var']);
}
}
The core concept behind unit testing is breaking down your app into the smallest pieces possible, and testing each in isolation. Once you have your unit tests sorted out, you can work on integration tests that cover more than one function, but many projects never reach that stage, and that's okay. The redirect issue can be interesting to work with, but you can mock out controller::redirect as described in this blog post. It's a bit old but still useful.

Did you check the book? http://book.cakephp.org/2.0/en/development/testing.html#testing-controllers
When testing actions that contain redirect() and other code following
the redirect it is generally a good idea to return when redirecting.
The reason for this, is that redirect() is mocked in testing, and does
not exit like normal. And instead of your code exiting, it will
continue to run code following the redirect.
It exactly describes your problem.
I haven't tested this but try it, the manual says the controller is already mocked when using ControllerTestCase so you should be able to expect it:
$this->controller->expects($this->at(0))
->method('redirect')
->with('/your-expected-input');
Taking a look at the ControllerTestCase class might reveal how the controller is exactly mocked and set up. Alternatively you could just fall back to the regular CakeTestCase and set the controller mocks up by yourself.
Another alternative would be to extend your controller you want to test and override the redirect() method, not calling the parent but setting the first arg to a property like Controller::$redirectUrl. After your action call you can then assertEqual the properties value. But this still requires you to return after the redirect call in your controller. Also this won't work either when using ControllerTestCase because it would mock your overriden method.

Related

In CakePHP 2, how do you tell the Paginator component which model to use?

Given the following working example,
// ProductsController.php
<?php
App::uses('AppController', 'Controller');
class ProductsController extends AppController {
public $helpers = array('Html', 'Form');
public $components = array('Session', 'Paginator');
public $paginate = array(
'limit' => 5
);
public function index() {
$this->Product->recursive = -1;
$this->set('products', $this->paginate());
}
}
?>
What tells Paginator which model to use when it sets the variable? Currently this seems to be automatically using the Products model, but I don't really understand why. Is it just part CakePHP's magic that it selects the model that has the same name as the current controller? And if so, how would I tell Paginator to use some other model? Like if I wanted to also paginate the User model on the same page, how would I implement that?
According to Cakephp2,
$this->paginate() by default works on the current model.
if you want to use other model on the same page you can do like this:
$this->paginate('User');
You can all pass other parameters like:
$this->Paginator->settings = array(
'fields' => array('User.*'),
'order' => array('User.username' => 'asc'),
'limit' => 10,
);
$this->set('users', $this->paginate('User'));
Reference: Pagination
So, after some trial and error, it seems like by default Paginator will just use whatever model is associated with the controller via the naming conventions (the 'User' model is associated with the 'UsersController' controller, and so on).
The first argument of $this->paginate() will accept a different model if you want to use one, for example $this->paginate('Dinglehopper'), but the specified model needs to be available to the controller/action in order for it to work. In order to do that you need $this->loadModel('Dinglehopper'); inside the action where $this->paginate('Dinglehopper') is called.
So in the hypothetical situation where you want to use and paginate the model 'Dinglehopper' inside your 'Products' controller you would do,
// ProductsController.php
<?php
App::uses('AppController', 'Controller');
class ProductsController extends AppController {
public $helpers = array('Html', 'Form');
public $components = array('Session', 'Paginator');
public $paginate = array(
'limit' => 5
);
public function index() {
$this->loadModel('Dinglehopper');
$this->Product->recursive = -1;
$this->set('dinglehoppers', $this->paginate('Dinglehopper'));
}
}
?>
$this->loadModel('Dinglehopper'); makes the model 'Dinglehopper' available to the action, and then $this->paginate('Dinglehopper') returns the paginated Dinglehopper model.

CakePHP 2.x custom "Authentication adapter "LdapAuthorize" was not found

I'm building an application using CakePHP and trying to incorporate a custom authentication object but it does not seem to be able to find it. I get the following error when I try to log in: "Authentication adapter "LdapAuthorize" was not found". I have created the file app/Controller/Component/Auth/LdapAuthorize.php with my code for my authentication. Near the top of "AppController.php" I have
App::uses('LdapAuthroize', 'Controller/Component/Auth/LdapAuthorize');
and within the AppController class I have
public $components = array(
'Session',
'Auth' => array(
'loginRedirect' => array('controller' => 'pendings', 'action' => 'index'),
'logoutRedirect' => array('controller' => 'users', 'action' => 'login'),
'authorize' => array('Controller'),
'authenticate' => array('LdapAuthorize')
)
);
and then in my UsersController.php I have the following login function.
public function login() {
if($this->request->is('post')) {
if($this->Auth->login()) {
// My Login stuff...
}
else
$this->redirect(array('controller'=>'someController', 'action'=>'someAction'));
}
}
If anyone has any idea why it can't seem to load my custom authentication object that would be awesome. Thanks!
I put my custom authentication class inside Controller/Component/Auth. For example, the name of my class is CustomUserAuthenticate and the path to the file is,
Controller/Component/Auth/CustomUserAuthenticate.php.
Then in my AppController I added the following to the authenticate array,
class AppController extends Controller {
public $components = array(
'Auth' => array(
/** Any other configuration like redirects can go here */
'authenticate' => array(
'CustomUser'
)
)
);
}
The string in the authenticate array must match the name of the class except for the Authenticate word.
My CustomUserAuthenticate class extends CakePHP's Controller/Component/Auth/BaseAuthenticate and overrides the authenticate method. CakePHP's documentation states that this is not required. I haven't tried that way.
I think your App::uses() is wrong so it can't find the class. Your current code:
App::uses('LdapAuthroize', 'Controller/Component/Auth/LdapAuthorize');
Is trying to find Controller/Component/Auth/LdapAuthorize/LdapAuthroize.php
The first parameter is the class name (you have a typo with that), the second is just the path to the directory containing the class, you don't need to add the class name again.
Try this:
App::uses('LdapAuthorize', 'Controller/Component/Auth');

CakePHP: using a different users table

After setting up the simple Cakephp login concept I would like to let CakePHP use a different table to check the users and the login. I can't figure out how to change the table name within the Auth-component.
Below my basic Controller. How can I let Cakephp know it has to look into a different database table?
class AppController extends Controller {
public $components = array(
'Session',
'Auth'=>array(
'loginRedirect'=>array('controller'=>'users', 'action'=>'index'),
'logoutRedirect'=>array('controller'=>'users', 'action'=>'index'),
'authError'=>"You can't access that page",
'authorize'=>array('Controller')
)
);
public function isAuthorized($user) {
return true;
}
public function beforeFilter() {
//$this->Auth->allow('index', 'view');
$this->set('siteCategory', 'home');
$this->set('logged_in', $this->Auth->loggedIn());
$this->set('current_user', $this->Auth->user());
}
}
Best Solution:
This is something that's done in the User model with the useTable property.
I.e. in app/Model/User.php you should have something like this:
class User extends AppModel {
public $useTable = 'table_name';
//... rest of Model stuff here
}
Alternative:
Alternatively you can specify a different model to be used for the user, although I don't think that's what you're asking for. If I'm wrong there though, just set the userModel value like this:
public $components = array(
'Auth'=>array(
'authenticate'=>array(
'Form' => array('userModel' => 'ADifferentUserModel')
)));

cant understand how this function works $this->Auth->login() in cakephp 2.x

i am new in cakephp. i am making a logging system in cakephp 2.x .. i am stuck here
UsersController.php extending AppController
public function login()
{
if ($this->request->is('post')) {
if ($this->Auth->login()) {
$this->redirect($this->Auth->redirect());
} else {
$this->Session->setFlash('Your email/password combination was incorrect');
}
}
}
the problem is that it is not checking that whether the email and password typed by the user is correct or not..and is logging the user in without checking .. i have never used the auth component before ... so i am feeling hard to grasp that how this function is checking the email and password from the database as on the internet and the cakephp website they are using this function to check whether the user has logged in successfully or not./i always used sql queries but i dont know how this component is working .. please correct this function and explain me where it is checking the email and password from the database
here is my
AppController
class AppController extends Controller {
public $components = array(
'Session',
'Auth'=>array(
'loginRedirect'=>array('controller'=>'users', 'action'=>'admin'),
'logoutRedirect'=>array('controller'=>'users', 'action'=>'admin'),
'authError'=>"You can't access that page",
'authorize'=>array('Controller')
)
);
public function isAuthorized($user) {
}
public function beforeFilter() {
$this->Auth->allow('index');
}
}
class AppController extends Controller {
// added the debug toolkit
// sessions support
// authorization for login and logut redirect
public $components = array(
'Session',
'Cookie',
'Auth' => array(
'authenticate' => array('Form' => array('fields' => array('username' => 'email', 'password' => 'password'),)),
'authorize' => array('Controller'))
);
public function isAuthorized($user) {
return true;
}
}
please replace the co in app controller.

Cakephp Simple Authentication tutorial page not redirecting to current page

I am start going through the cakephp tutorials, I copy the source code exactly as shown in the tutorial.
I have done the Blog tutorial and all seems good, now I am onto the "Simple Authentication and Authorization Application" (http://book.cakephp.org/2.0/en/tutorials-and-examples/blog-auth-example/auth.html) tutorial, but are running into this issue.
The add page loads fine:
".../app/webroot/index.php/Users/add"
After hitting submit, it redirects me to this url (with the additional "Users" string) and with an error message.
".../app/webroot/index.php/Users/Users/add"
Missing Method in UsersController
Error: The action Users is not defined in controller UsersController
Error: Create UsersController::Users() in file: app/Controller/UsersController.php.
class UsersController extends AppController {
public function Users() {
}
}
Let me know where I should start checking, Thanks.
AppController
class AppController extends Controller {
public $components = array(
'Session',
'Auth' => array(
'loginRedirect' => array('controller' => 'posts', 'action' => 'index'),
'logoutRedirect' => array('controller' => 'pages', 'action' => 'display', 'home'),
'authorize' => array('Controller') // Added this line
)
);
public function beforeFilter() {
$this->Auth->allow('index', 'view');
}
public function isAuthorized($user) {
// Admin can access every action
if (isset($user['role']) && $user['role'] === 'admin') {
return true;
}
// Default deny
return false;
}
}
Because I still can't comment, I'll tell you here and edit this answer if I know it.
Show me your AuthComponent configuration in AppController.php.
EDIT:
Answer is in the comments below. :)

Resources