Inserting one to many relationship - laravel

I've got three tables: blogs, posts, blog_post. Here is my code.
$post = new Post();
$post->title = HTML::entities(Input::get('title'));
$post->content = Input::get('content');
$post->status = isset($_POST['save']) ? 2 : 1;
$post->save();
$blog = Blog::where('user_id', '=', Auth::user()->id)->first();
$post = $blog->posts()->insert($post);
And I get:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry
'47' for key 'PRIMARY'
I have one to many relation ships. A post can belong to many blogs.

at13 answer is correct. You are saving the post and then trying to insert it again through blog relationship.
According to your comments you should have:
$post->has_many_and_belongs_to('blog');
$blog->has_many_and_belongs_to('post');
With that in mind, to create many to many relationships, you should use attach().
For instance:
$post = new Post;
$post->title = "Foo Bar";
// ...
$post->save();
$user = Auth::user();
$blog = $user->blogs()->first();
$blog->posts()->attach($post);
Obs: I don't quite understand the concept of a post belonging to more than one blog.

Related

Laravel Join with where not in gives "Column xxxxx in IN/ALL/ANY subquery is ambiguous"

I have two tables: leads and hts_patients. Both table has phone column and I want to list all leads that has no record on hts_patients table(foreign key is phone).
So far, I have tried this and it works but taking so much long time.
$countries = ['DE','TR'];
$dateS = Carbon::now()->startOfMonth()->subMonth(4);
$dateE = Carbon::now()->startOfMonth();
$leads = Lead::whereBetween('created_at',[$dateS,$dateE])->whereIn('visitor_country',$countries)
->select('id','name','phone','visitor_country','source','description','contact','created_at')->get();
$patient = HtsPatient::pluck('phone');
foreach ($leads as $key=>$item){
if (isset($item->phone)){
$data =$patient->where('phone',$item->phone)->first();
if (!empty($data)){
$leads->forget($key);
}
}
}
return view('poll.leadSecond',['leads' => $leads]);
Thing, that I want is probably something like this;
$countries = ['DE','TR'];
$dateS = Carbon::now()->startOfMonth()->subMonth(4);
$dateE = Carbon::now()->startOfMonth();
$leads = DB::table('leads')->join('hts_patients','hts_patients.phone', '=', 'leads.phone')
->whereBetween('leads.created_at',[$dateS,$dateE])->whereIn('leads.visitor_country',$countries)
->whereNotIn('phone', function($query) {
$query->select('phone')
->from('hts_patients');
})
->select('leads.id','leads.name','leads.phone','leads.visitor_country','leads.source','leads.description','leads.contact','leads.created_at')->get();
But it gives an error says
SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'phone'
in IN/ALL/ANY subquery is ambiguous
Any help?
you have tow tables with column called 'phone', in your whereNotIn clause you should specify witch on you wants.
I think the result should be like:
->whereNotIn('leads.phone', function($query) {
$query->select('hts_patients.phone');
// ->from('hts_patients'); you do not need this 'from'
})

Laravel eloquent query loads hundreds of models

I'm querying a relationship with pagination, yet in my debugbar I can see that all models are loaded in memory and if I'm correct that should not be happening.
I have a Post model with a hasMany relationship to Comments. I have a few lines of code as below. They are written in this order because there are parameters in between that I need to apply. I have shown filterScore here but there are multiple that work the same way.
$post = Post::find(1);
$comments = $post->comments();
$comments = $comment->filterScore($comments)
$comments = $comments->orderBy('created_at', 'DESC');
return $comments->paginate(25);
private function filterScore($q)
{
if($this->score > 0)
return $q->where('score', $this->score);
return $q;
}
The raw query if $this->score = 0:
select * from `comments` where `comments`.`post_id` = 1 and `comments`.`post_id` is not null order by `created_at` desc limit 25 offset 0
UPDATE
I've tried writing it like this, based on this post, but then I still get the same result: all models are loaded into memory.
$post = Post::find(1);
$comments = Comment::query();
$comments = Comment::where('post_id', $post->id);
$comments = $comment->filterScore($comments);
return $comments->paginate(25);
In the Laravel debugbar you can see that all models are loaded into memory, instead of just 25:
One solution is, as #nikistag wrote in comment: $post->comments()->orderBy('created at' , 'DESC')->paginate(25); (you have to have all in one chained expression).
But if you use optional parameters, it can be difficult to achieve someting like that.
In this case, you can just change it to 2 seperate codes, where you do not use laravel relationship:
$post = Post::find(1);
$comments = Comment::where('post_id', $post->id);
if(!empty($from)) //if set optional parameter, add condition
$comments->where('created_at', '>=', $from);
$comments->orderBy('created_at', 'desc')->paginate(25);

