class SongsCollection extends ResourceCollection
{
public function toArray($request)
{
return [
'data' => SongResource::collection($this->collection),
'meta' => ['song_count' => $this->collection->count()],
];
}
}
in the controller
$data = new SongsCollection(Song::all());
dd($data);
`
it only display the image below, but without the meta array contain the song_count?
How to get the meta->song_count value ?
Laravel doc says:
Every resource class defines a toArray method which returns the array of attributes that should be converted to JSON when the resource is returned as a response from a route or controller method.
So, dd($data) will just dump the resource object which has the toArray method. If you want to get the meta field, you must call $data->toJson() method. If you just return $data in your api endpoint, laravel itself will call toJson method internally as stated in the above doc.
In the blade template, the laravel gives a song collection, which can not be retrive the meta from this collection, Below is how I get the meta data:
$datas = json_encode($datas,true);
//dd($data);
$datas = json_decode($datas);
// dd($datas);
foreach($datas->meta as $link){
echo $link;
}
Hope this helps.
Related
This is used to export excel
My controllers:
public function reportExport(Request $request)
{
return Excel::download(new ReportExport($request), 'LAPORAN ABSENSI.xlsx');
}
Export folder : ReportExport
return [
"att_cross" => $att_cross,
"belum_absen" => $belum_absen,
"absen" => $absen,
];
but, when I return one of the data is successful, for example :
return $absen;
I want to display the contents of the variable $absent, $belum_absen, $att_cross but I get an error message "Call to a member function all() on array "
how can I display the data for these three parameters?
Read the docs for Excel package, you need to map() the output.
I have a nested route like this:
Route::get('/products/{product}/auctions/create', [AuctionController::class, 'create']);
All it does is it sets an auction on a given product. A Product - hasMany - Auctions.
AuctionPolicy to be invoked to authorize actions on an Auction instance:
// App\Providers\AuthServiceProvider
protected $policies = [
Auction::class => AuctionPolicy::class
]
AutionPolicy:
public function create(User $user, Product $product) // <-- where do I get this $product from?
{
if( $product->user_id === $user->id ) {
return $product->canCreateNewAuction();
}
return false;
}
AuctionController:
public function create(Request $request, Product $product)
{
$this->authorize('create', Auction::class);
}
It throws an Exception: AuctionPolicy::create expects two params, only one passed.
How do I pass $product to AuctionPolicy::create method.
Laravel allows to pass additional data to policies.
Supply Additional Context
In the ->authorize method, instead of passing Auction class string, we can also pass an array with additional data.
In this example, we want to be able to pass $product to the invoked Auction Policy:
$this->authorize('create', [Auction::class, $product]);
The first item of this array specifies which Policy (Auction::class => AuctionPolicy::class) to invoke and rest are additional data.
It doesn't have to be a class string, it could also be an instance.
$this->authorize('show', [$auction, $product]);
I am using craftable to generate an admin panel for my app.
I have an Organisation model that belongs to an Organisation Type model.
In the index listing, I want to be able to display the Organisation Type name rather than the _id. To do this, I have to modify this query, to eager load the relationship using the 'with' method.
The method signature for the listing is:
public static function processRequestAndGet($request, $columns = array(), $searchIn = null, $modifyQuery = null, $locale = null)
and the index method is:
$data = AdminListing::create(Organisation::class)->processRequestAndGet(
// pass the request with params
$request,
// set columns to query
['id', 'organisation_type_id', 'name', 'active'],
// set columns to searchIn
['id', 'name']
);
if ($request->ajax()) {
return ['data' => $data];
}
return view('admin.organisation.index', ['data' => $data]);
Craftable, provides a modifyQuery method to, but i'm not sure how to use it:
public function index(IndexMovie $request)
{
$data = AdminListing::create(Movie::class)
->modifyQuery(function($query) use ($request){
if ($request->has('author_id')) {
$query->where('author_id', $request->author_id);
}
})
->get();
Can someone help me use the callback to modify the query so that I can include the related table data?
Okay so I've came across the exact same problem and I'd like to share my way of doing it.
craftable uses a processRequestAndGet function that takes as a 4th parametre the intended callable query. So when you need to use that parametre rather than trying to access the modifyQuery function directly.
$data_r = AdminListing::create(Organisation::class)
->processRequestAndGet(
// pass the request with params
$request,
// set columns to query
['id', 'organisation_type_id', 'name', 'active'],
// set columns to searchIn
['id', 'name'],
function($query) use ($request){
if ($request->has('author_id')) {
$query->where('author_id', $request->author_id);
}
}
);
You were almost right, just pass the intended callback inside your processRequestAndGet and voilà.
I’ve recently discovered that presenters (like this one) implement the decorator pattern and are a great way to add fields and logic to existing Laravel models. Take the following example for my question below:
// Tack on a new readable timestamp field.
public function timeago()
{
return $this->object->created_at->whenForHumans();
}
// Wrap an existing field with some formatting logic
public function created_at()
{
return $this->object->created_at->format('Y-m-d');
}
I can then use these presenter fields in my view:
{{ $object->timeago }}
{{ $object->created_at }}
How would you implement the decorator pattern for an API that returns JSON responses rather than Blade views? In all the Laravel/JSON articles I have read, objects are immediately returned without undergoing any transformation / presenter logic. e.g.:
// converting a model to JSON
return User::find($id)->toJson();
// returning a model directly will be converted to JSON
return User::all();
// return associated models
return User::find($id)->load('comments')->get();
How can I implement presenter fields in my JSON response?
$object->timeago
$object->created_at
As you mentioned, User::all returns JSON, so do something like:
Some function to get data and return a decorated response:
public function index()
{
$news = News::all();
return $this->respond([
'data' => $this->newsTransformer->transformCollection($news->toArray())
]
);
}
The above function will call Transformer::transformCollection:
<?php namespace Blah\Transformers;
abstract class Transformer {
public function transformCollection(array $items)
{
return array_map([$this, 'transform'], $items);
}
public abstract function transform($item);
}
which in turn will call NewsTransformer::transform():
public function transform($news)
{
return [
'title' => $news['title'],
'body' => $news['body'],
'active' => (boolean) $news['some_bool'],
'timeago' => // Human readable
'created_at' => // Y-m-d
];
}
The end result being JSON with the format you require, in this case:
{
data: {
title: "Some title",
body: "Some body...",
active: true,
timeago: "On Saturday, 1st of March",
created_at: "2014-03-01"
}
}
By the way, Laracasts has an excellent series on building APIs -- hope that helps!
For clarity, the respond function in the first code snippet just wraps the data with a status code, and any headers, something like:
return Response::json($data, 200);
So I'm making an API that produces a json response instead of doing View::make('foo', compact('bar')).
With blade templating
My controller simply returns the Eloquent model for Users:
public function index()
{
return User::all();
}
protected function getFooAttribute()
{
return 'bar';
}
And my view will be able to use it, along with the foo attribute (which isn't a field in the user's table).
#foreach($users as $user)
<p>{{$user->name}} {{$user->foo}}</p>
#endforeach
With Angular JS + json response
However, now that I'm not using blade but rather grabbing the json and displaying it with Angular JS I'm not able to do this:
<p ng-repeat="user in users">{{user.name}} {{user.foo}}</p>
Is there a way to cleanly pack the json response such that I have:
[{"name": "John", "foo": "bar"}, ...]
Warning: I've never built an API before and I've only started programming/web dev last December. This is my attempt:
public function index()
{
$response = User::all();
foreach($response as $r)
{
$r->foo = $r->foo;
}
return $response;
}
Yeah there is, example:
return Response::json([User:all()], 200);
Usually you want more than that though..
return Response::json([
'error' => false,
'data' => User:all()
], 200);
200 is the HTTP Status Code.
To include the attributes you need to specify these attributes to automatically append onto the response in your model.
protected $appends = array('foo');
public function getFooAttribute()
{
return 'bar';
}