Laravel 5.7: QueryBuilder Get returning all records even custom query execution returning no records - laravel

Its really strange, i am working on my real estate related website and having two tables users and user_metas where user table have all the basic details of user and user_metas having all the meta related information of user.
user_metas table structure
----------------------------------------------------------------------
id | user_id | key | value | created_at | updated_at
----------------------------------------------------------------------
1 | 2 | age | 20 | 2019-17-01 | 2019-17-01
----------------------------------------------------------------------
2 | 3 | age | 40 | 2019-17-01 | 2019-17-01
and i just execute the query:
(new User)->newQuery()->where('user_type','rn')->with(['usermeta' => function($query) use ($minAge, $maxAge){
return $query->where('key','age')->where('value','>=',$minAge);
}])->whereHas('usermeta', function($query) use ($minAge, $maxAge){
return $query->where('key','age')->where('value','>=',$minAge);
})->toSql();
toSql() returning me:
when i am executing this query in phpmyadmin its returning nothing to me, but laravel get() returning me all records.
can anyone please tell me where i am wrong?

This is because eager loaded relations (usermeta in your case) are exacuted as a separate SQL query. They are then mapped to the User model with PHP, not at your database level.

Related

Confused with Laravel's hasOne Eloquent Relationships

I have a new Laravel 5.8 application. I started playing with the Eloquent ORM and its relationships.
There is a problem right away that I encountered.
I have the following tables. (this is just an example, for testing reasons, not going to be an actual application)
Login table:
--------------------------
| id | user | data_id |
--------------------------
| 1 | admin | 1 |
| 2 | admin | 2 |
| 3 | admin | 3 |
--------------------------
Data table:
--------------
| id | ip_id |
--------------
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
--------------
IP table:
----------------------
| id | ip |
----------------------
| 1 | 192.168.1.1 |
| 2 | 192.168.1.2 |
| 3 | 192.168.1.3 |
----------------------
What I wanted is to get the IP belonging to the actual login.
So I added a hasOne relationship to the Login table that has a foreign key for the Data table:
public function data()
{
return $this->hasOne('App\Models\Data');
}
Then I added a hasOne relationship to the Data table that has a foreign key for the IP table:
public function ip()
{
return $this->hasOne('App\Models\Ip');
}
Once I was done, I wanted to retrieve the IP address for the first record of the Login table:
Login::find(1)->data()->ip()->get();
But I get this error:
Call to undefined method Illuminate\Database\Eloquent\Relations\HasOne::ip()
What am I missing here and how can I get the IP of that login in the correct way? Do I need a belongsTo somewhere?
1st error: Wrong relationship definition
Laravel relationships are bi-directional. On one-to-one relationships, you can define the direct relationship (HasOne) and the inverse relationship (BelongsTo)
The direct relationship should be:
HasOne HasOne
[ Login ] <----------- [ Data ] <----------- [ IP ]
And the inverse relationship should be:
BelongsTo BelongsTo
[ Login ] -----------> [ Data ] -----------> [ IP ]
See Eloquent: Relationships - One-to-One docs for details on how defining it.
Note that you don't need to define both directions for a relationship unless you need it. In your case, I think you just need to define the belongsTo direction.
2nd error: You are calling the relationship method, not the relationship itself
When you do:
Login::find(1)->data()->ip()->get();
You are calling the method data that defines your relationship, not the related model. This is useful in some cases, but not on your case.
The correct is call the relationship magic property instead:
Login::find(1)->data->ip;
Note that we don't use the () and we do not need the get() here. Laravel takes care of loading it for us.
Use Eager Loading
Laravel Eloquent have a Eager Loading for relationships that's very useful in some cases because it pre-loads your relationships, and reduce the quantity of queries you do.
In the situation that you described (loading a single Login model) it doesn't make any performance improvement, but also it doesn't slow down.
It's useful when you load many models, so it reduces your database query count from N+1 to 2.
Imagine that you are loading 100 Login models, without eager loading, you will do 1 query to get your Login models, 100 queries to get your Data models, and more 100 queries to get your Ip models.
With eager loading, it will do only 3 queries, causing a big performance increase.
With your database structure:
Login belongsTo Data
Data hasOne Login
Data belongsTo IP
IP hasOne Data
After fixed your methods you can use of your relations like this
$login = Login::with(['data.ip'])->find(1);
You can try like this:
Login
public function data()
{
return $this->belongsTo('App\Models\Data', 'data_id');
}
Data
public function ip()
{
return $this->belongsTo('App\Models\Ip', 'ip_id');
}
$login = Login::with(['data.ip'])->find(1);
And inside data you will have ip like $login->data->ip.

Eloquent Nested Relationship Returning null. Creating bad query

