Laravel 7 Single row echo belongsToMany relationship - php

I'm trying to display the value of brand_id column from brands table. Here's so far what I've done:
Car model
use App\Brand;
class Car extends Model
{
public function brands(){
return $this->belongsToMany(Brand::class);
}
}
Brand model
use App\Car;
class Brand extends Model
{
protected $fillable = [
'brand_name'
];
public function cars(){
return $this->hasMany(Car::class);
}
}
ShowroomController
use App\Car;
class ShowroomController extends Controller
{
public function details($name){
$data = Car::where('car_name' , '=', $name)->first();
if ($data == null){
return redirect(route('index'));
}else{
return view('showroom')->with('detail', $data);
}
}
}
showroom view
#if (isset($detail))
{{ $detail }}
{{ $detail->brands->brand_name }} //this doesn't work
#endif
Database
Brands table:
+----+------------+
| id | brand_name |
+----+------------+
| 1 | Brand1 |
| 2 | Brand2 |
+----+------------+
Cars table:
+----+----------+----------+
| id | car_name | brand_id |
+----+----------+----------+
| 1 | Car | 1 |
+----+----------+----------+
I got lost on this point. Is this the right way to do the belongstomany and hasmany relationship? Thanks.

Change
return $this->belongsToMany(Brand::class);
to
return $this->belongsTo(Brand::class); on the Car model
Also rename name function to brand. because car have only single brand
After it you can do $detail->brand->brand_name

Hi I know it seems simple, thanks to #Imboom I got a hint to fix my problem. I made some changes on Car model:
return $this->belongsToMany(Brand::class); to return $this->belongsTo(Brand::class)
rename name function to brand
Lastly, I just added 'brand_id' to specify the column in cars table.
public function brand(){
return $this->belongsTo(Brand::class,'brand_id');
}
In ShowroomController, I changed my return statement detail to car. See the code below:
public function details($name){
$data = Car::where('car_name' , '=', $name)->first();
if ($data == null){
return redirect(route('index'));
}else{
return view('showroom')->with('car', $data);
}
}
Then in showroom view, $car->brand->brand_name .
#if (isset($car))
{{ $car->car_name }}
{{ $car->brand->brand_name }} // Output is Brand1
#endif
Thank you!

Related

Laravel Display table product if not exist on quantity table

In PHP-MySQL I can create this query...
$sql = "SELECT * FROM product";
$result = $conn->query($,con, $sql);
while($row =mysql_fetch_array($result)){
$sqlquantity = "SELECT * FROM quantity where branchid='4' and productid='$row['productid']'";
$resultquantity = $conn->query($,con, $sqlquantity);
if (mysqli_num_rows($resultquantity) == 0) {
echo $row['productname']. "not available in branch"
}
else {
echo $row['productname']. "available in branch"
}
}
But how can I do this using Laravel?
I have 3 tables
+-----------------+ +-----------------+ +----------------+
| product table | | quantity table | | branch table |
+-----------------+ +-----------------+ +----------------+
| id | | productid | | id |
| productname | | branchid | | branchname |
+-----------------+ | quantity | +----------------+
+-----------------+
My problem is that I am trying to create a model, view and controller where I can display all the products that is not available yet on each branch base on the quantity table. Can anyone help?
Product model
public function quantity()
{
return $this->hasMany('App\Quantity', 'productid', 'id');
}
Quantity model
public function product()
{
return $this->belongsTo('App\Product', 'productid', 'id');
}
Branch Model
public function products()
{
return $this->hasMany('App\Quantity', 'branchid', 'id');
}
What I am trying to create is that if I view the branch I can add those product quantity table if the product does not exist.
You could also try this one...
Please check many-to-many relationship at the Official Docs for better explanation. .
You don't need to create a Quantity model because it serves as a pivot or joining table (not an entity) between Product and Branch model. Since you have custom pivot table name, which is quantity you need to pass it to the 2nd argument or else Eloquent will automatically create a table name for you which is branch_product (alphabetical). 3rd and 4th arguments are foreign keys of current model and the joining model respectively.
Product model
public function branches()
{
return $this->belongsToMany('App\Branch', 'quantity', 'productid', 'branchid')
->withPivot('quantity'); //additional pivot column
}
Branch model
public function products()
{
return $this->belongsToMany('App\Product', 'quantity', 'branchid', 'productid')
->withPivot('quantity');
}
Product Controller
$products = Product::all();
if($products){
$x = 0;
foreach ($products as $prod) {
$products[$x] = $prod->branches()
// ->wherePivot('productid', '=', $prod->id)
->wherePivot('branchid', '=', 4)
->wherePivot('quantity', '=', 0)
->get();
$x++;
}
}
return response(['products' => $products],200);
//get all the products in branch 4 with quantity = 0
Then you could do the conditional if to determine if it is available or not.
You could use whereHas() method like :
Product::whereHas( 'Quantity', function($sQuery){
$sQuery->where('branchid', 4);
})->get();

