Isolate Key/Value Pair from Laravel Model Relationship - php

In my Laravel App, a poll has many poll options. I can create a collection of those options by simply running:
$result = Poll::find(1)->options()->get();
This query returns:
Collection {#387 ▼
#items: array:6 [▼
0 => PollOption {#388 ▼
#table: "poll_options"
#connection: null
#primaryKey: "id"
#keyType: "int"
#perPage: 15
+incrementing: true
+timestamps: true
#attributes: array:8 [▼
"id" => 1
"poll_id" => 1
"option_text" => "Never"
"responses" => 54
"is_public" => 0
"created_at" => null
"updated_at" => null
"deleted_at" => null
]
#original: array:8 [▶]
#relations: []
#hidden: []
#visible: []
#appends: []
#fillable: []
#guarded: array:1 [▶]
#dates: []
#dateFormat: null
#casts: []
#touches: []
#observables: []
#with: []
#morphClass: null
+exists: true
+wasRecentlyCreated: false
}
1 => PollOption {#389 ▶}
2 => PollOption {#390 ▶}
3 => PollOption {#391 ▶}
]
}
Within my poll option, there is a column called responses, which returns an integer. I need to take the collection above and isolate the responses key/value pair.
Collection {#385 ▼
#items: array:6 [▼
"responses" => 54
"responses" => 20
"responses" => 10
"responses" => 123
"responses" => 33
"responses" => 11
]
}
The only() collection method does exactly what I need, but I can't figure out how to structure the query when working with Eloquent models:
$options = Poll::find(1)->options()->get();
$responses = $options->only('responses');
dd($responses->all());
Returns an empty collection because the responses value is nested within the PollOption object.
I've also tried flatten(), but that seems to have no effect in this scenario.
Is there an easier way to return a single key/value pair within an Eloquent model collection?

It's not actually possible to assign the same key to multiple values within a collection. I knew this, but I wasn't thinking the problem through properly.
For future devs: the pluck() method takes two arguments: the value you want to pluck, and a second value that gets assigned to the key. Using the scenario above, I was able to write:
$result = $poll->options()->pluck('responses', 'option_text'); //Value and corresponding key
This results in something like:
Collection {#386 ▼
#items: array:6 [▼
"Never" => 54
"Occasionally" => 21
"2–3 times a week" => 80
"4–5 times per week" => 33
"Daily" => 11
]
}
Which ultimately did what I need it to do. Amit Gupta's mapWithKeys() answer is also correct, and will land you in the same place.

Related

How check multiple column?

