How do I create a custom relationship in laravel? - php

Is it possible to create custom relationships in Laravel like this,
SELECT tasks.*
FROM tasks
LEFT JOIN priorities ON tasks.priority_identifier LIKE CONCAT('%', priorities.identifier)
WHERE priority.id = 10
I could use query builder to create this join but how can i return this as a laravel relationship ?
Edit
I'm trying to do this without using existing relationship methods(hasMany, hasOne etc)

Yes, you can add conditions to Laravel relations just like any other query builder. I don't know what your relation will look like, but you could do this for example:
public function tasks()
{
return $this->hasMany(Task::class)
->where('priority', 10);
}

I don't think you can create a custom relationship, unless overriding Eloquent base class.
And add your own.
But you can use Eloquent scopes alternative to custom relationships.
Also take a look here and here

Related

leftJoin method in Eloquent ORM?

I'm beginner in Laravel and I'm using 5.5 version.
Is there a method leftJoin in Eloquent ORM?
I know there is one on DB facade (query builder), but if I want to use Eloquent only is there a leftJoin method?
Let's suppose, as an example, I have a model CarBrand and another one CarModel.
CarBrand have a relationship type hasMany with CarModel, and CarModel belongsTo CarBrand.
Suppose I want to find CarBrand's id's without CarModel correspondence.
I found on this site, several responses like this:
CarBrand::leftJoin('CarModelTableName',
'CarBrandTableName.id','=','CarModelTableName.carBrandId')->
whereNull('CarModelTableName.carBrandId')->first();
I have checked and it does function as a left join :)
But in this case is ::leftJoin an Eloquent method or silently it goes to DB facade?
I can't find any for leftJoin in Laravel 5 official docs other than DB facade.
Any links would be appreciated.
Hope I was clear,
Thank you for your attention.
I think I found the answer....
I find out that I can use something like:
LaravelModellName::AnyQueryBuilderMethod
so that's why is using DB facade methods
The problem in my primary question could be solved 100% in eloquent way using doesntHave model method:
$result = CarBrand::doesntHave('RelationshipNameWithCarModel')->get();

laravel Eloquent join and Object-relationship mapping

