Cakephp - Select2 - php

Can someone help me with multiple select in CakePHP 3?
I have a project in CakePHP 3.6. In one of the view, I need to add student's presences, and I wanna do it with a multiple select (Select2).
In one lesson I can choose many students. The students are saved in DB, and in the select input, I wanna get the students from there (DB).
I try to use select2.org script, but it does not work as I want. The input doesn't show the student's name.
This is my input:
echo $this->Form->input('students_id', [
'type' => 'select',
'multiple' => true,
'options' => $students,
'hiddenField' => false,
'id' => 'students_id',
]);
This my script:
$('#students_id').select2({
tag: true,
multiple: 'multiple'
});
And in the controller I get students list in this way:
$students = $this->Students->find('list', ['limit' => 200]);
EDIT:
StudentsTable:
class StudentsTable extends Table
{
/**
* Initialize method
*
* #param array $config The configuration for the Table.
* #return void
*/
public function initialize(array $config)
{
parent::initialize($config);
$this->setTable('students');
$this->setDisplayField('name');
$this->setPrimaryKey('id');
$this->belongsTo('Courses', [
'foreignKey' => 'course_id',
'joinType' => 'INNER'
]);
$this->hasMany('LessonPresences', [
'foreignKey' => 'student_id'
]);
}
/**
* Default validation rules.
*
* #param \Cake\Validation\Validator $validator Validator instance.
* #return \Cake\Validation\Validator
*/
public function validationDefault(Validator $validator)
{
$validator
->integer('id')
->allowEmpty('id', 'create');
$validator
->scalar('name')
->maxLength('name', 45)
->requirePresence('name', 'create')
->notEmpty('name');
$validator
->scalar('lastname')
->maxLength('lastname', 45)
->requirePresence('lastname', 'create')
->notEmpty('lastname');
$validator
->email('email')
->allowEmpty('email');
$validator
->scalar('phone')
->maxLength('phone', 18)
->allowEmpty('phone');
$validator
->integer('grander')
->allowEmpty('grander');
$validator
->scalar('address')
->maxLength('address', 100)
->allowEmpty('address');
$validator
->dateTime('add_date')
->requirePresence('add_date', 'create')
->notEmpty('add_date');
$validator
->date('sign_date')
->requirePresence('sign_date', 'create')
->notEmpty('sign_date');
$validator
->integer('status')
->allowEmpty('status');
$validator
->date('course_end')
->allowEmpty('course_end');
return $validator;
}
}

Related

How can I get a Value from my Database and use and show it inside an Input Field?