Laravel 5.4 | Fetching data from Pivot Table

I have 4 tables in my database:
Table 1: Category
---|------
id | name
---|------
1 | Cars
In 'Category' model class I have defined the following relationship:
class Category {
public function fields() {
return $this->belongsToMany('App\Field');
}
}
Table 2: Field
id | name
---|-------
1 | Make
In 'Field' model class I have defined the following relationship:
class Field {
public function categories() {
return $this->belongsToMany('App\Category');
}
}
Table 3: Field_Options
field_id | value
---------|-------
1 | Audi
1 | BMW
In 'FieldOption' model class I have defined the following relationship:
class FieldOption extends Model
{
public function field() {
return $this->belongsTo('App\Field');
}
}
Table 4: Category_Field
category_id | field_id
------------|-------
1 | 1
Now I need to fetch all the fields and field_options for category_id=1. How can I achieve this using Laravel?
Thanks!
First define relationship between Field and FieldOptions
public function options() {
return $this->hasMany('App\FieldOption');
}
Then you can eager load all relationships like this
$category = Category::with('fields.options')->find(1);
//Get category 1, with all fields and their respectif fieldOptions

Eloquent :: One to One where active in both tables, but specific roles

I am trying to only return specific profiles for users that have roles (role_id 5 & 6) that are active in both tables. It would also be nice if I can order by first_name ASC as well (user table).
user
+---------+---------+-------------+-----------+
| user_id | role_id | first_name | is_active |
+---------+---------+-------------+-----------+
| 1 | 5 | Dan | 1 |
| 2 | 6 | Bob | 0 |
+---------+---------+-------------+-----------+
profile
+------------+---------+------+-------------+-----------+
| profile_id | user_id | bio | avatar | is_active |
+------------+---------+------+-------------+-----------+
| 1 | 1 | text | example.jpg | 1 |
| 2 | 2 | text | noimage.gif | 1 |
+------------+---------+------+-------------+-----------+
My user model
namespace App\Model;
use Illuminate\Database\Eloquent\Model;
class User extends Model{
protected $table = 'user';
protected $primaryKey = 'user_id';
protected $fillable = [
'role_id',
'first_name',
'is_active'
];
public function scopeActive(){
return $this->where('is_active', '=', 1);
}
public function role(){
return $this->belongsTo('App\Model\Role');
}
public function profile(){
return $this->hasOne('App\Model\Profile');
}
}
My profile model
namespace App\Model;
use Illuminate\Database\Eloquent\Model;
class Profile extends Model{
protected $table = 'profile';
protected $primaryKey = 'profile_id';
protected $fillable = [
'user_id',
'avatar',
'is_active'
];
public function scopeActive(){
return $this->where('is_active', '=', 1);
}
public function user(){
return $this->belongsTo('App\Model\User');
}
}
My UserController
namespace App\Controller\User;
use App\Model\User;
use App\Model\Profile;
use App\Controller\Controller;
final class UserController extends Controller{
public function listExpert($request, $response){
$user = User::active()->whereIn('role_id', array(5, 6))->orderBy('first_name', 'asc')->get();
$profile = $user->profile ?: new Profile;
$data['experts'] = $profile->active()->get();
$this->view->render($response, '/Frontend/experts.twig', $data);
return $response;
}
}
So I am getting all of my records just fine. I am getting all the profiles but not the ones that belong only to role_id's 5 & 6 in the user table. Also if I set is_active to 0 in the user table, they still show. But if I set is_active in the profile table they do not. I need them to not show whether the User or Profile table has those rows set to inactive. Because you can have a user but they may not want an active profile.
Okay I got it!
$data['experts'] = User::whereIn('role_id', array(5, 6))
->where('is_active', '1')
->whereHas('profile', function($q){
$q->where('is_active', '1');
})
->with('profile')
->orderBy('first_name', 'ASC')
->get();
In case you want to know how to return this in twig....
{% if experts|length > 0 %}
<ul>
{% for item in experts %}
<li>First Name: {{ item.first_name }}, Bio: {{ item.profile.bio }}, Avatar: {{ item.profile.avatar }}</li>
{% endfor %}
</ul>
{% else %}
<p>No records found.</p>
{% endif %}

Laravel - model modifications

