I am writing an assignment system for radio newscasts. The data tables:
station
id | calls
---| -----
1 | cxri
newscast
id | name_input | for_station_id
---|------------|---------------
1 | am | 1
assignment
id | newscast_id | user_id
1 | 1 | 5
The controller for Assignment.edit is as follows:
if (! Gate::allows('assignment_edit'))
return abort(401);
}
$relations = [
'anchors' => \App\User::get()->pluck('name', 'id')->prepend('Please select', ''),
'casts' => \App\Newscast::get()->pluck('name_input', 'id')->prepend('Please select', ''),
];
return view('assignment.create', $relations);
The Newscasts model:
public function for_station()
{
return $this->belongsTo(Station::class, 'for_station_id')->withTrashed();
}
Right now I get
"casts" => Collection {#451 ▼
#items: array:2 [▼
"" => "Please select"
1 => "am"
]
}
I want
"casts" => Collection {#451 ▼
#items: array:2 [▼
"" => "Please select"
1 => "cxri-am"
]
}
How do I make that happen?
Or should I denormalize the data and make name_input 'cxri-am' instead of 'am'?
What I've tried:
Accepted answer in Laravel pluck fields from relations
'casts' => \App\Newscast::with('station')->get()->pluck('name_input', 'id'),
errors with
Call to undefined relationship [station] on model [App\Newscast]
I included the Newscast model above based on the discussion in Laravel: get/show data from related tables. Based on that discussion it appears to me the newscast should already be able to access the Station calls. But as shown above, the calls are not in $casts.
You are close with what you have tried. The with() function needs the name of the relation function, not the table, so this should work for getting the relation model loaded:
'casts' => \App\Newscast::with('for_station')->get(),
As for getting the data to concat the way you want, I would make an accessor on the Newscast model that will return the data you want:
function getNameInputStationAttribute() {
return $this->for_station->calls . "-" . $this->input_name;
}
You would then use this like:
'casts' => \App\Newscast::with('for_station')->get()->pluck('name_input_station', 'id')->prepend('Please select', ''),
If I could point out a few other things, the return code of 401 indicates Unauthenticated whereas 403 indicates Unauthorized which would be more applicable to the Gate returning false. Also, class functions should be cammel case, so your for_station function should be forStation or even just station.
Related
I am trying to iterate a set of array values returned from my laravel view in a multi-select dropdown field. When I submit my form, below is the data sent to my livewire component.
^ array:4 [▼
"scheduled_date" => "2022-09-30 12:00"
"recipient" => "2"
"classrooms" => array:4 [▼
0 => "2"
1 => "3"
2 => "4"
3 => "5"
]
"smsdetail" => "Testing for a particular Class"
]
I need to iterate data in classrooms array and save them as different records with the rest of the top-level data to db which is not the problem. My struggle is to iterate and pick values for classrooms.
The below set of codes gives me the error Expected type 'iterable|object'. Found 'string'. I need help.
case ('2'):
$recipients = $this->state['classrooms'];
foreach ($recipients as $key => $recipient)
{
dd($recipient);
}
case ('2'):
$recipients = $this->state['classrooms'];
foreach ($recipients as $recipient)
{
dd($recipient);
}
I have a table called posts that stores all the post types, each post can have multiple and dynamic meta values, so I have the post_meta table which handle all of this.
The post_meta table have the following structure:
id | post_id | meta_key | meta_value
This is the structure of the posts table:
id | content | type | created_at | updated_at | deleted_at
I need to order the post with the type section, so what I did so far is this:
$sections = Post::with('meta')->where([
'type' => 'section',
'language' => 'it',
'status' => 'published',
])->get();
$sections->sortBy(function ($sec) {
return $sec->getMeta('order')->meta_value;
});
where getMeta is a custom method that I have added within the Post model:
public function getMeta(string $metaKey)
{
$key = array_search($metaKey, array_column($this->meta->toArray(), 'meta_key'));
return $key !== false ? $this->meta[$key] : null;
}
The issue is that I doesn't get any ordering, what I'm doing wrong?
Current datasets:
id | type
1 section
2 section
3 section
id | post_id | meta_key | meta_value
1 1 order 0
2 2 order 2
3 3 order 1
I should get this sequence: 1, 3, 2 instead of 1, 2, 3
When you call sortBy on collection you don't modify the existing collection,
so you need to do:
$sections = $sections->sortBy(function ($sec) {
$sections = Post::with('meta')->where([
'type' => 'section',
'language' => 'it',
'status' => 'published',
])->get();
That Where clousure is not well executed, you need 3 parameteres per array to consult, like this:
$sections = Post::with('meta')->where([
['type' '=>' 'section'],
['language' '=>' 'it'],
['status' '=>' 'published'])->get();
And i'm not pretty sure what's the query builder you are trying to build because to me it looks like more like an assignation with those arrows.......whatever but at least you have the correct format now.
I'm using Laravel Analytics to get data of the visitors of my application.
In my Google Analytics dashboard, every page have it own visits numbers, unique visitors, countries of visitors etc .. like in this image :
In my web.php, I'm creating a route to test the package :
Route::get('/data', function () {
$analyticsData = Analytics::fetchMostVisitedPages(Period::days(7));
dd($analyticsData);
});
This route returns :
Illuminate\Support\Collection {#1564 ▼
#items: array:3 [▼
0 => array:3 [▼
"url" => "/new"
"pageTitle" => "test"
"pageViews" => 1534
]
1 => array:3 [▼
"url" => "/"
"pageTitle" => "test"
"pageViews" => 450
]
2 => array:3 [▼
"url" => "/customize/8"
"pageTitle" => "test"
"pageViews" => 196
]
As you can see the returned array have only url, pageTitle and pageViews. How can I add additional informations in the returned array such as countries or geographic localisation as shown in the first image ?
I've never used the package, but reading the docs, something like this will do.
The package docs state you can use any query you want, and the Google Analytics docs give an example of getting session by location.
public function myCustomMethod($maxResults = 20)
{
$response = $this->performQuery(
$period,
'ga:sessions', // metrics
[
'dimensions' => 'ga:country',
'sort' => '-ga:sessions',
'max-results' => $maxResults,
],
);
return collect($response['rows'] ?? [])->map(fn (array $pageRow) => [
// Do something with the rows that are returned.
// I'm not sure how they're returned from the main response.
]);
}
Note, this is completely untested, you might want to fiddle with some of the data here.
Assuming I understand the documentation, this will get all countries (dimensions), it will use sessions (ga:sessions from second parameter) to measure the countries data.
It'll then just sort and get a maximum number of results.
You could change the metrics to ga:pageviews, but it's ultimately down to you what queries you want to use.
I've linked the documentation so you can find them out yourself.
You're using spatie/laravel-analytics package.
As you can see here: spatie laravel analytics - Analytics.php the fetchMostVisitedPages method that you are calling only returns that data.
Please take a look in github to see more information about this package.
fetchMostVisitedPages method:
public function fetchMostVisitedPages(Period $period, int $maxResults = 20): Collection
{
$response = $this->performQuery(
$period,
'ga:pageviews',
[
'dimensions' => 'ga:pagePath,ga:pageTitle',
'sort' => '-ga:pageviews',
'max-results' => $maxResults,
],
);
return collect($response['rows'] ?? [])->map(fn (array $pageRow) => [
'url' => $pageRow[0],
'pageTitle' => $pageRow[1],
'pageViews' => (int) $pageRow[2],
]);
}
I have two models. Expense and Method. I want to grab the sum of all expenses for each method type. I have four types:
- bank
- credit-card
- wallet
- savings
Each Expense belongsTo a Method and each Method hasMany Expenses. So it's a One-to-Many relation. So a method_id is stored for each Expense.
The following query works to get the sum of all expenses that have a method with the type bank for example:
$type = 'bank';
$expenses = auth()->user()->expenses()->with('method')->whereHas('method', function ($query) use ($type) {
$query->where('type', $type);
})->sum('amount');
But the thing is, if I want to get the total amount of all expenses for each method type, I will have to run too many queries. I would prefer just grabbing all Expenses, and then filtering through them to get the sum of all expenses for each method type.
The following for example doesn't work:
$expenses = auth()->user()->expenses()->with('method')->get();
$bank_balance = $expenses->filter(function ($expense)
{
$expense->whereHas('method', function ($query) {
$query->where('type', 'bank');
})->get(); // with or without ->get()
});
Any ideas how to get what I want by not using too many queries?
Edit:
I've unaccepted the chosen answer because it didn't give me what I needed in the end. I need to be able to do something like this in my view:
{{ $bank_balance }}
Which means, with xyz's answer, I wouldn't be able to do that, since I cannot distinguish between them. I only get results based on method_id's, but I need to be able to distinguish them by the method name.
DigitalDrifter's answer is the one that almost does the trick, but it gives me this:
Collection {#800 ▼
#items: array:3 [▼
"bank" => Collection {#797 ▼
#items: array:30 [▼
0 => array:2 [▼
"type" => "bank"
"amount" => 1536
]
1 => array:2 [▶]
2 => array:2 [▶]
3 => array:2 [▶]
4 => array:2 [▶]
5 => array:2 [▶]
]
}
"credit-card" => Collection {#798 ▶}
"wallet" => Collection {#799 ▶}
]
}
And I basically need something simple like this:
"bank" => "total sum here for all expenses that have a method of 'bank'"
"credit-card" => "total sum here for all expenses that have a method of 'credit-card'"
And so on..
I think this bit ->groupBy('type')->each->sum('amount') does the trick, but not completely. It does group by type but it does not give a sum for each type, as you can see in the collection example above.
You can group by the method id and then sum the result in a select statement.
The following is untested.
$expenses = auth()->user()
->expenses()
->select(DB::raw('SUM(amount) as total'), 'other_select_fields', ...)
->with('method')
->groupBy('method_id')
->get();
You could do this using the available collection methods:
$expenses = auth()->user()->expenses()->with('method')->get();
$groupedSums = $expenses->map(function ($expense) {
return [
'type' => $expense['method']['type'],
'amount' => $expense['method']['amount']
];
})->groupBy('type')->each->sum('amount');
I have an array of array which results from several sql requests.
First I make a sql request in a foreach in order to have all the datas i need
foreach ($users as $user) {
// Two different Eloquent requests
$todo = User::select().....where('users.id' = $id);
$done = User::select().....where('users.id' = $id);
// I have operation on Collection that work fine ...
$totalTimes = $todo->toBase()->sum('dureeformation') ;
$spendTimes = $done->toBase()->sum('dureeformation') ;
$remainingTimes = $totalTimes - $spendTimes;
$all[] = ['user_id' => $id, 'totalTime' => $totalTimes, 'spendTime' => $spendTimes,'remainingTime' => $remainingTimes ];
}
My issue is the following... Outside the foreach i display the values and i have this array of array ...
array:16 [▼
0 => array:4 [▼
"user_id" => 1
"totalTime" => 465
"spendTime" => 0
"remainingTime" => 465
]
1 => array:4 [▼
"user_id" => 3
"totalTime" => 375
"spendTime" => 0
"remainingTime" => 375
]
I would need to have a Collection instead ... I tried to make $all = Collect(....) but i doesn't give me the expected result.
I need a collection because i have to create a Collection with this created collection and another one from another request.
Concerning this part i already had this case and i can solve it.
Thanks for your help
try this helper function :
$collection = collect($all);
This function will convert your array to collection.