Laravel. Keep eloquent relationship after join - php

suddenly i faced problem which I can't solve by myself. I wrote query which returns me some data:
$users = User::whereIn('users.status', array(2,3))
->leftJoin('firsts', 'firsts.user_id', '=', 'users.id')
->leftJoin('seconds', 'seconds.user_id', '=', 'users.id')
->leftJoin('thirds', 'thirds.user_id', '=', 'users.id')
->leftJoin('offers', 'offers.user_id', '=', 'users.id')
->where(function($query){
$query->where('users.status', '=', '2');
$query->where('firsts.status', '=', 'approved');
$query->where('seconds.status', '=', 'approved');
$query->where('offers.user_id', '=', 'approved');
})
->orWhere(function($query){
$query->where('users.status', '=', '3');
$query->where('users.stripe_active', '=', '1');
$query->where('firsts.status', '=', 'approved');
$query->where('seconds.status', '=', 'approved');
$query->where('thirds.status', '=', 'approved');
$query->where('offers.status', '=', 'approved');
})
->get();
I were expecting simple object as a return from query. At the moment I have one proper record in my users table, but this query returns me that object 6 times, and I can't understand why. Results I'm expect:
Collection {#353 ▼
#items: array:1 [▼
0 => User {#354 ▼
#dates: array:2 [▶]
#table: "users"
#fillable: array:3 [▶]
#hidden: array:2 [▶]
+admin: "eval.butkus#gmail.com"
+admin2: "Evaldas"
#connection: null
#primaryKey: "id"
#perPage: 15
+incrementing: true
+timestamps: true
#attributes: array:31 [▼
"id" => 1
"username" => "evaldas"
"password" => "$2y$10$ARTGHBTqIl/X6UsblylF5ugMPFlASwDKUEVbS5Nh3TjtycGG/NU7."
"email" => "eval.butkus#gmail.com"
"remember_token" => "A42ezMckkvjCLrpj4jxyHf2iSQWp3iAGfzGoTqMygDimFSzXNx6FW42qCOhP"
"name" => ""
"subscribe" => 0
"profile_picture" => "VNlQxOlCbXkCGEQ6ZdFS1pbK2tixhsmmhQPhLNLMBRKqDzXegWbqQiJOsplMADKg.jpg"
"about_you" => ""
"writing_service" => 0
"f_card" => 0
"logo" => ""
"website" => ""
"youtube" => ""
"status" => 3
"code" => ""
"active" => 1
"address" => ""
"phone" => ""
"news" => 0
"terms" => 1
"radius" => 0
"created_at" => "2015-07-13 10:26:47"
"updated_at" => "2015-07-15 10:25:30"
"stripe_active" => 1
"stripe_id" => "cus_6c0xE8OxR7fdXJ"
"stripe_subscription" => "sub_6c0x4RzEoBplCb"
"stripe_plan" => "small"
"last_four" => "4242"
"trial_ends_at" => null
"subscription_ends_at" => null
]
#original: array:31 [▶]
#relations: []
#visible: []
#appends: []
#guarded: array:1 [▶]
#casts: []
#touches: []
#observables: []
#with: []
#morphClass: null
+exists: true
}
]
}
Results i get:
Collection {#364 ▼
#items: array:6 [▼
0 => User {#365 ▼
#dates: array:2 [▶]
#table: "users"
#fillable: array:3 [▶]
#hidden: array:2 [▶]
+admin: "eval.butkus#gmail.com"
+admin2: "Evaldas"
#connection: null
#primaryKey: "id"
#perPage: 15
+incrementing: true
+timestamps: true
#attributes: array:53 [▼
"id" => 2
"username" => "evaldas"
"password" => "$2y$10$ARTGHBTqIl/X6UsblylF5ugMPFlASwDKUEVbS5Nh3TjtycGG/NU7."
"email" => "sadsad"
"remember_token" => "A42ezMckkvjCLrpj4jxyHf2iSQWp3iAGfzGoTqMygDimFSzXNx6FW42qCOhP"
"name" => "sadsa"
"subscribe" => 0
"profile_picture" => "VNlQxOlCbXkCGEQ6ZdFS1pbK2tixhsmmhQPhLNLMBRKqDzXegWbqQiJOsplMADKg.jpg"
"about_you" => ""
"writing_service" => 0
"f_card" => 0
"logo" => ""
"website" => "das"
"youtube" => ""
"status" => "approved"
"code" => ""
"active" => 1
"address" => "asfas"
"phone" => "dasd"
"news" => 0
"terms" => 1
"radius" => 0
"created_at" => "2015-07-15 07:31:37"
"updated_at" => "2015-07-15 07:44:31"
"stripe_active" => 1
"stripe_id" => "cus_6c0xE8OxR7fdXJ"
"stripe_subscription" => "sub_6c0x4RzEoBplCb"
"stripe_plan" => "small"
"last_four" => "4242"
"trial_ends_at" => null
"subscription_ends_at" => null
"country" => "Highland"
"mobile" => "asd"
"descripsion" => "Ddescription"
"landline" => "asdas"
"company_name" => "das"
"facebook" => "dsad"
"twitter" => "sadsa"
"linkedln" => "dsadasd"
"company_number" => "sad"
"google" => "sadasd"
"vat" => "asdsad"
"experience" => ""
"privacy" => 0
"user_id" => 1
"post_code" => "AB115QN"
"latitude" => "57.14270109"
"longitude" => "-2.093014619"
"identify" => "grEa6JEaj6P0I7Zc3ZCq5CADojzApSJZ.jpg"
"bill" => "N8WKjRlSttsHNt1crrNdwxG7uqWEg5GB.jpg"
"comment" => "asdsad"
"image" => "7dmURWxbzO4pinqbek0yzdIKqEyZrjOD.jpg"
"title" => "new offer"
]
#original: array:53 [▶]
#relations: []
#visible: []
#appends: []
#guarded: array:1 [▶]
#casts: []
#touches: []
#observables: []
#with: []
#morphClass: null
+exists: true
}
1 => User {#366 ▶}
2 => User {#367 ▶}
3 => User {#368 ▶}
4 => User {#369 ▶}
5 => User {#370 ▶}
]
}
Could any explain how did i lose all the relationships between tables and how can I avoid it? Since structure of result changed, I can't use loops, relationships and etc. Thanks!.

If im reading this right, you just want to
(delete join onto orders)...->groupBy('users.id')->get();
That will return you one user matching the conditions.
You can achieve this with 2 queries, first group by on users (don't join orders), then do a second query for the orders. What else to join would depend on which tables you are using to filter users by vs which tables you are using to add data to orders with.
Put data to add to orders in the second query, stuff your using to filter users in the first. You could also try a subquery but that isn't supported well in eloquent.
Also your whereIn is completely pointless, as you are already testing for where user status is 2 or 3.
Edited for a little more clarity,I was a little hasty. Originally thought that the poster wanted one row back - which wasn't the case.

Related

Podio fields property is empty in Item object

This has just started happening with no changes to our implementation.
When I query (it seems any item) the API is no longer returning data in the fields property.
PodioItem {#354 ▼
-__attributes: array:32 [▼
"item_id" => 1234567890
"external_id" => null
"title" => "INV-1234567890-Deposit"
"link" => "[redacted]"
"rights" => array:8 [▶]
"created_on" => "2019-09-10 22:28:37"
"app_item_id_formatted" => "1310"
"app_item_id" => 1310
"created_by" => PodioByLine {#362 ▶}
"created_via" => PodioVia {#363 ▶}
"initial_revision" => PodioItemRevision {#364 ▶}
"current_revision" => PodioItemRevision {#367 ▶}
"fields" => PodioVia {#370 ▼
-__attributes: []
-__belongs_to: array:2 [▶]
-__properties: array:5 [▶]
-__relationships: []
#__id_column: null
}
"like_count" => null
"is_liked" => false
"ratings" => array:1 [▶]
"user_ratings" => array:1 [▶]
"last_event_on" => "2019-09-10 23:17:06"
"participants" => []
"tags" => []
"refs" => []
"linked_account_id" => null
"subscribed" => false
"invite" => []
"app" => PodioApp {#371 ▶}
"ref" => PodioReference {#372 ▶}
"reminder" => PodioReminder {#373 ▶}
"recurrence" => PodioRecurrence {#374 ▶}
"linked_account_data" => PodioLinkedAccountData {#375 ▶}
"comments" => PodioLinkedAccountData {#376 ▶}
"revisions" => PodioVia {#392 ▶}
"files" => PodioVia {#401 ▶}
]
-__belongs_to: null
-__properties: array:38 [▶]
-__relationships: array:15 [▶]
#__id_column: "item_id"
}
You can see __attributes are empty for fields. Again, for every item I have tested and for several apps, it is the same.
As I said nothing has changed in our implementation - last week it was working fine.
Any ideas?

How to get Laravel set table to 'stick' for collection

We have a Laravel model and sometimes we want to get data from it's default table, but other times from a different table. It all works from a data perspective, but when the collection is returned from the alternate table, the 'table' attribute still references the original table (even though the data is from the other one as expected).
If we dd() getTable(), it is correct:
$model = COUNTRY;
$table = "countires";
$org_id = 1;
$org_collection = $model->setTable('merge_' . $table)->get()
->where('organization_id', $org_id)->keyBy('id');
dd($model->getTable()); // *** THIS SHOWS THE 2nd TABLE AS EXPECTED
dd() ouput:
"merge_countries"
But with the exact same code, if we dd() the result the table attribute in the collection is still the 1st one ('orgs') and not 'merge_orgs' as expected even though the data is correctly coming from the 'merge_orgs' table:
$model = COUNTRY;
$table = "countires";
$org_id = 1;
$org_collection = $model->setTable('merge_' . $table)->get()
->where('organization_id', $org_id)->keyBy('id');
dd($org_collection); // *** THIS SHOWS THE 1st TABLE EVEN THOUGH THE getTable() ABOVE DOES NOT
dd() output:
Collection {#297
#items: array:1 [
3 => Country {#295
#connection: "common"
#table: "countries" <---- WHY IS THIS NOT 'merge_countries'???
#hidden: array:2 [
0 => "created_at"
1 => "updated_at"
]
#appends: array:1 [
0 => "level"
]
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#attributes: array:7 [
"id" => 3
"organization_id" => 1
"region_id" => 2
"name" => "Southpark"
"active" => 1
"created_at" => "2018-06-21 14:05:36"
"updated_at" => "2018-06-21 13:25:27"
]
#original: array:7 [
"id" => 3
"organization_id" => 1
"region_id" => 2
"name" => "Southpark"
"active" => 1
"created_at" => "2018-06-21 14:05:36"
"updated_at" => "2018-06-21 13:25:27"
]
#changes: []
#casts: []
#dates: []
#dateFormat: null
#dispatchesEvents: []
#observables: []
#relations: []
#touches: []
+timestamps: true
#visible: []
#fillable: []
#guarded: array:1 [
0 => "*"
]
}
]
}
Any idea how to address this? We're not sure what else to even try at this point. Laravel if 5.6 if that matters.
OK, there is a fix reference and more detail at github.com/laravel/framework/issues/26058. In the interim you can also override the model newInstance method in the trait to work around it:
public function newInstance($attributes = [], $exists = false)
{
// Overridden in order to allow for late table binding.
$model = parent::newInstance($attributes, $exists);
$model->setTable($this->table);
return $model;
}

Laravel 5.6 Many to Many relationship throwing errors during display

**** UPDATE *******************************************************
I'm not sure why, but moving everything into the controllers index() method rather than having it in the show() method solved the problem. Don't know why it works, but it does.
Original Question:
Cant figure out what is wrong here, i have followed the docs, tried variations, etc... still no luck making this work correctly.
Model A: (Slide)
public function carousels() {
return $this->belongsToMany(Carousel::class)->withTimestamp()
}
Model B: (Carousel)
public function slides() {
return $this->belongsToMany(Slide::class)->withTimestamp()
}
Pivot Table
--------------------------------------------------
|carousel_id | slide_id | created_at | updated_at|
--------------------------------------------------
From Controller:
public function show(Carosuel $carousels) {
$carousels = $carousel->with('slides)->get();
return view('myView', compact(['carousels']));
}
In the following dump, the "slides" are not in the attributes object of the collection; however, they are in the relations object. Im not sure if this is normal behavior or if the slides array should be in the attributes object. If the latter is the case, then how does one go about making that happen?
$caousels dump:
Collection {#1320 ▼
#items: array:20 [▼
0 => Carousel {#798 ▼
#fillable: array:4 [▶]
#connection: "mysql"
#table: null
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#attributes: array:7 [▼
"id" => 1
"name" => "Prof. Andre Gerlach"
"category" => "Dr."
"active" => 0
"deleted_at" => null
"created_at" => "2018-04-07 21:10:52"
"updated_at" => "2018-04-07 21:10:52"
]
#original: array:7 [▶]
#changes: []
#casts: []
#dates: []
#dateFormat: null
#appends: []
#dispatchesEvents: []
#observables: []
#relations: array:1 [▼
"slides" => Collection {#1300 ▼
#items: array:5 [▼
0 => Slide {#1023 ▶}
1 => Slide {#1024 ▶}
2 => Slide {#1025 ▶}
3 => Slide {#1026 ▶}
4 => Slide {#1027 ▶}
]
}
]
#touches: []
+timestamps: true
#hidden: []
#visible: []
#guarded: array:1 [▶]
}
1 => Carousel {#799 ▶}
2 => Carousel {#800 ▶}
In the View:
foreach($carousels as $carousel){
echo $carousel->name;
foreach($carousel->slides as $slide){
echo $slide->tag;
}
}
This throws the E_ERROR Invalid argument supplied for foreach() in view
If, however, I cast this to an array, it works. Problem is that i also need to paginate the results. Once i do, the slides array is again inaccessible.
public function show(Carosuel $carousels) {
// This works - slides are available to me in the view
$carousels = $carousel->with('slides)->get()->toarray();
// This DOESN'T work - slides are not available to me in the view
$carousels = $carousel->with('slides)->paginate(6)->toarray();
return view('myView', compact(['carousels']));
}
dump as array:
array:12 [▼
"current_page" => 1
"data" => array:6 [▼
0 => array:8 [▼
"id" => 1
"name" => "Prof. Andre Gerlach"
"category" => "Dr."
"active" => 0
"deleted_at" => null
"created_at" => "Apr 07 2018"
"updated_at" => "2018-04-07 21:10:52"
"slides" => array:5 [▼
0 => array:11 [▶]
1 => array:11 [▶]
2 => array:11 [▶]
3 => array:11 [▶]
4 => array:11 [▶]
]
]
1 => array:8 [▶]
2 => array:8 [▶]
3 => array:8 [▶]
4 => array:8 [▶]
5 => array:8 [▶]
]
"first_page_url" => "//localhost:3000/admin/carousel/show?page=1"
"from" => 1
"last_page" => 4
"last_page_url" => "//localhost:3000/admin/carousel/show?page=4"
"next_page_url" => "//localhost:3000/admin/carousel/show?page=2"
"path" => "//localhost:3000/admin/carousel/show"
"per_page" => 6
"prev_page_url" => null
"to" => 6
"total" => 20
The problem here is that, in the view, the slides key is no longer accessible. Throws following error (only if I use ->paginate()).
E_ERROR Trying to get property 'slides' of non-object
Everything I have read in the docs and from other sources show this to be a pretty basic operation. For the live of me, i cant figure out why its causing such an issue. I should be able to access this in the view by simply nesting a foreach.
Any help with this would be greatly appreciated.
In the following dump, the "slides" are not in the attributes object of the collection; however, they are in the relations object.
Yes this is normal.
This is where you have a problem:
public function show(Carosuel $carousels) {
// ...
return view('myView', compact(['carousels']));
}
Typehinting a model in a function is reserved for model binding. Which is not what you're doing here since you don't have an {id} or some other parameter in your route.
Remove the typehinting and call the model instead:
public function show() {
$carousels = Carousel::with('slides')->get();
return view('myView', compact(['carousels']));
}
If you'd like to remove the dependency from the method, you should do it in the constructor instead.
Edit:
While I don't see any other problem and the above solution should work, if it's true that ->toArray() works for you (but you still need pagination), you could just convert the underlying collection:
public function show() {
$carousels = Carousel::with('slides')->paginate();
$carousels->setCollection(collect($carousels->getCollection()->toArray()));
return view('myView', compact(['carousels']));
}
Can you try this?
Model B: (Carousel)
public function slides() {
return $this->hasMany(Slide::class)->withTimestamp();
}

How do I check if a row of a table was insert in laravel eloquent?

Before query all the information from DB I want to check if a row of a table was insert or not and if there are no any new insert I will not use query method.But I'm much understand about how to check up if it was inserted or not in Laravel5 with Eloquent library.
I've research some tutorial I found as below sql sentence but I don't how to used it in Eloquent and this sql is work as my expected or not.
On checkingIfNotificationUpdated method I want to checking for true and false when a row was insert into that tables only but as this sentence it will query all data
public function checkingIfNotificationUpdated(){
// SELECT * FROM INFORMATION_SCHEMA.'.$this->table.' WHERE DATE_SUB(NOW(), INTERVAL 1 HOUR) < UPDATE_TIME
RETURN self::select('*')->where(DB::raw('DATE_SUB(NOW(), INTERVAL 1 HOUR)'),'<','UPADTE_TIME')->get();
}
Here is my query method within checking Notification table is insert or not
public function getNotification($user_id, $gId)
{
if($this->checkingIfNotificationInserted() == true){
$this->_data = self::select('*')->join('users', 'users.id', '=', 'n_user_id')
->where('n_group_code_id','=', $gId)
->get();
if (count($this->_data)) {
return $this->_data;
} else {
return false;
}
}else{
// to go with old data.
}
}
Here is data my respond data when Used dd()
Collection {#619 ▼
#items: array:1 [▼
0 => Notification {#620 ▼
#table: "notification"
+timestamps: true
-_data: false
#connection: null
#primaryKey: "id"
#perPage: 15
+incrementing: true
#attributes: array:11 [▼
"n_id" => 269
"n_user_id" => 69
"n_group_code_id" => 11
"n_source_id" => 231
"n_activity_type" => "Issue Till"
"n_create_times" => "2016-04-06 09:04:40"
"n_description" => "Issue Till"
"n_status" => 0
"url" => "teller/trans_issues"
"updated_at" => "2016-04-06 09:45:40"
"created_at" => "2016-04-06 09:45:40"
]
#original: array:11 [▼
"n_id" => 269
"n_user_id" => 69
"n_group_code_id" => 11
"n_source_id" => 231
"n_activity_type" => "Issue Till"
"n_create_times" => "2016-04-06 09:04:40"
"n_description" => "Issue Till"
"n_status" => 0
"url" => "teller/trans_issues"
"updated_at" => "2016-04-06 09:45:40"
"created_at" => "2016-04-06 09:45:40"
]
#relations: []
#hidden: []
#visible: []
#appends: []
#fillable: []
#guarded: array:1 [▼
0 => "*"
]
#dates: []
#casts: []
#touches: []
#observables: []
#with: []
#morphClass: null
+exists: true
}
]
}
i think you can check with your input fields when you inserted:
Here,
in Controller :
$input = $request->all();
//check input value if exists or not in db...
$b_exists = ModelClass::where('title','=',$input['title'])->exists();
if($b_exists){
//show message: alteady exists
}
else{
//
....new data inserted
}
If you are using Eloquent there is no need to query back to the DB.
Assume you do an insert like this:
$myModel = ModelClass::create($params);
or this:
$myModel = new ModelClass($params);
$myModel->save();
You can then do this check:
if (! empty($myModel->id)) {
// Model has been successfully inserted
}

Transform eloquent model using fractal

I am trying to use fractal to convert dates in my eloquent model when sending it to a web page via ajax. However, I'm not getting the expected transformed data object. Here's my code:
Transformer:
<?php
namespace App\Transformers\Models;
use App\Models\Student;
use League\Fractal;
class StudentTransformer extends Fractal\TransformerAbstract
{
public function transform(Student $student)
{
return [
'name' => $student->name,
'birth_date' => date('d-m-Y', strtotime($student->birth_date)),
'start_date' => date('d-m-Y', strtotime($student->start_date)),
'is_active' => $student->is_active ? 'Yes' : 'No',
'course_title' => $student->course_title,
'university_id' => $student->university_id,
'institution_id' => $student->institution_id,
'course_id' => $student->course_id,
];
}
}
Routes file:
Route::get('/', function () {
$student = App\Models\Student::first();
$response = new League\Fractal\Resource\Item($student, new App\Transformers\Models\StudentTransformer);
return response()->json([$response]);
});
returns this:
[
{ }
]
if I dd(), like so:
Route::get('/', function () {
$student = App\Models\Student::first();
$response = new League\Fractal\Resource\Item($student, new App\Transformers\Models\StudentTransformer);
dd($response);
});
I get the following, with no apparent transformations made
Item {#299 ▼
#data: Student {#305 ▼
#fillable: array:10 [▼
0 => "name"
1 => "birth_date"
2 => "start_date"
3 => "is_active"
4 => "course_title"
5 => "university_id"
6 => "institution_id"
7 => "course_id"
]
#connection: null
#table: null
#primaryKey: "id"
#perPage: 15
+incrementing: true
+timestamps: true
#attributes: array:13 [▼
"id" => 1
"name" => "Michel Jast"
"birth_date" => "1979-12-22"
"start_date" => "2015-08-02"
"is_active" => 1
"course_title" => "quia"
"university_id" => "10954"
"institution_id" => 1044
"course_id" => 1
"created_at" => "2015-11-23 09:40:35"
"updated_at" => "2015-11-26 10:24:14"
]
#original: array:13 [▼
"id" => 1
"name" => "Michel Jast"
"birth_date" => "1979-12-22"
"start_date" => "2015-08-02"
"is_active" => 1
"course_title" => "quia"
"university_id" => "10954"
"institution_id" => 1044
"course_id" => 1
"created_at" => "2015-11-23 09:40:35"
"updated_at" => "2015-11-26 10:24:14"
]
#relations: []
#hidden: []
#visible: []
#appends: []
#guarded: array:1 [▶]
#dates: []
#dateFormat: null
#casts: []
#touches: []
#observables: []
#with: []
#morphClass: null
+exists: true
}
#meta: []
#resourceKey: null
#transformer: StudentTransformer {#301 ▼
#availableIncludes: []
#defaultIncludes: []
#currentScope: null
}
}
Any ideas what I'm missing here?
My implementation is the following :
Route::get('/', function () {
$student = App\Models\Student::first();
$response = new League\Fractal\Resource\Item($student, new App\Transformers\Models\StudentTransformer);
$manager = new \League\Fractal\Manager();
$manager->setSerializer(new \League\Fractal\Serializer\ArraySerializer());
return response()->json($manager->createData($response)->toArray());
});
You have to create a \League\Fractal\Manager instance and assign a serializer into it. The manager will return the data into array or others.
In fractal page, there is more detail.
Ive not used Factral in a project but I think you need to do something like.
Route::get('/', function () {
$student = App\Models\Student::first();
$response = new League\Fractal\Resource\Item($student, new App\Transformers\Models\StudentTransformer);
return response()->json($response->toArray());
});

Categories