Null Coalescing Operator not working in laravel eloquent - php

Controller
Tag::with('tagTranslation')->find(5)
Tag Model
function tagTranslation()
{
$locale = Session::get('locale'); // $locale = 'bn';
return $this->hasOne(TagTranslation::class, 'tag_id')
->where('locale', $locale)
->select('tag_name', 'locale')
?? // Or ternary ?:
$this->hasOne(TagTranslation::class, 'tag_id')
->where('locale', 'en')
->select('tag_name', 'locale');
}
If locale='bn', then it is showing the expected results like:
{
"id": 5,
"slug": "desktop",
"is_active": 1,
"created_at": "2022-02-25T17:59:18.000000Z",
"updated_at": "2022-03-02T13:42:49.000000Z",
"tag_translations": {
"tag_id": 5,
"tag_name": "ডেস্কটপ",
"local": "en"
}
}
And if I set locale='xyz' which does not exists in database, then I want to show default data base on locale='en' like this:
{
"id": 5,
"slug": "desktop",
"is_active": 1,
"created_at": "2022-02-25T17:59:18.000000Z",
"updated_at": "2022-03-02T13:42:49.000000Z",
"tag_translations": {
"tag_id": 5,
"tag_name": "Desktop",
"local": "en"
}
}
But it returns NULL value like this
{
"id": 5,
"slug": "desktop",
"is_active": 1,
"created_at": "2022-02-25T17:59:18.000000Z",
"updated_at": "2022-03-02T13:42:49.000000Z",
"tag_translations": null
}
How can I solve it ?

public function tagTranslation(){
$locale = 'bn';
// below you are drectly returning the value. If there is no item you can make count check or
return $this->hasOne(TagTranslation::class,'tag_id')
->where('locale',$locale)
->select('tag_name','locale') ?? //or ternary ?:
$this->hasOne(TagTranslation::class,'tag_id')
->where('locale','en')
->select('tag_name','locale')
}
You can do something like that (It will check $locale if it does not exits it return 'en'):
public function tagTranslation(){
$locale = 'bn';
return $this->hasOne(TagTranslation::class,'tag_id')
->where('locale',$locale ?? 'en')
->select('tag_name','locale');
}

Related

Laravel 8 Multiple Table Relationship

