Codeigniter 4 - Validation messages are not displayed correctly - codeigniter

I decided to put the validations and messages inside the HunterModel.php model. My createHunter() method inside the HunterController.php file should insert a record.
The following snippet shows the problem i'm having: Apparently $this->$data->listError();, doesn't reveal the message (or messages) i defined in $validationMessages.
HunterModel.php
// Validation
protected $validationRules = [
'name_hunter' => 'required|max_length[30]',
'age_hunter' => 'required|integer',
'height_hunter' => 'required|decimal',
'weight_hunter' => 'required|decimal',
'type_hunter' => 'required|max_length[30]',
'type_nen' => 'required|max_length[30]',
'type_blood' => 'required|max_length[3]'
];
protected $validationMessages = [
'name_hunter' => [
'required' => 'Hunter name cannot be empty.',
'max_length' => 'The hunter name must have a maximum of 30 characters.'
],
'age_hunter' => [
'required' => 'Hunter age cannot be empty.',
'integer' => 'The hunter's age must be an integer.'
],
'height_hunter' => [
'required' => 'Hunter height cannot be empty.',
'decimal' => 'The hunter height must be a decimal number.'
],
'weight_hunter' => [
'required' => 'Hunter weight cannot be empty.',
'decimal' => 'The hunter weight must be a decimal number.'
],
'type_hunter' => [
'required' => 'It is necessary to define the type of hunter.',
'max_length' => 'The hunter type must be a maximum of 30 characters.'
],
'type_nen' => [
'required' => 'It is necessary to define the nen of the hunter.',
'max_length' => 'The hunter's nen must have a maximum of 30 characters.'
],
'type_blood' => [
'required' => 'It is necessary to define the hunter's blood type.',
'max_length' => 'The hunter's blood type must be a maximum of 3 characters.'
]
];
HunterController.php
public function createHunter()
{
try {
$hunter = new HunterModel();
$data = [
'name_hunter' => $this->request->getPost('name_hunter'),
'age_hunter' => $this->request->getPost('age_hunter'),
'height_hunter' => $this->request->getPost('height_hunter'),
'weight_hunter' => $this->request->getPost('weight_hunter'),
'type_hunter' => $this->request->getPost('type_hunter'),
'type_nen' => $this->request->getPost('type_nen'),
'type_blood' => $this->request->getPost('type_blood')
];
if ($hunter->insert($data)){
return $this->response->redirect(site_url('/read_hunters'));
} else {
$this->$data->listError();
}
} catch (\Exception $e) {
exit($e->getMessage());
}
}

