Im using cakephp 3.2 to build an application. Im using the bookmarks tutorial as a basis for my project. in one of my bookmarks .ctp view files I would like to have a number of select boxes with data specific to the user loggged in. i have two tables namely users and bookmarks. My bookmarks table contains foreign key from users table user_id.
Here's my bookmark table with the fields i would like the dropdowns. id, user_id, title, systemregistration, systemroles, country, province, metropolitan.
Code for my appcontroller
namespace App\Controller;
use Cake\Controller\Controller;
use Cake\Event\Event;
/**
* Application Controller
*
* Add your application-wide methods in the class below, your controllers
* will inherit them.
*
* #link http://book.cakephp.org/3.0/en/controllers.html#the-app-controller
*/
class AppController extends Controller
{
/**
* Initialization hook method.
*
* Use this method to add common initialization code like loading components.
*
* e.g. `$this->loadComponent('Security');`
*
* #return void
*/
/*public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler');
$this->loadComponent('Flash');
}*/
public function initialize()
{
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
'fields' => [
'username' => 'email',
'password' => 'password'
]
]
],
'loginAction' => [
'controller' => 'Users',
'action' => 'login'
],
//'storage' => 'Session'
'Session'
]);
// Allow the display action so our pages controller
// continues to work.
$this->Auth->allow(['display']);
}
/*public function initialize()
{
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'loginRedirect' => [
'controller' => 'Bookmarks',
'action' => 'index'
],
'logoutRedirect' => [
'controller' => 'Pages',
'action' => 'display',
'home'
]
]);
}
public function beforeFilter(Event $event)
{
$this->Auth->allow(['index', 'view', 'display']);
}*/
/**
* Before render callback.
*
* #param \Cake\Event\Event $event The beforeRender event.
* #return void
*/
public function beforeRender(Event $event)
{
if (!array_key_exists('_serialize', $this->viewVars) &&
in_array($this->response->type(), ['application/json', 'application/xml'])
) {
$this->set('_serialize', true);
}
}
}
//BookmarksController looks like this
namespace App\Controller;
use App\Controller\AppController;
/**
* Bookmarks Controller
*
* #property \App\Model\Table\BookmarksTable $Bookmarks
*/
class BookmarksController extends AppController
{
public function internalprotocol()
{
$bookmark = $this->Bookmarks->newEntity();
$users = $this->Bookmarks->Users->find('list', ['limit' => 200]);
$tags = $this->Bookmarks->Tags->find('list', ['limit' => 200]);
$this->set(compact('bookmark', 'users', 'tags'));
$this->set('_serialize', ['bookmark']);
$bookmarks = $this->paginate($this->Bookmarks);
$this->set(compact('bookmarks'));
$this->set('_serialize', ['bookmarks']);
}
}
//my internalprotocol.ctp looks like this
<div>
<?php echo $this->Form->input('user_id', ['options' => $bookmarks]); ?>
<?php echo $this->Form->input('title', ['options' => $bookmarks]); ?>
<?php echo $this->Form->input('systemregistration', ['options' => $bookmarks]); ?>
<?php echo $this->Form->input('systemroles', ['options' => $bookmarks]); ?>
<?php echo $this->Form->input('country', ['options' => $bookmarks]); ?>
</div>
I would like to populate each of the fields with data specific to the user logged in. Could you please help!
You don't need to do anything. If a login is successful you can access the logged in user details through the Auth component using $this->Auth->user();
If you need to add any more information to the session you can use the Session component like $this->Session->write('User.AscociatedData', $AscociatedData);
Easiest way to access this data in the view is to set authenticated user as a view variable in the controller:
$this->set('user',$this->Auth->user());
then you can accesses the users info in the view with $user e.g$user->fieldName
Not entirely sure what your asking but I hope one of my answers is relevant.
we only need to show bookmarks for the currently logged in user.
We can do that by updating the call to paginate().Make your index() action from Controller/BookmarksController.php look like:
public function index()
{
$this->paginate = [
'conditions' => [
'Bookmarks.user_id' => $this->Auth->user('id'),
]
];
$this->set('bookmarks', $this->paginate($this->Bookmarks));
$this->set('_serialize', ['bookmarks']);
}
We should also update the tags() action and the related finder method as we done for bookmarks above
Please read the tutorial
http://book.cakephp.org/3.0/en/tutorials-and-examples/bookmarks/part-two.html#fixing-list-view-and-forms
Related
This is my code in my view:
if($this->request->session->read('Auth.User')) {
echo $this->Html->link('Log Out', array('controller' => 'users','action' => 'logout'));
}
if(!$this->request->session->read('Auth.User')) {
echo $this->Html->link('Log Out', array('controller' => 'users','action' => 'logout'));
}
But I get this error:
Call to a member function read() on null
I'm connected but is dont work.
You can try another way for checking Authenticate User from your View
From your AppController you can set $AuthUser variable
Example:
public function initialize(){
parent::initialize();
$this->loadComponent('Auth', [
#All configurations for AuthComponent
]);
$this->set('AuthUser',$this->Auth->user()); #Set for all Views
}
Note : Now you can use $AuthUser variable to your View directly.
So i have this method inside of my:
JobsController.ctp:
<?php
namespace App\Controller;
use App\Controller\AppController;
use Cake\ORM\TableRegistry;
/**
* Jobs Controller
*
* #property \App\Model\Table\JobsTable $Jobs
*/
class JobsController extends AppController
{
public $name = 'Jobs';
public function add()
{
//Some Vars assigning skipped, var job is empty
$this->set('job','Job');
$this->Job->create();
}
}
And I have this view with the form itself:
add.ctp:
<?= $this->Form->create($job); ?>
<fieldset>
<legend><?= __('Add Job Listing'); ?></legend>
<?php
echo $this->Form->input('title');
echo $this->Form->input('company_name');
echo $this->Form->input('category_id',array(
'type' => 'select',
'options' => $categories,
'empty' => 'Select Category'
));
echo $this->Form->input('type_id',array(
'type' => 'select',
'options' => $types,
'empty' => 'Select Type'
));
echo $this->Form->input('description', array('type' => 'textarea'));
echo $this->Form->input('city');
echo $this->Form->input('contact_email');
?>
</fieldset>
<?php
echo $this->Form->button('Add');
$this->Form->end();
?>
Also this table class:
JobsTable.php
<?php
namespace App\Model\Table;
use Cake\ORM\Table;
class JobsTable extends Table
{
public function initialize(array $config)
{
$this->belongsTo('Types', [
'foreignKey' => 'type_id',
'joinType' => 'INNER',
]);
$this->belongsTo('Categories', [
'foreignKey' => 'category_id',
'joinType' => 'INNER',
]);
}
}
And when I submit it, it gives me next error:
Error: Call to a member function create() on boolean
No idea how to fix.
I also have an entity
Job.php:
<?php
namespace App\Model\Entity;
use Cake\ORM\Entity;
/**
* Job Entity.
*/
class Job extends Entity
{
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
* #var array
*/
protected $_accessible = array(
'category_id' => true,
'user_id' => true,
'type_id' => true,
'company_name' => true,
'title' => true,
'description' => true,
'city' => true,
'contact_email' => true,
'category' => true,
'user' => true,
'type' => true,
);
}
So how do I fix this error, that appears on form submit?
Error: Call to a member function create() on boolean
I guess I need to do something with $this->set('job'); ? but I'm not sure what exactly
By convention the default, auto-loadable table for a controller is based on the controller name without the trailing Controller, so for JobsController a table class named Jobs(Table) can be autoloaded.
In case the table class cannot be loaded (for example because it doesn't exist, or because the name doesn't match the one derived from the controller name), the magic getter that handles this will return false, a boolean, and this is where you are trying to call a method on, hence the error.
create() btw doesn't exist anymore, you should have a look at the ORM migration guide, and the docs in general to get a grasp on how things now work.
So either use $this->Jobs and make sure that you have a table class named JobsTable, or override the default model to use (Controller::_setModelClass()), or load the desired table manually (TableRegistry::get() or Controller::loadModel()).
See also
Cookbook > Database Access & ORM
Cookbook > Controllers > Loading Additional Models
So this is my login method:
public function login()
{
if ($this->request->is('post')) {
$user = $this->Auth->identify();
if ($user) {
$this->Auth->setUser($user);
return $this->redirect($this->Auth->redirectUrl());
} else {
$this->Flash->error(__('Invalid username or password, try again'));
}
}
}
And this is how I has my password inside my User entity:
<?php
namespace App\Model\Entity;
use Cake\Auth\DefaultPasswordHasher;
use Cake\ORM\Entity;
/**
* User Entity.
*/
class User extends Entity
{
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
* #var array
*/
protected $_accessible = array(
'first_name' => true,
'last_name' => true,
'email' => true,
'username' => true,
'password' => true,
'role' => true,
'created' => true
);
protected function _setPassword($password)
{
return (new DefaultPasswordHasher)->hash($password);
}
}
I already have working user registration and it's working without problems(password is being hashed), but for some reason I can't login, it always says that
Invalid username or password, try again
But those are present in my table, here is the query:
SELECT
Users.id AS `Users__id`,
Users.first_name AS `Users__first_name`,
Users.last_name AS `Users__last_name`,
Users.email AS `Users__email`,
Users.username AS `Users__username`,
Users.password AS `Users__password`,
Users.role AS `Users__role`,
Users.created AS `Users__created`
FROM
users Users
WHERE
Users.username = 'admin' LIMIT 1
But for some reason it does nothing in my app. I guess something is wrong with the password?
Form:
<div class="users form">
<?= $this->Flash->render('auth') ?>
<?= $this->Form->create() ?>
<fieldset>
<legend><?= __('Please enter your username and password') ?></legend>
<?= $this->Form->input('username') ?>
<?= $this->Form->input('password') ?>
</fieldset>
<?= $this->Form->button(__('Login')); ?>
<?= $this->Form->end() ?>
</div>
AppController:
class AppController extends Controller
{
/**
* Initialization hook method.
*
* Use this method to add common initialization code like loading components.
*
* #return void
*/
public function initialize()
{
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'loginRedirect' => [
'controller' => 'Jobs',
'action' => 'index'
],
'logoutRedirect' => [
'controller' => 'Jobs',
'action' => 'index'
],
'authorize' => ['controller']
]);
}
public function beforeFilter(Event $event)
{
$this->Auth->allow(['index', 'browse', 'view', 'register']);
}
}
Found the answer here:
Login [ Auth->identify() ] always false on CakePHP 3
Summary:
Table field password was VARCHAR(45) instead of VARCHAR(255)
Sorry im new to cakephp 3.0. In my user table, there are two user types, admin and public. How do I display/hide links according to user types in default.ctp? Can anyone guide me thanks!!
This is my app controller
namespace App\Controller;
use Cake\Controller\Controller;
use Cake\Event\Event;
class AppController extends Controller
{
//...
public function initialize()
{
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
'fields' => [
'username' => 'email',
'password' => 'password'
]
]
],
'loginRedirect' => [
'controller' => 'Users',
'action' => 'index'
],
'logoutRedirect' => [
'controller' => 'Pages',
'action' => 'display',
'home'
]
]);
}
public function beforeFilter(Event $event)
{
$this->Auth->allow(['controller' => 'Users', 'action' => 'add', 'index',
]);
}
}
The AppController you've posted has nothing to do with what I understand of your request so that's got me a little confused. Either way, you can access the session of the current logged in user through session variables.
For example - if your users table had the column 'type' in which the values 'public' or 'admin' were stored, it would look something like this:
<?php if ($this->session->read('Auth.User.type') == 'admin') { ?>
Link to admin functions
<?php } else { ?>
Boring public link
<?php } ?>
That's assuming you're working with logged in users. If you haven't got that far yet, read the CakePHP 3 tutorial on authentication and authorization.
Consider this code:
Controller Code
<?php
App::uses('AppController', 'Controller');
class UsersController extends AppController {
public $components = array(
'Security',
'Session'
);
public function example() {
if ($this->request->is('post')) {
$this->set('some_var', true);
}
}
}
View Code
<?php
echo $this->Form->create();
echo $this->Form->input('name');
echo $this->Form->end('Submit');
Since I have the Security component in place, tampering with the form in any way (such as adding a field to it) will cause the request to be black-holed. I'd like to test this:
Test Code
<?php
class UsersControllerTest extends ControllerTestCase {
public function testExamplePostValidData() {
$this->Controller = $this->generate('Users', array(
'components' => array(
'Security'
)
));
$data = array(
'User' => array(
'name' => 'John Doe'
)
);
$this->testAction('/users/example', array('data' => $data, 'method' => 'post'));
$this->assertTrue($this->vars['some_var']);
}
public function testExamplePostInvalidData() {
$this->Controller = $this->generate('Users', array(
'components' => array(
'Security'
)
));
$data = array(
'User' => array(
'name' => 'John Doe',
'some_field' => 'The existence of this should cause the request to be black-holed.'
)
);
$this->testAction('/users/example', array('data' => $data, 'method' => 'post'));
$this->assertTrue($this->vars['some_var']);
}
}
The second test testExamplePostInvalidData should fail because of some_field being in the $data array, but it passes! What am I doing wrong?
By adding the 'some_field' in the data of ->testAction, the security component will assume that field is part of your app (since it's coming from your code, not a POST array) so it won't be seen as a "hack attempt".
Checking for blackholes is a little more convoluted. But Cake core tests already test the blackhole functionality, so if those tests pass, you don't need to check it in your app.
If you insist though, check out the core Cake tests for guidance:
Specifically:
/**
* test that validatePost fails if any of its required fields are missing.
*
* #return void
*/
public function testValidatePostFormHacking() {
$this->Controller->Security->startup($this->Controller);
$key = $this->Controller->params['_Token']['key'];
$unlocked = '';
$this->Controller->request->data = array(
'Model' => array('username' => 'nate', 'password' => 'foo', 'valid' => '0'),
'_Token' => compact('key', 'unlocked')
);
$result = $this->Controller->Security->validatePost($this->Controller);
$this->assertFalse($result, 'validatePost passed when fields were missing. %s');
}
Lots more examples in the file:
https://github.com/cakephp/cakephp/blob/master/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php