CakePHP3.x custom validation not working - cakephp

Inside UsersTable class, I am trying to implement custom validation following the CakeBook but I got an error saying, Object of class App\Model\Table\UsersTable could not be converted to string [CORE/src/Validation/ValidationRule.php, line 128]. Below is my code in UsersTable.php.
class UsersTable extends Table{
public function validationDefault(Validator $validator){
$validator->add(
"password",[
"notEmpty"=>[
"notEmpty"
],
"custom"=>[
"rule"=>[$this,"customFunction"],
"message"=>"foo"
]
]
);
}
public function customFunction($value,$context){
//some logic here
}
}
Looking at ValidationRule.php in core CakePHP library, I have noticed that array_shift() (on line 185) is taking the first element of [$this,"customFunction"], that is, $this and assigning it to $value. But actually $value should be [$this,"customFunction"]. Therefore, for my code to work without any error, I needed to add one more nesting to [$this,"customFunction"](So it is now [[$this,"customFunction"]]). Do I misunderstand something or is this some kind of bug?
UPD: This problem is now fixed.

I think you've spotted that correctly, the problem seems to be that CakePHP expects the rule key value to be in
[string or callable, ...args]
format when it is in array, ie it doesn't test whether the value itself already is a callable.
The documentation says that the non-nested variant should work, so you might want to report this as a bug.

Use this in your model for custom validation
public function validationCustom($validator)
{
return $validator
->notEmpty('username', 'A username is required');
}
Use validation method name except validation keyword in your controller when you want to save or update
$user = $this->Articles->newEntity($this->request->data,
['validate' => 'custom']);

Related

How can i fetch dynamic data from database based on selected language.?

Hi i am working on a project in laravel 7.0, in back-end i have a table called Posts which contains 2 text language input one in french and the other is arabic added by the back-end application.
what i am trying to do is when the user uses the French Language i want the title_fr to be displayed on the view and same thing in Arabic language the title should be title_ar.
P.S data are stored in French and Arabic
I have tried the similar solution given in an other similar question but none of it worked in my case!
Any idea how i might get this to work ?
Thanks in advance.
You can do something similar to below. We have a model Post, this model has an attribute title. I also assume that you have an attribute that will return user's language from the User model.
class Post extends Model
{
public function getTitleAttribute(): string
{
return Auth::user()->language === 'fr' ? $this->title_fr : $this->title_ar;
}
}
FYI above is just a demo on what can be done. For a full blow solution I would recommend decorator pattern.
Also it might be worth considering using morph for things like that. You can have a service provider that will initiate the morph map for you post model relevant to the language that user has, I.e.
Class ModelProvider {
Protected $models = [
‘fr’ => [
‘post’ => App/Models/Fr/Post::class,
],
‘ar’ => [
‘post’ => App/Models/Ar/Post::class,
]
];
Public function boot() {
$language = Auth::user()->Settings->language;
Relation::morphMap($This->models[$language]);
}
}
Afterwards you just need to call to Relation::getMorphModel(‘post’) to grab Post class that will return correct language.
I.e. App/Models/Fr/Post can have a an attribute title:
Public function getTitleAttribute(): string {
Return $this->title_fr;
}
For example above you would also want to utilise interfaces to make sure that all models follow the same contract, something below would do the trick:
Interface I18nPostInterface {
Public function getTitleAttribute(): string
}
Also, depending on the database you use, to store titles (and other language data) in a JSON format in the database. MySQL 8 has an improve support for JSON data, but there are limitations with that.
So I was Able to fetch data from my database based on the Language selected by the user.
Like i said before I have a table called Posts and has columns id,title_fr and title_ar. I am using laravel Localization.
Inside my PostController in the index function i added this code:
public function index()
{
//
$post = Post::all();
$Frtitle = post::get()->pluck('title_fr');
$Artitle = post::get()->pluck('title_ar');
return view('post.index',compact('post','Frtitle','Artitle'));
}
if anyone has a better way then mine please let me know, i am sure
there is a better way.

1146 Table 'Accounting.users' doesn't exist Cake\Database\

I'm working with cakephp3. I want to make login page. Name of table in Accounting database is 'users'.
This is my code:
<?php
namespace App\Controller;
use App\Controller\AppController;
class UsersController extends AppController {
public function login() {
if ($this->request->is('post')) {
$data = $this->request->data;
$cnt = $data->Users->find()
->count();
if ($cnt > 0) {
$this->redirect(['action' => 'index']);
} else {
$this->set('error', 'username or password is incorrct ');
}
}
}}
and this is Users.php
<?php
namespace App\Model\Table;
use Cake\ORM\Table;
class UsersTable extends Table {
}
after login in login page:
Error: Call to a member function find() on a non-object
In your opinion, what is the problem.
$data is not a Table object.
$data = $this->request->data;
$cnt = $data->Users->find()
This is pretty obvious.
I strongly recommend you to take some time and learn about debugging techniques and how to tackle this kind of problem and error messages. A developer should be able to resolve this kind of problem pretty quickly without external help. This is considered normal ever days work for a developer.
1) Read the whole error message 2) Search for it on Google and Stackoverflow, it is very unlikely nobody else ever got that message before. 3) Act according to whatever the cause of the error message is.
In the case of this error message debug what kind of object you're dealing with and figure out why it is not the object you expect it to be. Going trough the call stack helps. Use Xdebugs profiler for that, it's a great tool.
Also don't use variable names like $cnt I assume this is supposed to mean "account" which doesn't even fit into the context it is used. It's very bad named. Instead use proper variable names that are readable and fit into the context. It is a totally wrong assumption that keeping variable names short is any kind of time saver - it is clearly not. The next person working with this will need a dictionary or do a lot of guesswork on what these variables mean.
Instead of $cnt = $data->Users->find()->count(); use $cnt = $this->{$this->modelClass}->find('count');