Ok so i'm kind of newish to eloquent and laravel (not frameworks tho) but i hit a wall here.
I need to perform some queries with conditions on different tables, so the eager load (::with()) is useless as it creates multiples queries.
Fine, let use the join. But in that case, it seems that Laravel/Eloquent just drops the concept of Object-relationship and just return a flat row.
By exemple:
if i set something like
$allInvoicesQuery = Invoice::join('contacts', 'contacts.id', '=', 'invoices.contact_id')->get();
and then looping such as
foreach ($allInvoicesQuery as $oneInvoice) {
... working with fields
}
There is no more concept of $oneInvoice->invoiceFieldName and $oneInvoice->contact->contactFieldName
I have to get the contacts fields directly by $oneInvoice->contactFieldName
On top of that the same named columns will be overwrited (such as id or created_at).
So my questions are:
Am i right assuming there is no solution to this and i must define manually the field in a select to avoid the same name overwritting like
Invoice::select('invoices.created_at as invoice.create, contacts.created_at as contact_create)
In case of multiple joins, it makes the all query building process long and complex. But mainly, it just ruins all the Model relationship work that a framework should brings no?
Is there any more Model relationship oriented solution to work with laravel or within the Eloquent ORM?
Instead of performing this join, you can use Eloquent's relationships in order to achieve this.
In your Invoice model it would be:
public function contact(){
return $this->belongsTo('\App\Contact');
}
And then of course inside of your Contact model:
public function invoices(){
return $this->hasMany('\App\Invoice');
}
If you want to make sure all queries always have these active, then you'd want the following in your models:
protected $with = ['Invoice']
protected $with = ['Contact'];
Finally, with our relationships well defined, we can do the following:
$invoices = Invoice::all();
And then you can do:
foreach($invoices as $invoice)[
$invoice->contact->name;
$invoice->contact->phone;
//etc
}
Which is what I believe you are looking for.
Furthermore, you can find all this and much more in The Eloquent ORM Guide on Laravel's site.
Maybe a bit old, but I've been in the same situation before.
At least in Laravel 5.2 (and up, presumably), the Eloquent relationships that you have defined should still exist. The objects that are returned should be Invoice objects in your case, you could check by dd($allInvoiceQuery); and see what the objects are in the collection. If they are Invoice objects (and you haven't done ->toArray() or something), you can treat them as such.
To force only having the properties in those objects that are related to the Invoice object you can select them with a wildcard: $allInvoicesQuery = Invoice::select('invoices.*')->join('contacts', 'contacts.id', '=', 'invoices.contact_id')->get();, assuming your corresponding table is called invoices.
Hope this helps.

Laravel 5.1: Pagination on Models with hasManyThrough()

I have "Brand" hasManyThrough "MarketProduct" through "Product". So,
Brand >> Product >> MarketProduct
where >> represents a hasMany relationship. I'm able to get a collection (Illuminate\Database\Eloquent\Collection) of MarketProductsas below using the hasManyThrough() method defined in Brand.
$collection = Brand::find($someId)->marketProducts;
The issue is that $colletion is not an instance of the Query Builder or Eloquent, so I can't use ->paginate($num). Is it possible to use the default pagination feature when using hasManyThrough, or do I need build the query manually to use the pagination?
If you look at the document, it mentions
...since all relationships also serve as query builders, you can add
further constraints to which comments are retrieved by calling the
comments method and continuing to chain conditions onto the query...
So the solution is:
$collection = Brand::find($someId)->marketProducts();

get *related* linked models in laravel eloquent instead of raw SQL

I'm trying to get 'related' linked models by querying a link table, named company_projects which holds (as you expect) the id's of companies and projects (projects are kind of product-categories).
In this case, the used flow to determine a related project is:
Get companies who are in the same project ('product category') as you
Find the other project id's which are linked to those companies
Get the info of the linked projects fetched by last step
What i'm trying to do is already functional in the following raw query:
SELECT
*
FROM
projects
WHERE
projects.id IN
(
SELECT cp1.project_id
FROM company_projects cp1
WHERE cp1.company_id IN
(
SELECT cp1.company_id
FROM projects p
LEFT JOIN company_projects cp2 ON cp2.project_id = p.id
WHERE p.id = X AND cp2.company_id != Y
)
)
AND projects.id != X
X = ID of current project ('product category')
Y = ID of current 'user' (company)
But my real question is, how to do this elegantly in Laravel Eloquent (currently v4.2). I tried it, but I have no luck so far...
Update:
I should note that I do have experience using Eloquent and Models through multiple projects, but for some reason I just fail with this specific query. So was hoping to see an explained solution. It is a possibility that I'm thinking in the wrong way and that the answer is relatively easy.
You will need to utilize Eloquent relationships in order to achieve this. (Note that I am linking to the 4.2 docs as that is what you are using, but I would highly suggest upgrading Laravel to 5.1)
I am assuming you have a 'Company' and 'Project' model already. Inside each of those models, you need to a define a method that references its relationship to the other model. Based on your description, it sounds like the two have a Many to Many relationship, meaning that a company can have many projects and a project can also belong to many companies. You already have a database table linking the two. In the Eloquent ORM this linking table is called a pivot table. When you define your relationships in the model, you will need to pass the name of that pivot table as your second argument. Here's how it could look for you.
Company model:
class Company extends Model
{
/**
* Get the projects attached to a Comapny. Many To Many relationship.
*/
public function projects()
{
return $this->belongsToMany('Project','company_projects');
}
}
Project model:
class Project extends Model
{
/**
* Get the companies this project belongs to. Many To Many relationship.
*/
public function companies()
{
return $this->belongsToMany('Company','company_projects');
}
}
If your models have these relationships defined, then you can easily reference them in your views and elsewhere. For example, if you wanted to find all of the projects that belong to a company with an ID of 1234, you could do this:
$company = Company::find(1234);
$projects = $company->projects;
Even better, you can utilize something called eager loading, which will reduce your data lookup to a single line (this is mainly useful when passing data to views and you will be looping over related models in the view). So those statements above could be rewritten as:
$company = Company::with('projects')->find(123);
This will return your Company model with all its related products as a property. Note that eager loading can even be nested with a dot notation. This means that you can find all the models that link to your main model, and then all the models for those models, and so on and so forth.
With all of this in mind, let's look at what you specifically want to accomplish.
Let us assume that this method occurs in a Controller that is being passed a project id from the route.
public function showCompaniesAndProjects($id)
{
//Get all companies in the same project as you
//Use eager loading to grab the projects of all THOSE companies
//Result will be a Project Object with all Companies
//(and those projects) as Eloquent Collection
$companies = Project::with('companies.projects')->find($id);
//do something with that data, maybe pass it to a view
return view('companiesView')->with('companies',$companies);
}
After defining your relations in your models, you can accomplish that whole query in a single line.

How does Laravel's ORM works comparated to Symfony's Doctrine

I'm a Symfony 2 developper who's beginning on Laravel. I'm a little bit lost with Laravel's ORM, it seems that we have to directly deal with the database to create tables manually... On Symfony, this was automatically made by Doctrine according to the mapping classes (and #ORM annotations).
Is the concept totally different on Laravel, or did I just not find the way to do it like on Symfony ?
Your question is not clear enough but I guess you want to know how Eloquent models map tables, in this case you have to use your table names (in database) the plural form of the word (but not mandatory), for example, a table that used to contain user data should be users or for post data the table should be posts but you may use whatever you want.
To map the users table with an Eloquent model; all you need to do i; create a model like this:
Post extends Eloquent {
//...
}
Now you may use something like this:
$posts = Post::all();
$post = Post::find(1);
Laravel will query from the posts table but if your table name is different than the standard way Laravel wants then you have to tell Laravel what is the table name by adding a property in the model, for example:
Post extends Eloquent {
protected $table = 'article'; // Laravel will query from article table
//...
}
You can use Post model as;
// Laravel will query from article table in the database
// because you gave the $table property with the table name
$posts = Post::all();
$post = Post::find(1);
Read more on the manual.
Laravel have migration like DoctrineMigrationsBundle, so in your model(entitie) you just write (for exemple):
class YourClass extends Eloquent {
}
So no need to overcharge your model with attribute, laravel do it automatically
http://laravel.com/docs/migrations for more information aboutmigration

Categories