Cache to Avoid Database calls in validator : Laravel 5.2 - php

What I am doing ?
I am fetching the records from database in 2 ways.
Approach 1
Imposing the validation before saving the record
$v = \Validator::make($request->all(), [
'Category' => 'required|unique:tblcategory|max:25|min:5'
]);
if ($v->fails()) {
return \Redirect::back()
->withErrors($v)
->withInput();
}
Approach 2
Fetching the records from database
$Categories = \App\Models\Skill\Category_Model::all();
What's the question ?
In Approach 2, I could avoid database calls by implementing the cache with below code \Cache::put('Categories', $Categories, 60);
How can I avoid Database calls in case of Approach 1

you could retrieve the categories. and then use it like so:
$cats = implode(',', $Categories);
$v = \Validator::make($request->all(), [
'Category' => 'required|not_in:'.$cats.'|max:25|min:5'
]);

You have a validator rule unique:tblcategory. unique rule will check the database if the category (I suppose, the id) exists. You can't really have that validation and expect it not to check the database.
Caching the unique rule would be quite a weird way to go since you REALLY don't want the values to duplicate which could happen if you cache the categories.

Related

Laravel Eloquent get only one specific field with relationship and paginate

Here my code :
$prestations = Prestation::with('service:name','conciergeries.network:name')->orderBy($orderBy, $orderDirection)->simplePaginate(100);
$res = [
'results' => $prestations,
'total' => Prestation::all()->count(),
];
return $res;
I need to get only the network name and not all datas of "conciergeries" and "network" because actually is too heavy.
I have tried some things like
$prestations = Prestation::with('service:name','conciergeries.network:name')->orderBy($orderBy, $orderDirection)->pluck('network.name')->simplePaginate(100);
Thank you !
When using eager loading with specific columns, you should always include the id column and any relevant foreign key columns in the list of columns you wish to retrieve.
So try this instead:
$prestations = Prestation::with(
'service:id,name',
'conciergeries:id,network_id',
'conciergeries.network:id,name'
)
//->orderBy(...
Don't forget to add/modify any other relevant foreign keys you use, I just guessed these keys.

Is there a way to check if a couple of inputs are unique in laravel 5.2?

update
What I have is a table with these columns:
- ID
- production_year
- type
If the type is already present in the table with the value the user wants to pass, check if production_year is already present too, but fail the validation ONLY if these values are present in the same record. Otherwise let the user to store this record.
I'm trying to check the uniqueness of a couple of fields in the same record...
I've seen the documentation about the conditional validation, but I didn't quite find the answer there.
the code
public function rules()
{
return [
// I'd like to check the uniqueness of both of them. In the same record
'production_y' => 'required|unique',
'fk_type' => 'required|unique',
];
}
Any idea? Thanks!
Laravel 5.3 Update:
Now, you can generate the same rule fluently using the Rule (\Illuminate\Validation\Rule) class.
NULL,id part of the string way is no more required. See:
public function rules()
{
$type = $this->get('fk_type');
return [
'production_y' => [
'required',
Rule::unique('your_table', 'production_year')->where(function($query) {
$query->where('type', $type);
}),
],
];
}
Original Answer
Can't test right now, can you try:
public function rules()
{
$type = $this->get('fk_type');
return [
'production_y' => "required|unique:your_table,production_year,NULL,id,type,{$type}",
// ...
];
}
Explaination:
unique:your_table Set the table for the unique check.
,production_year This matches with production_y.
,NULL,id check all the records.
3.1. if you use like {$id},id it will check uniqueness except the record with the {$id},
,type,{$type} and the type should be {$type}
That will produce sth. like (not exact query, just to express the idea):
select count(*) from your_table where production_year = $product_y and where type = $type and where id <> null
if someone cames from laravel 8, i tried this and it worked !!
for me i need to check the uniqueness of (category_id,subcategory_id) which mean you can find (1,2),(1,3),(2,1),(2,3) but you cant find similar couple !!
'category' => "required|unique:tickets,category_id,NULL,id,subcategory_id,{$request->input('subcategory')}"

How do I optimise laravel seeds beyond mass insertion for faster seeding/

So I am developing a laravel application and I am trying to get my seeds optimised so that they run faster.
http://bensmith.io/speeding-up-laravel-seeders
This guide helped a ton. According to this, I should minimise the number of SQL queries by doing mass insertions and it cut down the time to 10% of the original seeding time which is awesome.
So now I am doing something like:
$comments = [];
for ($i = 0; $i < 50; $i++) {
$bar->advance();
$comments[] = factory(Comment::class)->make([
'created_at' => Carbon\Carbon::now(),
'updated_at' => Carbon\Carbon::now(),
'comment_type_id' => $comment_types->shuffle()->first()->id,
'user_id' => $users->shuffle()->first()->id,
'commentable_id' => $documents->shuffle()->first()->id,
])->toArray();
}
Comment::insert($comments);
This works like a charm. It gets the queries down to a single one.
But then I have other seeders where I to work with dumps and they are more complex:
$dump = file_get_contents(database_path('seeds/dumps/serverdump.txt'));
DB::table('server')->truncate();
DB::statement($dump);
$taxonomies = DB::table('server')->get();
foreach($taxonomies as $taxonomy){
$bar->advance();
$group = PatentClassGroup::create(['name' => $taxonomy->name]);
preg_match_all('/([a-zA-Z0-9]+)/', $taxonomy->classes, $classes);
foreach(array_pop($classes) as $key => $class){
$type = strlen($class) == 4 ? 'GROUP' : 'MAIN';
$inserted_taxonomies[] = PatentClassTaxonomy::where('name', $class)->get()->count()
? PatentClassTaxonomy::where('name', $class)->get()->first()
: PatentClassTaxonomy::create(['name' => $class, 'type' => $type]);
}
foreach($inserted_taxonomies as $inserted_taxonomy){
try{
$group->taxonomies()->attach($inserted_taxonomy->id);
}catch(\Exception $e){
//
}
}
}
So here when I am attaching taxonomies to groups, I use the native eloquent code so taking the record and mass inserting is difficult.
Yes, I can fiddle around and figure out a way to mass insert that too but my problem is that I have to write and optimise all seeds and every part of those seeds to mass insert.
Is there a way, where I can listen to DB queries laravel is trying to execute while seeding. I know I can do something like this:
DB::listen(function($query) {
//
});
But it would still be executed right. What I would like to do is somehow catch the query in a variable, add it to a stack and then execute the whole stack when the seed is coming to an end. Or in between too since I might need some ids for some seeds. What is a good workaround this? And how to really optimise the seeds in laravel with a smart solution?

