Assigning ids to relationships in Laravel - laravel

I have an eloquent model called "Customer". Customers have a one-to-many relationship with another model, "Image". I want to group the images owned by a customer so that I can assign them to different usecases - a customer would have a single image for a Logo, for instance, but many images for their gallery section.
How do I assign a usecase to a relationship in Laravel?
I'm thinking I will make an intermediary model called 'Usecase' and then access the images using the hasManyThrough method. Many relationships in my system need their usecases defined. I'm new to laravel, is this something that is already covered in the framework?
EDIT:
I also want to have Images assigned to Customers when they are not in use - so I could upload a bunch of images and say that they belong to a particular customer, but they aren't used anywhere until we assign a 'usecase' (ie, 'logo' or 'gallery'). This way I would have an image gallery of all the images that are assigned to the customer, and then a gallery for images assigned as 'gallery'. Bleh, does that make sense?

There are 3 approaches that I can think of to accomplish this.
1: You turn 'Logo' into a column on 'Customer' rather than a separate model and keep 'Image' for all gallery images.
2: You turn 'Logo' into a separate model, same for 'Customer' and 'Image'
3: You complicate your life and keep 'Logo' and gallery images as 'Image', then add a way to distinguish between the two (perhaps a flag: is_logo or an enum column: image_type).
If you ask me, the 2nd option is the most appealing.

You may use Polymorphic Relationships relationship for this or separate the 2 images table
Customer
Logo
Image
Customer can have 1 logo
Customer can have 1 or many Images
$customer = new Customer;
$customer->with('images', 'logo')->get();
The will help you query in a group of result for all of your images and logo.

You could use 2 relations for the same model.
Model:
class Customer extends Model
{
public function gallery()
{
return $this->hasMany(Image::class)->where('type', 'gallery');
}
public function logo()
{
return $this->hasOne(Image::class)->where('type', 'logo');
}
}
Retrieving:
$customer = Customer::with(['gallery', 'logo'])->get();
Outputing:
#foreach($customer->gallery as $image)
{{ $image->some_attribute }}
#endforeach
{{ $customer->logo->some_attribute }}

I think the cleanest approach is to...
1) Have a "UseCase" table that can define all types of use cases. This allows for simple scalability and readability without cluttering the image table with a bunch of new VARCHARs or whatever.
2) Create a "use_case" column in the "Image" table and assign the corresponding ID from the "UseCase" table above per image.
3) Create a hasOne/belongsTo relationship between "Image" and "UseCase" on UseCase.id = Image.use_case
4) Create a scope in your "Customer" table something like below...
public function scopeUseCase($query, $case){
$query->with(['Image.UseCase' => function($relationQuery) use ($case) {
return $relationQuery->where('name', '=', $case);
}]);
}
5) Finally, reference the cases by name in queries using the scope like so...
Customer::useCase('logo')->get();
Should be a pretty clean and straightforward process from there. Sorry for formatting issues stuck on mobile.

Related

Eloquent with diferent relationships for same table

