Laravel accessors appends to all results - php

I have a table field:
products
-title:New Product
-stock:9
-slug:new-product
And I want is get the additional data 'is_in_stock'. The result will be:
products
-title:New Product
-stock:9
-slug:new-product
-is_in_stock:true
for single data, I can modify the result on the controller itself, but I get stack when getting it to multiple data results. exp. Product::all();
I have read about Eloquent Mutators and Accessors. I have tried the logic on Model files. But I didn't know how to get the result.
This is my Product Model code:
class Product extends Model
{
protected $appends = ['is_in_stock'];
public function getIsInStockAttribute()
{
return $this->attributes['is_in_stock'] = false; // this will be boolean(true/false) result based on the current stock
}
}
Please help for any clue or reference for me to learn.
Thank you in advance :)

Finally I found the reference on http://laraveldaily.com/why-use-appends-with-accessors-in-eloquent/
So I change my Product Model Code to:
public function getIsInStockAttribute()
{
return ($this->stock > 0) ? true : false;
}

Related

Property [group] does not exist on this collection instance

I have retrieved an instance of a product item at blade, so when I do dd($product), I get this result:
And the Product Model is connected to GroupProduct Model like this:
public function groupproducts()
{
return $this->hasMany(GroupProduct::class,'product_id','id');
}
So at group_product table, the product has a custom group_id like this:
So when I do dd($product->groupproducts); I get this result properly:
Then at the Model GroupProduct, I've added these two relationships:
public function product()
{
return $this->belongsTo(Product::class,'product_id','id');
}
public function group()
{
return $this->belongsTo(Group::class,'group_id','id');
}
Now I need to access the name of the group that comes with the retrieved product_id, but when I try this:
dd($product->groupproducts->group->name);
I get this error:
Property [group] does not exist on this collection instance.
However the relationships seems to be applied and it should be showing the name of group...
So what's going wrong here? How can I fix this issue?
UPDATE #1:
Controller:
public function addAttribute(Product $product)
{
return view('admin.products.addAttribute', compact('product'));
}
$product->groupproducts is a collection(array) of products.
You can do:
dd($product->groupproducts->first()->group->name);
This will get first element from collection which is instance of Group class.
Your relation from your product model to the group products model is a one to many. This means, that even if there's only one result, you will be receiving a collection.
You can see in your own screenshot that the return value of $product->groupproducts is an instance of a collection with 1 item.
If you only ever want the first, you should change your relation to a one to one.
However, if you just want the first in this particular case, you should call for the first on the query instance, not on the collection instance.
So $product->groupproducts()->first()->group->name. This way you don't load x amounts, but instead only 1, from your database, which is much faster.
you have to use nested relationship:
1- you can use it in your Model via:
public function groupproducts()
{
return $this->hasMany(GroupProduct::class,'product_id','id')->with('group');;
}
2- you can use it in your controller:
Products::with('groupproducts.group')->get()
REFRENCE

Retrieving data by other field than id in has many relations

I have a has many relation between models: post and category in laravel application. I've defined these relations as:
public function category() {
return $this->belongsTo('artSite\category');
}
public function posts() {
return $this->hasMany('artSite\post');
}
Now I'm trying retrieve posts belonging to the particular category which are derived in http request:
Route::get('posts/categories/{categoryName}','postsViewController#showPostGivenCategory')
Below I show my controller function (it does work fine!):
public function showPostGivenCategory($categoryName) {
$category = category::where('category_name','=',$categoryName)-first();
$posts = category::find($category->id)->posts;
return view('pages.homePage')->with('categories',$categories)with('posts',$posts);
}
In this solution I'm creating 2 queries. Is any possible way to create 1 query to retrieve posts of particular category in has many relation?
Something like that doesn't work:
$posts = category::where('category_name','=',$categoryName)->posts;
Could someone help me with this problem? I would be very grateful, greetings.
we can get rid of the second line :
$posts = Category::find($category->id)->posts;
So You can say :
$posts = Category::where('category_name','=',$categoryName)->first()->posts;

Laravel eloquent model how to get data from relationship's table

