User model has follow relation:
public function getWorkload() : ActiveQuery
{
return $this->hasMany(ScheduleWorkload::className(), ['staff_id' => 'id']);
}
Find method:
$staffs = User::find()
->alias('u')
->joinWith(['workload as uw' => function($q) {
$q->select(['uw.staff_id', 'uw.date', 'uw.time_ranges']);
}], true)
->select([
'u.id',
'CONCAT(u.first_name, \' \', u.last_name) as name',
'u.first_name',
'u.last_name',
'u.undelivered_messages',
])
->where(['u.is_staff' => 1])
->asArray()
->all()
;
I need get data without uw.staff_id in result set? Is it possible without post-processing?
UPDATE:
Result set that I have
I need "workload" as array parameter but do not use post-processing and just exclude "staff_id" from result set.
Raw sql:
SELECT `u`.`id`, `u`.`undelivered_messages`
FROM `user` `u`
LEFT JOIN `schedule_workload` `uw` ON `u`.`id` = `uw`.`staff_id`
WHERE `u`.`is_staff`=1
You can't do in Yii without any post-processing because ActiveQuery will search for foreign key in nested query result to build nested arrays for joined relation.
The most convenient way for you is to use ArrayHelper:
$staffs = User::find()
->alias('u')
->joinWith(['workload')
->where(['u.is_staff' => 1])
->all();
return \yii\helpers\ArrayHelper::toArray($staffs, [
User::className() => [
'id',
'first_name',
'last_name',
'name' => function ($user) {
return $user->first_name . ' ' . $user->last_name
},
'undelivered_messages',
'workload',
],
ScheduleWorkload::className() => [
'date',
'time_ranges',
'comment'
]
], true);
Related
I am looking for a way to get the correct SQL queries for an INSERT statement. I'm having to export this data for use in another (non-laravel) system. The post at How to get the raw SQL for a Laravel delete/update/insert statement? got me part of the way there but my queries are still parameterized:
Post::all()->each(function($post)
{
$builder = DB::table('posts');
$insertStatement = $builder->getGrammar()->compileInsert($builder->select(['created_at', 'title']), [
'created_at' => $post->created_at,
'title' => $post->title
]);
Storage::disk('sql')->append('posts-latest.sql', $insertStatement);
dump($insertStatement);
}
this results in...
insert into `posts` (`created_at`, `title`) values (?, ?)
So I've managed to set the fields to be updated but how to swap out the parameters for real values?
You can do this:
Post::all()->each(function($post){
$builder = DB::table('posts');
$grammar = $builder->getGrammar();
$values = [
'created_at' => $post->created_at,
'title' => $post->title
];
$table = $grammar->wrapTable($builder->from);
if (!is_array(reset($values))) {
$values = [$values];
}
$columns = $grammar->columnize(array_keys(reset($values)));
$parameters = collect($values)->map(function ($record) use ($grammar) {
$record = array_map(function($rec){
$rec = str_replace("'", "''", $rec);
return "'$rec'";
},array_values($record));
return '('.implode(', ', $record).')';
})->implode(', ');
$insertStatement = "insert into $table ($columns) values $parameters";
// $insertStatement should contains everything you need for this post
});
I ended up discovering DB::pretend which will generate the query without running it. Then it's a case of substitution. It seems that there is no way to get the raw SQL without substitution due to the use of parameters.
Post::all()->each(function($post)
{
$builder = DB::table('posts');
$query = DB::pretend(function() use ($builder, $post)
{
return $builder->insert([
'created_at' => $post->created_at,
'title' => $post->title,
'content' => $post->content,
'featured_image_link' => $post->featured_image_link,
'slug' => $post->slug
]);
});
$bindings = [];
collect($query[0]['bindings'])->each(function($binding) use (&$bindings)
{
$binding = str_replace("'", "\\'", $binding);
$bindings[] = "'$binding'";
});
$insertStatement = Str::replaceArray('?', $bindings, $query[0]['query']);
Storage::disk('sql')->append('posts-latest.sql', $insertStatement.';');
});
In Laravel-5.8 I applied Rules Request for multiple fields as shown below:
public function rules()
{
return [
'goal_type_id' => [
'required',
Rule::unique('appraisal_goals')->where(function ($query) {
return $query
->where('employee_id', 1)
->where('appraisal_identity_id', 1);
})
],
'appraisal_doc' => 'nullable|mimes:doc,docx,xls,xlsx,ppt,pptx,pdf,jpg,jpeg,bmp,png,|max:5000',
'weighted_score' => 'required|numeric|min:0|max:500',
];
}
This is mysql query:
ALTER TABLE appraisal_goals
ADD CONSTRAINT appraisal_goals_uniq1 UNIQUE KEY(goal_type_id,appraisal_identity_id,employee_id);
This is meant for create. From the code the combination of goal_type_id, employee_id and appraisal_identity_id are unique.
When I click on submit in create blade, it allows duplicate.
How do I resolve this?
Also, how do I write the one for update?
Please note that my route is appraisal_goal
Thank you
Try this code for update
public function rules()
{
$appraisal_goal_id = 'take your appraisal_goals id here from request';
return [
'goal_type_id' => [
'required',
Rule::unique('appraisal_goals')->ignore($appraisal_goal_id, 'id')->where(function ($query) {
return $query
->where('employee_id', 1)
->where('appraisal_identity_id', 1);
})
],
'appraisal_doc' => 'nullable|mimes:doc,docx,xls,xlsx,ppt,pptx,pdf,jpg,jpeg,bmp,png,|max:5000',
'weighted_score' => 'required|numeric|min:0|max:500',
];
}
I want to create a hashtags system. Currently I have this code:
private function hashtags($post){
$htag = '#';
$arr = explode(" ", $post->description);
$arrc = count($arr);
$i = 0;
while($i < $arrc){
if(substr($arr[$i], 0, 1) === $htag ){
$hash = Hashtag::where('name', ltrim($arr[$i], '#'))
->where('slug', str_slug(ltrim($arr[$i], '#')))
->first();
if(!$hash){
Hashtag::create([
'name' => ltrim($arr[$i], '#'),
'type' => 1,
'slug' => str_slug(ltrim($arr[$i], '#'))
]);
}
$current_hash = Hashtag::where('type', 1)
->where('name', ltrim($arr[$i], '#'))
->first();
\DB::insert('insert into hashtag_post (hashtag_id, post_id) values (' .$current_hash->id. ', ' .$post->id. ')');
}
$i++;
}
}
This code isn't good for me because I prefer use attach method but if I try use $post->hashtags()->attach([1, 2, 3]); or other array which I created with hashtag's id, it display error:
"Call to undefined method App\Post::hashtags()".
My question is:How I can use attach with this example and how I can improve my code. It doesn't look well.
Firstly, your relationships should be public methods.
Secondly, both relationships should be belongsToMany.
Post class
public function hashtags()
{
return $this->belongsToMany(Hashtag::class);
}
Hashtag class
public function posts()
{
return $this->belongsToMany(Post::class);
}
Just an FYI, Laravel comes with helper methods that can reduce how much you have to write e.g. firstOrCreate(). So, this:
$hash = Hashtag::where('name', ltrim($arr[$i], '#'))
->where('slug', str_slug(ltrim($arr[$i], '#')))
->first();
if(!$hash){
Hashtag::create([
'name' => ltrim($arr[$i], '#'),
'type' => 1,
'slug' => str_slug(ltrim($arr[$i], '#'))
]);
}
can become:
$hash = Hash::firstOrCreate(
['name' => ltrim($arr[$i], '#'), 'slug' => str_slug(ltrim($arr[$i], '#'))],
['type' => 1]
);
I trying to do a left join with where IN clause search. But I couldn't able to bind the array to the query.
$query = DB::table('offers');
$query->select('id', 'business_id', 'address_id', 'title', 'details', 'value', 'total_available', 'start_date', 'end_date', 'terms', 'type', 'coupon_code', 'is_barcode_available', 'is_exclusive', 'userinformations_id', 'is_used');
$query->leftJoin('user_offer_collection', function ($join)
{
$join->on('user_offer_collection.offers_id', '=', 'offers.id');
$join->on('user_offer_collection.user_id', 'IN', DB::Raw('?'));
})->setBindings(array_merge($query->getBindings() , array(array(
1,2,3
))));
You don't have to bind parameters if you use query builder or eloquent ORM. However, if you use DB::raw(), ensure that you binding the parameters.
Try the following:
$array = array(1,2,3);
$query = DB::table('offers');
$query->select('id', 'business_id', 'address_id', 'title', 'details', 'value', 'total_available', 'start_date', 'end_date', 'terms', 'type', 'coupon_code', 'is_barcode_available', 'is_exclusive', 'userinformations_id', 'is_used');
$query->leftJoin('user_offer_collection', function ($join) use ($array)
{
$join->on('user_offer_collection.offers_id', '=', 'offers.id')
->whereIn('user_offer_collection.user_id', $array);
});
$query->get();
If I store in DB criterias what I want to use to build and filter queries - how to build query with Laravel Fluent Query Builder? Maybe you can give advice for refactoring this array for adding OR/AND to make complex filter by such conditions? Thanks!
For example if I read from database these criteria and made array:
$array = array(
'0' => array(
'table' => 'users',
'column' => 'name',
'criteria' => 'LIKE'
'value' => 'John'
),
'1' => array(
'table' => 'groups',
'column' => 'name',
'criteria' => 'NOT LIKE'
'value' => 'Administrator'
),
...
)
If you are really set on doing it your way, make a switch statement to set the flag for the index of the array
switch ($query)
{
case 0:
$this->get_data($x);
break;
case 1:
$this->get_data($x);
break;
case 2:
$this->get_data($x);
break;
default:
Return FALSE;
}
public function get_data($x){
$value = DB::table($array[$x]['table'])
->where($array[$x]['name'], $array[$x]['criteria'], $array[$x]['value'])
->get();
Return $value;
}
However, I would not advise this at all. Instead of storing the query filters in an array I feel you should just make them methods in your model. This will help with readability, modularity, and having reusable code.
public function get_user_by_name($name){
$user = DB::table('users')->where('name', 'LIKE', '%'.$name.'%')->get();
return $user;
}
public function get_group_by_name($name, $criteria = 'LIKE'){
$groups = DB::table('groups')->where('name', $criteria, '%'.$name.'%')->get();
return $groups;
}
http://laravel.com/docs/database/fluent