This is a long post, sorry in advance.
I have a couple of questions regarding the diagram below.
How do I create a relationship for these tables? (tried "belongsToMany" and "hasMany")
Should I use Eloquent or Query Builder to get desired result? (image is attached below for desired result)
Is "client_order_items" a pivot table?
How can you distinguish a pivot table? Is it because the table has multiple
foreign keys?
How can I access "images" table from "Manufacturer" model? Can "hasOneThrough / hasManyThrough" achieve this?
Is the desired result achievable purely using Eloquent or DB Query?
//sample:
Manufacturers::find(2)->client_order_items->cars->images->car_image
I tried considering "client_order_items" as a pivot table then making relationships using "belongsToMany" in "Manufacturer", "Car" and "ClientOrder" models.
// App\Model\Manufacturer.php
public function client_orders() {
return $this->belongsToMany(ClientOrder::class,
"client_order_items", "manufacturer_id", "client_order_id")
->withPivot('id', 'quantity', 'car_id');;
}
public function cars() {
return $this->belongsToMany(Car::class,
"client_order_items", "manufacturer_id", "car_id");
}
// App\Model\Car.php
public function client_orders() {
return $this->belongsToMany(ClientOrder::class,
"client_order_items", "car_id", "client_order_id");
}
public function manufacturers() {
return $this->belongsToMany(Manufacturer::class,
"client_order_items", "car_id", "manufacturer_id");
}
// App\Model\ClientOrder.php
public function cars() {
return $this->belongsToMany(Manufacturer::class,
"client_order_items", "client_order_id", "car_id");
}
public function manufacturers() {
return $this->belongsToMany(Manufacturer::class,
"client_order_items", "client_order_id", "manufacturer_id");
}
I also tried "hasMany" relationship:
// App\Model\Manufacturer.php
public function client_order_items() {
return $this->hasMany(ClientOrderItems::class);
}
// App\Model\Cars.php
public function client_order_items() {
return $this->hasMany(ClientOrderItems::class);
}
// App\Model\ClientOrder.php
public function client_order_items() {
return $this->hasMany(ClientOrderItems::class);
}
// App\Model\ClientOrderItems.php
public function car() {
return $this->belongsTo(Car::class);
}
public function manufacturer() {
return $this->belongsTo(Manufacturer::class);
}
public function client_order() {
return $this->belongsTo(ClientOrder::class);
}
My goal is to get the result if i did something like this:
// Manufacturer::find(2)->client_orders
// Desired Result:
[
{
"client_order_id": 88062,
"first_name": "Clark",
"last_name": "Kent",
"order_items": [
{
"client_order_item_id": 37394,
"quantity": 1,
"car_id": 68,
"image": "path_img1"
}
]
},
{
"client_order_id": 60978,
"first_name": "Bruce",
"last_name": "Wayne",
"order_items": [
{
"client_order_item_id": 79913,
"quantity": 1,
"car_id": 68,
"image": "path_img1"
},
{
"client_order_item_id": 84743,
"quantity": 1,
"car_id": 95,
"image": "path_img2"
}
]
}
]
But the result I'm currently getting (with "belongsToMany") is:
// Manufacturer::find(2)->client_orders
// Current Result:
[
{
"id": 88062,
"first_name": "Clark",
"last_name": "Kent",
"pivot": {
"manufacturer_id": 2,
"client_order_id": 88062,
"id": 37394,
"quantity": 1,
"car_id": 68
}
},
{
"id": 60978,
"first_name": "Bruce",
"last_name": "Wayne",
"pivot": {
"manufacturer_id": 2,
"client_order_id": 60978,
"id": 79913,
"quantity": 1,
"car_id": 68
}
},
{
"id": 60978,
"first_name": "Bruce",
"last_name": "Wayne",
"pivot": {
"manufacturer_id": 2,
"client_order_id": 60978,
"id": 84743,
"quantity": 1,
"car_id": 95
}
}
]
Sorry again for the long post.
Thank you in advance.
After experimenting and reading for couple of hours, I was able to get the result I want.
Making the relationships:
Manufacturer model has "belongsToMany" relationship with "ClientOrder"
// App\Model\Manufacturer
public function client_orders() {
return $this->belongsToMany(ClientOrder::class, 'client_order_items', 'manufacturer_id', 'client_order_id');
}
"Car" and "Image" model has "hasMany" relationship. This will give us access to "Image" model from "ClientOrderItems" model.
// App\Models\Car
public function image() {
return $this->belongsTo(Image::class);
}
// App\Models\Image
public function cars() {
return $this->hasMany(Car::class);
}
Creating Accessors to Models
In "ClientOrder" model, create an accessor for the "order_items" key. This will fetch rows from "OrderLineItems" that are related to the "manufacturer_id" and "client_order_id".
// App\Models\ClientOrder
protected $appends = ["order_items"];
public function getOrderItemsAttribute() {
$items = ClientOrderItems::where("manufacturer_id", '=', $this->pivot->manufacturer_id)
->where("client_order_id","=",$this->pivot->client_order_id)
->select(["id as client_order_item_id","car_id","quantity"])
->get();
return $items;
}
In "ClientOrderItems" pivot model, create an accessor for the "image".
// App\Models\ClientOrderItems
protected $appends = ["image"];
public function getImageAttribute() {
return Car::find($this->car_id)->image->car_image;
}
The result of the 2 codes above looks something like this:
[
{
"client_order_item_id": 79913,
"quantity": 1,
"car_id": 68,
"image": "path_img1"
},
{
"client_order_item_id": 84743,
"quantity": 1,
"car_id": 95,
"image": "path_img2"
}
]
More on Accessors & Mutators:
https://laravel.com/docs/8.x/eloquent-mutators#accessors-and-mutators
Retrieving Records
To get the "client orders" that are related to manufacturer_id, use:
/// App\Http\Controllers\ManufacturerController;
public function index() {
$client_order = Manufacturer::find($manufacturer_id)->client_orders->unique("id")->values();
}
Above code will only fetch unique rows from "client_orders" table. Appending the related "order_items" for each row with the help of accessors.
[
{
"client_order_id": 88062,
"first_name": "Clark",
"last_name": "Kent",
"order_items": [
{
"client_order_item_id": 37394,
"quantity": 1,
"car_id": 68,
"image": "path_img1"
}
]
},
{
"client_order_id": 60978,
"first_name": "Bruce",
"last_name": "Wayne",
"order_items": [
{
"client_order_item_id": 79913,
"quantity": 1,
"car_id": 68,
"image": "path_img1"
},
{
"client_order_item_id": 84743,
"quantity": 1,
"car_id": 95,
"image": "path_img2"
}
]
}
]