I am developing a laravel application which has the following eloquent models
Product hasMany('App/Sku','products_id')
Sku belongTO('App/Product')
I have a controller 'ProductController' where the following code is available
public function index()
{
$products = Product::all();
foreach($products as $product){
$products_id = $product->products_id;
}
}
I am exposing RESTfull API which will allow my users to get all product details (including skus, shipping types etc..).
Suppose if I have an API GET : /products
The code which fetches all the product details will be some what the following
public function index()
{
$products = Product::all();
foreach($products as $product){
$products_id = $product->products_id;
$skus_data = Product::find($products_id)->skus;
}
// Now I have both the product details + skus which I can bundle into an array/json.
}
Now my question is , is this logic proper? In this case all the logics are in the controller since im using eloquent models I have a model for each table and the relationships are defined in it. Is there a way I can get all the details of a product/associated model (Products details (in table 1)+ Sku details (in table 2)) rather than using the below
foreach($products as $product){
$products_id = $product->products_id;
$skus_data = Product::find($products_id)->skus;
}
I am pretty new to laravel development and eloquent models. I will be using repository pattern for the development and in that case where does the aboe logic (Product+Sku combining) resides.
Please help out.
Yes, you can get the details of the products and skus without making one additional query per product using eager loading
( this is referred as the typical N+1 query problem where N is the number of the products )
Suppose the relation between your Product and Sku models model is:
Product
public function skus()
{
return hasMany('App/Sku','products_id');
}
To fetch the products data along with the sku data you can use the with method. In your controller:
Controller
$products = Product::with('skus')->get();
Then, in your views, you can get the info this way:
View
foreach ($products as $product)
{
//$product->skus is a collection of Sku models
dd( $product->skus );
}
For the repository question: if you want to use a repository you can place the eloquent-access part of your code inside the repository. So, for example you could have this method inside the repository:
ProductRepository
public function getProductsData()
{
//access eloquent from the repository
return Product::with('skus')->get();
}
then you can use your repository in your controller:
Controller
//inject the repository in the controller
public function __construct( ProductRepository $productRepo )
{
$this->productRepo = $productRepo;
}
//use the injected repository to get the data
public function index()
{
$products = this->productRepo->getProductsData();
}
If the repository pattern is used, do it like this.
public function index() {
$data = $this->passportRepository->with('user')->findWhere(['id'=>1]);
}
If I understand your question correctly, you can use eager loading.
public function index()
{
$products = Product::with('skus')->get();
}
This will give you an array of products that have a skus array in each product object.
You can try this:
public function index()
{
$products = Product::all();
foreach($products->skus as $product)
{
return $product;
}
}
This will give you the exact result in the object form.

Laravel 4 Eloquent/Model Relationships

I am setting up several Models an want to know the correct approach to table structure and Model relationships.
Let's assume we have a shop containing products, each with properties size and color.
Table products
id
size_id
color_id
price
Table sizes
id
name
Table colors
id
name
Models
class Product extends Eloquent {
public function size() {
return $this->hasOne('Size', 'id');
}
public function color() {
return $this->hasOne('Color', 'id');
}
}
class Size extends Eloquent {
public function products() {
return $this->belongsTo('Product', 'size_id');
}
}
class Color extends Eloquent {
public function products() {
return $this->belongsTo('Product', 'color_id');
}
}
This way I can easily echo the color/size of a product using {{ Product->size['name'] }}. Also, I want to pass Eloquent the size's foreign key size.id like Product::where('size_id', '5') rather than its name size.name.
Problem: Doing $products = Product::has('size', '=', '5')->get() does not give me any results, yet doing $products = Product::where('size_id', '5')->get() does.
I am pretty confused, what went wrong?
I think that the problem is that your ::has() method is looking for products with exactly 5 different sizes on each specific product, which would assume that you would be using $this->hasMany('Size') in your Product model. Where as the ::where() method is returning results where the size of the product is 5.
In the documentation they use an example of comments. A post will have a list of comments. You can find posts that have at least one comment (ie. Post::has('comments')->get()) or you can find posts that have more than 3 comments (ie. Post::has('comments', '>=', '3')->get()).
http://laravel.com/docs/eloquent#querying-relations

Laravel Eloquent select from relationship

I've been trying to get the hang of Laravel. I'm using Laravel 4.
Right now I have two tables, a 'Products' table and a 'Images' table.
A product can have many images and an image belongs to a product.
So I have two models:
class Product extends Eloquent {
public function images()
{
return $this->hasMany('Image');
}
}
class Image extends Eloquent {
protected $table = 'product_images';
public function product()
{
return $this->belongsTo('Product');
}
}
Now I'm building the 'index' page of a resource, so I do Product::all() in the controller and send this to the view.
In the view I do a foreach and loop over all products. But now I want to get an image to show with the product. But I can't seem to figure out how to get, for instance, the first image.
When I do $product->images I get an object of all images related to the product.
When I do $product->images->url I get an error (Undefined property 'url')
I've tried $product->images->first()->url this also gives an error (Trying to get property of non-object)
What am I doing wrong?
Have you tried eager-loading?
foreach (Product::with('images')->get() as $product)
{
echo $product->images->first()->url;
}
The images property is an array-like property that you can loop through.
foreach ($product->images as $image) {
echo $image->url;
}
Alternatively, if you only wanted the first, you can access the index.
$product->images[0]->url;
You can try using the following PHP function.
$first_image = array_shift($product->images);
Then, $first_image will be one image object, and accessing the URL of the image should be easy: $first_image->ulr
Note: Haven't tested it, but should work. Let us know.

Categories