Convert API resource to array - laravel

I want to store data on Firestore. I need to send an array to Firestore. I have API resources and I wanted to use it.
My ApiResource:
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'phone' => $this->phone,
'addresses' => AddressResource::collection($this->addresses),
];
}
Firestore store data:
public function set(User $user){
$this->firestore->document($user->id)->set((new UserResource($user)));
}
It is an error:
Argument 1 passed to
Google\Cloud\Firestore\DocumentReference::set() must be of the type
array, object given,...

You can call the toJson() on your Api Resource object:
$data = MyModel::with('addresses')->find(1);
$myArray = json_decode((new MyModelResource($data))->toJson(), true);
So you could just:
$this->firestore->document($user->id)->set($myArray);

Do it:
public function set(User $user){
$this->firestore->document($user->id)->set(toArray($user));
}

Related

HJow to add property in the request during 'prepareForValidation'

I am using Laravel 6.
I have this POST (for api usage) :
http://localhost:8000/api/v1/schools/d4866265-3965-4b91-8d0a-a621c9eb68c6/periods/854624d4-69b2-419b-9763-416b5d146e2d/exams/bd0127fe-185a-42f5-b121-15f856daee43
I use the formRequest validation. Like this :
public function rules(Request $request)
{
return [
'classroom_id' => [
'required',
new CoherenceSchoolPeriodClassroom($request->school_id, $request->period_id),
],
As you see, I need the $request->school_id for the test. But this data is not on the request payload, but present on the route.
So I would like to add this data using the prepareForValidation method :
protected function prepareForValidation(): void
{
$this->merge([
'school_id' => 'the school_id present on the route'
]);
}
My question is : how to get the school_id present in the route and merge it in request ?
Assuming your route parameter is called school_id, you can access it as a property or with the route() method.
'school_id' => $this->route('school_id')
// or
'school_id' => $this->school_id
If you only need it to validate the classroom_id you don't have to merge it into the request:
public function rules(Request $request)
{
return [
'classroom_id' => [
'required',
new CoherenceSchoolPeriodClassroom($this->route('school_id'), $request->period_id),
],
...
But you can merge it like so:
protected function prepareForValidation(): void
{
$this->merge([
'school_id' => $this->route('school_id')
]);
}

When collection->map returnes array then data in Collection raise error

In laravel 6 app I have collection defined as :
class PermissionCollection extends ResourceCollection
{
public static $wrap = 'permissions';
public function toArray($request)
{
return $this->collection->transform(function($permission){
return [
'id' => $permission->id,
'name' => $permission->name,
'is_checked' => !empty($permission->is_checked) ? $permission->is_checked : null,
'guard_name' => $permission->guard_name,
'created_at' => $permission->created_at,
];
});
}
}
I use it in a control, like :
$permissions = $user->permissions->all();
$userPermissionLabels= Permission
::get()
->map(function ($item) use($permissions) {
$is_checked= false;
foreach( $permissions as $nextPermission ) {
if($nextPermission->permission_id === $item->id) {
$is_checked= true;
break;
}
}
return [ 'id'=> $item->id, 'name'=> $item->name, 'is_checked' => $is_checked];
})
->all();
return (new PermissionCollection($userPermissionLabels));
and I got error :
Trying to get property 'id' of non-object
Looks like the reason is that collection->map returnes array of data, not objects.
If there is a way to fix it without creating new collection(using array) ?
MODIFIED :
I logged loging in my collection,
public function toArray($request)
{
return $this->collection->transform(function($permission){
\Log::info(' PermissionCollection $permission');
\Log::info($permission);
return [
'id' => $permission->id,
'name' => $permission->name,
'is_checked' => !empty($permission->is_checked) ? $permission->is_checked : null,
'guard_name' => $permission->guard_name,
'created_at' => $permission->created_at,
];
});
}
and I see in logs:
PermissionCollection $permission
array (
'id' => 1,
'name' => 'App admin',
'is_checked' => false,
)
local.ERROR: Trying to get property 'id' of non-object
The value is valid array, not null.
I mean I have already use this collenction in other part of the app, can I use it without creating a new one...
I think you get this error because you CollectionResource need to object of the Permission model, but in your case it is trying to get id from an array, after map function. Try to extend your model instead of returning an new array

Additional data in Laravel Resource

I use Laravel resource from the controller:
$data = Project::limit(100)->get();
return response()->json(ProjectResource::collection($data));
I like to pass additional information to the ProjectResource. How it's possible? And how can i access the additional data?
I tried like this:
$data = Project::limit(100)->get();
return response()->json(ProjectResource::collection($data)->additional(['some_id => 1']);
But it's not working.
What's the right way?
I like to access the some_id in the resource like this.
public function toArray($request)
{
return [
'user_id' => $this->id,
'full_name' => $this->full_name,
'project_id' => $this->additional->some_id
];
}
In your controller don't wrap return Resource in response()->json.
Just return ProjectResource.
So like:
$data = Project::limit(100)->get();
return ProjectResource::collection($data)->additional(['some_id => 1']);
Sorry for misunderstanding the question.
I don't think there is an option to pass additional data like this. So you will have to loop over the collection and add this somehow.
One option is to add to resources in AnonymousCollection. For example:
$projectResource = ProjectResource::collection($data);
$projectResource->map(function($i) { $i->some_id = 1; });
return $projectResource;
and then in ProjectResource:
return [
'user_id' => $this->id,
'full_name' => $this->full_name,
'project_id' => $this->when( property_exists($this,'some_id'), function() { return $this->some_id; } ),
];
Or add some_id to project collection befour passing it to ResourceCollection.

Find data before validate form request laravel

I want to update the data using the request form validation with a unique email role, everything works normally.
Assume I have 3 data from id 1-3 with url:
127.0.0.1:8000/api/user/update/3
Controller:
use App\Http\Requests\Simak\User\Update;
...
public function update(Update $request, $id)
{
try {
// UPDATE DATA
return resp(200, trans('general.message.200'), true);
} catch (\Exception $e) {
// Ambil error
return $e;
}
}
FormRequest "Update":
public function rules()
{
return [
'user_akses_id' => 'required|numeric',
'nama' => 'required|max:50',
'email' => 'required|email|unique:users,email,' . $this->id,
'password' => 'required',
'foto' => 'nullable|image|max:1024|mimes:jpg,png,jpeg',
'ip' => 'nullable|ip',
'status' => 'required|boolean'
];
}
but if the updated id is not found eg:
127.0.0.1:8000/api/user/update/4
The response gets The email has already been taken.
What is the solution so that the return of the data is not found instead of validation first?
The code looks like it should work fine, sharing a few things below that may help.
Solution 1: Check if $this->id contains the id you are updating for.
Solution 2: Try using the following changes, try to get the id from the URL segment.
public function rules()
{
return [
'user_akses_id' => 'required|numeric',
'nama' => 'required|max:50',
'email' => 'required|email|unique:users,email,' . $this->segment(4),
'password' => 'required',
'foto' => 'nullable|image|max:1024|mimes:jpg,png,jpeg',
'ip' => 'nullable|ip',
'status' => 'required|boolean'
];
}
Sharing one more thing that may help you.
Some person uses Request keyword at the end of the request name. The Update sounds generic and the same as the method name you are using the request for. You can use UpdateRequest for more code readability.
What I understand from your question is, you need a way to check if the record really exists or not in the form request. If that's the case create a custom rule that will check if the record exists or not and use that rule inside your request.
CheckRecordRule
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class CheckRecordRule implements Rule
{
protected $recordId;
public function __construct($id)
{
$this->recordId = $id;
}
public function passes($attribute, $value)
{
// this will check and return true/false
return User::where('id', $this->recordId)->exists();
}
public function message()
{
return 'Record not found.';
}
}
Update form request
public function rules()
{
return [
'email' => 'required|email|unique:users,email,' . $this->id.'|'. new CheckRecordRule($this->id),
];
}
So when checking for duplicate it will also check if the record really exists or not and then redirect back with the proper message.

How can I access data stored as JSON using casts in Laravel?

I entered information into my database like this:
public function addFlight(){
Flight::create([
'name' => 'Sidney',
'address' => [
'street' => 'Williams road',
'suburb' => 'Parow'
]
]);
return "Saved";
}
So, in my database, address is stored as json and I have this done inside my model:
protected $casts = [
'address' => 'array'
];
What I want now, is to get the address information everytime I am looping through the flights.At the moment I have this:
public function getFlight(){
$flights = Flight::all();
foreach ($flights as $flight) {
foreach($flight->address as $address){
echo $address->street;
}
}
}
How do I access the address information(street and suburb) ?
At the moment, if I try to access the getFlights method via url, I get the following error:
Trying to get property 'street' of non-object

Resources