I want to create two Input Fields. One will save an Int the other one a value like K-0001. After saving those Input Fields and reloading the Form, I want to see inside the Fields the last Values they saved to the Database. The reason I want to do it like this, is because that way I only need to change the last digit and can save the Form again. The Problem is I don't know how I can do that.
Example for better Explaining:
Form:
Field 1: First Value 20000. I Input the number 20001.
Field 2: First Value K-0000. I Input the text K-0001.
After saving my Form and Reloading it I want that it looks like this.
Field 1: Shows the Value 20001. I change it to 20005.
Field 2: Shows the Value K-0001. I change it to K-0005.
And again:
Field 1: Shows the Value 20005. I change it to 20007.
Field 2: Shows the Value K-0005. I change it to K-0007.
etc.
I guess that I need to create a Function which gets the Values from my Database. After that I need to put those inside my Input Fields, atleast that's what I'm thinking.
Code:
add.ctp
div class="customers form large-9 medium-8 columns content">
<?= $this->Form->create($customer) ?>
<fieldset>
<legend><?= __('Neuen Kunden erstellen') ?></legend>
<?php
echo $this->Form->control('tour_id', ['options' => $tours, 'empty' => true]);
/* echo $this->Form->control('order', array('label' => __('Bestellung', true))); */
echo $this->Form->control('kdnr', array('label' => __('Kundennummer', true)));
echo $this->Form->control('debinr', array('label' => __('Debitorennummer', true)));
echo $this->Form->control('anrede', array('label' => __('Anrede', true)));
echo $this->Form->control('name', array('label' => __('Name', true)));
echo $this->Form->control('strasse', array('label' => __('Straße', true)));
echo $this->Form->control('plz', array('label' => __('PLZ', true)));
echo $this->Form->control('ort', array('label' => __('Ort', true)));
echo $this->Form->control('tel', array('label' => __('Telefon', true)));
echo $this->Form->control('kontonummer', array('label' => __('Kontonummer', true)));
echo $this->Form->control('bankleitzahl', array('label' => __('Bankleitzahl', true)));
echo $this->Form->control('lastschrift', array('label' => __('Lastschrift', true)));
echo $this->Form->control('detail', array('label' => __('Weitere Details', true)));
echo $this->Form->control('betreuer_anrede', array('label' => __('Betreuer Anrede', true)));
echo $this->Form->control('betreuer_name', array('label' => __('Betreuer Name', true)));
echo $this->Form->control('betreuer_strasse', array('label' => __('Betreuer Straße', true)));
echo $this->Form->control('betreuer_plz', array('label' => __('Betreuer PLZ', true)));
echo $this->Form->control('betreuer_ort', array('label' => __('Betreuer Ort', true)));
echo $this->Form->control('betreuer_on_bill', array('label' => __('Betreuer soll auf der Rechnung stehen', true)));
?>
</fieldset>
<?= $this->Form->button(__('Bestätigen')) ?>
<?= $this->Form->end() ?>
</div>
CustomersTable.php
class CustomersTable extends Table
{
/**
* Initialize method
*
* #param array $config The configuration for the Table.
* #return void
*/
public function initialize(array $config)
{
parent::initialize($config);
$this->setTable('customers');
$this->setDisplayField('name');
$this->setPrimaryKey('id');
$this->belongsTo('Tours', [
'foreignKey' => 'tour_id'
]);
$this->hasMany('Bills', [
'foreignKey' => 'customer_id'
]);
$this->hasMany('Orders', [
'foreignKey' => 'customer_id'
]);
}
/**
* Default validation rules.
*
* #param \Cake\Validation\Validator $validator Validator instance.
* #return \Cake\Validation\Validator
*/
public function validationDefault(Validator $validator)
{
$validator
->integer('id')
->allowEmptyString('id', 'create');
$validator
->integer('order')
->allowEmptyString('order');
$validator
->scalar('kdnr')
->maxLength('kdnr', 45)
->allowEmptyString('kdnr');
$validator
->scalar('debinr')
->maxLength('debinr', 31)
->allowEmptyString('debinr');
$validator
->scalar('anrede')
->maxLength('anrede', 45)
->allowEmptyString('anrede');
$validator
->scalar('name')
->maxLength('name', 45)
->allowEmptyString('name');
$validator
->scalar('strasse')
->maxLength('strasse', 45)
->allowEmptyString('strasse');
$validator
->integer('plz')
->allowEmptyString('plz');
$validator
->scalar('ort')
->maxLength('ort', 45)
->allowEmptyString('ort');
$validator
->scalar('tel')
->maxLength('tel', 45)
->allowEmptyString('tel');
$validator
->boolean('lastschrift')
->allowEmptyString('lastschrift');
$validator
->scalar('kontonummer')
->maxLength('kontonummer', 32)
->allowEmptyString('kontonummer');
$validator
->integer('bankleitzahl')
->maxLength('bankleitzahl', 32)
->allowEmptyString('bankleitzahl');
$validator
->scalar('detail')
->allowEmptyString('detail');
$validator
->scalar('betreuer_anrede')
->maxLength('betreuer_anrede', 45)
->allowEmptyString('betreuer_anrede');
$validator
->scalar('betreuer_name')
->maxLength('betreuer_name', 45)
->allowEmptyString('betreuer_name');
$validator
->scalar('betreuer_strasse')
->maxLength('betreuer_strasse', 45)
->allowEmptyString('betreuer_strasse');
$validator
->integer('betreuer_plz')
->allowEmptyString('betreuer_plz');
$validator
->scalar('betreuer_ort')
->maxLength('betreuer_ort', 45)
->allowEmptyString('betreuer_ort');
$validator
->boolean('betreuer_on_bill')
->allowEmptyString('betreuer_on_bill');
return $validator;
}
/**
* Returns a rules checker object that will be used for validating
* application integrity.
*
* #param \Cake\ORM\RulesChecker $rules The rules object to be modified.
* #return \Cake\ORM\RulesChecker
*/
public function buildRules(RulesChecker $rules)
{
$rules->add($rules->existsIn(['tour_id'], 'Tours'));
return $rules;
}
}
I hope I explained my Goal well enough and didn't forgot something. I'm still learning so if I forogt something just let me know and I will edit my Question.
Found my Solution!
I created a function inside my Controller to get me the Values i need:
CustomersController.php
$query = $this->Customers->find('list', [
'order' => ['Customers.kdnr' => 'DESC'],
'valueField' => 'kdnr',
'limit' => 1]);
$kdnr = $query->first();
$kdnr++;
$query = $this->Customers->find('list', [
'order' => ['Customers.debinr' => 'DESC'],
'valueField' => 'debinr',
'limit' => 1]);
$debinr = $query->first();
$debinr++;
$this->set(compact('customer', 'tours', 'kdnr', 'debinr'));
after that I only needed to add my $kdnr and $debinr to my ctp.
add.ctp
echo $this->Form->control('kdnr',['value' => $kdnr]);
echo $this->Form->control('debinr',['value' => $debinr]);
That was all I needed to do.