I need to check if schedules_id equal to request schedules_id then need to check profile 'booked' or 'pending' then need to pass all the 'booked' profile seat values into blade.php. How can i do that or if another way or logic to do this please suggest me i'm new to laravel
how i getting data now :
class PassengersController extends Controller
{
public function booking(Request $request)
{
//river is used to pass important params with flow of it from page to page
$seat = $request->seat;
$buses_id = $request->buses_id;
$schedules_id = $request->schedules_id;
$data = Buses::where('buses_id', $buses_id)->first();
$seat = json_decode($data->seat_layout, true);
$front = json_decode($data->front_layout, true);
$bookingSeat = Bookings::whereColumn('schedules_id', 'schedules_id')->get();
$bookingSeat = $bookingSeat->map(function ($bookSeat) {
$bookSeat->seat = explode(",", $bookSeat->seat);
return $bookSeat;
});
return view('frontend.booking', ['seat' => $seat, 'buses_id' => $buses_id, 'schedules_id' => $schedules_id, 'front' => $front, 'bookingSeet' => $bookingSeat]);
}
}
blade.php
<div class="bus">
#foreach($seat as $key => $item)
#foreach($bookingSeet as $seer)
<div class="col-md-1">
<div class="seats back seats
#if(in_array($item['name'], $seer['seat']))
activeSeat
#endif"
data-id="{{$key}}">
<div class="special-attributes"></div>
#if(isset($item['name'])){{$item['name']}}#else 11A #endif
<input type="checkbox" name="seat_id[]" id="{{$key}}" value="{{$key}}">
</div>
</div>
#endforeach
#endforeach
</div>
table
bookings_id users_id schedules_id buses_id routes_id seat price profile
1 1 6 1 3 1 Null pending
2 1 6 1 3 2 Null booked
3 1 6 1 3 3 null booked
Problem with my current code is getting 2 array with all bookings table column how to pass that value into blade, when i try i getting duplicated checkbox for ex. one bus have a 50 seat but now showing 100 seat. seats like 1,1,2,2 in view
One array look like this :
Collection {#426 ▼
#items: array:2 [▼
0 => Bookings {#431 ▼
#fillable: array:7 [▶]
#primaryKey: "bookings_id"
#connection: "mysql"
#table: null
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#attributes: array:10 [▼
"bookings_id" => 1
"users_id" => 1
"schedules_id" => 6
"buses_id" => 1
"routes_id" => 3
"seat" => "1"
"price" => null
"profile" => "pending"
"created_at" => "2019-04-09 00:00:00"
"updated_at" => "2019-04-09 00:00:00"
]
#original: array:10 [▶]
#changes: []
#casts: []
#dates: []
#dateFormat: null
#appends: []
#dispatchesEvents: []
#observables: []
#relations: []
#touches: []
+timestamps: true
#hidden: []
#visible: []
#guarded: array:1 [▶]
}
1 => Bookings {#432 ▶}
]
}
try this
Bookings::where('schedules_id', $schedules_id)->where('profile', 'booked')->get();
Try this:
$bookingSeat = Bookings::where('schedules_id', $request->schedules_id)->where(function ($q) {
$q->where('profile', 'booked')->orWhere('profile', 'pending');
})->get();
or this:
$profileTypes = ['booked', 'pending'];
$bookingSeat = Bookings::where('schedules_id', $request->schedules_id)->whereIn('profile', $profileTypes)->get();
#Edit
In this way, if your Bookings table contains all seats, already registered (1 to 50), it will return all seats that your profile is "booked" or "pending" for a particular bus, route, and time.
$profileTypes = ['booked', 'pending'];
$bookingSeat = Bookings::where('schedules_id', $request->schedules_id)
->whereIn('profile', $profileTypes)
->where('buses_id', $buses_id)
->where('routes_id', $request->route_id)
->get();
You are allowed to use arrays als wheres.
For example:
$model->where([
['field-one', '=', 'valueOne'],
['field-two', '=', 'valueY']
]);
If I understand the situation correctly, if schedules_id is provided schedules_id and the profile is either booked or pending, you want to retrieve data, the query should be
Bookings::where('schedules_id', $schedules_id)->whereIn('profile', ['booked', 'pending'])->get();

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();
}

Laravel 5 can not access atributes from model

I got a slight issue,for some reason I'm unable to access my attributes from a relationship model.
I keep getting the same error, 'Undefined property: Illuminate\Database\Eloquent\Collection::$season'
I have been staring at this all day and I couldn't find a solution for it.
<?php namespace App\Http\Controllers;
use App\Show;
use App\Episode;
class TestController extends Controller {
public function test(){
$shows = Show::where('active',1)->get();
foreach ($shows as $show) {
if($show->active == 1 && $show->airday == date('N'))
{
echo 'test';
$episode = $show->episodes()->orderBy('id', 'desc')->take(1)->get();
\Debugbar::info($episode);
//this is the line where he gives me
echo('New episodes avaible, Season '.$episode->season.' Episode '.$episode->episode.' From '.$show->name);
//end error
}
}
}
}
?>
Although if I do a print out of the $episode variable I can clearly see the properties I wish to access.
Illuminate\Database\Eloquent\Collection {#150
#items: array:1 [
0 => App\Episode {#241
#table: "episodes"
+timestamps: true
#connection: null
#primaryKey: "id"
#perPage: 15
+incrementing: true
#attributes: array:6 [
"id" => "6"
"show_id" => "6"
"season" => "3"
"episode" => "15"
"created_at" => "2016-02-07 11:45:53"
"updated_at" => "2016-02-07 11:45:53"
]
#original: array:6 [
"id" => "6"
"show_id" => "6"
"season" => "3"
"episode" => "15"
"created_at" => "2016-02-07 11:45:53"
"updated_at" => "2016-02-07 11:45:53"
]
#relations: []
#hidden: []
#visible: []
#appends: []
#fillable: []
#guarded: array:1 [
0 => "*"
]
#dates: []
#dateFormat: null
#casts: []
#touches: []
#observables: []
#with: []
#morphClass: null
+exists: true
+wasRecentlyCreated: false
}
]
At the moment I'm clueless whats wrong with the code.
I hope someone can point me in the right direction.
When you call ->take(1)->get() you're telling Eloquent (the builder, really) to give you back a Collection object with 1 item in it.
So when you're trying to access your $season property, you're actually trying to access it on a Collection object and not the Model that you think.
You can do a couple of things:
You can replace your ->take(1)->get() call with ->first(),
or you can treat your current $episode variable as a collection, and retrieve the actual episode you care about by accessing $episode[0],
or you can call first on your current $episode variable ($episode = $episode->first()) to get the first model object within it.

