I'm looking for a way to return a model as JSON including an association model after save (within a controller).
I know how to respond as JSON with associations by doing the following :
$objects = MyModel::with(['assocation1', 'association2.dependencies'])->get();
return response()->json($objects, 200);
But in a case of an object already found ? I've tried to use the same concept as above but it returns every rows.
$object = MyModel::first();
$object->with(['assocation1', 'association2.dependencies'])->get();
Laravel's documentation unfortunately does says much about it. What I'm trying to do is to return a JSON object including an association after save, within a controller :
class ExampleController extends Controller {
public function store()
{
$object = new MyModel($request->input('object'));
$response = DB::transaction(function () use ($object) {
if (object()->save()) {
// Here I want to return the object with association1 as JSON
return response()->json($object->with('association1')->get(), 201);
}
});
return $response;
}
}
Edit
More clarification about this case. Using either with or load seems to produce the same result: returning all rows from the Object object including associations. My goal here is to only return ONE object with it's association as JSON, not all of them.
I believe you aren't as far off as you think. In your second example, you shouldn't call get(). Try this instead:
if ( $object = $object->save() )
{
$object->load(['assocation1', 'association2.dependencies']);
return response()->json($object, 201);
}
Related
I'm currently creating a laravel vue spa, and just wondering on how can I get designation names with these designation id's with the same structure. This is the json of designation id's:
[
[
1,
5
],
[
1,
3
]
]
This is my getDesignations function in EmployeesController.php:
public function getDesignations($id) {
$employee_designation_ids = Employees::find($id)->pluck('designation_id')->toArray();
$designation_name = [];
foreach ($employee_designation_ids as $employee_designation_id) {
$designation = Designations::where('id', '=', $employee_designation_id);
//$designation_name[] = $designation;
}
return $employee_designation_ids;
}
If you want specifically that format, you can do it like this (with a lot of guesses in my part since you did not share your Tables structures)
public function getDesignations($id) {
$employee_designation_ids = Employees::find($id)->designation_id;
return [[$id, $employee_designation_ids]];
}
But why are you returning a double table for a single row result.
Thanks for all your help! I've managed to fix it with this method in my controller:
public function getDesignations(Request $request, $id) {
$employee_designation_ids = Employees::where('id', $id)->pluck('designation_id');
return Designations::whereIn('id', $employee_designation_ids[0])->pluck('name');
}
Hope the title isn't too specific.
The back-end I am working with returns Dates as a string. I have a function to convert that string to a javascript Date object. I use a Rxjs map to convert the json response to my Typescript objects like so.
getAllRecordsByEmployeeId(employeeId: number): Observable<Record[]> {
return this.http.get<Record[]>(
this.basePath
+ this.recordPath
+ this.recordEmployeeIdParam
+ employeeId,
this.httpOptions)
.pipe(
map((res: any) => res.records as Record[]),
);
}
I want to mutate res.records.startDate with a function before it gets turned into a Record object. How can I accomplish this?
getAllRecordsByEmployeeId(employeeId: number): Observable<Record[]> {
return this.http.get<Record[]>(
I understand, that your http request does not actually return a Record array. It returns an object with a Record Array field, which is basically another Record model. It is very similar, but it's a different model.
Please consider changing it to:
interface RecordFromApi extends Record {
startDate: string; // overwrite attribute
}
interface RecordResponse {
records: RecordFromApi[];
}
getAllRecordsByEmployeeId(employeeId: number): Observable<Record[]> {
return this.http.get<RecordResponse>(
this.basePath
+ this.recordPath
+ this.recordEmployeeIdParam
+ employeeId,
this.httpOptions)
.pipe(
map((res: RecordResponse) => res.records.map(record => mapRecord(record))), // mapRecord is a custom function which maps RecordFromApi model to Record model
);
}
We do something similar in my application. But instead of returning
res.records as Record[]
we do something like this:
.pipe(
map((records: Record[]) => records.map(records => new Record(record)))
);
and then on the record.ts
export class Record {
/*
properties
*/
date: Date;
constructor(params: Partial<Record> = {}) {
this.date = new Date(params.date);
}
}
This way you actually get instances of your class and you can use any functions you may have in your class (that's the issue we had when we came up with this solution).
I have one third Party API which returns data as below - It has been called from Angular Service using HttpClient.
const someObject = {
employees:[
{name:"XYZ",age:30},
{name:"ABC",age:28},
]
}
Now I have one interface with structure as below -
interface EmployeeData{
campus:{
property1:string;
property2:string;
};
details:{
name:string;
age:number
}
}
So EmployeeData.details exactly mimics someObject.employees structure
Now I want to return data from my service as below -
getData():Observable<EmployeeData[]>{
}
So , employees array from someObject should map to EmployeeData.details
and this should be returned as EmployeeData[].
How can I achieve this ?
I have tried below approach but it is giving different results.
getData():Observable<EmployeeData[]> {
return this.http.get<any>(url).pipe(
tap(value => console.log(value)),
map(data => data.employees),
map(employees =>{
return employees.map(employee =>{
return{
details:{
name:employee.name,
age:employee.age,
}
}
}
}
)
}
What it returns is -
details:{}
details:{}
But what I want is :
{
details:{}
}
{
details:{}
}
Can anybody please help here ?
If you want to type the function with Observable<EmployeeData>, your returned Observable must contain an array of objects implementing the EmployeeData interface, meaning that you will need to define them fully, not just the details property.
If you can't define all properties at this time, you have to use a type assertion with the as keyword. Be aware that you will lose type safety and might run into errors because missing properties will be undefined.
getData(): Observable<EmployeeData[]> {
return this.http.get<any>(url)
.pipe(
map(data => data.employees),
map(employees => employees.map(employee => ({ details: employee } as EmployeeData)))
);
}
See it in action here : https://stackblitz.com/edit/angular-msd6ym
I have two models in laravel project Item and ItemImgs
Item.php
class Item extends Model
{
protected $appends = [
'photo',
];
public function imgs()
{
return $this->hasMany(ItemImage::class);
}
public function getPhotoAttribute()
{
$img = $this->imgs->first();
return $img.src;
}
}
it's worked in views
dd(Item::all()); //worked
{{ $cane->photo}}; //worked
but when I try to get json
return response()->json([
'items' => Item::with('imgs')->get(),
]);
// not worked. Got timeout 500
You cannot use dot notation in PHP.
public function getPhotoAttribute()
{
$img = $this->imgs->first();
return $img.src; // Dot notation is not allowed
}
but you've to use:
public function getPhotoAttribute()
{
$img = $this->imgs->first();
return $img->src;
}
if what you're trying to do is to get the items that have imgs() then what you should do is query by relationship existence, as mentioned in the docs
https://laravel.com/docs/5.8/eloquent-relationships#querying-relationship-existence
'items' => Item::has('imgs')->get()
It is not possible to refer to the linked model tables in attributes. It works in views but gives out a memory error when outputting an array through json.
public function getPhotoAttribute(){
$img = ItemImage::where('item', $this->id)-
>first();
}
It works that way, but it's not elegant.
I have a class which extends from yii\rest\Controller, under this class is a function which returns an instance of ArrayDataProvider in JSON format.
public function actionIndex()
{
$user = User::find();
return $this->query($user->asArray()->all(), true);
}
protected function query($qry, $paginate=false)
{
$this->serializer['preserveKeys'] = false;
$dataProvider = new ArrayDataProvider([
'allModels' => $qry,
]);
if ($paginate) {
$dataProvider->setPagination(['pageSize' => 20]);
} else {
$dataProvider->setPagination(false);
}
return $dataProvider;
}
Assuming that the array returned is composed of 130k items (from actionIndex). Do everytime I hit this API with a page parameter on it, the ArrayDataProvider will process the 130k records and sliced it all over again?
Can someone tell what's the exact behavior an ArrayDataProvider is running? Is there any efficient way of handling such big array? What's the perks of using this as opposed with other providers?
Thank you!