How to save data in cakephp 3 with saving to joinTable

I am new to php frameworks and I've started to learn cakephp few days ago, but even after reading cakephp cookbook about saving belongsToMany associations I still don't know how to implement it in my situation.
I have three tables:
clients:
id | firstname | lastname | phone | email
interests:
id | text | comment | status_id | created_at
clients_interests:
client_id | interest_id
Models and entities were baked so I don't think it's something wrong there, but here is the code:
ClientsTable.php
class ClientsTable extends Table
{
public function initialize(array $config)
{
parent::initialize($config);
$this->setTable('clients');
$this->setDisplayField('id');
$this->setPrimaryKey('id');
$this->belongsToMany('Interests', [
'foreignKey' => 'client_id',
'targetForeignKey' => 'interest_id',
'joinTable' => 'clients_interests'
]);
}
public function validationDefault(Validator $validator)
{
$validator
->integer('id')
->allowEmptyString('id', 'create');
$validator
->scalar('firstname')
->maxLength('firstname', 64)
->requirePresence('firstname', 'create')
->allowEmptyString('firstname', false);
$validator
->scalar('middlename')
->maxLength('middlename', 64)
->allowEmptyString('middlename');
$validator
->scalar('lastname')
->maxLength('lastname', 64)
->requirePresence('lastname', 'create')
->allowEmptyString('lastname', false);
$validator
->scalar('phone')
->maxLength('phone', 24)
->requirePresence('phone', 'create')
->allowEmptyString('phone', false)
->add('phone', 'unique', ['rule' => 'validateUnique', 'provider' => 'table']);
$validator
->email('email')
->allowEmptyString('email');
return $validator;
}
public function buildRules(RulesChecker $rules)
{
$rules->add($rules->isUnique(['email']));
$rules->add($rules->isUnique(['phone']));
return $rules;
}
}
InterestsTable.php
class InterestsTable extends Table
{
public function initialize(array $config)
{
parent::initialize($config);
$this->setTable('interests');
$this->setDisplayField('id');
$this->setPrimaryKey('id');
$this->belongsTo('Statuses', [
'foreignKey' => 'status_id',
'joinType' => 'INNER'
]);
$this->belongsToMany('Clients', [
'foreignKey' => 'interest_id',
'targetForeignKey' => 'client_id',
'joinTable' => 'clients_interests'
]);
}
public function validationDefault(Validator $validator)
{
$validator
->integer('id')
->allowEmptyString('id', 'create');
$validator
->scalar('text')
->maxLength('text', 128)
->requirePresence('text', 'create')
->allowEmptyString('text', false);
$validator
->scalar('comment')
->maxLength('comment', 128)
->allowEmptyString('comment');
$validator
->date('created_at')
->requirePresence('created_at', 'create')
->allowEmptyDate('created_at', false);
return $validator;
}
public function buildRules(RulesChecker $rules)
{
$rules->add($rules->existsIn(['status_id'], 'Statuses'));
return $rules;
}
public function getAll($id)
{
$connection = ConnectionManager::get('default');
$results = $connection
->execute('SELECT i.*, s.name status_name, s.classname status_classname FROM interests i INNER JOIN clients_interests ci ON ci.interest_id=i.id AND ci.client_id=:client_id INNER JOIN statuses s ON i.status_id=s.id ORDER BY created_at DESC;', ['client_id' => $id])
->fetchAll('assoc');
return $results;
}
}
ClientsInterestsTable.php
class ClientsInterestsTable extends Table
{
public function initialize(array $config)
{
parent::initialize($config);
$this->setTable('clients_interests');
$this->setDisplayField('client_id');
$this->setPrimaryKey(['client_id', 'interest_id']);
$this->belongsTo('Clients', [
'foreignKey' => 'client_id',
'joinType' => 'INNER'
]);
$this->belongsTo('Interests', [
'foreignKey' => 'interest_id',
'joinType' => 'INNER'
]);
}
public function buildRules(RulesChecker $rules)
{
$rules->add($rules->existsIn(['client_id'], 'Clients'));
$rules->add($rules->existsIn(['interest_id'], 'Interests'));
return $rules;
}
}
Client entity - Client.php
class Client extends Entity
{
protected $_accessible = [
'firstname' => true,
'middlename' => true,
'lastname' => true,
'phone' => true,
'email' => true
];
}
Interest entity - Interest.php
class Interest extends Entity
{
protected $_accessible = [
'text' => true,
'comment' => true,
'status_id' => true,
'created_at' => true,
'clients_interest' => true,
'status' => true
];
}
ClientsInterests entity - ClientsInterests.php
class ClientsInterest extends Entity
{
protected $_accessible = [
'client' => true,
'interest' => true
];
}
And then in my controller I get all the data from a form. Interest entity after patchEntity() gets all its data besides client data for joinTable. And after save method new interest in interests table is created but there is no new row in clients_interests table. I've tried a lot of things from stackoverflow but it didn't work because I can't understand the mechanism of saving associated data even after reading the manual. Could anyone explain me in simple words how to save belongsToMany associated data?
Here is the code of my save method in InterestsController.php:
public function add()
{
$this->request->allowMethod(['ajax', 'post']);
$this->response->withDisabledCache();
$interest = $this->Interests->newEntity();
$interest = $this->Interests->patchEntity($interest, $this->request->getData(),
['associated'=>['Clients._joinData']]
);
if($this->Interests->save($interest)) {
$result = ['error' => null, 'error_text' => 'SUCCESSFUL'];
} else {
$result = ['error' => null, 'error_text' => 'ERRORS ERRORS ERRORS'];
}
$result = ['error' => null, 'error_text' => 'ERRORS ERRORS ERRORS'];
$this->set('result', $result);
$this->set('_serialize', ['result']);
}
And in my template I use this input for getting client_id:
<?php echo $this->Form->control('clients.0.client_id', ['hidden', 'type'=>'text','id'=>'client-id', 'class'=>'form-control']); ?>
Request data looks like this: request data
And Interest entity after patchEntity() looks like this: Interest entity
If you want to add an 'interest', I think your request data should look differently.
Here is an example, but sorry, I haven't tested it, it's made so you get the idea : you have to tell CakePHP you want to create a Interest entity, and inside add a Client information (just like in the "Converting BelongsToMany Data" in "Saving Data" of book.cakephp.org/3.0/en/orm/saving-data.html).
$data = [
_csrfToken => "...",
'interests' => [
'text' => 'texttext',
'comment' => '',
'created_at' => '2019-01-10',
'status_id' => 2,
'clients' => [
'_ids' => [0],
]
];
Personally, I learnt a lot looking at the requests generated through the Form Helper from the automatically baked templates.

What happen to my validation using cakephp3.4.13?

It always says 'This value is already in use' eventhough not yet present in database.
Sometimes it will say "This field cannot be left empty"
public function validationDefault(Validator $validator)
{
$validator
->integer('id')
->allowEmpty('id', 'create');
$validator->requirePresence('username', 'Please enter username.');
$validator
->requirePresence('password', 'create')
->notEmpty('password', 'You must enter a password', 'create')
->add('password', [
'length' => [
'rule' => ['minLength', 8],
'message' => 'Passwords must be at least 8 characters long.',
]
]);
$validator
->requirePresence('age', 'create')
->notEmpty('age');
$validator
->requirePresence('address', 'create')
->notEmpty('address');
$validator
->email('email')
->requirePresence('email', 'create')
->notEmpty('email');
$validator
->requirePresence('gender', 'create')
->notEmpty('gender');
return $validator;
}
public function buildRules(RulesChecker $rules)
{
$rules->add($rules->isUnique(['username']));
$rules->add($rules->isUnique(['email']));
return $rules;
}
<?php
namespace App\Model\Entity;
use Cake\Auth\DefaultPasswordHasher;
use Cake\ORM\Entity;
/**
* User Entity.
*/
class User extends Entity
{
protected $_accessible = [
'*' => true,
'id' => false
];
protected function _setPassword($password)
{
return (new DefaultPasswordHasher)->hash($password);
}
}
?>
I cant register or add more data now, unlike before I can add or register, I recently updated the version of my cakephp, I also added, gender, address and age fields in database
Im a newbie,
I ran into this issue myself and the culprit for me was the 'isUnique' call on the field. My issue was the email field and it didn't need to be unique.
Additionally, after changing a model on a production environment you must clear the cache for newly submitted fields to go into the db.
'cake cache clear_all'.
I wasn't able to post a comment.

Custom Laravel validation messages

I'm trying to create customized messages for validation in Laravel 5. Here is what I have tried so far:
$messages = [
'required' => 'Harap bagian :attribute di isi.',
'unique' => ':attribute sudah digunakan',
];
$validator = Validator::make($request->all(), [
'username' => array('required','unique:Userlogin,username'),
'password' => 'required',
'email' => array('required','unique:Userlogin,email'),$messages
]);
if ($validator->fails()) {
return redirect('/')
->withErrors($validator) // send back all errors to the login form
->withInput();
} else {
return redirect('/')
->with('status', 'Kami sudah mengirimkan email, silahkan di konfirmasi');
}
But it's not working. The message is still the same as the default one. How can I fix this, so that I can use my custom messages?
Laravel 5.7.*
Also You can try something like this. For me is the easiest way to make custom messages in methods when you want to validate requests:
public function store()
{
request()->validate([
'file' => 'required',
'type' => 'required'
],
[
'file.required' => 'You have to choose the file!',
'type.required' => 'You have to choose type of the file!'
]);
}
If you use $this->validate() simplest one, then you should write code something like this..
$rules = [
'name' => 'required',
'email' => 'required|email',
'message' => 'required|max:250',
];
$customMessages = [
'required' => 'The :attribute field is required.'
];
$this->validate($request, $rules, $customMessages);
You can provide custom message like :
$rules = array(
'URL' => 'required|url'
);
$messages = array(
'URL.required' => 'URL is required.'
);
$validator = Validator::make( $request->all(), $rules, $messages );
if ( $validator->fails() )
{
return [
'success' => 0,
'message' => $validator->errors()->first()
];
}
or
The way you have tried, you missed Validator::replacer(), to replace the :variable
Validator::replacer('custom_validation_rule', function($message, $attribute, $rule, $parameters){
return str_replace(':foo', $parameters[0], $message);
});
You can read more from here and replacer from here
For Laravel 8.x, 7.x, 6.x
With the custom rule defined, you might use it in your controller validation like so :
$validatedData = $request->validate([
'f_name' => 'required|min:8',
'l_name' => 'required',
],
[
'f_name.required'=> 'Your First Name is Required', // custom message
'f_name.min'=> 'First Name Should be Minimum of 8 Character', // custom message
'l_name.required'=> 'Your Last Name is Required' // custom message
]
);
For localization you can use :
['f_name.required'=> trans('user.your first name is required'],
Hope this helps...
$rules = [
'username' => 'required,unique:Userlogin,username',
'password' => 'required',
'email' => 'required,unique:Userlogin,email'
];
$messages = [
'required' => 'The :attribute field is required.',
'unique' => ':attribute is already used'
];
$request->validate($rules,$messages);
//only if validation success code below will be executed
//Here is the shortest way of doing it.
$request->validate([
'username' => 'required|unique:Userlogin,username',
'password' => 'required',
'email' => 'required|unique:Userlogin,email'
],
[
'required' => 'The :attribute field is required.',
'unique' => ':attribute is already used'
]);
//The code below will be executed only if validation is correct.
run below command to create a custom rule on Laravel
ı assuming that name is CustomRule
php artisan make:rule CustomRule
and as a result, the command was created such as PHP code
if required keyword hasn't on Rules,That rule will not work
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class CustomRule implements Rule
{
/**
* Create a new rule instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
//return true or false
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'The validation error message.';
}
}
and came time using that
first, we should create a request class if we have not
php artisan make:request CustomRequest
CustomRequest.php
<?php
namespace App\Http\Requests\Payment;
use App\Rules\CustomRule;
use Illuminate\Foundation\Http\FormRequest;
class CustomRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules(): array
{
return [
'custom' => ['required', new CustomRule()],
];
}
/**
* #return array|string[]
*/
public function messages(): array
{
return [
'custom.required' => ':attribute can not be empty.',
];
}
}
and on your controller, you should inject custom requests to the controller
your controller method
class FooController
{
public function bar(CustomRequest $request)
{
}
}
You can also use the methods setAttributeNames() and setCustomMessages(),
like this:
$validation = Validator::make($this->input, static::$rules);
$attributeNames = array(
'email' => 'E-mail',
'password' => 'Password'
);
$messages = [
'email.exists' => 'No user was found with this e-mail address'
];
$validation->setAttributeNames($attributeNames);
$validation->setCustomMessages($messages);
For those who didn't get this issue resolve (tested on Laravel 8.x):
$validated = Validator::make($request->all(),[
'code' => 'required|numeric'
],
[
'code.required'=> 'Code is Required', // custom message
'code.numeric'=> 'Code must be Number', // custom message
]
);
//Check the validation
if ($validated->fails())
{
return $validated->errors();
}
$rules = [
'name' => 'required',
'email' => 'required|email',
'message' => 'required|max:250',
];
$customMessages = [
'required' => 'The :attribute field is required.',
'max' => 'The :attribute field is may not be greater than :max.'
];
$this->validate($request, $rules, $customMessages);
In the case you are using Request as a separate file:
public function rules()
{
return [
'preparation_method' => 'required|string',
];
}
public function messages()
{
return [
'preparation_method.required' => 'Description is required',
];
}
Tested out in Laravel 6+
you can customise the message for different scenarios based on the request.
Just return a different message with a conditional.
<?php
namespace App\Rules;
use App\Helpers\QueryBuilderHelper;
use App\Models\Product;
use Illuminate\Contracts\Validation\Rule;
class ProductIsUnique implements Rule
{
private array $attributes;
private bool $hasAttributes;
/**
* Create a new rule instance.
*
* #return void
*/
public function __construct(array $attributes)
{
$this->attributes = $attributes;
$this->hasAttributes = true;
}
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
$brandAttributeOptions = collect($this->attributes['relationships']['brand-attribute-options']['data'])->pluck('id');
$query = Product::query();
$query->when($brandAttributeOptions->isEmpty(), function ($query) use ($value) {
$query->where('name', $value);
$this->hasAttributes = false;
});
return !$query->exists();
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return ($this->hasAttributes) ? 'The Selected attributes & Product Name are not unique' : 'Product Name is not unique';
}
}
Laravel 10.x
If you are using Form Requests, add another method called messages(): array in your request.
class YourRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => 'required',
'email' => 'required|email',
...
];
}
//Add the following method
public function messages(): array
{
return [
'email.required' => 'Custom message for Email Required',
];
}
}
Then the message will be displayed automatically once the request is send from the form.

