CakePHP 3 How to detect if an entity field is changed - cakephp

I'm developing a CakePHP 3 application.
Now, i need to encrypt some data with SHA1 before the save of the entity.
I tried the beforeSave() callback in Table Object, like in CakePHP 2.x, but it doesn't work.
So, i discovered that type of change (update data on beforeSave/beforeUpdate) in current version, needs to be adapted to accessors & mutators, like the docs says (http://book.cakephp.org/3.0/en/orm/entities.html#accessors-mutators).
Documentation even has a note about check if an entity field was modified (http://book.cakephp.org/3.0/en/orm/entities.html#checking-if-an-entity-has-been-modified) but i dont understand how to use this.
I need some simple logic, just like an authentication system.
Before Save, in User Model, the field responsible_card_password must be hashed with SHA1 if this is filled. If isnt filled, the field stays the same.
Currently, with the acessors and mutators method, if i put the field on form blank, the entity save this field blank.
How i can solve this? Very thanks CakePHP developers on the world! :-D

you can add code in your entity table to auto hashing password
protected function _setPassword($password)
{
return (new DefaultPasswordHasher)->hash($password);
}

Related

How to save a recordset without overwritting existing records with Cakephp 3

Is there an easy way to save a recordset, i mean multiple records, but only the "new ones"?
I have a table users and a users form in the view. First field you must enter is passport number, so if user already exists in database the rest of the form will be auto completed and disabled to prevent changes but if passport dont exist then you have to enter all data. As anyone can change those existing users data controls from the browser even if they are disabled, i want to make sure only new records are saved in database. First of all i thought i could find again in database and delete existing users from recordset before save, but i wonder if there is a more elegant approach.
Ty in advance.
I write this here, cause comments are too short:
Thank you for your answer, André. I'm sorry if i didnt explain perfectly, but the form is done by disabling all controls except passport and if passport dont exist (i check it on passport focusout) then the rest of controls are set to enabled. I mean, that is already done. The question was only about the saving.
The validation method you talk about, well i'm actually validating all the controls in the form and i must disable the 'unique' rule so a user can link an existing user to the current bill, otherwise it will fail validation on submit and it wont allow the user to proceed (i did this because it happened to me when testing). The actual setting is much more complicated: the form belongs to a model (bills) which is associated with 4 other models and 2 of those relationships are many to many, bills_users and bills_clients, where users are the persons who do the job and clients pay for it, but I was trying to make the question easier. Anyway, what I am looking for is, in fact, some kind of saving setting which I can't find. In documentation I found "When converting belongsToMany data, you can disable the new entity creation, by using the onlyIds option. When enabled, this option restricts belongsToMany marshalling to only use the _ids key and ignore all other data." The first half of the sentence was promising, but the explanation says different, and I actually tried it without success.
First:
Is there an easy way to save a recordset, i mean multiple records, but only the "new ones"?
Yes there is you can validate it in model, something like this:
public function buildRules(RulesChecker $rules)
{
$rules->add($rules->isUnique('passportNumber'));
return $rules;
}
This will prevent to save a duplicate passport number register, but you can different.
I have a table users and a users form in the view. First field you must enter is passport number, so if user already exists in database the rest of the form will be auto completed and disabled to prevent changes but if passport dont exist then you have to enter all data.
There is two different ways to do this:
First you have your form, you develop an ajax function when you fill the first field (passport number) this ajax function do a request to your controller to search for a passport with that number if find something get data and fill others fields and turn them just readable, else just nothing and let user fill the fields by himself
second add a step-by-step where you first do a form to try find by pass number, user fill this only field with a number then submit, on submit this search for a record, if find fill the entire next step fields, else the next step will be the rest of form with the fields to be filled.
This may help you too: https://book.cakephp.org/3.0/en/orm/validation.html
Tell me how you decided to do :)

CakePHP - Prevent model data being save in a saveMany call when certain fields are blank

I have scenario where I have 3 different models data being saved from one form, by means of the saveAll pass through method in CakePHP 2.x
The models on the form are:
Project
ProjectImage
ProjectAttachment
1 and 2 are saving perfectly, but I am having problems with the ProjectAttachment fields. If you look at the following image, the fields in question are at the bottom right, highlighted by a red frame: http://img.skitch.com/20120417-bnarwihc9mqm1b49cjy2bp13cf.jpg
Here is the situation:
I have named the fields as follows: *ProjectAttachment.0.project_id*, ProjectAttachment.0.name .... *ProjectAttachment.6.project_id* etc where the numbers are relative to the already present amount of attachments the user has added, as there is no limit. So if the user has ALREADY added 6 documents, the field would be called ProjectAttachment.7.id and so on. This is because of the naming convention when using the saveAll method.
I have made use of two hidden fields, one to store the user ID, the other to store the project ID.
The problem is that if the user does not fill in the Document Title and select a file to upload, the form fails! If I remove all validation rules, the form no longer fails BUT a blank ProjectAttachment record is inserted.
I suspect the problem may also be that the project_id and user_id fields (that are hidden) already have values in them?
I gave it some thought, and came up with a simple concept: In my controller, before the saveAll call, I would check to see if a blank Document Title field was submitted, and if so, I would completely eliminate the relevant array entry from the $this->request->data['ProjectAttachment'] array, but this did not seem to work.
To clarify, I am not looking for validation rules. If the user decides they only want to upload images and not touch the ProjectAttachment form, them the saveAll operation must not fail, it must simple not attempt to save the blank fields in the form, if this is at all possible.
Any suggestions?
Kind regards,
Simon
Well it seems that the solution was far simpler than I had initially thought! I was partially on the right track, and I had to unset the variable ProjectArray key in the $this->request->data array if I had encountered any blank fields.
I did this as follows:
if(!empty($this->request->data['ProjectAttachment'])){
foreach($this->request->data['ProjectAttachment'] as $key => $value){
if(is_array($value) && array_key_exists('upload_file', $value)){
if($value['upload_file']['name'] == ''){ // Blank document file
unset($this->request->data['ProjectAttachment']);
}
}
}
}
I hope someone finds this somehow useful in some form or another.
Kind regards,
Simon

Codeigniter - Data for database from Input class or Form Validation class?

I'm building my first CodeIgniter app - and have a registration form. I'm using the built-in form validation class to validate the data, and am at the point of adding that data to the database.
Should I be taking that data from the form validation class or from the input class ($this->input->post('username'))?
I'm guessing the correct way is from the input class, but just wanted to be sure. If that's the case, if there any prepping of the data I need to do before it gets inserted into the database such as 'trim'?
Thanks
Yes you would get the data from the input class. Operations such as trim() can be done using the form validation library by adding the trim to the set of rules for validation. When the validation is done, your data is ready to be inserted to the database.
I've always used $this->input->post('lalal'); and found it to work since the validation is already done when i use the values. But you could also use the set_value('lalal'); helper function, this is particularly useful if you found an error but don't want the user to entery every form field again but just the one that was faulty.
Your prepping of the data should be in the validation rules, you can add any php-functions that take one argument, ie trim, also you can call on the helper functions CI offers if they are loaded when the validation happens. And you have the built-in's that CI has with the validation class.
For more info check out: http://codeigniter.com/user_guide/libraries/form_validation.html#thecontroller

Making Related Models Optional

I have a form where a user can enter a location address as well as the utility companies that provide service to that address. The Utility data is associated to the building:
Location hasMany Utility
Solely within the context of the utility, the name field is required so there's validation indicating as much. Within the context of a location, though, any utility information is optional. The user can choose not to enter that data when entering a location which would simply indicate that they don't want to associate the location with any or all of the utility companies we track.
Using the FormHelper, though, the validation is detected and the field gets marked as required. I want to retain that validation for the instances where utility data is being entered independently, but remove the required indicator on the location form.
I know I can hack this in any number of ways (e.g. removing the required class via javascript, etc.), but I'm wondering if there's a clean way to do this using the Cake API. I haven't seen anything obvious, so I'm hoping someone else has been here and found a clean, simple solution.
Thanks.
You can either ask the user how many utilities they want to add before creating the form, or you can add the Utility record inputs dynamically using js (the later is more work to do, and not as error-proof as the former).
An example of the view (if you want to do it in 1 view):
if (empty($this->data){
// a form to ask how many utility records the users want to create.
}else{
// generate the form based on user input.
}
I assume you know what to do in the controller.
I would add a class to the form element that are optionnal, and use that class to override the "required" indicator.
In fact there is a Cake solution, use the error param
$this->Form->input('Model.field', array('error' => false));
To disable error message output set the error key to false.

Django: cannot detect changes on many-to-many field with m2m_changed signal - auditing at model-level

I'd like to keep track on what field has changed on any model (i.e. audit at model level since it's more atomic, not at admin/form-level like what django and django-reversion can already do). I'm able to do that for any field using pre/post save/delete signals. However, I have a problem of doing that on an m2m field.
For the code sample below, i define 'custom_groups' m2m field in user change form since it's a reverse relation. When user saves the form on admin interface for example, I'd like to log if there's a change in 'custom_groups' field.
Model:
from django.contrib.auth.models import User
class CustomGroup(models.Model):
users = models.ManyToManyField(User, related_name='custom_groups')
ModelForm:
class CustomUserChangeForm(UserChangeForm):
custom_groups = forms.ModelMultipleChoiceField(required=False, queryset=CustomGroup.objects.all())
The problem with using m2m_changed signal is that i can't check what has actually changed for the case where the m2m field is updated using assignment operator:
user.custom_groups = self.cleaned_data['custom_groups']
This is because internally django will perform a clear() on *custom_groups*, before manually adding all objects. This will execute pre/post-clear and then pre/post save on the m2m field.
Am I doing all this the wrong way? Is there a simpler method that can actually work?
Thanks!
I had a similar problem and I think I could solve it. I don't know how you are using the m2m_changed but it should be on models.py and should be similar to something like this:
signals.m2m_changed.connect(your_function, sender=CustomGroup.users.through)
Now, I would create a signals.py file containing that function, and the following code should print you the options that you have selected:
def your_function(sender, instance, action, reverse, model, pk_set, **kwargs):
if action == 'post_add':
for val in pk_set:
print val
Now, you know the updated values. I hope this could solve your problem.

Resources