Date condition (visits) - yii2

I'm trying to make a condition where if the registry has the same the same image as the same date cannot be saved
public function validateVisit()
{
if (Visit::find()->where(['date_visit'=>$this->date_visit])->all()) {
if (Visit::find()->where(['imagen_id'=>$this->imagen_id])->all()) {
$this->addError('imagen_id', 'Already exists this visit within the range.');
}
}
}
In my code it does not save when the image that is entered already exists in the database, in my case, I require that you do not save when the same date that is entered with the same image already exists

You can use unique validator for this.
public function rules()
{
return [
[['imagen_id'], 'unique', 'targetAttribute' => ['imagen_id', 'date_visit']],
// ... other validations ...
];
}
The first item in rule definition ['date_visit'] says to what attribute the error will be set. The targetAttribute define combination of attributes that must be unique. In this case the validation will only pass when the combination of imagen_id and date_visit attributes doesn't exist.
See more about unique validator.

Related

How can I translate Laravel's default validation errors in JSON file?

I need to translate Laravel's default validation errors in JSON files. The problem is if I want to overwrite a translation, like the 'required' validation error in resourses/lang/de.json file, it doesn't work.
The reason why I have to do this is the Phrase translator system what I am using.
Any idea? Thanks!
UPDATE
After some research, now I see what is my 'problem'. Laravel using the trans() function for translating the validation errors but if you want to use Laravel's JSON translation then you have to use the __() function. Okey, I know why they are doing in that way, because the validation errors are structured by 'short keys' and the JSON formatted translation if for use strings as keys.
But what if I still want to translate the default errors in the JSONish (I know it's a futuristic word) way? Follow my solution here:
First of all you have to create a form request (https://laravel.com/docs/7.x/validation#creating-form-requests):
php artisan make:request UserUpdateRequest
In the newly created form request file you have to overwrite the messages function to be able to translate the validation errors:
namespace App\Http\Requests\v1;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use App\Exceptions\ApiValidationException;
class UserUpdateRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => ['required', 'string', 'min:3', 'max:255'],
];
}
/**
* Get custom messages for validator errors.
*
* #return array
*/
public function messages()
{
return [
'name.required' => __('The user name is required.'),
'name.string' => __('The user name must be a string.'),
'name.min' => __('The user name must be at least three characters.'),
'name.max' => __('The user name may not be greater than 255 characters.'),
];
}
}
Now we have to create the translations files (https://laravel.com/docs/7.x/localization#using-translation-strings-as-keys) and put the new translation strings into them.
# resourses/lang/de.json
{
"The user name is required." : "The user name is required.",
"The user name must be a string." : "The user name must be a string.",
"The user name must be at least three characters." : "The user name must be at least three characters.",
"The user name may not be greater than 255 characters." : "The user name may not be greater than 255 characters."
}
And that's all.
I hope this description of translation process it will be useful for someone else.
I need to translate Laravel's default validation errors in JSON files. The problem is if I want to overwrite a translation, like the 'required' validation error in resourses/lang/de.json file, it doesn't work.
The reason why I have to do this is the Phrase translator system what I am using.
Any idea? Thanks!
ANSWER
After some research, now I see what is my 'problem'. Laravel using the trans() function for translating the validation errors but if you want to use Laravel's JSON translation then you have to use the __() function. Okey, I know why they are doing in that way, because the validation errors are structured by 'short keys' and the JSON formatted translation if for use strings as keys.
But what if I still want to translate the default errors in the JSONish (I know it's a futuristic word) way? Follow my solution here:
First of all you have to create a form request (https://laravel.com/docs/7.x/validation#creating-form-requests):
php artisan make:request UserUpdateRequest
In the newly created form request file you have to overwrite the messages function to be able to translate the validation errors:
namespace App\Http\Requests\v1;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use App\Exceptions\ApiValidationException;
class UserUpdateRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => ['required', 'string', 'min:3', 'max:255'],
];
}
/**
* Get custom messages for validator errors.
*
* #return array
*/
public function messages()
{
return [
'name.required' => __('The user name is required.'),
'name.string' => __('The user name must be a string.'),
'name.min' => __('The user name must be at least three characters.'),
'name.max' => __('The user name may not be greater than 255 characters.'),
];
}
}
Now we have to create the translations files (https://laravel.com/docs/7.x/localization#using-translation-strings-as-keys) and put the new translation strings into them.
# resourses/lang/de.json
{
"The user name is required." : "The user name is required.",
"The user name must be a string." : "The user name must be a string.",
"The user name must be at least three characters." : "The user name must be at least three characters.",
"The user name may not be greater than 255 characters." : "The user name may not be greater than 255 characters."
}
And that's all.
I hope this description of translation process it will be useful for someone else.
Based on the answer provided I digged some more and discovered the double underscore function is working as intended in the default validation.php file! I tested it with Laravel 5.6.
I have a similar issue that I need to provide a way for users to give translations for everything in the web app and so I started to test the solution. While it works as explained it does not use the placeholder attribute anymore and therefore it is not very scalable in my situation.
I tested using the double underscore function with the following requirements:
locale and fallback_locale are set to 'en' in app.php
There is an en folder inside resources/lang
There is a validation.php file inside the en folder
There is a locale json file (like pt-br.json) inside resources/lang folder
The application sets the locale dynamically using App::setlocale()
All that is needed to change in validation.php is to use the function in the string, like the following:
# before
'unique' => 'The :attribute has already been taken.',
#after
'unique' => __('The :attribute has already been taken.'),
And the json file needs to have a string key with the same string, like the following:
"The :attribute has already been taken.": ":attribute j\u00e1 existe!"
Thanks for making me thinking more on this problem. I think Laravel should have better support for use cases like this.

Yii2: Prevent empty string in attribute of ActiverRecord

What's the best way to prevent that an empty string gets inserted into a field of an MySQL's InnoDB table? Allowed values are strings with more than zero characters or NULL.
I'm asking that because ActiveRecord model objects often get loaded with view's form data which don't know and thus don't send NULL values. In such a case I'd prefer that a NULL gets stored instead of the empty string.
Should I define a rule? Should I implement a setter? Use a trigger?
You should simply use the default validator, add this rule to your model :
public function rules()
{
return [
// ...
['attribute', 'default', 'value' => null],
// ...
];
}

Ignore validation on soft deleted models

I have user table. I created a form with 3 fields:
Username
phonenumber
status
The first two fields are unique. Model rules for those fields look like this:
[['Username', 'phonenumber'], 'required'],
[['Username', 'phonenumber'], 'unique'],
I use soft deletion, so when record is deleted, it actually stays in database but status value will change to 0.
The problem is, if I add a record with existing username it shows an error message like "already added". I need to ignore validation if username have a status with value 0.
Use filter property of UniqueValidator
public function rules()
{
return [
...
['username', 'unique', 'filter' => ['<>', 'status', 0]];
...
];
}
It's better to declare constant instead of 0 (something like const STATUS_DELETED = 0) and user it as self::STATUS_DELETED inside of User class. Also you can use != instead of <>.
The last recommendation will be to use username instead of Username to follow convention of naming database table columns.
Read more about ways of declaring filter in official docs.
The ways of setting filter condition as array is described here.
You can use your own function to decide the given username already exists in active status or not. Use this function in "when" property of your unique validation rule.
Have a look :
public function rules()
{
$check = function($model) {
$existActiveUser = User::model()->findByAttributes(array("username"=>$model->username,"status"=>1));
if($existActiveUser)
return true;
else
return false;
};
return [
['Username', 'phonenumber'], 'required'],
[['Username','phonenumber'],'unique','when'=>$check],
}

Save Model Values Without Null

Everytime i try attempt to update a row i receive an error which says "something is required". In codeigniter you can update rows without the need to set everything to null in the mysql tabel settings.
I just want to update one value not the entire row.
Is this possible?
if ($users->save() == false) {
echo "Umh, We can't update the user right now: \n";
foreach ($users->getMessages() as $message) {
echo $message, "<br>";
}
$this->flash->error("Error in updating information.");
$this->response->redirect('user/profile');
} else {
echo "Great, a new robot was saved successfully!";
$this->flash->success("Member has been updaed successfully.");
//$this->response->redirect('user/profile');
}
Your isseue happens because you have already filled table and not yet properly defined model. Phalcon is validating all fo model data BEFORE trying to save it. If you define your model with all defaults, skips etc. properly, updates will be fired on single columns as you wish.
If you have definitions, that does not allow nulls, but you need an empty or default value there anyway, you may want to use 'beforeCreate' actions in model implementations. Also if there are things with defaults to set on first insert, you may wanto to use skipAttributes method.
More information is in documentation: Working with Models. So far best bit over internet I've found.
Also, below is an example for nullable email column and NOT NULL DEFAULT '0' 'skipped' column from my working code:
public function initialize() {
$this->skipAttributesOnCreate(['skipped']);
}
public function validation()
{
if($this->email !== null) {
$this->validate(
new Email(
array(
'field' => 'email',
'required' => true,
)
)
);
if ($this->validationHasFailed() == true) {
return false;
}
}
}
You do want errors of "something is required". All you're missing are just proper implementations of defaults over models. Once you get used to those mechanics, you should find them easy to handle and with more pros than cons.
What you are doing is called an insert. To set a column to a different value in a pre-existing row is called an update.
The latter is flexible, the former in not.
I highly recommend not treating a database like this is what i feel like
Put all the data in. Null is your enemy

Preventing malicious users update data at add action

Here is a basic add action:
public function add()
{
$article = $this->Articles->newEntity();
if ($this->request->is('post')) {
$article = $this->Articles->patchEntity($article, $this->request->data);
if ($this->Articles->save($article)) {
$this->Flash->success('Success.');
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error('Fail.');
}
}
$this->set(compact('article'));
}
If a malicious user injects at form a field with name id and set the value of this field to 2. Since the user do that the id value will be in $this->request->data so at $this->Articles->patchEntity($article, $this->request->data) this id will be patched and at $this->Articles->save($article) the record 2 will be updated instead of create a new record??
Depends.
Entity::$_accessible
If you baked your models, then this shouldn't happen, as the primary key field will not be included in the entities _accessible property, which defines the fields that can be mass assigned when creating/patching entities. (this behavior changed lately)
If you baked your models, then this shouldn't happen, as the primary key field(s) will be set to be non-assignable in the entities _accessible property, which means that these the fields cannot be set via mass assignment when creating/patching entities.
If you didn't baked your models and haven't defined the _accessible property, or added the primary key field to it, then yes, in case the posted data makes it to the patching mechanism, then that is what will happen, you'll be left with an UPDATE instead of an INSERT.
The Security component
The Security component will prevent form tampering, and reject requests with modified forms. If you'd use it, then the form data wouldn't make it to the add() method in the first place.
There's also the fieldList option
The fieldList option can be used when creating/patching entities in order to specifiy the fields that are allowed to be set on the entity. Sparse out the id field, and it cannot be injected anymore.
$article = $this->Articles->patchEntity($article, $this->request->data, [
'fieldList' => [
'title',
'body',
//...
]
]);
And finally, validation
Validation can prevent injections too, however that might be considered a little wonky. A custom rule that simply returns false would for example do it, you could create an additional validator, something like
public function validationAdd(Validator $validator) {
return
$this->validationDefault($validator)
->add('id', 'mustNotBePresent', ['rule' => function() {
return false;
}]);
}
which could then be used when patching the entity like
$article = $this->Articles->patchEntity($article, $this->request->data, [
'validate' => 'add'
]);