How can I correctly relate these tables in cakephp?

I'm trying to create a set of CRUDs using cakephp3. My database model looks like this:
I used the cake's tutorial on authentication to create the users table and it's classes, it's working fine. But I want to use a more complex set of roles, so I created these other tables. After creating the database model I baked the corresponding classes, made a few tweaks and got the systems and the roles CRUD's to work. Now I want to integrate the roles_users table, probably inside of user's CRUD.
I would like to see how cake's bake would do it before coding this relation myself, but I'm unable to open /rolesUsers. When I call the URL, I get the following error message:
Cannot match provided foreignKey for "Roles", got "(role_id)" but expected foreign key for "(id, system_id)" RuntimeException
I think it happens because system_id is a PK in roles table and isn't present in roles_users (I'll show the baked models and this PK will be present at roles class). Is there an easy way to make it work without adding system_id in roles_users? IMO adding this extra field wouldn't be a big problem, but I would like to know if I'm doing something wrong, some bad design decision.
My src/Model/Table/RolesUsersTable.php:
<?php
namespace App\Model\Table;
use App\Model\Entity\RolesUser;
use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;
/**
* RolesUsers Model
*
* #property \Cake\ORM\Association\BelongsTo $Users
* #property \Cake\ORM\Association\BelongsTo $Roles
*/
class RolesUsersTable extends Table
{
/**
* Initialize method
*
* #param array $config The configuration for the Table.
* #return void
*/
public function initialize(array $config)
{
parent::initialize($config);
$this->table('roles_users');
$this->displayField('user_id');
$this->primaryKey(['user_id', 'role_id']);
$this->belongsTo('Users', [
'foreignKey' => 'user_id',
'joinType' => 'INNER'
]);
$this->belongsTo('Roles', [
'foreignKey' => 'role_id',
'joinType' => 'INNER'
]);
}
/**
* Default validation rules.
*
* #param \Cake\Validation\Validator $validator Validator instance.
* #return \Cake\Validation\Validator
*/
public function validationDefault(Validator $validator)
{
$validator
->add('valido_ate', 'valid', ['rule' => 'date'])
->requirePresence('valido_ate', 'create')
->notEmpty('valido_ate');
return $validator;
}
/**
* Returns a rules checker object that will be used for validating
* application integrity.
*
* #param \Cake\ORM\RulesChecker $rules The rules object to be modified.
* #return \Cake\ORM\RulesChecker
*/
public function buildRules(RulesChecker $rules)
{
$rules->add($rules->existsIn(['user_id'], 'Users'));
$rules->add($rules->existsIn(['role_id'], 'Roles'));
return $rules;
}
}
My src/Model/Table/RolesTable.php:
<?php
namespace App\Model\Table;
use App\Model\Entity\Role;
use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;
/**
* Roles Model
*
* #property \Cake\ORM\Association\BelongsTo $Systems
*/
class RolesTable extends Table
{
/**
* Initialize method
*
* #param array $config The configuration for the Table.
* #return void
*/
public function initialize(array $config)
{
parent::initialize($config);
$this->table('roles');
$this->displayField('name');
$this->primaryKey(['id', 'system_id']);
$this->belongsTo('Systems', [
'foreignKey' => 'system_id',
'joinType' => 'INNER'
]);
}
/**
* Default validation rules.
*
* #param \Cake\Validation\Validator $validator Validator instance.
* #return \Cake\Validation\Validator
*/
public function validationDefault(Validator $validator)
{
$validator
->add('id', 'valid', ['rule' => 'numeric'])
->allowEmpty('id', 'create');
$validator
->requirePresence('name', 'create')
->notEmpty('name');
$validator
->add('status', 'valid', ['rule' => 'numeric'])
->requirePresence('status', 'create')
->notEmpty('status');
return $validator;
}
/**
* Returns a rules checker object that will be used for validating
* application integrity.
*
* #param \Cake\ORM\RulesChecker $rules The rules object to be modified.
* #return \Cake\ORM\RulesChecker
*/
public function buildRules(RulesChecker $rules)
{
$rules->add($rules->existsIn(['system_id'], 'Systems'));
return $rules;
}
}
My src/Model/Table/UsersTable:
<?php
namespace App\Model\Table;
use Cake\ORM\Table;
use Cake\Validation\Validator;
class UsersTable extends Table{
public function validationDefault(Validator $validator){
return $validator
->notEmpty('username', 'O campo nome de usuário é obrigatório')
->notEmpty('password', 'O campo senha é obrigatório')
->notEmpty('role', 'O campo perfil é obrigatório')
->add('role', 'inList', [
'rule' => ['inList', ['admin', 'author']],
'message' => 'Escolha um perfil válido'
]
);
}
}
?>
Answered by user jose_zap in #cakephp #freenode:
In RolesUsersTable.php, initialize function, I added a parameter to both $this->belongsTo calls, including the 'bindingKey' and value 'id'. So this old code:
$this->belongsTo('Users', [
'foreignKey' => 'user_id',
'joinType' => 'INNER'
]);
$this->belongsTo('Roles', [
'foreignKey' => 'role_id',
'joinType' => 'INNER'
]);
became this:
$this->belongsTo('Users', [
'foreignKey' => 'user_id',
'bindingKey' => 'id',
'joinType' => 'INNER'
]);
$this->belongsTo('Roles', [
'foreignKey' => 'role_id',
'bindingKey' => 'id',
'joinType' => 'INNER'
]);

Categories