InvalidArgumentException: Malformed UTF-8 characters, possibly incorrectly encoded in file - Laraval

When returning Std class type object, the error is showing. I'm using PHP 7 and the Laravel 7.0
The error is returning from the setData function of JsonResponse.php (Illuminate\Http)
the setData function using DEFAULT_ENCODING_OPTIONS = 15. this is the reason for that issue
I have no way to fix this issue, but i tried to change JsonResponse setData method $this->encodingOptions into JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_IGNORE.
Now the error resolved. but I need another way to fix this.
public function setData($data = [])
{
$this->original = $data;
if ($data instanceof Jsonable) {
$this->data = $data->toJson($this->encodingOptions);
//$this->data = json_encode($data->jsonSerialize(), JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_IGNORE); // LINE NO: 01
} elseif ($data instanceof JsonSerializable) {
$this->data = json_encode($data->jsonSerialize(), $this->encodingOptions);
//$this->data = json_encode($data->jsonSerialize(), $this->encodingOptions); // LINE NO: 02
} elseif ($data instanceof Arrayable) {
$this->data = json_encode($data->toArray(), $this->encodingOptions);
} else {
$this->data = json_encode($data, $this->encodingOptions);
//$this->data = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_IGNORE); // LINE NO: 03
}
if (!$this->hasValidJson(json_last_error())) {
throw new InvalidArgumentException(json_last_error_msg());
}
return $this->update();
}
Uncomment line no 1,2,3 error resolved !
I need another way to fix this. because, after run, composer install that change dismissing...
this is part of my retrieving json
{ "cart": [
{
"id": "a9756db0d79a11ea96c7cf86f7c6e0ee",
"book_id": "81180660d2ed11eaa5299b806f9af290",
"user_customer_user_id": "437a2b60d23611ea942efb15df219288",
"status": "ACTIVE",
"book": {
"id": "81180660d2ed11eaa5299b806f9af290",
"user_admin_user_id": "9c80e8006d5b11e9bb9835ecbe2a229e",
"publisher_id": "7b0d3ac0d6ec11ea8cb15deb159804b0",
"printed_price": 319,
"purchase_link": "no",
"description": "no",
"pages": -1,
"rating_value": 0,
"file_type": "e-pub",
"revenue_split_type": "OP",
"book_authors": [
{
"user_id": "a6d99c206d5b11e9af1a4bbf4f149b08",
"reference_no": "XN87397509",
"description": null,
"search_tags": null,
"bank_name": null,
"account_number": null,
"user": {
"id": "a6d99c206d5b11e9af1a4bbf4f149b08",
"name": "Anton Dias",
"email": "Anton Dias#email.com",
"country_code": null,
"contact_number": null,
"status": "ACTIVE"
}
},
{
"user_id": "aa45c0206d5b11e9941ae50cf510f0f3",
"reference_no": "EB26705547",
"description": null,
"search_tags": null,
"bank_name": null,
"account_number": null,
"user": {
"id": "aa45c0206d5b11e9941ae50cf510f0f3",
"name": "K.G.Karunathilake",
"email": "K.G.Karunathilake#email.com",
"country_code": null,
"contact_number": null,
"status": "ACTIVE"
}
}
],
"book_images": [
{
"book_id": "81180660d2ed11eaa5299b806f9af290",
"type": "LIST",
"size": 0.67
},
{
"book_id": "81180660d2ed11eaa5299b806f9af290",
"type": "PROFILE",
"size": 0.67
}
],
"promotions": []
}
}
]
}

