How to have a dehydrated function in edit operation but not in create operation

Hi community - hoping someone could point me in the right direction. In my user resource, I have the form function contain ->dehydrated(function (?array $state, ?Model $user){...} that should only be used on the edit page. However the form logic currently serves both the create and edit form. I'd like to separate the two. However on the create user page, this dehydrate call will attempt to instantiate a $user model but it's obviously not instantiable on create (since the user hasn't been created yet). How can I only have the dehydrated call occur on the edit operation but not on the create page? Like how can I split up the form function based on whether its on the create or edit page?
public static function form(Form $form): Form
...
....
Select::make('roles')
->relationship('roles','name',self::getRoleOrder())
->preload()->searchable()->label('Primary User Role')->default('Restricted')
//Only have the following dehydrated function run on edit page - not on create
->dehydrated(function (?array $state, ?Model $user,){
//check if role ID is same as whats in the db
$initialRoles = $user->roles->pluck('id');
$stateRole = current($state);
//ray($initialRoles, $stateRole);
$hasChanged = $initialRoles !== $stateRole;
if(!$hasChanged){
//if changed, prevent field from being returned by dehydrate(false)
return false;
}
return true;
})->required(self::isCreating())
])->columns(2),
public static function form(Form $form): Form
...
....
Select::make('roles')
->relationship('roles','name',self::getRoleOrder())
->preload()->searchable()->label('Primary User Role')->default('Restricted')
//Only have the following dehydrated function run on edit page - not on create
->dehydrated(function (?array $state, ?Model $user,){
//check if role ID is same as whats in the db
$initialRoles = $user->roles->pluck('id');
$stateRole = current($state);
//ray($initialRoles, $stateRole);
$hasChanged = $initialRoles !== $stateRole;
if(!$hasChanged){
//if changed, prevent field from being returned by dehydrate(false)
return false;
}
return true;
})->required(self::isCreating())
])->columns(2),
Solution:
You’re logic might be backwards. You’re returning true if it’s on create. Could also use an additional check if $user is null or not. Might also need to use $record instead of $user.
Jump to solution
9 Replies
awcodes
awcodes8mo ago
Not sure if it’s injectable on dehydrated but you can try injecting $operation then checking if it’s equal to ‘edit’ or ‘create’ to run your logic.
ashattack
ashattack8mo ago
Hi @awcodes - thank you for your response and helping me! So the logic for dehydrate is only needed on the Edit page for Users. So even if I inject the $operation, I will get an error because the dehydrate function contains a parameter that only exists for users that have been already created (i.e when you edit a user). Target [Illuminate\Database\Eloquent\Model] is not instantiable. Since on create operation there is no $user model because the user hasn't been created yet. ->dehydrated(function (?array $state, ?Model $user,string $operation){ Any way I could accomplish something equivalent to wrapping the ->dehydrate() around an ifOperation('edit') == true?
Here is how I injected the operation per your suggestion which threw the error:
Select::make('roles')
->relationship('roles','name',self::getRoleOrder())
->preload()->searchable()->label('Primary User Role')->default('Restricted')
//Only have the following dehydrated function run on edit page - not on create
->dehydrated(function (?array $state, ?Model $user,string $operation){
if($operation === 'edit'){
//check if role ID is same as whats in the db
$initialRoles = $user->roles->pluck('id');
$stateRole = current($state);
//ray($initialRoles, $stateRole);
$hasChanged = $initialRoles !== $stateRole;
if(!$hasChanged){
//if changed, prevent field from being returned by dehydrate(false)
return false;
}
}
return true;
})->required(self::isCreating())
Select::make('roles')
->relationship('roles','name',self::getRoleOrder())
->preload()->searchable()->label('Primary User Role')->default('Restricted')
//Only have the following dehydrated function run on edit page - not on create
->dehydrated(function (?array $state, ?Model $user,string $operation){
if($operation === 'edit'){
//check if role ID is same as whats in the db
$initialRoles = $user->roles->pluck('id');
$stateRole = current($state);
//ray($initialRoles, $stateRole);
$hasChanged = $initialRoles !== $stateRole;
if(!$hasChanged){
//if changed, prevent field from being returned by dehydrate(false)
return false;
}
}
return true;
})->required(self::isCreating())
awcodes
awcodes8mo ago
Can you dd($operation) to make sure it’s injectable there. I just don’t remember. Try $context too.
ashattack
ashattack8mo ago
@awcodes just checked I believe so! When I do ->dehydrated(function (string $operation){ and dd/ray($operation) it does output create. However if i include ?Model $user in the dehydrated function, it will only work when I'm editing an existing user. When i create a new user and hit create user it will perform an error because $user can't be instantiated because I believe it assumes it exists, which it doesn't if on the create operation. My latest attempt - I thought ?$model $user if not instantiable - would return null. Target [Illuminate\Database\Eloquent\Model] is not instantiable. Type Illuminate\Contracts\Container\BindingResolutionException
->dehydrated(function (?array $state, ?Model $user,string $operation){
if(is_null($user)){
return true;
}
if($operation === 'edit'){
//check if role ID is same as whats in the db
$initialRoles = $user->roles->pluck('id');
$stateRole = current($state);
//ray($initialRoles, $stateRole);
$hasChanged = $initialRoles !== $stateRole;
if(!$hasChanged){
//if changed, prevent field from being returned by dehydrate(false)
return false;
}
}
return true;
})->required(self::isCreating())
->dehydrated(function (?array $state, ?Model $user,string $operation){
if(is_null($user)){
return true;
}
if($operation === 'edit'){
//check if role ID is same as whats in the db
$initialRoles = $user->roles->pluck('id');
$stateRole = current($state);
//ray($initialRoles, $stateRole);
$hasChanged = $initialRoles !== $stateRole;
if(!$hasChanged){
//if changed, prevent field from being returned by dehydrate(false)
return false;
}
}
return true;
})->required(self::isCreating())
Solution
awcodes
awcodes8mo ago
You’re logic might be backwards. You’re returning true if it’s on create. Could also use an additional check if $user is null or not. Might also need to use $record instead of $user.
awcodes
awcodes8mo ago
Not fully following but my gut is telling you’re doing things backwards. I could be entirely wrong though.
ashattack
ashattack8mo ago
Sorry there, I really do appreciate your patience. Your gut is right - initially I thought I had to dehydrate the roles field since I had a session reset error and added the dehydrate function so that if the role of the user in the database didn't change from what was in the field - to not send the role back to the server... However the true reason for that was because my chrome autofilled my password in the Edit page on my frontend even though ->autocomplete for password field was set to false. That let me assume it was due to the role being re-assigned - but it turns out it was because it reset my password even though it was the same because my chrome injected my saved password onto the user-edit form - something that would only happen if the logged in admin edits its own user if their chrome browser happened to autofill the password field faceplam.... The dehydrate ended up working on edit user, but then it failed when creating a user...in my incognito browser - which conveniently caused chrome not to auto inject the password causing me to not realize what the actual problem was... Turns out I spent over an hour trying to debug the dehydrate function when I didn't even need it 😢 At least I learned some stuff. Thank you and sorry for wasting your time!
awcodes
awcodes8mo ago
It’s never a waste of time if you learned something.
ashattack
ashattack8mo ago
@awcodes that's the attitude! Thank you ❤️