Eloquent whereHas Requires from() when Using Different Connections - laravel

I have two models - User and Announcement, and they exist on two separate connections - mysql and intranet respectively. The User model hasMany Announcements and the Announcement belongsTo a single User.
In the Announcement model I have protected $connection = 'intranet' and in the User model I have protected $connection = 'mysql'. Originally I wasn't specifying the $connection property on the User model as it is the default for the application but added it in for testing.
Doing any sort of query works normally. As an example these work:
User::find(1)->announcements()->where('name', 'something')->get()
Announcement::find(2)->user
However, when using whereHas on the Announcements model I get the following SQL Error: Base table or view not found: 1146 Table 'intranet.associate' - associate being the User's table and intranet being the database connection specified in the Announcement model.
While I did find an answer to the question here. I am curious, though, as to why you're required to use ->from(..). Is this intended functionality? I could not find anything in the documentation about using from().
As a side note I was able to fix this "issue" by assigning the $table property in the __construct method in the User model:
__construct(array $attributes = []) {
$this->table = env('DB_DATABASE').'.associate';
}
env('DB_DATABASE') being the default connection's database.

Related

Laravel find record in another table associated with $data

I am looking over some laravel code and I have a few questions regarding the code. In the view, I see a piece of code "$data->profile->age". Does this code automatically find the profile record in the profile table associated with the $data? How does it find the associated profile?
Controller:
return view('new-design.pages.influencer.info')
->withData($data)
View:
$data->profile->age
Yes. It finds the associated profile using the relations you definied in your Profile model
Once the relationship is defined, we may retrieve the related record using Eloquent's dynamic properties. Dynamic properties allow you to access relationship methods as if they were properties defined on the model:
Here's a simple example from the documentation to help you understand:
Let's say you have a posts table and a comments table:
We need to define a relationship between this two tables.
A one-to-many relationship is used to define relationships where a single model owns any amount of other models. For example, a blog post may have an infinite number of comments.
Note: you must have a foreign key in your comments table referencing the posts table, like post_id, in this case, if you use a different name you should inform that in your relation:
Remember, Eloquent will automatically determine the proper foreign key column on the Comment model. By convention, Eloquent will take the "snake case" name of the owning model and suffix it with _id. So, for this example, Eloquent will assume the foreign key on the Comment model is post_id.
In your Post model you could do:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
/**
* Get the comments for the blog post.
*/
public function comments()
{
return $this->hasMany('App\Comment');
}
}
And in your Comment model you should define the inverse relationship
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
/**
* Get the post that owns the comment.
*/
public function post()
{
return $this->belongsTo('App\Post');
}
}
Now, if you want to access all comments from a post you just need to get the relation:
$post = Post::find($id); // find a post
$post->comments; // This will return all comments that belong to the given post
So, you basically access them as if they were a property from the model, as said in the documentation
In your view you could do something like this:
#foreach($post->comments as $comment)
{
{{$comment->text}}
}
#endforeach
This example will print every comment text from the Post we get in the controller.
I reckon in your model for $data there is a function called profile. From that it is getting the equivalent profile.
Example: Imagine you have a model called phone and you want to find the user who owns it. You can write the following function in your model.
public function user()
{
return $this->belongsTo('App\User');
}
And in the view you may write something like
$phone->user->name
Now, behind the scene laravel will go to the phone and get the value from user_id for that phone. (If the foreign key is located in different column you can specify that too). Then laravel will find the users table with that user_id and retrieve the row. Then show the name on view.
Now if there is a complex query you can also write a function for that in the model.

Many-to-many withouth relations (Laravel)

I have two application, in two different server.
In the first Laravel application I have my User model, and in the secound application I have my Blog model.
There is a many-to-many relationship between them, a user can have multiple blogs, and one blog can belongs to many user.
They have two different database, but everything is built like its only one app in one server.
They have a REST API, and its communicating between them. The problem is, I cant set up real relations between them (like belongsToMany in the Eloquent Model), and I can't list User's blogs.
Is there a way to copy the "User::blogs()" relation function, with some query work on Blog:: class? For e.g. select all blogs where user_id is equal to 1 in the pivot table?
<?php
class User extends Model{
protected $connection = 'Your Connection';
public function blogs(){
return $this->belongsToMany(Blog::class);
}
}
Blog.php
class Blog extends Model{
protected $connection = 'Your other connection';
public function users(){
return $this->belongsToMany(User::class);
}
}
You can set the multiple connections in your database.php and assign each model a different connection.
I am assuming that you have a user_blogs table. some where
hope this helps.
I found it, like this:
Blog::join('blog_user', 'blogs.id','=','blog_user.blog_id')->where('blog_user.user_id', '=', $this->userId)->get();

