I'm fairly new to Laravel and have primarily focused most of my development time on Codeigniter in the past as this is what my job involves for the most part.
I'm currently building a client's website and also building a custom CMS (for both experience and particular needs of the client).
Currently I'm stuggling to figure out how to deal with relationships in Laravel/Eloquent as for example, I have a products table. Each product can have a type. I'm storing these types in a separate table so I've got better control over them in the future when the content starts to build up. All I need is a query to fetch all products with their associated type. In other frameworks, I could simply do this using a query builder to define the columns and joins, however due to the way Eloquent works, I'm struggling to find the way to do this!
Just for a bit of context, in the CMS, there will be a products datatable which will show all products in the system and one of the columns will be type, however I want to show the name of the type, not the id.
Probably me being stupid so feel free to point out something obvious!
What you're looking for is "Eager Loading" which is here in the documentation: https://laravel.com/docs/5.8/eloquent-relationships#eager-loading
In their example on the website, you can replace their "Book" with your "Product" and then their "Author" with your "Type" and you will achieve what you are trying to do.
If you want to load the relationships in the views, i.e. using Blade, you would need to do something like the following:
#foreach($products as $product)
<div> {{ $product->type->name }} </div>
#endforeach
you can search for with() function it will be useful in this :
in your example you need to relate product model with type model so in product you will add
`public function type()
{
return $this->hasOne(Type::class);
}`
and in type add
public function Product()
{
return $this->belongsTo(Product::class);
}
and your query will be
$result=Product::with("type")->get();
this will return the related type row with each related product row as
this example get user with profile
and you can get type name for each product row from
foreach($result as $res){
$type_name=$res->type->name;
}
Related
I'm actually trying to create an E-Commerce application in Laravel and have the following database layout...
TABLE PRODUCTS:
product_id PK,
material,
description,
brand_id,
category_id,
TABLE PRODUCTS_CHILDREN:
id,
sku,
color,
price,
size,
qty,
product_id (FK to products table)
Now I'm a beginner in Laravel, but I was thinking to build an E-Commerce application and just wanted solve this issue before going to far.
My question is, is there a way, when displaying the products, to also retrieve the products children?
My thought process was:
Products -> get( product_id, $product_id ) -> getChildren ( product_id, product_id );
I know the syntax is not correct, I was just wondering if this was a possible solution in Laravel - by chaining the query ( as I believe is common with the Laravel framework ).
I guess what I'm asking is, what would the blade syntax look when displaying the data?
Judging from what I've seen from tutorials, it seems this would work, but I just wanted to confirm. Thank you for any help!
Yeah it would work once you set up relationships by following the documentation.
For instance, in your example you would have two models, one for the products table and another for the products_children table (I would call them: Product and Variant respectively).
Between them you would have a 1:N relation (one product can have many variants, one variants belongs to one and only one product).
So you could model the relation as following:
Model: Product
class Product
{
// Other methods/properties...
public function variants()
{
return $this->hasMany(Variant::class);
}
}
Model: Variant
class Variant
{
// This is needed, otherwise Laravel would search for a
// table called as the pluralized model name's (eg: variants)
protected $table = 'products_children';
// Other methods/properties...
public function product()
{
return $this->belongsTo(Product::class, 'products_children');
}
}
Once you set up relations like so you can chain methods like your example:
// Assuming $id is the variable holding the product id you want to retrive
$product = Product::find($id);
$variants = $product->variants;
// You can now access the main Product properties, but you can also
// iterate through each Variant entity linked to that product.
Depending on the query use case, the last query might not be the optimal way to do it. You sometimes have to eager-load the relation for all of entities you are querying. If you want to look more in depth about this topic, refer to the official documentation.
Disclaimer: The code I wrote it's just a PoC and hasn't been tested. It was written to give a quick overview about how simple is to setup and use relationships among models.
I have a database with a table articles and a table category.
My table articles have some fields. And one that is category_id and a another orientation.
Categories, in my design, are arranged by orientation. Here is an example
So, I would like to get all category BUT these categories must belong to the right orientation. I want list of all category who have articles with 'web' orientation, by example.
I do not know if it's possible with this architecture and if you understand me.
Any help is welcome
UPDATE : adding the schemas
If you have your models and relations set up, I believe this should do what you want:
$categories = Category::whereHas('articles', function($query) {
$query->where('orientation', 'web')
})->get()
From the Laravel documentation:
If you need even more power, you may use the whereHas and orWhereHas
methods to put "where" conditions on your has queries. These methods
allow you to add customized constraints to a relationship constraint,
such as checking the content of a comment
I'm working on octoberCMS(laravel framework), I have a doubt on retrieving relation model on where clause.
I have fetched a clothing_type record from "clothing type" model based on its primary key "id".
$clothing_type = ClothingType::where('id',post('clothingtype_id'))->where('status','Active')->first();
This "clothing type" model is related with "products" model, the relation is => each clothing type hasMany products.
Every thing works fine; Now my business logic has two cases, one is to get all the products of the clothing type and another is to get the first product of the clothing type. So I have used the $clothing_type->products to get all the products and $clothing_type->products->first() to get the first product.
Now I have to apply a condition for both the cases. The condition is that only the product whose status is "Active" should be fetched, hence
$products = $clothing_type->products->where('status','Active'); and$first_product_detail = $products->first();.
Every thing works as expected but how come the products are fetched without "get()" method. $clothing_type->products->where('status','Active')->get(); Since I'm new to relation I want to know how this works or is this a bad way to get records or improper assumption. But every thing works good.
$clothing_type = ClothingType::where('id',post('clothingtype_id'))->where('status','Active')->first();
if(count($clothing_type->products))
{
$products = $clothing_type->products->where('status','Active');
$first_product_detail = $products->first();
}
You are doing it the correct way. When you access the relationship as an attribute Eloquent automatically retrieves the records.
However, if you access the relationship as a method, you get the query itself, to which you can add your filters:
if(count($clothing_type->products))
{
$products = $clothing_type->products()->where('status','Active')->get();
$first_product_detail = $products->first();
}
This would solve your problems
(documentation is over here (see the first item))
Edit: Also note that the first method is not a method of Eloquent, but from Collection, which is pretty powerful!
Edit2:
I misread the part of your question where you want to know HOW this is possible. Both Eloquent and Collections have a where method. I assume you understand the working of the Eloquent one, but the one from Collection is pretty much the same (see documentation on the Collection where here)
I prefer the Eloquent one myself, because that limits the amount of records that is retrieved from the database. But if you need all the products (even the inactive ones) later on in your code, just use the Collection method to filter the active ones out
There is nothing to be afraid of...
first() and where()
are functions of both Illuminate\Database\Query\Builder as well as Illuminate\Support\Collection and all first does is limit the records to take 1 and then give you the first record. When you use Builder a query is made to get 1 record and 1 you use it on a collection, all records are first get() and then the first of those records is returned.
Here,
When you do,
$clothing_type->products, Laravel gives you a collection of products...
So...
$products is an object of Illuminate\Support\Collection
and
$products->first() calls for the first() function in that class.
Documentation on where and first methods of a collection...
I want to ask if its clean possible to change the mapping process.
For example, if i have an database, with products and offers, so the relation is 1 product n offers.
I want to get on fetch an product with multiple offers not an collection of offers, instead of i want to get an class named "AggregateOffers" which calculates the highest the lowest price and includes the offers collection.
Did anyone know an good/clean solution?
For an better understanding, schema.org defines the relation between an product an multiple offers, within an aggregateoffer, so i want to abstract them, to generate at the end an json-ld.
My actually design looks like schema, as you can see i have an 1-n relation from Product to Offer, what i actually want to get when i read from the DB, is an extended relation.
For example:
Product -> getOffers (should not return an collection of offers, instead it should return an "AggregateOffers" which hold the collection of offers).
The only idea, is to update the "getOffers" function and return die Aggregation class, but this acts not really good on me.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I need to develop a custom form generator using Laravel.
That means there will be a GUI to select and customise the forms like Registration Form or Booking Form.User should be able to add/edit/delete different form controls, define it as mandatory, etc.
Here I am little confused to handle this in back-end. What is the better way to achieve this?
Or how can I implement a database architecture to use some metadata table which can be used to handle multiple items like Wordpress and is there any built-in Laravel functionalities to handle these meta objects?
And how the insert/update/delete handled in this metadata approach?
Here an insert should have only one row in the meta table. Suppose at the time of user registration, without saving the firstname and lastname in separate rows in the meta table, it should use some objects like this in a single row.
a:3:{s:9:"firstname";s:10:"irshad.far";s:8:"lastname";s:0:"";s:5:"_meta";a:7:{s:2:"ip";s:10:"14.99.80.3";s:9:"confirmip";s:10:"14.99.80.3";s:11:"confirmtime";d:1407932201;s:8:"signupip";s:10:"14.99.80.3";s:10:"signuptime";d:1407932201;s:4:"lang";s:2:"en";s:4:"form";s:7:"unknown";}}
Handling a table of meta data is fairly straight forward using Laravel's Eloquent relations. Let's say you have a users table in your database that contains:
id email password created_at updated_at deleted_at
If you want to keep it simple and not add all sorts of extra data to your users table you could create a meta table and then a link table user_meta to relate the two.
But what if you also have a posts table (as with Wordpress) and your posts also need meta data? Instead of also creating a posts_meta table to link your posts to their meta, we can use Laravels Eloquent relations and create some Polymorphic Relations.
The Database
Here's our setup, along with our users table (above) we have a posts table which has the fields:
id title content created_at updated_at deleted_at
We also have our meta table that follows the guidelines for a polymorphic relation:
id name value metable_id metable_type
//int meta key meta value post/user id resource ie post/user
Using this we could add meta for a post or user to our meta table like this:
id name value metable_id metable_type
------------------------------------------------------
1 nickname Steve 1 User
2 author Steve O 1 Post
All we need to do to grab this info from the database is define the relations in our respective models.
The Models
So now we have our DB ready we need to setup our models (one model for User, one for Post and one for Meta) with our polymorphic relationship. Our User and Post models are both going to use the same function to relate to our Meta model:
User.php
========================================
class User extends Eloquent {
public function meta()
{
return $this->morphMany('Meta', 'metable');
}
}
Post.php
========================================
class Post extends Eloquent {
public function meta()
{
return $this->morphMany('Meta', 'metable');
}
}
Now we define the inverse of those relations in our meta model:
Meta.php
========================================
class Meta extends Eloquent {
public function metable()
{
return $this->morphTo();
}
}
That's it!
Getting the data
Now all you need to do to get at the meta data for a user or post is:
// Load in a post with an id of 1 and get all it's related meta
$post = Post::find(1);
$meta = $post->meta;
If we were to return the meta object we might see something like:
[{"id":2,"metable_id":1,"metable_type":"Post","name":"author","value":"Steve O"}]
Onwards!
From here you can create helper functions like this one that checks if the meta you're after exists in the results:
public function hasMeta($key)
{
$meta = $this->meta;
foreach ($meta as $item):
if( $item->name == $key ) return true;
endforeach;
return false;
}
// Use it like:
if($post->hasMeta('author')){
// Display author
}
Read more about Laravels Eloquent relationships in the docs here: http://laravel.com/docs/eloquent-relationships
I once did something similar, my approach was to build a mini DB engine where forms are like tables and data is rows:
A form which describes the structure and design of a form:
Form {
id,
title,
layout,
...
}
Fields of the form with types and validation rules
Field {
formId,
name,
type (String, Date, Image, Integer, Double, List, ...),
pattern (Regex validation maybe),
...
}
Inserted data in a form is a row belonging to that form
Row {
id,
formId,
}
Each row is a group of entries to fields of the corresponding form that can be validated following the predefined rules.
Entry {
rowId,
fieldId,
value
}
Type and rules can be regrouped in another object so you can have dynamic types that you can manage.
Lists can have another object that stores choices and type of list (multi-select, mono-select)
Metadataobjects itself would be saved in one table. But performance-wise I think those object should their own data tables.
Approach 1)
These types of forms needs to be predefined and linked to a specific controller. This must be either so that there is only one controller for each type of form like Registeration, and only one user defined metadataobject can be in use at either time. This controller's table parameter would be set to point to a database table created specifically for that metadataobject (or perhaps same table could be migrated according to metadata but then that table should be empty).
Or 2) every metadataobject should have it's own controller created which points to the object's data table.
In each approach routes needs to be created to point to the one controller of each type at use in each time.
One dilemma is how to manage revisions of those objects. Perhaps each object might have a running number postfix, and have their own controllers and data tables created (then it might be easier to migrate even populated tables [then user would be notified on front-end if his action would result in data loss, like for example with deleting a form data field]).
Another part of this project is to create an intelligent generator engine for assembling the HTML, CSS, and JS code according to a metadataobject. The generated code can be saved to reside in the same table as the objects themselves, and when used should be cached in the backend for rendering views.
Such metadataobject must itself have a clever format, so that it composes of predefined pieces of settings which will be converted to functionality by the form generator code.