I'm writing a new application with CakePHP (just-released 1.2.4), using SimpleTest 1.0.1. I have read the relevant sections of the Cookbook, searched on the Bakery, and read Mark Story's postings on controller testing (the hard way and with mocks).
Unfortunately, none of this talks about real-world testing of non-trivial controllers. Lots of apps put areas of the site behind a login, yet I cannot figure out how to test the simple scenario of:
guest access to protected page redirects?
valid credentials sets expected session variables?
invalid credentials re-displays login page with error message?
The controller and test below do not work as I thought they would. Both assertions fail and I also get a PHP error:
FAILED
[NULL] should not be null at [.../app/tests/cases/controllers/users_controller.test.php line 79]
.../app/tests/cases/controllers/users_controller.test.php -> UsersControllerTest -> testLogin
FAILED
Equal expectation fails as [NULL] does not match [Integer: 1] at [.../app/tests/cases/controllers/users_controller.test.php line 80]
.../app/tests/cases/controllers/users_controller.test.php -> UsersControllerTest -> testLogin
ERROR
Unexpected PHP error [Undefined index: action] severity [E_NOTICE] in [.../cake/libs/controller/components/auth.php line 266]
.../app/tests/cases/controllers/users_controller.test.php -> UsersControllerTest -> testLogin
Here is the controller (baked plus Mark Story's "hard way" testing method):
class UsersController extends AppController
{
var $name = 'Users';
var $helpers = array('Html', 'Form');
var $components = array('Auth');
function login()
{
}
function logout()
{
$this->redirect($this->Auth->logout());
}
function index()
{
$this->set('users', $this->paginate());
}
function view($id = null)
{
if (!$id)
{
$this->Session->setFlash(__('Invalid User.', true));
$this->redirect(array('action'=>'index'));
}
$this->set('user', $this->User->read(null, $id));
}
function add()
{
if (!empty($this->data))
{
$this->User->create();
if ($this->User->save($this->data))
{
$this->Session->setFlash(__('The User has been saved', true));
$this->redirect(array('action'=>'index'));
}
else
{
$this->Session->setFlash(__('The User could not be saved. Please, try again.', true));
}
}
}
function edit($id = null)
{
if (!$id && empty($this->data))
{
$this->Session->setFlash(__('Invalid User', true));
$this->redirect(array('action'=>'index'));
}
if (!empty($this->data))
{
if ($this->User->save($this->data))
{
$this->Session->setFlash(__('The User has been saved', true));
$this->redirect(array('action'=>'index'));
}
else
{
$this->Session->setFlash(__('The User could not be saved. Please, try again.', true));
}
}
if (empty($this->data))
{
$this->data = $this->User->read(null, $id);
}
}
function delete($id = null)
{
if (!$id)
{
$this->Session->setFlash(__('Invalid id for User', true));
$this->redirect(array('action'=>'index'));
}
if ($this->User->del($id))
{
$this->Session->setFlash(__('User deleted', true));
$this->redirect(array('action'=>'index'));
}
}
}
Here is the test:
/* SVN FILE: $Id$ */
/* UsersController Test cases generated on: 2009-08-05 17:08:03 : 1249507923*/
App::import('Controller', 'Users');
class TestUsers extends UsersController
{
var $autoRender = false;
var $redirectUrl;
var $redirectStatus;
var $renderedAction;
var $renderedLayout;
var $renderedFile;
var $stopped;
function redirect($url, $status = null, $exit = true)
{
$this->redirectUrl = $url;
$this->redirectStatus = $status;
}
function render($action = null, $layout = null, $file = null)
{
$this->renderedAction = $action;
$this->renderedLayout = (is_null($layout) ? $this->layout : $layout);
$this->renderedFile = $file;
}
function _stop($status = 0)
{
$this->stopped = $status;
}
}
class UsersControllerTest extends CakeTestCase
{
var $fixtures = array('user');
var $Users = null;
function startTest()
{
$this->Users = new TestUsers();
$this->Users->constructClasses();
$this->Users->Component->initialize($this->Users);
}
function prepareForAction()
{
$this->Users->beforeFilter();
$this->Users->Component->startup($this->Users);
}
function endTest()
{
$this->Users->Session->destroy();
unset($this->Users);
ClassRegistry::flush();
}
//-----------------------------------------------------------------------
function testUsersControllerInstance()
{
$this->assertTrue(is_a($this->Users, 'UsersController'));
}
function testLogin()
{
$this->Users->data = array(
'User' => array(
'username' => 'admin',
'password' => 'admin'
)
);
$this->prepareForAction();
$this->Users->login();
$this->assertNotNull($this->Users->redirectUrl);
$this->assertEqual($this->Users->Session->read('Auth.User.id'), 1);
}
}
The test you have isn't really testing your UsersContoller, you're really testing the AuthComponent. If you want to do this you need to make sure you setup your TestUsersController the same as it would be in your app. In the case of your testLogin you need to set the controller's action and url:
function testLogin()
{
$this->Users->data = array(
'User' => array(
'username' => 'admin',
'password' => 'admin'
)
);
$this->Users->params['url']['url'] = '/users/login';
$this->Users->params['action'] = 'login';
$this->prepareForAction();
$this->Users->login();
$this->assertNotNull($this->Users->redirectUrl);
$this->assertEqual($this->Users->Session->read('Auth.User.id'), 1);
}
Alternately, I would suggest taking another look at Mark's mock objects post and using those methods to write tests for the controller code and mocking the auth component.
Related
I have opted out of using Laravel's built in User Authentication due to my application's requirements. We rely on a Third Party SSO to authenticate our users, and I was unable to get Socialite to work with their SSO, so I am having to custom build a Controller to handle the authentication process. The Controller is performing b-e-a-utifully up until the part when I need to redirect the user from the Callback Route & Controller to the Member Route & Controller. It won't redirect. Period. I have tried every method I know how to redirect to another route from within the controller and it will not work.
Here is my custom AuthController for Laravel 5.3:
<?php
namespace App\Http\Controllers;
use App\User;
use Curl\Curl;
use App\Http\Controllers\PhealController as Pheal;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use Illuminate\Routing\Redirector;
class AuthController extends Controller
{
protected $curl;
private $data;
public function __construct ()
{
$this->curl = new Curl();
$this->pheal = new Pheal();
$this->data = [];
}
public function sendToSSO()
{
$url = env('EVE_SSO_LOGIN')."?response_type=code&redirect_uri=".env('EVE_CALLBACK_URL')."&client_id=".env('EVE_CLIENT_ID')."&scope=".env('EVE_SCOPES');
return redirect($url);
}
public function handleCallback(Request $request)
{
$this->curl->setHeader('Authorization', "Basic ". base64_encode(env('EVE_CLIENT_ID').":".env('EVE_SECRET')));
$this->curl->setHeader('Content-Type', "application/x-www-form-urlencoded");
$this->curl->setHeader('Host', "login.eveonline.com");
$this->curl->post('https://login.eveonline.com/oauth/token', [
'grant_type' => 'authorization_code',
'code' => $request->code
]);
$response = $this->curl->response;
if (isset($response->error)) {
throw new \Exception($response->error_description);
}
$this->data = [
'accessToken' => $response->access_token,
'refreshToken' => $response->refresh_token
];
$this->verifyToken();
}
public function verifyToken ()
{
$this->curl->setHeader('User-Agent', "David Douglas ddouglas#douglaswebdev.net");
$this->curl->setHeader('Authorization', "Bearer ". $this->data['accessToken']);
$this->curl->setHeader('Host', "login.eveonline.com");
$this->curl->get('https://login.eveonline.com/oauth/verify');
$response = $this->curl->response;
if (isset($response->error)) {
throw new \Exception($response->error_description);
}
$this->data['characterID'] = $response->CharacterID;
$this->data['characterName'] = $response->CharacterName;
$this->data['accessTokenExpire'] = $response->ExpiresOn;
try {
$characterInfo = $this->pheal->call('eve', 'CharacterInfo', ['characterID' => $this->data['characterID']])['result'];
} catch (\Exceoption $e) {
abort(404);
}
if (!isset($characterInfo['allianceID'])) {
abort(403, "Care Factor Alliance Members Only. Sorry :-(");
}
if ($characterInfo['allianceID'] !== env('CF-ALLIANCE-ID')) {
abort(403, "Care Factor Alliance Members Only. Sorry :-(");
}
$this->data['corporationID'] = $characterInfo['corporationID'];
$this->data['corporation'] = $characterInfo['corporation'];
$user = User::find($this->data['characterID']);
if ($user) {
$this->updateUserAndLogin($user);
} else {
$this->createNewUserAndLogin();
}
}
private function getData()
{
return $this->data;
}
public function createNewUserAndLogin()
{
dd('To be Created');
}
public function updateUserAndLogin($user)
{
$user->corporationID = $this->data['corporationID'];
$user->corporation = $this->data['corporation'];
$user->accessToken = $this->data['accessToken'];
$user->refreshToken = $this->data['refreshToken'];
$user->accessTokenExpire = $this->data['accessTokenExpire'];
$user->save();
//Auth::login($user);
return redirect('member/dashboard/');
}
}
I have also tried:
return redirect()->route('member.dashboard');
With no luck.
You mean the $this->createNewUserAndLogin()? Maybe trying return $this->updateUserAndLogin($user); and return $this->verifyToken(); so you return the response on the main method of the route?
I made a blog and I can leave comments to my articles, then I made an Approve button, need to make the approve function.
I need to make it to work. I just can't, no matter what I try. I want to be able to approve or not a comment before it's posted. I have tried everything I could think of.
<?php
namespace App\Controller;
class CommentsController extends AppController
{
public function index()
{
$comments = $this->Comments->find('all');
$this->set(compact('comments'));
}
public function view($id = null)
{
$comment = $this->Comments->get($id);
$this->set(compact('comment'));
}
public function add()
{
$comment = $this->Comments->newEntity();
if ($this->request->is('post')) {
$comment = $this->Comments->patchEntity($comment, $this->request->data);
$comment->user_id = $this->Auth->user('id');
$comment->aproved = 0;
$comment->article_id = $this->request->data['article_id'];
if ($this->Comments->save($comment)) {
$this->Flash->success(__('Your comment has been saved.'));
return $this->redirect(['controller' => 'Articles', 'action' => 'view', $comment->article_id]);
}
$this->Flash->error(__('Unable to add your comment.'));
}
$this->set('comment', $comment);
}
public function aprove()
{
}
}
Try this
Your link should look like this:
$this->Html->link('approve', array('controller' => 'your-controller', 'action' => 'aprove', $comment_id, $value['Comment']['aproved']));
and your controller function is:
public function aprove($comment_id, $approve_value)
{
if(isset($comment_id) && !empty($comment_id)){
$approve = $this->Comments->find('first',array('conditions'=>array('id'=>$comment_id),'fields'=>array('Comment.id, Comment.approve')));
if(!empty($approve)){
$this->Comments->id = $approve['Comment']['id'];
$this->Comments->saveField('aproved', $approve_value);
}
}
}
I am trying to extend onto the 'blog tutorial' from cakephp and am having a little trouble with linking to a logged in user's homepage, which I created on a file called view.ctp.
I can link to most of my file path http://localhost:8888/blogtest/users/view/ up until I need the 'id' to define which page to send someone too.
This is how I am linking to the page:
go
I know I need some logic within the php tags to tell the browser to retrieve the id of the current logged in user.
How would I got about doing this? Where would I create a variable?*
Does the var go in the UsersController.php or is it in the User.php? Any help is greatly appreciated!
UsersController php:
<?php
// app/Controller/UsersController.php
App::uses('AppController', 'Controller');
class UsersController extends AppController {
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());
}
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'));
}
}
?>
Pay attention to the blog tutorial text:
The single instruction in the action uses set() to pass data from the
controller to the view (which we’ll create next). The line sets the
view variable called ‘posts’ equal to the return value of the
find('all') method of the Post model.
It goes on here and explains exactly what you want:
<td>
<?php echo $this->Html->link($post['Post']['title'],
array('controller' => 'posts', 'action' => 'view', $post['Post']['id'])); ?>
</td>
Honestly I have doubts you tried to read it at all. If you really did read this section again. It is all there in great detail.
I've recently been pouring over some CakePHP tutorials on the Auth Component, and am using this for reference: http://miftyisbored.com/a-complete-login-and-authentication-application-tutorial-for-cakephp-2-3/
My Cake version is 2.3.1
I'm using Firebug for debugging. The database passwords are hashing right, and I can Register and new user just fine, however logging in is a different story. When I try to access a page that requires Authentication, I get the login page, enter a valid user/pass, and it redirects me right back to the login page. In firebug the POST header is 200 OK and just returns the login page again. I'm guessing I may have something wrong with my session config or something, as if the session isn't being looked up. Here's my UsersController.php:
<?php
class UsersController extends AppController {
public $name = 'Users';
public $helpers = array('Html','Form');
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('add', 'login');
}
public function login() {
//if already logged-in, redirect
if($this->Session->check('Auth.User')){
$this->redirect(array('controller'=>'admin','action' => 'admin_index'));
}
// if we get the post information, try to authenticate
if ($this->request->is('post')) {
if ($this->Auth->login()) {
$this->Session->setFlash(__('Welcome, '. $this->Auth->user('username')));
$this->redirect($this->Auth->redirectUrl());
} else {
$this->Session->setFlash(__('Invalid username or password'));
}
}
}
public function logout() {
return $this->redirect($this->Auth->logout());
}
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' => 'login'));
}
$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) {
$this->request->onlyAllow('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'));
}
}
?>
My Model seems to be working ok, but I can provide any additional code if this isn't where my error is at! Thanks bunches!
the problem is in the encryptacion of your passwords, see if you're doing a beforesave and you need make a encryption when saving and password that you log in to verify if they are the same in your DB
User model
public function beforeSave($options = array()) {
// hash our password
if (!$this->id) {
$passwordHasher = new SimplePasswordHasher();
$this->data['User']['password'] = $passwordHasher->hash($this->data['User']['password']);
}
return true;
}
AppController
public function beforeFilter() {
Security::setHash('sha1');
$this->Auth->allow('index', 'display', 'view');
}
In your database for the password the right is varchar (30)
here i done code for contact us page with two fileds like email,body it stores values in db
but it s not working i post the code here
Model
//model/pages.php
<?php
class pages extends AppModel{
var $useTable = 'contact';
}
?>
Controller
class PagesController extends AppController {
public $uses = array();
public function display() {
$path = func_get_args();
$count = count($path);
if (!$count) {
return $this->redirect('/');
}
$page = $subpage = $title_for_layout = null;
if (!empty($path[0])) {
$page = $path[0];
}
if (!empty($path[1])) {
$subpage = $path[1];
}
if (!empty($path[$count - 1])) {
$title_for_layout = Inflector::humanize($path[$count - 1]);
}
$this->set(compact('page', 'subpage', 'title_for_layout'));
try {
$this->render(implode('/', $path));
} catch (MissingViewException $e) {
if (Configure::read('debug')) {
throw $e;
}
throw new NotFoundException();
}
}
public function index(){
$this->set('post', $this->contact->find('all'));
}
public function create() {
if ($this->request->is('post'))
//this function for methods like get, post, set,delelte
{
// print_r('post');
$this->contact->create();
if ($this->contact->save($this->request->data)) {
$this->Session->setFlash(__('Your post has been saved.'));
return $this->redirect(array('action' => 'index'));
}
$this->Session->setFlash(__('Unable to add your post.'));
}
}
}
view
here code for display
view/contact.ctp
<?php
echo 'welcome to Contact us';
echo $this->Form->create('pages');
echo $this->Form->input('email');
echo $this->Form->input('body', array('rows' => '6'));
echo $this->Form->end('Save pages');
?>
added in db table and values contact
Did you read something to start in CakePHP like Getting Started or CakePHP Conventions?
Reading some documentation, you will find that your tables should be named in plural and models in singular. Your model in app/Model/Contact.php looks like this:
class Contact extends AppModel {
public $useTable = 'contacts'; // It is not necessary, because CakePHP implicitly understands that your table will be in the plural
}
Now, your view located in app/View/Contacts/index.ctp:
echo $this->Form->create('Contact');
echo $this->Form->input('email');
echo $this->Form->input('body', array('rows' => '6'));
echo $this->Form->end('Save');
And your controller in app/Controller/ContactsController.php:
class ContactsController extends AppController {
public function index() {
if ($this->request->is('post')) {
$this->Contact->create();
if ($this->Contact->save($this->request->data)) {
$this->Session->setFlash(__('Your contact has been saved.'));
} else {
$this->Session->setFlash(__('Unable to add your contact.'));
}
}
}
}
This is a basic usage. I recommend you read the documentation to start with CakePHP because it has lots of interesting things that you may need.