CakePHP 3- Showing all error and buildRules messages in controller

I have this Model/Table/UsersProfilesTable.php where I have specified all the error messages and buildRules.
My intention is to list all the validation errors in the controller while attempting to save the data.
The code is mentioned below.
// Model/Table/UsersProfilesTable.php
class UserProfilesTable extends Table{
public function validationDefault(Validator $validator){
$validator = new Validator();
$validator
->notEmpty("first_name","First name cannot be empty.")
->requirePresence("first_name")
.......
->notEmpty("email", "Email cannot be empty.")
->requirePresence("email")
->add( "email", "email",[
"rule" => ["email", true],
"message" => "Enter a valid e-mail."
]);
return $validator;
}
public function buildRules(RulesChecker $rules){
$rules->add($rules->isUnique(['email'], 'Email should be unique'));
return $rules;
}
//UsersController.php
$user = $this->Users->patchEntity($user, $this->request->data);
if($this->Users->save($user)){
// Success msg
}
if($user->errors()){
// This shows all the error messages except the one specified in the buildRules for unique email.
pr($user->errors());
}
Can anyone please come up with a way in which I can list all the validation errors including the message specified in the buildRules method?
Any help would be appreciated. Thanks in advance!
Peace! xD
Remember that validation is a 2 phase process, first all the validatiton rules are checked (during marshalling - i.e. patchEntity()), only if they pass are the rules in buildRules are used. This means that the unique email rule will not be run until the standard validation rules all pass.
If you need immediate feedback for email uniqueness you can also add a validation rule for email uniqueness in the validator.
You can use this to force Cake to check the rules even if validation fails:
$this->Users->checkRules($user);

cakephp beforesave question

I follow in book.cake and I don't know I should send something to the parameters.
function beforeSave() {
if (!empty($this->data['Article']['create_dt']) && !empty($this->data['Article']['modified_dt'])) {
$this->data['Article']['create_dt'] = $this->dateFormatBeforeSave($this->data['Article']['create_dt']);
$this->data['Article']['modified_dt'] = $this->dateFormatBeforeSave($this->data['Article']['modified_dt']);
}
return true;
}
I try to search example but don't found.
I need many example
somebody can help me to find big resource
thank for suggest
beforeSave is called automatically by Cake before it saves data. In it, you can do whatever you want to do before each save. Typically this means altering $this->data, which is the data that is about to be saved.
The method is passed one parameter: an array of the form array('validate' => true/false, ('fieldList' => array(...)). This corresponds to the two extra parameters you can supply to save():
$this->Model->save($this->data, false, array('foo', 'bar'));
In this case the array would look like
array('validate' => false, 'fieldList' => array('foo', 'bar')).
You can accept this array by specifying an argument:
public function beforeSave($options) { ... }
$options will look like described above. You can use this information any way you want.
If you don't return true from beforeSave, the save operation will be canceled altogether.
That's all.
try using created and modified magic fields with datetime type in table cake would automatically handle them
i want to mention, that beforeSave() should be used carefully, because it is used on every time when data is saved with this model.
if you forget that it is used, you will get unexpected results.
Happens to me several times... ;)

CakePHP Component not working

Hey guys, I'm working on a cakephp app that manages a list of alpha users. It's a simple form that accepts a name and email and then generates an alpha code after submission, that alpha code is then stored in the record with the name and email under the column "code." I'm using a component calleed PasswordHelper which is located here
Here' my code
class AlphaUsersController extends AppController {
var $name = 'AlphaUsers';
var $components = array('PasswordHelper');
function add() {
if(!empty($this->data)) {
if($this->AlphaUser->save($this->data)){
$this->AlphaUser->set('code', generatePassword(10));
$this->AlphaUser->save();
$this->Session->setFlash('User has been added.');
$this->redirect(array('action' => 'index'));
}
}
}
}
The form data saves just fine when I don't include the alpha code lines, but when I try to generate the password, I get this error.
Fatal error: Call to undefined function generatepassword() in /Users/Warren/Sites/caroverload/app/controllers/alpha_users_controller.php on line 22
What's going on here? I have the PasswordHelper file saved in the appropriate components directory and it's added in the components array for this controller.
I think the way you are calling the PasswordHelper methods should look more like this: $this->PasswordHelper->generatePassword(10).
As you have it now, it is looking for that as a global function, which doesn't exist and throws the error.

Resources