Create Validations.php in Libraries folder if it's does not exist.
Validations.php must be like:
<?php
namespace App\Libraries;
class Validations
{
public $hunter = [
'rules' => [
'name_hunter' => 'required|max_length[30]',
//other rules...
],
'error' => [
'name_hunter' => [
'required' => 'Hunter name cannot be empty.',
'max_length' => 'The hunter name must have a maximum of 30 characters.'
],
//other error messages....
]
];
}
HunterController.php must be like:
<?php
namespace App\Controllers;
use App\Libraries\Validations;
class HunterController extends BaseController
{
public function __construct()
{
$this->validator = new Validations();
}
public function createHunter()
{
$response = [];
$val = $this->validate(
$this->validator->hunter['rules'],
$this->validator->hunter['error']
);
if (!$val) {
$response = [
'success' => false,
'msg' => addslashes((preg_replace('/\s+/', ' ', $this->validation->listErrors())))
];
}else {
try {
$hunter = new HunterModel();
$data = [
'name_hunter' => $this->request->getPost('name_hunter'),
'age_hunter' => $this->request->getPost('age_hunter'),
'height_hunter' => $this->request->getPost('height_hunter'),
'weight_hunter' => $this->request->getPost('weight_hunter'),
'type_hunter' => $this->request->getPost('type_hunter'),
'type_nen' => $this->request->getPost('type_nen'),
'type_blood' => $this->request->getPost('type_blood')
];
if ($hunter->insert($data)){
return redirect()->to(site_url('/read_hunters'));
} else {
$response = [
'success' => false,
'msg' => //your custom error message
];
}
} catch (\Exception $e) {
exit($e->getMessage());
}
//if you are using ajax
return $this->response->setJSON($response);
}
}

Related

Laravel: Add custom data to resource

First I get the translator by his id using this line of code
$translator = Translator::where('id', $translator_id)->first();
Then I send a notification to him by this code:
$response = Http::withHeaders([
'Authorization' => 'key=myKey',
'Content-Type' => 'application/json'
])->post('https://fcm.googleapis.com/fcm/send', [
"notification" => [
"title" => "title",
"body" => "body",
],
"data" => [
"title" => "title",
"body" => "body",
],
"to" => $token,
]);
Everything works fine but my problem is that when I return the TranslatorResource I want to add the notification response to it, so I do this in my controller
$resource = new TranslatorResource($translator);
$resource->notif = $response;
return $resource;
And in TranslatorResource I have this code:
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'phone' => $this->phone,
'cv' => $this->cv,
'specialization' => $this->specialization,
'tr_languages' => $this->tr_languages,
'all_languages' => $this->all_languages,
'isVerified' => $this->isVerified == 0 ? false : true,
'isActive' => $this->isActive == 0 ? false : true,
'completed_orders' => $this->completed_orders,
'canceled_orders' => $this->canceled_orders,
'rejected_orders' => $this->rejected_orders,
'current_orders' => $this->current_orders,
'isTranslator' => true,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
But I only get the data specified in the resource, the notif key isn't added, anyone know how to add this data to my resource when I return it ?
You can use additional method provided by laravel.
return (new TranslatorResource($translator))->additional(['notif ' => $response]);
Reference: Eloquent: API Resources
You can look for the section Adding Meta Data When Constructing Resources.

How to use the 'privacy' attribute function in Laravel Rebing GraphQL?

i'm working on a graphql API using Laravel GraphQL.
As shown in the documentation "Privacy" section, it should be possible to add callback function to a GraphQLType fields privacy attribute. The field is supposed to return null, when the callback returns false.
Similar to the example in the laravel graphql Docs, i've added a privacy callback like so:
public function fields(): array {
return [
'email' => [
'type' => Type::string(),
'description' => 'The email of user',
'privacy' => function(User $user): bool {
return $user->isMe();
}
],
];
}
It appears to me, that this callback function never gets called.
I read something about a possible requirement, that i should resolve my query using the $getSelectFields function to query the $fields manually $with the selected columns. But unfortunately the $select
public function resolve($root, $args, $context, ResolveInfo $info, Closure $getSelectFields) {
$fields = $getSelectFields();
$with = $fields->getRelations(); // empty array
$select = $fields->getSelect(); // empty array
return User::select($select)->with($with)->get();
}
In my case this does not make any difference.
In my query resolver i do as following:
public function resolve($root, $args, $context, ResolveInfo $info, Closure $getSelectFields) {
/** #var SelectFields $fields */
$fields = $getSelectFields();
$select = $fields->getSelect();
$with = $fields->getRelations();
exit(var_dump($fields)); // #RESULT
}
My result looks like this:
object(Rebing\\GraphQL\\Support\\SelectFields)#4668 (2) {
[\"select\":\"Rebing\\GraphQL\\Support\\SelectFields\":private]=> array(0) {}
[\"relations\":\"Rebing\\GraphQL\\Support\\SelectFields\":private]=> array(0) {}
}
So my question is: "How do i use the privacy attribute callback in Laravel Rebing GraphQL?"
I'm using:
PHP 7.3
Laravel 7.17
Rebing Graphql Laravel 5.1
Thanks in advance,
greets Jules
Some more Details about my use case
EpUser.php
namespace App\GraphQL\Type;
use App\CommunityImage;
use App\User;
use Carbon\Carbon;
use GraphQL\Type\Definition\Type;
use Illuminate\Support\Facades\Auth;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Type as GraphQLType;
class EpUser extends GraphQLType {
protected $attributes = [
'name' => 'EpUser',
'description' => 'A type',
'model' => User::class,
];
public function fields(): array {
return [
'id' => [
'type' => Type::nonNull(Type::int()),
'description' => 'The id of the user',
'privacy' => function(User $user): bool {
return false;
}
],
'email' => [
'type' => Type::string(),
'description' => 'The email of user',
'privacy' => function(User $user): bool {
return $user->isMe();
}
],
'firstName' => [
'type' => Type::string(),
'description' => 'The firstName of user'
],
'lastName' => [
'type' => Type::string(),
'description' => 'The lastName of user'
],
'fullName' => [
'type' => Type::string(),
'description' => 'The fullName of user',
'selectable' => false,
'resolve' => function(User $user) {
return $user->firstName . " " . $user->lastName;
}
],
'gender' => [
'type' => Type::string(),
'description' => 'The gender of the user'
],
'isOnline' => [
'type' => Type::boolean(),
'description' => '',
'selectable' => false,
'resolve' => function(User $user, $args) {
return $user->isOnline();
}
]
];
}
[...]
And this is the UsersQuery which should respond with a user pagination object, that contains an array of users with a privacy attribute:
UsersQuery.php
namespace App\GraphQL\Query;
use App\Artist;
use App\FilePath;
use Closure;
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Query;
use Illuminate\Support\Facades\Auth;
use GraphQL\Type\Definition\ResolveInfo;
use Rebing\GraphQL\Support\Facades\GraphQL;
use App\User;
class UsersQuery extends Query {
protected $attributes = [
'name' => 'UsersQuery',
'description' => 'A query',
'model' => User::class,
];
public function type(): Type {
return GraphQL::type('userPagination');
}
public function authorize($root, array $args, $ctx, ResolveInfo $resolveInfo = NULL, $getSelectFields = NULL): bool {
return Auth::check();
}
public function args(): array {
return [
'id' => [
'type' => Type::int(),
'description' => 'The id of the user'
],
'slug' => [
'type' => Type::string(),
'description' => 'The slug of the user'
],
'pagination' => [
'type' => Type::nonNull(GraphQL::type('paginationInput')),
'description' => 'The pagination of the users to query',
'rules' => 'required',
],
'search' => [
'type' => Type::string(),
'description' => 'a string to search for users'
],
'roles' => [
'type' => Type::listOf(Type::string()),
'description' => 'The roles of the user',
'rules' => 'sometimes|required|array|in:user,developer,administrator'
]
];
}
public function resolve($root, $args, $context, ResolveInfo $info, Closure $getSelectFields) {
if(isset($args['id']) || isset($args['slug'])) {
if(isset($args['slug'])) {
$user = User::where('slug', $args['slug'])->first();
} else {
$user = User::find($args['id']);
}
return [
'items' => $args['pagination']['limit'] > 0 && $user ? [$user] : NULL,
'itemTotal' => $user ? 1 : 0
];
}
$sortBy = $args['pagination']['sortBy'] ?? 'id';
$sortByDesc = isset($args['pagination']['sortByDesc']) ? $args['pagination']['sortByDesc'] : true;
$sortByType = $sortByDesc ? 'desc' : 'asc';
$search = false;
if(isset($args['search']) && $args['search']) {
$search = true;
$query = User::search($args['search']);
} else {
$query = User::query();
}
if(!empty($sortBy)) {
$query->orderBy($sortBy, $sortByType);
}
// Todo: eloquent search can't serach for whereHas
if(isset($args['roles']) && !$search) {
if(is_array($args['roles'])) {
foreach($args['roles'] as &$role) {
$query->whereHas('roles',
function($q) use ($role) {
$q->where('name', $role);
});
}
} else {
$query->whereHas('roles',
function($q) use ($args) {
$q->where('name', $args['roles']);
});
}
}
if($search) {
$userPaginationObject = [
'itemTotal' => $query->count(),
'items' => $query->getWithLimitAndOffset($args['pagination']['limit'],
$args['pagination']['offset'])
];
} else {
$userPaginationObject = [
'itemTotal' => $query->count(),
'items' => $query->limit($args['pagination']['limit'])->offset($args['pagination']['offset'])->get()
];
}
return $userPaginationObject;
}
}

How to make a good validation on laravel?

I have data, they look like this:
{
sender_name : "Real fake sender name",
recipient_name : "Real fake recipient name",
goods: [
{
"no" : 1
"name":"Pen",
"unit": "1",
"qty":"50",
"price":"50",
"amount":"2500",
"vat_percent":"5",
"vat_sum": "125",
"total_sum": "2625"
}
]
}
I need to validate "goods" using extend validator. Here is his code:
Validator::extend('invoiceGoods' , function($attribute, $value, $parameters, $validator) {
$rulesForGoods = [
'no' => 'integer|required',
'name' => 'string|max:64|required',
'unit' => 'required|integer',
'qty' => 'required|string',
'price' => 'required|numeric',
'amount' => 'required|numeric',
'vat_percent' => 'nullable|numeric',
'vat_sum' => 'nullable|numeric',
'total_sum' => 'required|numeric'
];
foreach ($value as $good) {
$validator = Validator::make($good , $rulesForGoods);
if ($validator->fails()) {
return false;
}
}
return true;
});
This is the main code.
$validator = Validator::make($data , [
'goods' => 'invoiceGoods',
'sender_name' => 'string',
'recipient_name' => 'string',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'message' => 'Validation error.',
'data' => $validator->errors()
]);
}
If the goods validation error occurs, I get this answer:
But I would like to display errors like this: the wrong unit in the goods with no 1.
I know that the third argument can be passed an array with custom messages, but how to return it from the extended validator if it should return true or false?
https://laravel.com/docs/5.8/validation#custom-error-messages
$messages = [
'Validation.invoice_goods' => 'Errror message!',];
$validator = Validator::make($input, $rules, $messages);

Inputfilter for fileupload, basic usage

Now I'm a bit more into this ZF3 stuff. I could (with some help) implement nearly everything I wanted. To dive in the, for me new version, I developed a test project.
Some questions are still unanswered and I didn't find usable explanations.
My new issue is InputFilterAwareInterface. I tried the examples for strings from the tutorial, so far everything ok. But like always for the easy topics you find everything, if you go further it ends abruptly.
I need an Inputfilter for xls and xlsx files. I googled of course, read tutorials, searched in the zend tutorial, because I had the idea there must somewhere exist some complete reference, but I couldn't find any.
So I tried this one:
$inputFilter->add([
'type' => 'Zend\InputFilter\FileInput',
'name' => 'DCL_Path',
'required' => true,
'validators' => [
['name' => 'FileUploadFile'],
[
'name' => 'FileMimeType',
'options' => [
'mimeType' => ['text/xls', 'text/xlsx']
]
],
[
'name' => 'Filesize',
'options' => [
'max' => 4096
]
],
],
// 'filters' => [
// [
// 'name' => 'FileRenameUpload',
// 'options' => [
// 'target'=>'./data/upload',
// 'useUploadName'=>true,
// 'useUploadExtension'=>true,
// 'overwrite'=>true,
// 'randomize'=>false
// ]
// ]
// ],
]);
As you an see I'm still fighting the validator part. What would be the right syntax to validate xls and xlsx files with a maximum size of let's say 4 MB?
And after that, what about the filterarea, I did the following in my controller action just because I'm used to
if ($form->isValid()) {
$data = $form->getData();
// Upload path
$location = "public/files/";
// A bit validation of uploaded file
$allowedExtension = array('xls', 'xlsx');
$extension = explode('.', $data['DCL_Path']['name']);
$extension = end($extension);
//$import['DCL_Path']=$data['DCL_Path']['name'];
//$fileName = time() . '.' . $extension;
$fileName = $data['DCL_Path']['name'];
// Check if everything is OK!
//echo $fileName;
if (0 === $data['DCL_Path']['error'] && in_array($extension, $allowedExtension)) {
move_uploaded_file($data['DCL_Path']['tmp_name'], $location . $fileName);
} else {
echo 'Something went wrong!';
}
Is the move_uploaded_file($data['DCL_Path']['tmp_name'], $location . $fileName); obsolet with the filterstuff in the interface? And again how would be the syntax in this case?
And one of my biggest wish, does somebody know kind of a tutorial which explains plainly the different possibilities and keys of both options (validator and filter)? Sometimes I can't believe that you need so much time to find only the right keys.
EDIT 1: Show Form, filterstuff and changed controller
here is part my Form class:
<?php
namespace Import\Form;
use Zend\Form\Form;
class ImportForm extends Form
{
public function __construct($name = null)
{
// We will ignore the name provided to the constructor
parent::__construct('import');
$this->add([
'name' => 'DCLID',
'type' => 'hidden',
]);
$this->add([
'name' => 'UnitID',
'type' => 'text',
'options' => [
'label' => 'equipment',
],
]);
$this->add([
'name' => 'DCL_Path',
'type' => 'File',
//'required' => true,
'options' => [
'label' => 'path to file',
],
// 'name' => 'FileRenameUpload',
// 'filters' => [
// 'target'=>'./public/files',
// 'useUploadName'=>true,
// 'useUploadExtension'=>true,
// 'overwrite'=>true,
// 'randomize'=>false
// ],
// 'validators' => [ // Validators.
// // Put validator info here.
// ]
]);
here part of the class extended InputFilterAwareInterface
<?php
namespace Import\Model;
use DomainException;
use Zend\Filter\StringTrim;
use Zend\Filter\StripTags;
use Zend\Filter\ToInt;
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;
use Zend\Validator\StringLength;
class Import implements InputFilterAwareInterface
{
public $DCLID;
public $DCL_Path;
public $Unitname;
public $UnitID;
public $Importdate;
public $Importuser;
public $Importok;
public $DCL_Type;
public $Changed_per_User;
public $Description_Changes;
private $inputFilter;
public function exchangeArray(array $data)
{
$this->DCLID= !empty($data['DCLID']) ? $data['DCLID'] : null;
$this->UnitID= !empty($data['UnitID']) ? $data['UnitID'] : null;
$this->DCL_Path= !empty($data['DCL_Path']) ? $data['DCL_Path'] : null;
$this->Importdate= !empty($data['Importdate']) ? $data['Importdate'] : null;
$this->Importuser= !empty($data['Importuser']) ? $data['Importuser'] : null;
$this->Importok= !empty($data['Importok']) ? $data['Importok'] : null;
$this->DCL_Type= !empty($data['DCL_Type']) ? $data['DCL_Type'] : null;
$this->Changed_per_User= !empty($data['Changed_per_User']) ? $data['Changed_per_User'] : null;
$this->Description_Changes= !empty($data['Description_Changes']) ? $data['Description_Changes'] : null;
}
public function getArrayCopy()
{
// echo var_dump(get_object_vars($this)
// );
return get_object_vars($this);
}
public function setInputFilter(InputFilterInterface $inputFilter)
{
throw new DomainException(sprintf(
'%s does not allow injection of an alternate input filter',
__CLASS__
));
}
public function getInputFilter()
{
if ($this->inputFilter) {
return $this->inputFilter;
}
$inputFilter = new InputFilter();
// $inputFilter->add([
// 'name' => 'DCLID',
// 'required' => false,
// 'filters' => [
// ['name' => ToInt::class],
// ],
// ]);
// Validator für das Upload Element
$inputFilter->add([
'type' => 'Zend\InputFilter\FileInput',
'name' => 'DCL_Path', // Element's name.
'required' => true, // Whether the field is required.
'filters' => [ // Filters.
[
'name' => \Zend\Filter\File\RenameUpload::class,
'options' => [
'use_upload_extension' => true,
'randomize' => false,
'overwrite' => true,
'target' => 'public/files',
],
],
],
'validators' => [ // Validators.
[
'name' => \Zend\Validator\File\Extension::class,
'options' => [
'extension' => 'xls, xlsx',
'message' => 'File extension not match',
],
],
[
'name' => \Zend\Validator\File\MimeType::class,
'options' => [
'mimeType' => 'text/xls', 'text/xlsx',
'message' => 'File type not match',
],
],
[
'name' => \Zend\Validator\File\Size::class,
'options' => [
'min' => '1kB', // minimum of 1kB
'max' => '4MB',
'message' => 'File too large',
],
],
]
]);
and my part of my controlleraction, I think inhere might be the problem, something is probably not logic:
$form = new ImportForm();
$form->get('submit')->setValue('Add'); //Änderung des LAbels des Submit Buttons, um das Form wiederverwenden zu können
//echo "hier";
$request = $this->getRequest();
if (! $request->isPost()) { //wurden Daten über POST geschickt?
return ['form' => $form]; //Keine Daten, nur Form anzeigen, nicht verarbeiten
}
else {
//Es wurden Daten gesendet
//echo "Daten";
$import = new Import(); //Neue Instanz von Import
$form->setInputFilter($import->getInputFilter()); //Filter an Form binden
$form->setData($request->getPost()); //Daten abholen
//echo $form->isValid();
if (! $form->isValid()) {
return ['form' => $form]; //Wenn die Daten nicht valide sind
}
else{ //aus Tableadapter
$import->exchangeArray($form->getData());
$data = array_merge_recursive(
$this->getRequest()->getPost()->toArray(),
$this->getRequest()->getFiles()->toArray()
);
$form->setData($data);
if ($form->isValid()) {
$data = $form->getData();
// Upload path
// $location = "public/files/";
// $allowedExtension = array('xls', 'xlsx');
// $extension = explode('.', $data['DCL_Path']['name']);
// $extension = end($extension);
$fileName = $data['DCL_Path']['name'];
// // Check if everything is OK!
// //echo $fileName;
// if (0 === $data['DCL_Path']['error'] && in_array($extension, $allowedExtension)) {
// move_uploaded_file($data['DCL_Path']['tmp_name'], $location . $fileName);
// } else {
// echo 'Something went wrong!';
// }
//-----------------------------------------------------------------
// t_dcl befüllen
//-----------------------------------------------------------------
//$namen = explode(",", $import ); //Konvertierung des Strings in ein Array
//echo "<pre>"; var_dump($namen); echo "</pre>"; //Formartierte Ausgabe des Arrays
$this->table->saveImport($import);
EDIT2: Post part of controlleraction to discuss order of some statements:
controlleraction
$form = new ImportForm();
$form->get('submit')->setValue('Add');
$request = $this->getRequest();
if (! $request->isPost()) {
return ['form' => $form];
}
else {
$import = new Import(); //Neue Instanz von Import
$form->setInputFilter($import->getInputFilter());
$form->setData($request->getPost());
$data = array_merge_recursive(
$this->getRequest()->getPost()->toArray(),
$this->getRequest()->getFiles()->toArray()
);
$form->setData($data);
if (! $form->isValid()) {
return ['form' => $form];
}
else{
$import->exchangeArray($form->getData());
$data = $form->getData();
$fileName = $data['DCL_Path']['name'];
Is the position of $form->setInputFilter($import->getInputFilter()); correct? Or when do I have to bind the Inputfilter to form?
There is a small issue left: I now have a message:
File type not match
I tried to upload a .xlsx file
Please try this for InputFilter
$inputFilter->add([
'type' => 'Zend\InputFilter\FileInput',
'name' => 'DCL_Path', // Element's name.
'required' => true, // Whether the field is required.
'filters' => [ // Filters.
[
'name' => \Zend\Filter\File\RenameUpload::class,
'options' => [
'use_upload_extension' => true,
'randomize' => false,
'overwrite' => true,
'target' => 'public/files',
],
],
],
'validators' => [ // Validators.
[
'name' => \Zend\Validator\File\Extension::class,
'options' => [
'extension' => 'xls, xlsx',
'message' => 'File extension not match',
],
],
[
'name' => \Zend\Validator\File\MimeType::class,
'options' => [
'mimeType' => 'text/xls', 'text/xlsx',
'message' => 'File type not match',
],
],
[
'name' => \Zend\Validator\File\Size::class,
'options' => [
'max' => '4MB',
'message' => 'File too large',
],
],
]
]);
And here for controller
if($this->getRequest()->isPost()) {
// merge post and files
$request = $this->getRequest();
$data = array_merge_recursive(
$request->getPost()->toArray(),
$request->getFiles()->toArray()
);
// passing data
$form->setData($data);
// execute validator
if($form->isValid()) {
// execute file filters.
$data = $form->getData();
}
}
By using \Zend\Validator\File\Extension, \Zend\Validator\File\MimeType and \Zend\Validator\File\FileSize you don't need to check manually in your contoller using this code.
if (0 === $data['DCL_Path']['error'] && in_array($extension, $allowedExtension)) {}
Because validation will be executed when we call $form->isValid().
And by using \Zend\Filter\File\RenameUpload, you don't need to use move_uploaded_file() anymore. Because this filter will move the uploaded file to destination foder we defined in 'target' => 'public/files' option.
Filtering is executed when we call $form->getData();
And about explanation for Validator and Filter, I suggest you to create another post. By using a separate question, it will be easy to search in search engine and will help another to find it.

yii2 behaviors ActiveRecord::EVENT_BEFORE_INSERT not working

My behavior function in my model is as follows
public function behaviors()
{
return [
'timestamp' => [
'class' => 'yii\behaviors\TimestampBehavior',
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['log_in_time' ],
ActiveRecord::EVENT_BEFORE_UPDATE => ['log_in_time'],
],
'value' => new Expression('NOW()'),
],
];
}
/**
* validation rules
*/
public function rules()
{
return [
['username','filter', 'filter' => 'trim'],
['username','required'],
//['username','unique'],
['username','string', 'min' => 2, 'max' => 255],
['password','required'],
];
}
/* Your model attribute labels */
public function attributeLabels()
{
return [
/* Your other attribute labels */
];
}
public function scenarios()
{
$scenarios = parent::scenarios();
$scenarios['login'] = ['username','log_in_time'];//Scenario Values Only Accepted
return $scenarios;
}
But it is not updating the log_in_time column . log_in_time is DATETIME . The value getting inserted is 0000-00-00 00:00:00 .What is the problem ?
Are you by any chance overwriting beforeSave (or beforeInsert or beforeUpdate) in that particular model? If you do then you have to call something like
public function beforeSave($insert)
{
if (parent::beforeSave($insert)) {
............
return true;
}
return false;
}
I recently did something similar and spent some good time researching this only to realize that I did not call the parent before save.
If you use AttributeBehavior instead of TimestampBehavior and do exactly what you did, I believe it will work.
public function behaviors()
{
return [
'timestamp' => [
'class' => 'yii\behaviors\AttributeBehavior',
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['log_in_time' ],
ActiveRecord::EVENT_BEFORE_UPDATE => ['log_in_time'],
],
'value' => new Expression('NOW()'),
],
];
}
Or you can try setting createdAtAttribute and $updatedAtAttribute to 'log_in_time' in the TimestampBehavior, that should also work.
public function behaviors()
{
return [
'timestamp' => [
'class' => 'yii\behaviors\TimestampBehavior',
'createdAtAttribute' => 'log_in_time',
'updatedAtAttribute' => 'log_in_time',
],
];
}
I am not sure why it does not work like you posted.
This works for me 100%
/**
* #inheritdoc
*/
public function behaviors()
{
return [
'blameable' => [
'class' => BlameableBehavior::className(),
'attributes' => [
BaseActiveRecord::EVENT_BEFORE_INSERT => ['create_by', 'update_by'],
BaseActiveRecord::EVENT_BEFORE_UPDATE => 'update_by'
],
],
'timestamp' => [
'class' => TimestampBehavior::className(),
'attributes' => [
BaseActiveRecord::EVENT_BEFORE_INSERT => ['create_time', 'update_time'],
BaseActiveRecord::EVENT_BEFORE_UPDATE => 'update_time',
],
'value' => new Expression('NOW()'),
],
];
}

Resources