Update only one field on Cakephp 3

In some part of my app I need to update only the field is_active of some table with a lot of fields. What is the best approach to update only this field and avoid the validations and requiriments of all other fields?
And if you want to update particular row only , use this:
$users= TableRegistry::get('Users');
$user = $users->get($id); // Return article with id = $id (primary_key of row which need to get updated)
$user->is_active = true;
// $user->email= abc#gmail.com; // other fields if necessary
if($users->save($user)){
// saved
} else {
// something went wrong
}
See here (Updating data in CakePHP3).
This will work:
$users = TableRegistry::get('Users');
$query = $users->query();
$query->update()
->set(['is_active' => true])
->where(['id' => $id])
->execute();
http://book.cakephp.org/3.0/en/orm/query-builder.html#updating-data
When you don't want callbacks to be triggered, just use updateAll()
$table->updateAll(['field' => $newValue], ['id' => $entityId]);
Using the example here: http://book.cakephp.org/3.0/en/orm/database-basics.html#running-update-statements. Run the code below to update all records in table_name_here table with a new value for is_active column.
use Cake\Datasource\ConnectionManager;
$connection = ConnectionManager::get('default');
$connection->update('table_name_here', ['is_active' => 'new_value_here']);
I faced this issue when upgrading my project from 2.10 to 3.x.
In 2.10 you could update a single field using:
$this->Menus->saveField('css', $menucss);
But since this method was deprecated, we do as below now, considering that callbacks will not be triggered:
$this->Menus->updateAll(['css' => $menucss], ['id' => $menu_id]);
The other answers don't use internationalization and other models props, callbacks, etc.
I think this is because of the query builder, it does not use the models and so their behaviors, therefore you should use:
$this->loadModel('Inputs');
$input = $this->Inputs->find()->where(['`key`' => $this->request->data['id']])->first();
$this->Inputs->patchEntity($input, ['prop' => $this->request->data['prop']]);
if ($this->Inputs->save($input)) {
die(json_encode(true));
} else {
die(json_encode(false));
}

composite-unique-key-validation - laravel

seems it's not possible with built-in validators, how I should implement this feature in the model?
$rules = [
'user_id' => 'required|unique:service_details,user_id',
'service_id'=>'required|unique:service_details,service_id'
];
above will prevent duplicacy of user_id and service_id independently which is not my requirement
it will reject
(1,2)
(1,3)
because 1 is duplicate but it should be accepted as i want composite unique key
Composite unique field validation is provided out-of-the-box in 5.0+. I can't speak for earlier versions.
You can essentially specify a where clause for when your unique validation rule applies. E.g.
'term' => 'unique:terms,term,NULL,id,taxonomy,category'
This rule says that term should be unique on the terms table but only where the taxonomy is equal to "category".
For example, it will prevent a "news" category being duplicated but I can still have a "news" tag.
I don't know your schema but in your case it'd be something like this:
$user_id = Request::get('user_id', $default);
$service_id = Request::get('service_id', $default);
// or another way of specifying the accompanying service/user ID for the where clauses
$rules = [
'user_id' => 'unique:service_details,user_id,NULL,id,service_id,' . $service_id;
'service_id' => 'unique:service_details,service_id,NULL,id,user_id,' . $user_id;
];
My solution
Laravel 5.3 and 5.4
Note: Without model binding
Store
'required',
Rule::unique('service_details','service_id')->where(function ($query) {
$query->where('user_id', $this->request->get('user_id'));
})
Update
'required',
Rule::unique('service_details','service_id')->ignore($this->route()->id)->where(function ($query) {
$query->where('user_id', $this->request->get('user_id'));
})
This is not possible out of the box in Laravel. You would either have to write a custom validator or use a package for that.
Here is one that should do what you need:
- https://github.com/felixkiss/uniquewith-validator
With this package, your rules could look like the following:
$rules = array(
'user_id' => 'required|unique_with:service_details,service_id',
'service_id' => 'required',
);
It works for both Laravel 4 and 5.
With the help of this link , I am able to achieve composite validation from out of the box laravel 5.3. I knew it is old question and answered already. In my case vendor and client combination is unique.
My sample code is below
$this->validate($request, [
'Vendor'=> 'bail|required|int',
'Client'=> 'bail|required|int',
'discount'=> 'required|numeric',
'Client'=>'unique:billings,client_id,vendor_id'.$request->Vendor
]);

Categories