laravel eloquent ->with not working with one to one

now i have this method inside my Product model
public static function product_lines($request)
{
$keyword = Helper::clean_keyword($request['keyword']);
$data = Product::where
('number','like','%'.$keyword.'%')->
orWhere('name','like','%'.$keyword.'%')->
with('get_unit_relations')-> // this is one to many
limit(30)->
get();
return $data;
}
and this is the get_unit_relations
public function get_unit_relations()
{
return $this->hasMany('App\Models\Product_unit','product_id','id');
}
like this its working and its return data without any problem ..
{
"id": 1,
"number": "1",
"name": "test",
"foreign_name": null,
"get_unit_relations": [
{
"id": 3,
"unit_id": 2,
"product_id": 1,
"barcode": "455",
"smallest_unit_relation": 12,
"price": 12,
"cost": null,
"created_by": null,
"deleted_by": null,
"created_at": "2020-05-17T21:46:26.000000Z",
"updated_at": "2020-05-17T21:46:26.000000Z",
"deleted_at": null
}
]
}
but if i change the code like this ..
public static function product_lines($request)
{
$keyword = Helper::clean_keyword($request['keyword']);
$data = Product::where
('number','like','%'.$keyword.'%')->
orWhere('name','like','%'.$keyword.'%')->
with('get_smallest_unit_id')-> // this is one to one
limit(30)->
get();
return $data;
}
and this is the get_smallest_unit_id
public function get_smallest_unit_id()
{
return $this->hasOne('App\Models\Unit','id','smallest_unit_id');
}
im getting null in return like this ..
{
"id": 1,
"number": "1",
"name": "test",
"foreign_name": null,
"get_smallest_unit_id": null // it always return null in any one to one relaiton ..
}
how can i use ->with() method with one to one relation
thanks

Laravel sort object by Key