Laravel Left join Query explanation

I have the following tables:
Users, Studies, Study_User and Questions. The relationships are:
Many-to-Many between Users and Studies via study_user.
Studies One-to-Many Questions
Can someone please explain to me what does this query do?
Does it bring all the Questions that belongs to studies which a certain user is part of?
public function questions(){
$builder = Question::
groupBy('questions.id');
$builder = $builder
->leftjoin('studies', 'studies.id', '=', 'questions.study_id')
->leftjoin('study_users', 'studies.id', '=', 'study_users.study_id')
->where('study_users.user_id', '=', $this->id)
->where('studies.starts_at', '<=', Carbon::now())
->where('studies.ends_at', '>=', Carbon::now())
->select('questions.*');
return $builder;
}
That function is then called as
$user = Auth::user();
$user->questions()->get();
Ok and now the other question would be:
Assume that we add another table called Modules where : Studies one-to-many Modules and then Modules one-to-many Questions. So that we break the direct relationship between Studies and Questions. How the query should change to get the same results?

laravel relation issue in many to many case

i have three table in mysql:
1-users
table of users
2-projects
table of project
3-project_user
there is id and project_id and user_id for relation
there is two model : user and project
the relation between these table are belongsToMany
when a project create maybe one project define for two person
NOW how can i show the project of each person?
Assuming you properly defined your relationships, do
$users = User::with('projects')->get();
//show each user projects
foreach($users as $user) {
echo $user->projects;
}
//Getting project users
$projects = Project::with('users')->get();
This will give you projects list, in each list you can see which user has access or not.
Updates
Taking project with specified user_id
$projects = Project::with(['users' => function ($query) use ($user_id) {
$query->where('user_id', '=', $user_id);
}])->get();
New code
Or try to to get the user
$user = User::with('projects')->where('id', $user_id)->first();
Or via projects, constraining by user_id
$projects = Project::with('users')->whereHas('users', function ($query) use ($user_id) {
$query->where($user_id);
})->get();
the way i solve it:
//save user_id
$user_id = $request->id;
//select in project_user where user_id = $user_id
$project_user = DB::table('project_user')->where('user_id', '=', $user_id)->get();
//create an empty array
$p_id = array();
//fill empty array with project_id
foreach($project_user as $pro) {
$p_id[] = $pro->project_id;
}
//select code and id in project table where id = one of that [$p_id] array
$data = Project::select('code','id')->whereIn('id', $p_id)->get();
//return your data in json
return response()->json($data);
As far as I understood your question, you want to query Project as per user_id. Here is how you do it.
Project::with('users')->whereHas('users', function ($query) use ($user_id_array) {
$query->whereIn('id',$user_id_array);
})->get();
This will give you projects whose user_id are from $user_id_array. Let me know if you need any further help.

Inserting a new relationship

I'm just looking through the docs:
$post = Post::find(1);
$comments = array(
new Comment(array('message' => 'A new comment.')),
new Comment(array('message' => 'A second comment.')),
);
$post->comments()->save($comments);
I've implemented something similar to the above on my site, my question is, I wish to also insert a new Post at the same time, is there a way to do this, instead of using find?
Also what happens if the insert of the post fails, can I prevent the comments from being inserted?
Parent of the relationship must be saved prior to saving related models. Can't be done in 1 go. (btw push won't work for it either, in case you wonder).
$post = Post::create([ ... post data here ...]);
// or
$post = new Post;
$post->whatever = 'someValue';
$post->save();
// then
$post->comments()->saveMany($comments);
You can probably do it this way:
$post = new Post();
$post->title = 'my title';
$post->save();
$comments = array(
new Comment(array('message' => 'A new comment.')),
new Comment(array('message' => 'A second comment.')),
);
$post->comments()->saveMany($comments);
this way you will create new post and save comments for it. I haven't tested what happens if something goes wrong but I assume comments won't be inserted because there won't be related post id.
Why not first create a post then attach the related model something like this.
$post = new Post();
$post->save();
Then iterate through comments and assign the post_id attribute in comment table.
The id field of post model will be available if the post exists.
$comment = new Comment();
$comment->post_id = $post->id;
$comment->save();

Resources