Good afternoon,
I have tried my very hardest to fix this problem reading through all the threads I could find on this issue but I still have had no luck in fixing my problem.
If anyone could help me I would really appreciate it!
Background
I'm using Laravel 5.2 within the Homestead environment on Ubuntu 14.04.
Database
I have 3 tables: entries, comments, authors. All PK's are named 'id'
Here is a picture of the Database Schema.
Relevent Migration Details(comment table migration):
$table->integer('entry_id')->unsigned();
$table->foreign('entry_id')->references('id')->on('entries')->onDelete('cascade');
$table->integer('author_id')->unsigned();
$table->foreign('author_id')->references('id')->on('authors');
Models:
Entry model:
public function comments() {
return $this->hasMany('App\Models\Comment');
}
Author model:
public function comments() {
return $this->hasMany('App\Models\Comment');
}
Comment model:
public function entry() {
return $this->belongsTo('App\Models\Entry');
}
public function author() {
return $this->belongsTo('App\Models\Author', 'id');
}
Controller: (Nested relationship query)
$entries = Entry::with('comments.author')->get();
At this point everything is working correctly so the above $entries contains the expected Collection made up of:
*All entires, nested within each:
**all associated comments, and nested within that
***the associated author for each comment.
The Problem
The problem occurs when I have a multiple comments in the DB which contain the same author_id value.
In this scenario, the laravel Collection gives me the expected data for the first instance(a valid nested comment collection with nested author),
but any later instances which contain the same author_id have a value of null inside the relations property which results in the following error:
1/2 ErrorException in 991fecee1bbd0eb1ec5070d2f47d9c641ca4a735.php line 24:
Trying to get property of non-object
I only get the above error when multiple author_id are the same.
Therefore I know that there is no problem in the way I am accessing the collections data in the view.
Debugging the Queries created by eloquent:
Working query: (when all comments in the DB have a unique author_id)EG:
| id | author_id | text |
|---- |----------- |------- |
| 1 | 1 | blah1 |
| | | |
select * from `entries`
select * from `comments` where `comments`.`entry_id` in ('1')
select * from `authors` where `authors`.`id` in ('1')
#relations: array:1 [▼
"author" => Author {
//all correct data displays here
Problematic query: (when there is a comment in the DB which shares an author_id with another comment)EG:
| id | author_id | text |
|---- |----------- |------- |
| 1 | 1 | blah1 |
| 2 | 1 | blah2 |
| | | |
select * from `entries`
select * from `comments` where `comments`.`entry_id` in ('1', '2')
select * from `authors` where `authors`.`id` in ('1', '2')
#relations: array:1 [▼
"author" => null
]
I believe the issue is that the 3rd query contains: "in ('1', '2')" where 2 doesn't exist.
Does anyone have any thoughts on how to fix this?
I really would like to be able to successfully utilise Laravel's built in eloquent nested relationship system.
But if this is not doable do I need to write me own custom query?
Any input would be wonderful! I'm really stuck on this.
Thanks for your time and help.
Thanks to #Ravisha Hesh.
The problem was caused by the following:
public function author() {
return $this->belongsTo('App\Models\Author', 'id');
}
The solution:
public function author() {
return $this->belongsTo('App\Models\Author', 'author_id');
}

can I use laravel 4 eloquent model or do I need to use db:query