I have the following which I would like to order alphabetically by the Key i.e first for each array group would be "bname", followed by "created_at".
{
"leads": [
{
"lead_id": 1,
"zoho_lead": null,
"bname": "ABC Limited",
"tname": "ABC",
"source_id": 11,
"industry_id": 1,
"user_id": 1,
"created_at": "2017-09-06 15:54:21",
"updated_at": "2017-09-06 15:54:21",
"user": "Sean McCabe",
"source": "Unknown",
"industry": "None"
},
{
"lead_id": 2,
"zoho_lead": 51186111981,
"bname": "Business Name Limited",
"tname": "Trading Name",
"source_id": 11,
"industry_id": 1,
"user_id": 1,
"created_at": "2017-06-01 12:34:56",
"updated_at": null,
"user": "John Doe",
"source": "Unknown",
"industry": "None"
}
]
}
I'm trying to use ksort like so in the foreach loop:
class LeadController extends Controller
{
use Helpers;
public function index(Lead $leads)
{
$leads = $leads->all();
foreach($leads as $key => $lead){
$lead->user = User::where('id', $lead->user_id)->first()->name;
$lead->source = Source::where('id', $lead->source_id)->first()->name;
$lead->industry = Industry::where('id', $lead->industry_id)->first()->name;
$lead->ksort();
}
return $leads;
}
But I get the following error:
Call to undefined method Illuminate\\Database\\Query\\Builder::ksort()
How do I use this function, or is there a Laravel way of doing this, or a better way altogether?
Thanks.
Managed to get it to return with the Keys in alphabetical order, so below is the solution in-case someone else should require it:
public function index(Lead $leads)
{
$leadOut = Array();
$leads = $leads->all();
foreach($leads as $key => $lead){
$lead->user = User::where('id', $lead->user_id)->first()->name;
$lead->source = Source::where('id', $lead->source_id)->first()->name;
$lead->industry = Industry::where('id', $lead->industry_id)->first()->name;
//Convert to Array
$leadOrder = $lead->toArray();
//Sort as desired
ksort($leadOrder);
//Add to array
$leadOut[] = $leadOrder;
}
return $leadOut;
}
There is likely a cleaner way to do this, but it works for my instance, and perhaps additional answers may be posted that are better.
You could do something like:
return Lead::with('user', 'source', 'industry')->get()->map(function ($lead) {
$item = $lead->toArray();
$item['user'] = $lead->user->name;
$item['source'] = $lead->source->name;
$item['industry'] = $lead->industry->name;
ksort($item);
return $item;
});
This should be much more efficient as it will eager load the relationships rather than make 3 extra queries for each iteration.

Laravel 5.3 Eloquently Lazy/Eager load multiple models while selecting certain columns

Description:
Hello, in my scenario I'm trying to perform joins on 3 tables regarding a connections system I've built up. I'm able to use eloquent to connect these 3 tables together correctly and return the results no problem however, I'm trying to be more efficient in how it's done. I don't enjoy the fact that every query eloquent fires off defaults to a select * so I'd like to select specific columns instead. Here's where I'm currently at:
Connection Controller Code
Groups::with([
'list.userAccount.profile'
])->where('user_id_fk', $my->user_id)
->orderBy('group_num', 'ASC')
->take(3)
->get(['group_num','group_title','group_id']);
Group Settings Model
public function list() {
return $this->hasMany('App\UserConnections','group_id_fk');
}
User Connections Model
public function userAccount() {
return $this->hasOne('App\User','user_id_fk');
}
User Account Model
public function profile() {
return $this->hasOne('App\Profile','user_id_fk');
}
Now, If I make a call to it's assigned route to get users an example result is the following:
{
"conn_id_fk": 2,
"user_id_fk": 10,
"type": 0,
"group_id_fk": 4,
"status": 1,
"created_at": "2017-02-09 13:58:34",
"updated_at": "2017-02-09 13:58:34",
"user_account": {
"user_id": 10,
"email": "someemail#email.com",
"verified": 0,
"locked": 0,
"code": 0,
"request": "",
"created_at": "2017-02-09 13:20:51",
"updated_at": "2017-02-09 13:20:51",
"profile": {
"user_id_fk": 3,
"first_name": "Jillian",
"last_name": "Jacobs",
"avatar": "",
"age": 0,
"about_me": "",
"one_liner": "",
"inspire": "",
"created_at": "2017-02-09 13:18:32",
"updated_at": "2017-02-09 13:18:32"
}
}
Again My dilemma is that I don't want it to do select * to get all that data, it's unnecessary and will eventually slow down my server and cost me more money on I/O alone.
I've tried doing something like the following for example:
public function profileEnd() {
return $this->hasOne('App\Profile','user_id_fk');
}
public function profile() {
return $this->profileEnd->select('first_name','last_name','avatar');
}
///////////////////// AND I have tried///////////////////////////
public function profileEnd() {
return $this->hasOne('App\Profile','user_id_fk');
}
public function profile() {
return $this->profileEnd->select(['first_name','last_name','avatar'])->get(); <---Returns 500
}
which results in the following:
{
"conn_id_fk": 2,
"user_id_fk": 10,
"type": 0,
"group_id_fk": 4,
"status": 1,
"created_at": "2017-02-09 13:58:34",
"updated_at": "2017-02-09 13:58:34",
"user_account": {
"user_id": 10,
"email": "someemail#email.com",
"verified": 0,
"locked": 0,
"code": 0,
"request": "",
"created_at": "2017-02-09 13:20:51",
"updated_at": "2017-02-09 13:20:51",
"profile": null <------------------------------- Kills off the profile section
}
So What am I doing wrong here and how can I fix this? Any assistance is greatly appreciated.
Thanks in advance
Cheers!
Laravel needs the keys in order to match up the related collections of models. In your example, you did not select the key, so after the records are retrieved, Laravel has no idea which profiles are related to which user accounts. Add the key to the select and you should be good to go.
public function profileEnd() {
return $this->hasOne('App\Profile', 'user_id_fk');
}
public function profile() {
return $this->profileEnd->select('user_id_fk', 'first_name', 'last_name', 'avatar');
}

Categories