laravel use field in Eloquent model from another table

I have a model named "User". I want "Password" field from Eloquent from another table, and when user calls the user::all() method, all selected fields from different tables come in the result.
How can i do that?
Results are not displayed in with() .
my problem solved by using $appends in Eloquent model .
my code :
class User extends Eloquent {
protected $table = 'user';
protected $attributes = ['password'];
protected $appends = ['password'];
public function getPasswordAttribute()
{
return $this->getPAsswordMethod();
}
}
Your question is extremely board and borderline unanswerable but I will give you a board solution.
You are able to establish relationships to other tables via the Model objects you create. Lets pretend you have a Password table which belongs to the User.
User model:
public function password()
{
return $this->hasOne(Password::class, 'FK', 'PK');
}
You can now do User::with('password')->get(['FieldName']); and this will give you all of the passwords which have the above relationship to a user.

How does eloquent recognize tables?

I am curious about how eloquent knows in which table it should save the records we give it by running $ php artisan tinker . I do not actually remember setting so an option.
In Laravel when using Eloquent you should assign a table name using the property $table for example:
protected $table = 'some_thing';
Otherwise it assumes that the table name is the plural form of the model name and in this case for User model the table name should be users. Follwing paragraph is taken from Laravel website:
Table Names
Note that we did not tell Eloquent which table to use for our Flight
model. The "snake case", plural name of the class will be used as the
table name unless another name is explicitly specified. So, in this
case, Eloquent will assume the Flight model stores records in the
flights table.
// You may use this instead:
class Flight extends Model
{
// Explicit table name example
protected $table = 'my_flights';
}
So, if you don't follw this convention when creating/naming your database tables that Laravel expects then you have to tell Laravel the name of the table for a model using a protected $table property in your model.
Read the documentation here.
Actually if you not set the $table property, Eloquent will automatically look the snake case and plural name of the class name. For example if class name is User, it will users.
Here the code taken from Illuminate/Database/Eloquent/Model.php
public function getTable()
{
if (isset($this->table)) {
return $this->table;
}
return str_replace('\\', '', Str::snake(Str::plural(class_basename($this))));
}
Model name is mapped to the plural of table name, like User model maps to users table and so.
When you do
User::all() laravel knows that you want the records from users table.
To specify the table name explicitly you use protected $table ='name' field on model.
Actually, Eloquent in its default way, is an Active Record System just like Ruby On Rails has. Here Eloquent is extended by a model. Those model name can be anything starts with capital letter. Like for example User or Stock
but the funny thing is this active record system will imagine that if no other name of custom table is specified within the class model then the table name should be the small cased plural form of the Model name. In these cases users and stocks.
But by keeping aside theses names you can extensively can provide your own table name within the model. As in Laravel protected $table= 'customTableName'
Or, in a more descriptive way,
class Stock extends Eloquent{
// Custom Table Name
protected $table = 'custom_tables';
}
I hope this will solve your curious mind.

Laravel Eloquent BelongsToMany multiple databases

I have two databases ("internal" and "external") and I would like to create a BelongsToMany relation between them. The problem, how do I specify in which database the relation_table is stored?
In my current case, I have some users that I would like to connect to some objects from an external database.
User:
public function objects() {
return $this->belongsToMany('\App\Object', 'user_object_relation');
}
Object:
protected $connection = 'mysql_data';
protected $table = 'objects';
protected $primaryKey = 'ObjectID';
Eloquent now is assuming my user_object_relation table in the mysql_data (external) database, however I've created this in the "internal" database.
Q: How do I tell eloquent that the relation table is not in the external table?
// edit:
with return $this->belongsToMany('\App\Object', 'internal.user_object_relation');, I receive an access denied error because the "external" database user has no access to the internal ;)

Resources