How to get an item from a collection in Laravel 5?

I'm new to Laravel and I cannot figure out how to get the value of an item from within the returned collection. Here is my code:
$aircraft = Aircraft::join('pams_shared.shared_aircraft', 'aircraft.shared_aircraft_id', '=', 'pams_shared.shared_aircraft.shared_aircraft_id')
->select('aircraft.*', 'shared_aircraft.*')
->where('aircraft.owner_id',Auth::user()->owner_id)
->where('registration',$reg)
->get();
I want to get the value from aircraft.aircraft_id but that's where I get stuck. I've tried:
$id = $aircraft->aircraft_id;
I've tried:
$id = $aircraft->aircraft.aircraft_id;
I've also tried:
$id = array_get($aircraft, 'aircraft_id');
But I'm getting null as a value. When I perform either a var_dump($aircraft) or dd($aircraft) I'm able to confirm that the data is there.
In my view I am able to access the value by looping through, but I need this data in my controller to perform a second query on another table.
Hope that makes sense. Cheers.
EDIT
When running dd($aircraft); I get this:
Collection {#239 ▼
#items: array:1 [▼
0 => Aircraft {#240 ▼
#fillable: array:8 [▶]
#table: "aircraft"
#primaryKey: "aircraft_id"
#connection: null
#perPage: 15
+incrementing: true
+timestamps: true
#attributes: array:16 [▼
"aircraft_id" => 5
"owner_id" => 2
"shared_aircraft_id" => 67443
"year" => 2012
"serial_number" => "C127RG3"
"registration" => "C-SMTH"
"created_by" => 2
"modified_by" => 2
"created_at" => "0000-00-00 00:00:00"
"updated_at" => "0000-00-00 00:00:00"
"aircraft_code" => "2072438"
"aircraft_mfr" => "CESSNA"
"aircraft_model" => "172RG"
"aircraft_type" => 4
"aircraft_eng" => 1
"aircraft_cat" => 1
]
#original: array:16 [▶]
#relations: []
#hidden: []
#visible: []
#appends: []
#guarded: array:1 [▶]
#dates: []
#casts: []
#touches: []
#observables: []
#with: []
#morphClass: null
+exists: true
}
]
}
When you use get() method on a query builder it would return an array no matter how many record it gets. So you can access it by pointing it by index. By the way do not forget to check for emptiness to overcome possible errors.
$id = 0;
$aircraft = Aircraft::join('pams_shared.shared_aircraft', 'aircraft.shared_aircraft_id', '=', 'pams_shared.shared_aircraft.shared_aircraft_id')
->select('aircraft.*', 'shared_aircraft.*')
->where('aircraft.owner_id',Auth::user()->owner_id)
->where('registration',$reg)
->get();
// now you can access properties
if(count($aircraft) > 0) $id = $aircraft[0]->aircraft_id;
If you execute the query with get() you will always get a collection as result. Even if you just need one model. The simplest way to change that is to use first():
$aircraft = Aircraft::join('pams_shared.shared_aircraft', 'aircraft.shared_aircraft_id', '=', 'pams_shared.shared_aircraft.shared_aircraft_id')
->select('aircraft.*', 'shared_aircraft.*')
->where('aircraft.owner_id',Auth::user()->owner_id)
->where('registration',$reg)
->first();
$id = $aircraft->aircraft_id;

Categories