Laravel Resource append locally modified attributes - php

I would like to return a model's Resource while appending a local change to some attributes that already exist in the model (in a way that it does not change database values). What is the correct method to call to achieve this (because append function is not correct)?
// exists $model->currency
// Version: Laravel 7.x
// ModelResoruce is a Illuminate/Http/JsonResource
$tempCurrency = $this->findCurrecy($model->currency);
return ok(ModelResource::make($model)->append(['currency' => $tempCurrency, /* multiple dynamic changes*/]);
// updated: more real scenario:
// $localized has MANY dynamic keys that exist in model but MAYBE different values
$localized= ['currency' => 'x', 'name' => 'y',];
ok(ModelResource::make($model)->append($localized);
// I want: user will see temp but data is not modified
// What happens: append does not change currency's value

This won't modify the database:
$tempCurrency = $this->findCurrecy($model->currency);
$model->currency = $tempCurrency;
As long as you don't call save() on $model later on, the database won't be affected.

Related

php firebase api - delete children element from nested document

I'm using php sdk to delete some fields from firestore database,
i want to delete a map from an array inside a document, but instead the function used delete all maps inside the parent array.
My firestore database looks like this
What i'm trying to do is remove a specific index ex: index 0 with it's children from imageUrls array not all the maps inside it.
I tried these 2 functions :
$usersRef->update([
['path' => 'imageUrls.image_url', 'value' => FieldValue::arrayRemove(['image.png'])]
]);
and this one
$usersRef->update([
['path' => 'imageUrls.image_url', 'value' => FieldValue::deleteField()]
]);
The first function remove all imageUrls childrens and change imageUrls type from array to map, while the second one nothing happened. All the fields still exist in the document and no deletion occurd
<?php
namespace App\Services;
use Google\Cloud\Firestore\FirestoreClient;
use Google\Cloud\Firestore\FieldValue;
use Google\Cloud\Firestore\FieldPath;
class FirebaseService
{
public function delete()
{
// Create the Cloud Firestore client
$db = new FirestoreClient(
['projectId' => 'MyProjectId']
);
$usersRef = $db->collection('NewStories')->document('1');
$usersRef->update(
[
['path' =>'imageUrls.image_url',
'value' => FieldValue::arrayRemove(['image.png'])]
]);
}
}
This can be achieved using the arrayRemove() method. As the PHP Client for Firestore says
Returns a special value that can be used with set(), create() or update()
that tells the server to remove the given elements from any array value
that already exists on the server. All instances of each element
specified will be removed from the array. If the field being modified is
not already an array it will be overwritten with an empty array.
Update:
Firebase does not support updating an existing element in an indexed array.
More information can be found in the Official Documentation.
Workaround:
Reading the entire array out of the document, make modifications to it in memory, then update the modified array field entirely.**
Credits to this Firestore Update single item in an array field case.

Eloquent DB::Post->where()->update() returns 1 always regardless of any changes made

I'm trying to figure out how to properly code the update() function in eloquent to return either 0 or 1 based on user input in a form. For example, if I hit the update button without making any changes, it returns 1. Shouldn't it return 0?
I tried researching for solutions like here in stackoverflow to see if anyone has the same problem as I am facing. But so far not luck. I also tried modifying the code, but no luck.
public function update(Request $request, $id)
{
$UCPost = UCPost::find($id);
$UCPost->gown_2019 = $request->input('Gown2019');
$UCPost->gown_2017_2018 = $request->input('Gown20172018');
$UCPost->gown_2016 = $request->input('Gown2016');
$UCPost->gown_2015 = $request->input('Gown2015');
$UCPost->Light_Blue = $request->input('LightBlue');
$UCPost->Seconds = $request->input('Seconds');
$UCPost->Velveteen = $request->input('Velveteen');
$UCPost->Velveteen_discolored = $request->input('Velveteen_discolored');
$UCPost->Rental = $request->input('Rental');
$UCPost->Rentals_Out = $request->input('Rentals_Out');
$UCPost->Rentals_Left = $request->input('Rentals_Left');
return $UCPost->where('id', $id)->update(
[
'gown_2019' => $UCPost->gown_2019,
'gown_2017_2018' => $UCPost->gown_2017_2018,
'gown_2016' => $UCPost->gown_2016,
'gown_2015' => $UCPost->gown_2015,
'Light_Blue' => $UCPost->Light_Blue,
'Seconds' => $UCPost->Seconds,
'Velveteen' => $UCPost->Velveteen,
'Velveteen_discolored' => $UCPost->Velveteen_discolored,
'Rental' => $UCPost->Rental ,
'Rentals_Out' => $UCPost->Rentals_Out,
'Rentals_Left' => $UCPost->Rentals_Left
]
);
}
The code above as I mentioned earlier, it always returns 1 regardless of any changes made to the form. I want it to return 0 if there are no changes by the user or if they accidentally hit the update button. I'm trying to find the equivalent of mysqli_affected_rows in Eloquent.
You are calling the update() method on your model. This will return 1 if the update was successful. It doesn't matter if there were any changes made, always 1 on successful update.
If you would like to only save to the database if there are changes, you can use the save() method instead, which checks to see if changes are present, and only writes to the database if the data is different. You have already created code to do this, by setting the model to have all of the new data from the sheet, so a simple save() at the end (with a check to see if it saves), will do what you want.
However, your current code is doing a lot of extra work. You are assigning all the variables to the model, and then updating based on that assignment of data to the model. You don't have to do all that assignment again in the update method. Once you have set the fields, you can save immediately, you don't have to re-assign all the variables. So:
$UCPost->gown_2019 = $request->input('Gown2019');
// etc..
$UCPost->Rentals_Left = $request->input('Rentals_Left');
$UCPost->save();
Will get you where you want to go and will only save if different.
If you have control over your form, and can change the form element names to match your database, this can be even easier. You can do all of this in one line:
$UCPost->update($request->all());
If you want to check if the model is dirty just call isDirty():
if($UCPost->isDirty()){
// changes have been made
}
Finally, if you want to verify if anything was changed after either method (save or update):
if ($UCPost->wasChanged()) {
// changes have been made
}
Hope this helps

Output route url with two variables using only ID

If possible..how would this be done? Laravel 5.5
route('section.category.subcategory',$subcategory->id)
must output (routes/web.php has the get:: set as this too)
/section/{parent_slug}/{subcategory_slug}
I could easily do
route('section.category.subcategory',[
'subcategory_slug' => $subcategory->slug,
'parent_slug'=>$parent->slug
]
);
but I'm trying to avoid having to declare those things all the time.
I thought getRouteKeyName in model would be first place to go to, but it binds to only one variable as far as I could find.
RouteHandler isn't the place to do anything either because it reads the url, not outputs it right?
I'm assuming in some file that I don't know about I will have to set this sort of logic.
if(requested_route is section.category.subcategory)){
// get the parent_id of ID provided,
// get parent's slug
// build the url.
}
Even better, I think I could do a left join when pulling the list of subcategories, so I have $subcategory->parent_slug instead of going for $parent->slug. This way
route('section.category.subcategory',[$subcategory])
has all the variables it needs to work with.
I think for this helper would be a good choice so you could create url like this:
route('section.category.subcategory',build_category_parameters($subcategory))
and you can create function like this:
function build_category_parameters($subcategory)
{
// here any logic that is needed
// here return array something like this
return [ 'subcategory_slug' => $subcategory->slug,
'parent_slug'=> $subcategory->parent->slug
];
}
If you don't have helper file already you can create one using this way Laravel - require php script in a service provider

Laravel passing over variables to functions

I create a GUID everytime a new database entry is being made and will be saved with the database entry to the database. The GUID should be my unique reference for further usage as reference to this entry. This part works fine.
My question: I need this GUID to perform a seach afterwards in the database for this entry, as another function needs the database entry details to work. As all the necessecary information is only created before saving to the database, how do I get a hold of this variable GUID to be used in another function?
public function createIncident(PrepareIncidentRequest $request)
{
$incidentReference = TicketSystem::generateIncidentReference();
$incidentID = TicketSystem::generateIncidentID();
$data = $request->all();
$data = $data + [
'incident_reference' => $incidentReference,
'incident_id' => $incidentID,
];
$incident = Incident::create($data);
Auth::user()->incidents()->save($incident);
}
When the entry is saved, and for example this would happen 100times in an hour, how do I know what to search for in another function? So how do I "pass over" this GUID I created in the function above to be used in another function?
For example here: I want to search for a user, and all the info needed is in a specific database entry. This entry could be found with the GUID I created. But as soon as it is saved, I need a way how to know, what to search for in another function when I want to retrieve the info.
If you need to persist data between the page views then session is the way to do it.
Add data to session like this
Session::put('key', 'value');
And read like that
Session::get('key');

Laravel Updating Record with optional image

I'm trying to recreate a simple blog functionality and allowing an admin to update a blog post.
My problem is the photo that has its name stored in the blog table under 'thumbnail' is not getting updated correctly. My save a new post function works but my update function does not work.
When you do an update without updating the image the rest of the blog items get updated but the photo name get set to blank and if you do try to update the image the photo does get moved but the field in the database is getting set to the temporary location (/Applications/MAMP/tmp/php/phpx1jwMA).
That may be two separate issues.
In the update form I added a hidden field with the photos name:
{{ Form::hidden('old_photo', $blog->thumbnail) }}
And it produces this in the form as expected:
<input name="old_photo" type="hidden" value="1391122313-2013 12 01_0567.JPG">
And in my controller I have this as my update function:
public function update($id) {
$input = Input::all();
$blog = Blog::find($id);
if(Input::hasFile('thumbnail')) {
$file = Input::file('thumbnail');
$name = time() . '-' . $file->getClientOriginalName();
$file = $file->move(public_path() . '/images/blog/', $name);
$blog->thumbnail = $name;
}
$blog->save();
return View::make('admin.blog.index', [
'blogs' => Blog::all()
]);
}
I'm trying to say in that code that if there is a new file in the thumbnail then create a unique name, move the file and set 'thumbnail' to that name (That is how my create function works) but if there has been no uploaded file to 'thumbnail' then set the 'thumbnail' to the old name.
Is there a better way to handle this process? Obviously there is because this way does not work. I am just learning Laravel and I have 3 books on it but none of them cover how to do this.
Thanks.
Instead of $blog->update($input); use $blog->save();. You already modified the model, just save it. With the update() method, all key/value pairs of the array you pass in will be assigned to the model.
Also you don't need your else case. If you don't want to change a models property just don't do it. You don't need to assign the value explicitly if you don't want to change it.
Omit your else case.
Side note on that:
Assigning Model properties manually e.g.
$model = Model::find(5);
$model->prop = 'val';
$model->save();
is better most of the time than Mass Assigning them e.g.
$model->find(5)->update($newvalues);
You have more control over what get's inserted and updated, when mass-assigning you have to take care of what's going to be assigned otherwise just every property could be changed. That's a security issue. (However laravel comes with $guarded and $fillable)
Also in your case you would not want to pass the whole input since you probably don't want certain fields to get updated if they did not change. So if nothing changed you had to explicitly exclude the Key/Value pairs you don't want to update when you just pass your whole Input to it (this is because the keys exist but the values are empty).
Well you get what I mean. When you assign your values manually you have full control on when and what you assign.
Happy Coding!

Categories