i need some hints and what is the best way and pratice with laravel to solve this problem!
I have a main table called colors with the fields category_id and type and i have in my models 2 relationships for the category_id, the bluecategory and redcategory.
In some cases i use the id from bluecategory and in other exemples i use the redcategory id.
Now in one page i want to shows all the results from colors, but i can't do this $data->bluecategory or $data->redcategory because i dont'no what record is using what relationship.
My ideia was using a function to send parameters category_id and type and inside the function discover what is the correspondente relashion and return the correct result.
But how i can handle this?
Sorry its a bit confuse!
You could add a scope to your modal and than chain it to your existing query.
Example
public function scopeName($query, $catID, $type)
{
return $query->where('category_id, $catID)
->where('type', $type);
}

laravel/elequent - models and relations

I trying to learn laravel and to do some tests/demo apps. I've struggling now with laravel/eloquent tables relations. And I need advice.
I have 3 models [Application, Term, AppState] and their tables applications[id, terms_id, appStates_id, and other cols ], terms[id, startDate, endDate, ...], app_states[id, caption]
Application.php
public function term()
{
return $this->belongsTo('App\Term');
}
public function appState()
{
return $this->belongsTo('App\AppState');
}
in Term.php and AppState.php i have:
public function applications()
{
return $this->hasMany('App\Application');
}
How I can get let's say "caption"/"startDay"+"endDate" in blade for each application? I can get their ids $app->terms_id/$app->appStates_id in foreach loop, but i want get caption value from app_states table.
Has to be this relations also specified in migrations? In some tuts is mentioned, that is not needed in case i want to handle it only in laravel.
Thanks for advice
You can access a model's relationship values by calling the relationship method like a property.
$application = Application::find(1);
$application->term->startDate;
$application->term->endDate;
$application->appState->caption;
Also your relationship with AppState is wrong, since your foreign key doesn't follow a snake_case typing, you'll need to provide the appropriate key for it
public function appState()
{
return $this->belongsTo('App\AppState', 'appStates_id');
}
You might also want to check terms_id as well since the model name (Term) is singular but the foreign key is plural.
Has to be this relations also specified in migrations? In some tuts is mentioned, that is not needed in case i want to handle it only in laravel.
Well, yes, you don't need to if Laravel will only be the one accessing that database. But if any cases in the near future you decide to migrate to a different framework or use the same database in another application, it's better to include these relationships in the migration. Also a database administrator would probably cringe if you don't.
So provided your relationships are correctly setup, you can access them anywhere you have an instance of that model.
So for example, lets say you have passed a collection of applications to your view ($apps):
#foreach($apps as $app)
{{ $app->term->startDate }}
{{ $app->term->endDate }}
{{ $app->appState->caption }}
#endforeach
Important Note: We are accessing the Eloquent relationship using ->appState rather than ->appState(). The later is actually accessing a Query Builder instance and has some more advanced use cases

Laravel polymorphic hasMany relationship

From Laravel's docs, the model polymorphism is defined as follows:
Polymorphic relations allow a model to belong to more than one other model on a single association
Sounds like it's designed to work with belongsTo instead of hasMany side. Here's a scenario that I want to achieve:
In my system, there are many project types, each projec type will have its own invoice field layout. Let's say we have a Project model that has a type field, whose value could be contract or part-time. We have another two tables called ContractInvoice and PartTimeInvoice to define their respective field layout, both of these invoice tables have a project_id referencing a project record. What I want to do is I want a universal interface to retrieve all invoices given a project, something like $project->invoices.
Current solution
I can't figure out how to achieve this via polymorphism. So what I am currently doing is kind silly, using a switch statement in my invoice() method on Project model class:
switch ($this->type) {
case 'contract':
$model = 'App\ContractInvoice';
break;
case 'part-time':
$model = 'App\PartTimeInvoice';
break;
}
return $this->hasMany($model);
I feel like there must be a better way to do this. Can someone please shed some light?
I don't see how a polymorphic relationship would be beneficial in this case. If you had different project type models and a single invoices table, then the invoices could morphTo the projects. But as you've described it, the switch statement sounds like it is adequate. You could achieve the same means using when conditionals like:
public function invoices()
{
return $this->when($this->type === 'contract', function () {
return $this->hasMany(ContractInvoice::class);
})->when($this->type === 'part-time', function () {
return $this->hasMany(PartTimeInvoice::class);
});
}
The type attribute on the Project model and the separate invoice tables are defining a rigid relationship between them, which goes against the idea of polymorphism. Think likes for comments and posts.

Laravel grab related models based on tags

I have two models, Expense and Tag, which have a Many to Many relation.
For each Expense, I can add multiple tags, which are stored in a pivot table using sync. The table is called expense_tag.
Now on my expenses.show page, I want to display details about one expense, obviously. But, I want to show ALL related expenses, using the tags relationship.
The problem:
I only have the information for one expense. Which means, I need to collect all tags that are assigned to that expense, and then using those tags, grab all expenses that were assigned one or more of those tags as well.
I want to refrain from having to use foreach loops to accomplish this. I've been trying with filter but I am unsure how to go about it. I just prefer keeping it simple.
Any suggestions for this?
My relations in my model:
Expense:
public function tags()
{
return $this->belongsToMany(Tag::class);
}
Tag:
public function expenses()
{
return $this->belongsToMany(Expense::class);
}
The solution is to use a where in clause
$tagIds = $expense->tags()->pluck('id')->toArray();
$expenseIds = DB::table('expense_tag')->
whereIn('tag_id',$tagIds)->pluck('expense_id')->toArray();
$relatedexpenses = Expense::whereIn('id', $expenseIds)->get();
note: this uses 3 queries, so it might be slightly slower than a full sql solution, but it should be ok.

How do I keep models loosely coupled when querying a many-to-many table in CodeIgniter?

I'm using CodeIgniter and have three tables and a model for each:
User - table of users
Product - table of products
UserProduct - table showing which users have which products (two foreign key columns, and some other columns such as date)
In my code I want to display a list for a particular user showing which products they have. So I have a method in the UserProduct class that does a select on the UserProduct table matching for the userId, and a join bringing in all the data I need about each product.
This works fine, but I am concerned now that I am moving down a path of tight coupling. For example, say I want to find out the URL of a product image. I have a method in the product model to return this, I don't want a duplicate method in the UserProduct model, and I don't want to create a coupling by having the UserProduct model trying to access methods in other models (which I don't think CodeIgniter likes you to do).
This problem seems likely to occur in any model that accesses a DB table that has foreign keys where that model may need data from the parent table and want to manipulate it.
Is there an elegant solution, or do I need to accept that foreign keys necessarily create couplings in models or the need for similar methods across models?
TIA,
Phil.
My personal standard is to create 1 controller + 1 model always.
for example site.com/users will use model_users.php
or
site.com/products will use model_products.php
to slim your code and re-use methods use methods params for example a model method to be re-used could be:
function getUsers($data){
foreach($data as $key=>$value){
$this->db->where($key,$value);
}
$query = $this->db->get('users');
return $query->result();
}
the more you extend this method the more you can re-use, just another example of extending:
function getUsers($data,$order_by = false){
foreach($data as $key=>$value){
$this->db->where($key,$value);
}
if($order_by){
foreach($order_by as $key=>$value){
$this->db->order_by($key,$value);
}
}
$query = $this->db->get('users');
return $query->result();
}
//then you call results with this in your controller
$results = $this->model->getUsers(
$data = array('id'=>'12','country'=>'USA'),
$order_by = array('username'=>'DESC')
);
so now you got also order_by , and so on, you can add joins, limit,offset,like etc.. all in the same or quite the same way , the more accurated you are the more you can re-use the same methods

Resources