Hi I am trying my first attempt to use ORM with Laravel. I have a big table from Drupal that I want to grab some records of and I need to join those with another table in Drupal to get the records that I care about manipulating.
Like so...
Node
----------------------------------------------------------
| Nid | type | misc other stuff | N
==========================================================
| 1 | Programs | Test Service | 1 |
----------------------------------------------------------
| 2 | Programs | Example Service | 1 |
----------------------------------------------------------
| 3 | Something else | Another Service | 1 |
----------------------------------------------------------
Fields
----------------------------------------------------------
| id | title | NID | tag |
==========================================================
| 1 | Blog Title 1 | 1 | THER |
----------------------------------------------------------
| 2 | Blog Title 2 | 2 | TES |
----------------------------------------------------------
| 3 | Blog Title 3 | 3 | ANOTHER |
----------------------------------------------------------
I want to get all the Nodes where type='Programs' and inner join those with all fields where NIDs are the same. Do I do that with an Eloquent ORM in app/model/node.php? Or a query builder statement $model=DB:table? what is the code for this? Or do I just do it in PHP?
You could do this with the ORM, but would have to override everything that makes it convenient and elegant.
Because you say you're trying to "manipulate" data in the fields table, it sounds like you're trying to update Drupal tables using something other than the Drupal field system. I would generally not recommend doing this—the Drupal field system is big, complicated, and special. There's a whole CMS to go with it.
You should move the data out of the old Drupal database and into your new database using seeds (http://laravel.com/docs/4.2/migrations#database-seeding).
Define a "drupal" database connection in your app/config/database.php, in addition to whatever you're using as a "default" connection for a new application. You can seed Eloquent models from an alternative connection in this manner:
<?php
// $nodes is an array of node table records inner joined to fields
$nodes = DB::connection('drupal')
->table('node')
->join('fields', 'node.nid', '=', 'fields.nid')
->get();
Pull the data out and put it in proper tables using Laravel migrations into normalized, ActiveRecord-style tables (http://laravel.com/docs/4.2/migrations#creating-migrations).
I prefer query builder, it's more flexible
DB::table('Node')
->join('Fields', 'Fields.NID', '=', 'Node.Nid')
->where('type', 'Programs')
->get();
Create two models in app/model (node.php and field.php) like this:
class Node extends \Eloquent {
protected $fillable = [];
protected $table = 'Node';
public function fields()
{
return $this->hasMany('Field');
}
}
class Field extends \Eloquent {
protected $fillable = [];
public function node()
{
return $this->belongsTo('Node');
}
}
Than you could do something like this:
$nodes = Node::with('fields')->where('type', 'Programs')->get();
You will get all your nodes with their relation where type is Programs.

Laravel 4: one to many by on multiple columns?

I'm making a table that essentially maps rows in a table to rows in another table where the structures are as follows:
|--- Words --| |- Synonyms -|
|------------| |------------|
| id | | id |
| en | | word_id |
| ko | | synonym_id |
| created_at | | created_at |
| updated_at | | updated_at |
|------------| |------------|
Now then, I know I can essentially have the words model have many Synonyms through a function like:
public function synonyms()
{
return $this->hasMany('Synonym');
}
No problem, but this method always gets it by the the word_id, and I would like to get it from word_id OR synonym_id that way I don't have to make multiple entries in the DB.
Is there anyway I can do this?
Check laravel docs Eloquent relationships. It would only get word_id because that's the only foreign key I believe.
Also why do you have synonym_id in your Synonyms table?
I believe you are looking for polymorphic relationship.
http://laravel.com/docs/eloquent#polymorphic-relations
I think your best bet is to create a many-to-many relationship with words on itself using the synonyms table as your pivot table.
Add this to your Word model.
public function synonyms()
{
return $this->belongsToMany('Word', 'synonyms', 'user_id', 'synonym_id');
}
Using it:
$word = Word::where('en', '=', 'someword')->first();
foreach($word->synonyms as $synonym) {
// This method would probably return the same word as a synonym of itself so we can skip that iteration.
if($synonym->en == $word->en) {
continue;
}
// Echo the synonym.
echo $synonym->en;
}
I'm a bit confused on you wanting to be able to find synonyms by the word_id or synonym_id but I think if you are using the many-to-many, it won't matter because if you know the synonym, it's still technically just a word, and you'd do the exact same thing.

Laravel 4: A better way to represent this db structure/relationship within laravel

I have the following db table set up
+--------------+ +--------------+ +-----------------------+
| users | | clients | | user_clients |
+--------------+ +--------------+ +----------------------+
| id | | id | | usersid |
| name | | name | | clientid |
| authid | | email | +----------------------+
| (plus) | | (plus) |
+-------------+ +-------------+
I have set up the a relationship table [b]user_clients[/b] with foreign keys to the relevant db, so userid is link to users->id and clientid is linked to clients->id.
Dependant on the Users Authid is how many clients are linked:
Authid 1: User can only have one client associated to them.
Authid 2: User can only have one to many clients associated to them
Authid 3: User has access to ALL clients.
So as i am new to this relationship side of laravel currently i would do a lot of querying to get some details eg:
I would done something like:
$userClient =UsersClients::select('clientid')->where('userid','=',$userid)->get();
Then I would probably loop through the result to then get each client details and output to the page.
foreach($userClient as $i ->$cleint){
echo '<div>' .$cleint->name . '</div>';
........
}
Would this be an old way and could it be handled better??
----------------EDIT---------------
i have managed to sort it as the following:
User Model:
public function clients() {
return $this->hasMany('UsersClients','userid');
}
User Controller
$selectedUserClients = User::find(24)->clients;
I get the same out come as my previous result as in client id's 1 & 2, but now how to get the client details from the actual client db basically is there an easier way that the following:
foreach ($selectedUserClients as $key => $client) {
$clientInfo = Client::select('id','clientname')->where('id','=',$client->clientid)->get();
echo $clientInfo[0]->clientname;
}
The users_clients table needs it's own ID column in order for many-to-many relationships to work.
On your User Model, try
public function clients()
{
return $this->belongsToMany('Client','user_clients','userid','clientid');
}
Now you can find the clients assigned to each individual user with
User::find(24)->clients.
You could also do the inverse on your Client model...
public function users()
{
return $this->belongsToMany('User','user_clients','clientid','userid');
}
This would allow you to find all the users belonging to each client
Client::find(42)->users;
I would also like to mention that it's best practice to use snake case for your id's such as user_id or client_id.
Your table names should be plural. users and clients.
Your pivot table should be snake_case, in alphabetical order, and singular. client_user.
This would make working with Eloquent much easier because it's less you have to worry about when setting up the relationships and it might be easier for someone else to help you work on your project.
Instead of return $this->belongsToMany('Client','user_clients','userid','clientid'); all you'd have to do is return $this->belongsToMany('Client'); which should keep your app much cleaner and easier to read.

Resources