I have two tables (users and affiliates) that I want to relate with affiliate_id in users table, but I want to allow null value in affiliate_id in some cases, how can I do that?
What do you currently have that’s blocking it?
I don’t know.
This is the code for UsersTable.php:
<?php
declare(strict_types=1);
namespace App\Model\Table;
use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;
/**
* Users Model
*
* @property \App\Model\Table\ProfilesTable&\Cake\ORM\Association\BelongsTo $Profiles
*
* @method \App\Model\Entity\User newEmptyEntity()
* @method \App\Model\Entity\User newEntity(array $data, array $options = [])
* @method \App\Model\Entity\User[] newEntities(array $data, array $options = [])
* @method \App\Model\Entity\User get($primaryKey, $options = [])
* @method \App\Model\Entity\User findOrCreate($search, ?callable $callback = null, $options = [])
* @method \App\Model\Entity\User patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = [])
* @method \App\Model\Entity\User[] patchEntities(iterable $entities, array $data, array $options = [])
* @method \App\Model\Entity\User|false save(\Cake\Datasource\EntityInterface $entity, $options = [])
* @method \App\Model\Entity\User saveOrFail(\Cake\Datasource\EntityInterface $entity, $options = [])
* @method \App\Model\Entity\User[]|\Cake\Datasource\ResultSetInterface|false saveMany(iterable $entities, $options = [])
* @method \App\Model\Entity\User[]|\Cake\Datasource\ResultSetInterface saveManyOrFail(iterable $entities, $options = [])
* @method \App\Model\Entity\User[]|\Cake\Datasource\ResultSetInterface|false deleteMany(iterable $entities, $options = [])
* @method \App\Model\Entity\User[]|\Cake\Datasource\ResultSetInterface deleteManyOrFail(iterable $entities, $options = [])
*
* @mixin \Cake\ORM\Behavior\TimestampBehavior
*/
class UsersTable extends Table
{
/**
* Initialize method
*
* @param array $config The configuration for the Table.
* @return void
*/
public function initialize(array $config): void
{
parent::initialize($config);
$this->setTable('users');
$this->setDisplayField('username');
$this->setPrimaryKey('id');
$this->addBehavior('Timestamp');
$this->addBehavior('Search.Search');
$this->searchManager()
->value('username')
->value('email')
->add('search', 'Search.Like', [
'before' => true,
'after' => true,
'fieldMode' => 'OR',
'comparison' => 'LIKE',
'wildcardAny' => '*',
'wildcardOne' => '?',
'fields' => ['username','email']
]);
$this->belongsTo('Profiles', [
'foreignKey' => 'profile_id',
'joinType' => 'INNER',
]);
$this->belongsTo('Affiliates', [
'foreignKey' => 'affiliate_id',
'joinType' => 'LEFT',
]);
}
/**
* Default validation rules.
*
* @param \Cake\Validation\Validator $validator Validator instance.
* @return \Cake\Validation\Validator
*/
public function validationDefault(Validator $validator): Validator
{
$validator
->integer('id')
->allowEmptyString('id', null, 'create');
$validator
->scalar('username')
->maxLength('username', 100)
->allowEmptyString('username');
$validator
->scalar('password')
->maxLength('password', 100)
->allowEmptyString('password');
$validator
->email('email')
->allowEmptyString('email');
$validator
->scalar('firstname')
->maxLength('firstname', 100)
->allowEmptyString('firstname');
$validator
->scalar('lastname')
->maxLength('lastname', 100)
->allowEmptyString('lastname');
$validator
->boolean('active')
->notEmptyString('active');
$validator
->scalar('token')
->maxLength('token', 100)
->requirePresence('token', 'create')
->allowEmptyString('token');
$validator
->integer('affiliate_id')
->allowEmptyString('affiliate_id', null);
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): RulesChecker
{
$rules->add($rules->isUnique(['username']), ['errorField' => 'username']);
$rules->add($rules->isUnique(['email']), ['errorField' => 'email']);
$rules->add($rules->existsIn(['profile_id'], 'Profiles'), ['errorField' => 'profile_id']);
$rules->add($rules->existsIn(['affiliate_id'], 'Affiliates'), ['errorField' => 'affiliate_id']);
return $rules;
}
}
This is the code for add.php:
<?php
/**
* @var \App\View\AppView $this
* @var \App\Model\Entity\User $user
*/
?>
<div class="row">
<aside class="column">
<div class="side-nav">
<h4 class="heading"><?= __('Acciones') ?></h4>
<?= $this->Html->link(__('Listar Usuarios'), ['action' => 'index'], ['class' => 'side-nav-item']) ?>
</div>
</aside>
<div class="column-responsive column-80">
<div class="users form content">
<?= $this->Form->create($user) ?>
<fieldset>
<legend><?= __('Agregar Usuario') ?></legend>
<?php
echo $this->Form->control('username', ['label' => 'Nombre de usuario']);
echo $this->Form->control('password', ['label' => 'Contraseña']);
echo $this->Form->control('email', ['label' => 'E-mail']);
echo $this->Form->control('firstname', ['label' => 'Nombre']);
echo $this->Form->control('lastname', ['label' => 'Apellido']);
echo $this->Form->control('profile_id', ['label' => 'Perfil', 'empty' => '- Seleccione un perfil -', 'options' => $profiles]);
echo '<div id="selectAffiliate" style="display:none;">'.$this->Form->control('affiliate_id', ['label' => 'Afiliado', 'empty' => '- Seleccione un afiliado -', 'options' => $affiliates]).'</div>';
echo $this->Form->control('active', ['label' => 'Activo']);
?>
</fieldset>
<?= $this->Form->button(__('Submit')) ?>
<?= $this->Form->end() ?>
</div>
</div>
</div>
<script>
$(function(){
$('#profile-id').change(function(){
var profile_id = $(this).val();
if(profile_id=="5") $('#selectAffiliate').show();
else $('#selectAffiliate').hide();
})
})
</script>
And this is the code for add action in UsersController.php:
public function add()
{
$user = $this->Users->newEmptyEntity();
if ($this->request->is('post')) {
$user = $this->Users->patchEntity($user, $this->request->getData());
if ($this->Users->save($user)) {
$this->Flash->success(__('El usuario ha sido guardado.'));
$result = $this->Authentication->getResult();
// If the user is logged in send them away.
if ($result->isValid()) {
return $this->redirect(['action' => 'index']);
}else{
return $this->redirect(['action' => 'login']);
}
}
$this->Flash->error(__('El usuario no pudo ser guardado. Por favor, intente nuevamente.'));
}
$profiles = $this->Users->Profiles->find('list', ['limit' => 200]);
$affiliates = $this->Users->Affiliates->find('list', ['limit' => 200]);
$this->set(compact('user', 'profiles', 'affiliates'));
}
As you can see the affiliate_id control is hidden for the user, but I show it with jquery when the user selects profile_id number 5.
But even when I select an affiliate it doesn’t save the user.
I solved it, the problem was here;
$validator
->scalar('token')
->maxLength('token', 100)
->requirePresence('token', 'create')
->allowEmptyString('token');
I eliminated it and worked fine