cakephp 3 - Multiple relationship same table display in index.ctp - cakephp

Dears,
I have 2 fields (solicitante and resolvedor) related to the ID field of the users table, how can I display both in the index.ctp?
I use this code below, but I do not know how to differentiate the 2 fields, I put only one field because when I put the two, the information repeats itself
My index.ctp
<?= $chamado->has('user') ? $this->Html->link($chamado->user->nome, ['controller' => 'Users', 'action' => 'view', $chamado->user->id]) : '' ?>
My Controller
public function index()
{
$this->paginate = [
'contain' => ['Users']
];
$chamados = $this->paginate($this->Chamados);
$this->set(compact('chamados'));
$this->set('_serialize', ['chamados']);
}
My Model
public function initialize(array $config)
{
parent::initialize($config);
$this->setTable('chamados');
$this->setDisplayField('id');
$this->setPrimaryKey('id');
$this->addBehavior('Timestamp');
$this->belongsTo('Users', [
'foreignKey' => 'solicitante',
'joinType' => 'INNER'
]);
}
follows the screen image:
Index.ctp screen

you can differentiate this way:
$this->belongsTo('Solicitantes', [
'className' => 'Users'
'foreignKey' => 'solicitante',
'joinType' => 'INNER'
]);
$this->belongsTo('Resolvedores', [
'className' => 'Users'
'foreignKey' => 'resolvedor',
'joinType' => 'INNER'
]);
and in your view
<?= $chamado->has('solicitante') ? $this->Html->link($chamado->solicitante->nome, ['controller' => 'Users', 'action' => 'view', $chamado->solicitante->id]) : '' ?>
<?= $chamado->has('resolvedor') ? $this->Html->link($chamado->resolvedor->nome, ['controller' => 'Users', 'action' => 'view', $chamado->resolvedor->id]) : '' ?>
see the manual
https://book.cakephp.org/3.0/en/orm/associations.html#belongsto-associations

Related

Superuser or Admin in Cakephp 3 - E-Commerce with Admin

I'm creating an E-Commerce website using CakePHP 3
I need to create an Admin page that will allow the Admin to upload
products and possibly view a few KPI's etc..
Is there a way in Cake to have a User (general customer shopping on the site) and a Superuser (or Admin) at the same time? I have an 'is_admin' column in my Users table to differentiate between admin and user. Do I just need to have something like this in my addProducts function or is there a better way?:
public function addProducts(){
$user = $this->Auth->user();
if($user['is_admin']) {
//allow access
} else {
//throw anauthorised exception
}
}
Thanks in advance
You can manage it via different URL's for admin and front User. This can be managed via the routes and the APP Controller.
What I am using for one of my appplication is as below:
In the routes.php file
Router::prefix('admin', function ($routes) {
// All routes here will be prefixed with `/admin`
// And have the prefix => admin route element added.
$routes->fallbacks('DashedRoute');
$routes->connect('/', array('controller' => 'Users', 'action' => 'login'));
/* Here you can define all the routes for the admin */
});
Router::scope('/', function ($routes) {
$routes->connect('/', array('controller' => 'Users', 'action' => 'login', 'home'));
/* Here you can define all the routes for the frontend */
});
Please note for the Admin you need to create a directory in all /src/Controller, /src/Template named as "Admin" and within these directories you can use the same structure that we use in our code.
Now comes the code that needs to be written in /src/Controller/AppController.php
public $prefix = '';
public function initialize()
{
$this->prefix = (!empty($this->request->params['prefix'])?$this->request->params['prefix']:'');
$this->set('prefix',$this->prefix);
if( !empty($this->prefix) && $this->prefix==='admin' )
{
$this->loadComponent('Auth', [
'loginAction' => [
'controller' => 'Users',
'action' => 'login',
'prefix'=>'admin'
],
'loginRedirect' => [
'controller' => 'Users',
'action' => 'index',
'prefix'=>'admin'
],
'logoutRedirect' => [
'controller' => 'Users',
'action' => 'login',
'prefix'=>'admin'
],
'authError' => 'Did you really think you are allowed to see that?',
'authenticate' => [
'Form' => [
'finder' => 'admin',
'fields' => ['username' => 'email', 'password' => 'password']
]
],
'storage' => ['className' => 'Session', 'key' => 'Auth.Admin']
]);
}
else
{
$this->loadComponent('Auth', [
'loginAction' => [
'controller' => 'Users',
'action' => 'login'
],
'loginRedirect' => [
'controller' => 'Users',
'action' => 'myaccount'
],
'logoutRedirect' => [
'controller' => 'Users',
'action' => 'login'
],
'authError' => 'Did you really think you are allowed to see that?',
'authenticate' => [
'Form' => [
'finder' => 'user',
'fields' => ['username' => 'email', 'password' => 'password']
]
],
'storage' => ['className' => 'Session', 'key' => 'Auth.User']
]);
}
}
Here you can see that we are using different keys for the storage Auth.User and Auth.Admin
For the finder you need to write the below code in your user model table located at src\Model\Table\UsersTable.php
public function findAdmin(\Cake\ORM\Query $query, array $options)
{
$query
->select(array('Users.email', 'Users.password','Users.id','Users.role_id'))
->where(array('Users.role_id' => 1));
return $query;
}
public function findUser(\Cake\ORM\Query $query, array $options)
{
$query
->select(array('Users.email', 'Users.password','Users.id','Users.role_id'))
->where(array('Users.status' => 1,'Users.role_id' => 3));
return $query;
}
Note, Here I am keeping role_id "1" for Admin and "3" for front Users.
In this manner, even you can set the login for both in the same browser as key for both the user types is different.
Hope this helps you setup the structure accordingly.