I need to refactor project and I have problem. Below is old, working model, where 'active' column is in "people" table. I need to move 'active' column into "people_translations" table.
Do you have any Idea to modify scopeActive method?
Thanks a lot!
Old working model:
class BaseModel extends Eloquent
{
public function scopeActive($query)
{
return $query->where($this->table . '.active', '=', 1);
}
}
class People extends BaseModel
{
protected $table = 'peoples';
protected $translationModel = 'PeopleTranslation';
}
class PeopleTranslation extends Eloquent
{
public $timestamps = false;
protected $table = 'peoples_translations';
}
Old tables structure:
Table: peoples
id | type | date | active
-------------------------
7 | .... | ... | 1
Table: peoples_translations
id | people_id | language_id | name
-----------------------------------
1 | 7 | 1 | Ann
Old query:
$peoples = \People::active()->get();
New tables structure:
Table: peoples
id | type | date
----------------
7 | .... | ...
Table: peoples_translations
id | people_id | language_id | name | active
--------------------------------------------
1 | 7 | 1 | Ann | 1
Create a relation for translations inside People Model
public function translations()
{
return $this->hasMany('PeopleTranslation', 'people_id');
}
Create active scope in People model
public function scopeActive($query)
{
return $query->whereHas('translations', function($query) {
$query->where('active', 1);
});
}
It will make subquery for this table and as a result it will get where (count of translations with active = 1) > 0.
If you have one-to-one relation - look for hasOne relation method instead of hasMany.

Laravel: how to get average on nested hasMany relationships (hasManyThrough)

I have three tables:
products: id|name|description|slug|category_id|...
reviews: id|product_id|review_text|name|email|...
review_rows id|review_id|criteria|rating
the review table stores the review text, writer of the review and has a foreign product_id key. The review_rows table stores the ratings for different criteria like:
----------------------------------------
| id | criteria | rating | review_id |
----------------------------------------
| 1 | price | 9 | 12 |
----------------------------------------
| 2 | service | 8 | 12 |
----------------------------------------
| 3 | price | 6 | 54 |
----------------------------------------
| 4 | service | 10 | 54 |
----------------------------------------
review rows are linked to the review table with the review_id foreign key. I've set up my model relationships like this:
Product -> hasMany -> Review
Review -> belongsTo -> Product
Review -> hasMany -> ReviewRow
ReviewRow -> belongsTo -> Review
Now I would like to display the average rating for a product on my category and product pages. How can I achieve this?
I need to sum and average all the reviewRows per review and then sum and average all of those for each review to end up with the overall rating for that product. Is this possible via Eloquent or do I need a different solution or a different database design/structure?
Thanks in advance!
You need something like this http://softonsofa.com/tweaking-eloquent-relations-how-to-get-hasmany-relation-count-efficiently/ only slightly adjusted to match your needs:
public function reviewRows()
{
return $this->hasManyThrough('ReviewRow', 'Review');
}
public function avgRating()
{
return $this->reviewRows()
->selectRaw('avg(rating) as aggregate, product_id')
->groupBy('product_id');
}
public function getAvgRatingAttribute()
{
if ( ! array_key_exists('avgRating', $this->relations)) {
$this->load('avgRating');
}
$relation = $this->getRelation('avgRating')->first();
return ($relation) ? $relation->aggregate : null;
}
Then as simple as this:
// eager loading
$products = Product::with('avgRating')->get();
$products->first()->avgRating; // '82.200' | null
// lazy loading via dynamic property
$product = Product::first()
$product->avgRating; // '82.200' | null
Maybe you can try with Eloquent relationships and a little help from php function array_reduce
//model/Reviews.php
public function sum() {
return array_reduce($this->hasMany('ReviewRows')->lists('rating'), "sumItems");
}
public function sumItems ($carry, $item) {
$carry += $item;
return $carry;
}
Or with Eloquent RAW querys like:
//model/Reviews.php
public function avg() {
$result = $this->hasMany('ReviewRows')
->select(DB::raw('avg(rating) average'))
->first();
return $result->average;
}
Simple and easy solution. Add this into product model
protected $appends = ["avg_rating"];
public function reviewRows()
{
return $this->hasManyThrough('App\ReviewRow','App\Review','product_id','review_id');
}
public function getAvgRatingAttribute()
{
return round($this->reviewRows->average('rating'),2);
}
see https://github.com/faustbrian/laravel-commentable
public function comments(): MorphMany
{
return $this->morphMany($this->commentableModel(), 'commentable');
}
public function avgRating()
{
return $this->comments()->avg("rating");
}
$products = \App\Models\Products::with(
[
"comments" => function ($q) {
$q->with(["children" => function ($qch) {
$qch->take(2);
}
])->withCount("children")->where("parent_id", '=', null);
},]
)->take(5)->get();
foreach ($products as &$product) {
$product["avgRating"] = $product->avgRating();
}
dd($products);
use withAvg() as mentioned in laravel official documentation here

Categories