cakephp auth flash message params

Auth Flash params are not working for me.
AppController:
class AppController extends Controller {
public $helpers = array(
'Session',
'Facebook.Facebook',
'Html' => array('className' => 'BoostCake.BoostCakeHtml'),
'Form' => array('className' => 'BoostCake.BoostCakeForm'),
'Paginator' => array('className' => 'BoostCake.BoostCakePaginator'),
'AssetCompress.AssetCompress',
'PhpThumb.PhpThumb'
);
public $components = array(
'Session',
'RequestHandler',
'Auth' => array(
'authenticate' => array('Custom'),
'loginRedirect' => array('controller' => 'users', 'action' => 'index'),
'logoutRedirect' => array('controller' => 'pages', 'action' => 'index'),
'flash' => array(
'element' => 'alert',
'key' => 'auth',
'params' => array(
'plugin' => 'BoostCake',
'class' => 'alert-danger'
)
)
),
);
Default layout:
Session->flash();
echo $this->Session->flash('auth');
echo $this->fetch('content');
?>
I've debugged the params to make sure they're outputting correctly, but when the alert pops up this is what I see:
<div id="authMessage" class="message">Username or password is incorrect</div>
Thanks in advance
You need to create a ctp with the name alert.ctp in your view as follows:
<div id="authMessage" class="message">
<?php
echo $plugin;
echo $class;
?>
Username or password is incorrect
</div>
Have a look at this CakePHP custom flash for loginError

CakePHP 2.x Auth Custom Username (Code in place but not working!)

Sorry - Hate to ask but I've spent hour's working this out and researching but havent had any luck.
CakePHP (running the latest version) seems to refuse to use the fields setting (So that I can use the email column in the database as the username). If I set it to 'email' which is the field I wish to use from the database it simply refuses to login stating incorrect details. Cant get any output from SQL in DebugKit for some reason. Although when it's set to username as per below it works fine just using a 'temp' column in the DB. I've tried putting it in the components var but had no luck with that either. What could I be doing wrong? Debug is on, cant see any errors in the log or browser.
The model does contain an email column.
Controller/AppController.php
class AppController extends Controller {
public $components = array(
'Session',
'DebugKit.Toolbar',
'Auth' => array(
'allow' => array('login','logout'),
'loginAction' => array('controller' => 'users', 'action' => 'login'),
'loginRedirect' => array('controller' => 'dashboard', 'action' => 'index'),
'authorize' => 'Controller'
)
);
function beforeFilter() {
Security::setHash('md5');
$this->Auth->authenticate = array(
'Form' => array(
'fields' => array(
'username' => 'username',
),
),
);
}
}
Controller/UserController.php
class UsersController extends AppController {
public $uses = array('User');
public function beforeFilter() {
parent::beforeFilter();
}
public function isAuthorized($user){
return true;
}
public function login() {
$this->layout = 'login';
if ($this->request->is('post')) {
if ($this->Auth->login()) {
$this->redirect($this->Auth->redirect());
} else {
$this->Session->setFlash('Invalid username or password, try again','flash_error');
}
}
}
public function logout() {
$this->layout = 'login';
$this->Session->setFlash('Successfully logged out!','flash_success');
$this->redirect($this->Auth->logout());
}
}
View/Users/login.ctp
<?php
$this->set('title_for_layout', 'Login');
echo $this->Session->flash();
echo $this->Session->flash('auth','flash_info');
echo $this->Form->create('User', array(
'action' => 'login'
));
echo $this->Form->input('username',array(
'between' => '<br/>',
'before' => '<p>',
'after' => '</p>',
'class' => 'text',
'label' => 'Email:'
));
echo $this->Form->input('password',array(
'between' => '<br/>',
'before' => '<p>',
'after' => '</p>',
'class' => 'text',
'label' => 'Password:'
));
echo $this->Form->submit('Login', array(
'class' => 'submit',
'before' => '<p>',
'after' => '</p>'
));
echo $this->Form->end();
?>
You need to change the name of the field on your form from username to email. Just setting the label to "email" is not enough.
echo $this->Form->input('email',array(
'between' => '<br/>',
'before' => '<p>',
'after' => '</p>',
'class' => 'text',
'label' => 'Email:'
Try updating the components code in your appController to add the authenticate values to the Auth array like this:
public $components = array(
'Session',
'DebugKit.Toolbar',
'Auth' => array(
'allow' => array('login','logout'),
'loginAction' => array('controller' => 'users', 'action' => 'login'),
'loginRedirect' => array('controller' => 'dashboard', 'action' => 'index'),
'authorize' => 'Controller',
'authenticate' => array(
'Form' => array(
'fields' => array('username' => 'email')
)
)
)
);

CakePHP 2.x Reverse Routing Link Helper

In my CakePHP App I connected the following Route:
Router::connect('/:city/dealer/:id',
array('controller' => 'dealers', 'action' => 'view'),
array(
'pass' => array('city', 'id'),
'city' => '[a-z]+',
'id' => '[0-9]+'
)
);
This works great and enables: domain.com/washington/dealer/1
But how do I generate the proper HTML link in the View for this URL? If I just do this:
echo $this->Html->link(
'Testlink',
array('washington', 'controller' => 'dealers', 'action' => 'view', 1)
);
It adds all the params to the end of the generated link:
http://domain.com/dealers/view/washington/1
How do I do this properly?
I believe you still need to specify the params, like so:
echo $this->Html->link('Testlink',
array('controller' => 'dealers', 'action' => 'view', 'city' => 'washington',
'id'=> 1));
Cake has a similiar example in the cookbook:
<?php
// SomeController.php
public function view($articleId = null, $slug = null) {
// some code here...
}
// routes.php
Router::connect(
'/blog/:id-:slug', // E.g. /blog/3-CakePHP_Rocks
array('controller' => 'blog', 'action' => 'view'),
array(
// order matters since this will simply map ":id" to $articleId in your action
'pass' => array('id', 'slug'),
'id' => '[0-9]+'
)
);
// view.ctp
// this will return a link to /blog/3-CakePHP_Rocks
<?php
echo $this->Html->link('CakePHP Rocks', array(
'controller' => 'blog',
'action' => 'view',
'id' => 3,
'slug' => 'CakePHP_Rocks'
));
Hi Sebastian its probably too late to help you, but I may be able to help someone else with this problem. The key to solving your problem is adding to the url method in Helper class. I did this by creating a AppHelper.php in my View/Helper. It looks like this. I changed out my parameter for yours city.
View/Helper/AppHelper.php
<?php
App::uses('Helper', 'View');
class AppHelper extends Helper {
function url($url = null, $full = false) {
if (is_array($url)) {
if (empty($url['city']) && isset($this->params['city'])) {
$url['city'] = $this->params['city'];
}
if (empty($url['controller']) && isset($this->params['controller'])) {
$url['controller'] = $this->params['controller'];
}
if (empty($url['action']) && isset($this->params['action'])) {
$url['action'] = $this->params['action'];
}
}
return parent::url($url, $full);
}
}
?>
Then I create routes like
Router::connect('/:city/dealer/:id',
array('controller' => 'dealers', 'action' => 'view', 'id'=>':id'),
array('pass' => array('city', 'id'),
'city' => '[a-z]+',
'id' => '[0-9]+'
));
Hope this helps :)

Innerjoin with associated tables always ends up with "not associated with" error

I want to make this query (the $ownerQuery is the relevant part here):
$searchQuery = $this->Tickets
->find('byStatus',['status' =>$status])
->find('byTitle',['queries' => $queries]);
$ownerQuery = $searchQuery
->innerJoinWith(
'Projects.ProjectsTickets', function($q) use( &$userId){
return $q->where(['Tickets.id' => 'ProjectsTickets.ticket_id'])
->where(['Projects.id' => 'ProjectsTickets.project_id'])
->where(['Projects.user_id' => $userId]);
}
);
Or something that achieves the same effect, however every variation of this I have tried ends up with a not associated with error.
Here are my associations:
ProjectsTicketsTable:
class ProjectsTicketsTable extends Table
{
public function initialize(array $config)
{
parent::initialize($config);
$this->table('projects_tickets');
$this->displayField('project_id');
$this->primaryKey(['project_id', 'ticket_id']);
//$this->belongsTo('Projects', [
// 'foreignKey' => 'project_id',
// 'joinType' => 'INNER'
//]);
//$this->belongsTo('Tickets', [
// 'foreignKey' => 'ticket_id',
// 'joinType' => 'INNER'
//]);
$this->belongsTo('Projects');
$this->belongsTo('Users');
}
}
ProjectsTable:
class ProjectsTable extends Table
{
public function initialize(array $config)
{
parent::initialize($config);
$this->table('projects');
$this->displayField('title');
$this->primaryKey('id');
$this->addBehavior('Timestamp');
$this->belongsTo('Users', [
'foreignKey' => 'user_id',
'joinType' => 'INNER'
]);
$this->belongsTo('Tags', [
'foreignKey' => 'tag_id',
'joinType' => 'INNER'
]);
//$this->belongsToMany('Tickets', [
// 'foreignKey' => 'project_id',
// 'targetForeignKey' => 'ticket_id',
// 'joinTable' => 'projects_tickets'
//]);
$this->belongsToMany('Tickets', [
'through' => 'ProjectTickets',
]);
$this->belongsToMany('Users', [
'foreignKey' => 'project_id',
'targetForeignKey' => 'user_id',
'joinTable' => 'projects_users'
]);
}
}
TicketsTable:
class TicketsTable extends Table
{
public function initialize(array $config)
{
parent::initialize($config);
$this->table('tickets');
$this->displayField('title');
$this->primaryKey('id');
$this->addBehavior('Timestamp');
//$this->belongsToMany('Projects', [
// 'foreignKey' => 'ticket_id',
// 'targetForeignKey' => 'project_id',
// 'joinTable' => 'projects_tickets'
//]);
$this->belongsToMany('Projects', [
'through' => 'ProjectTickets',
]);
$this->belongsToMany('Comments', [
'foreignKey' => 'ticket_id',
'targetForeignKey' => 'comment_id',
'joinTable' => 'tickets_comments'
]);
$this->belongsToMany('Users', [
'foreignKey' => 'ticket_id',
'targetForeignKey' => 'user_id',
'joinTable' => 'tickets_users'
]);
}
}
Is there something I am doing wrong with the associations or the query that I could fix?
EDIT: By changing the associations like the link NDM provided I did manage to get rid of the 'no association errors' however all queries trying to combine columns from tables always result in 0 results.
For example this search that should return all tickets (because all of them are in the ProjectsTickets table) is returning nothing:
$ownerQuery = $searchQuery
->innerJoinWith(
'Projects.ProjectsTickets', function($q) use( &$userId){
return $q->where(['Tickets.id' => 'ProjectsTickets.ticket_id']);
//->where(['Projects.id' => 'ProjectsTickets.project_id'])
//->where(['Projects.user_id' => $userId]);
}
);
If I however uncomment only the user line it is correctly displaying all results.
EDIT 2: While the association workaround works the matching one doesnt wich proves a bit problematic. For example if I want to do this query without having to make an association between Tickets and ProjectsUsers:
$adminQuery = $searchQuery
->distinct()
->matching('ProjectsUsers')
->where([
'Tickets.id = ProjectsTickets.ticket_id',
'ProjectsTickets.project_id = ProjectsUsers.project_id',
'ProjectsUsers.user_id' => $userId,
'ProjectsUsers.role = Admin'
]);
This is still resulting in Tickets is not associated with ProjectsUsers

Resources