Invalidate Fields from Multiple Models - cakephp

I have a form with multiple models in it. The validates in the models seems correct and the models are associated properly. But how do I invalidateFields from two models and pass the display error back to the form?
Code in my users)_controller.php is:
$errors = $this->User->invalidFields(array('fieldList' => array('password','cpassword','firstname','lastname','email')));
$this->User->set('errors',$errors);
But I have a Profile model chained like this:
$this->User->Profile
and want it to invalidFields to Profile.zip.

you can use chained if clauses like described at
http://www.dereuromark.de/2010/10/09/about-php-basics-and-pitfalls/
basically, you use & instead of &&
so if you got a main model and related data:
$this->User->set($this->data);
$this->User->Profile->set($this->data);
if ($this->User->validates() & $this->User->Profile->validates()) {
//continue
}
the single & makes sure that both conditions are executed (with && you would only trigger the first one if there was an error and therefore the validation rules would not get rendered for the related model)
you could also do:
$val1 = $this->User->validates();
$val2 = $this->User->Profile->validates();
if ($val1 && $val2) {}
this way they both get executed before you go into the if clause.

Instead of manually setting errors in the invalid fields array, I would suggest to use the $validate array to set up validation rules.
You can define your own, complex rules if the built in ones are not enough.

Related

FireStore and maps/arrays, document-list to array in Kotlin

I've finally started to understand a lot of info regarding FireStore, but I'm wondering if I can get some assistance.
If I had a setup similar to or like this:
          races
                Android
                      name: Android
                      size: medium
                       stats          <---- this is the map
                                str: 10
                                sex: 12.... (more values)
How would I parse this? I am looking to make specific TextViews apply values found in the database so that I can simply update the database and my app will populate those values so that hard coding and code updating won't be nearly as troublesome in the future.
I currently use something like this:
val androidRef = db.collection("races").document("Android")
androidRef.get().addOnSuccessListener { document ->
if (document != null) {
oneOfTheTextViews.text = document.getString("str")
} else {
}
The issue is currently I can only seem to access from collection (races) / document (android) / then a single field (I have "str" set as a single field, not part of a map or array)
What would the best practice be to do this? Should I not nest them at all? And if I can reference said nesting/mapping/array, what functions need to be called? (To be clear, I am not asking only whether or not it is possible - the reference guides and documents allude to such - but what property/class/method/etc needs to be called in order to access only one of those values or point to one of those values?).
Second question: Is there a way to get a list of document names? If I have several races, and simply want to make a spinner or recycler view based on document names as part of a collection, can I read that to the app?
What would the best practice be to do this?
If you want to get the value of your str property which is nested within your stats map, please change the following line of code:
oneOfTheTextViews.text = document.getString("str")
to
oneOfTheTextViews.text = document.getString("stats.str")
If your str property is a number and not a String, then instead of the above line of code please use this one:
oneOfTheTextViews.text = document.getLong("stats.str")
Should I not nest them at all?
No, you can nest as many properties as you want within a Map.
Is there a way to get a list of document names?
Yes, simply iterate the collection and get the document ids using getId() function.

How to iterate through object array with form helpes in cakephp?

I have an object CuratedPage with property pageName.
I am creating an array of CuratedPage objects in controller and setting it for the view like this:
$this->set('curatedPages', $curatedPages);
In the view I am creating a dropdown of page names like this:
$pageNames = array();
foreach($curatedPages as $curatedPage) {
array_push($pageNames, $curatedPage->getPageName());
}
echo $this->Form->input('curatedPage', array('options' => $pageNames));
Is there a way in cakephp that will allow me to pass the array of CuratedPage objects to the Form->input(...) instead of creating an array of scalar values.
I'm not sure what you would expect the form helper to do in that case. However, depending on your PHP version (>= 5.2.0 required) the magic __toString() method might do it. If you implement it to return the pagename, then you would end up with the same result as with your posted snippet, ie an numerical indexed (the value attribute) HTML option list with the page names as labels.
However, implementing this only for that purpose in this specific view seems wrong to me, you're probably better of utilizing a custom helper, or as #BrianGlaz suggested prepare the data in the controller.

Is it better to manipulate $data for the AppHelper or use conditions to parse $data in it?

In these days I thought on how to work better with AppHelpers in CakePHP. I thought to use the AppHelper to make links and other html elements consistent depending by the context i need, for example, for users I have the method
$this->AppUser->profile($data, $options, $attributes);
this method returns a link styled for the users, with a specific css classes, maybe something line this:
<a class="user female" href="http://url/profiles/username">Username</a>
My problem is the data is structured differently by the situation, in some case I have an array like this:
$data['User']['id']
$data['User']['username']
$data['Profile']['user_id']
$data['Profile']['sex']
$data['Profile']['other']
And in some other cases, with different queries and different entities I have this:
$data['User']['id']
$data['User']['username']
$data['User']['Profile']['user_id']
$data['User']['Profile']['sex']
$data['User']['Profile']['other']
So I would like to understand if I missing something in the data hierarchy because it should be always structured in the same way?
And so should I to send data to the Helper always structured in the same way?
Should I let the helper parse the data depending by the situation, so with conditions to find where the data is?
That's pretty common, and is a result of finding related items multiple levels deep. I usually have a helper method on the Helper that normalizes the data.
I would always send the data to the helper as-is, and then restructure it as needed within the helper. It would look something like this:
function normalizeUserData($data) {
foreach ($data['User'] as $field => $value) {
if (is_array($value)) {
// move it to the same level as User
$data[$field] = $value;
unset($data['User'][$field]);
}
}
}
Now your functions can always expect the Profile data on the same level as the User key. This function isn't perfect and isn't recursive, but should give you a good start.

CakePHP: Use Inflector Class over whole array

I need to use Inflector::slug() over all results fetched from my database, which are, of course, retrieved in an array. Is it possible somehow, or I'll need to loop each result and slugify it?
Thanks!
PHP's array_map() function might do what you need (although it assumes a simple indexed array).
array_map( 'Inflector::slug', $your_result )
If you're looking at something more complex, CakePHP's Set utility class may be helpful in a multi-step implementation.
I haven't tried this in a CakePHP context (i.e. mapping through a CakePHP class method), but I can't think of any reason it wouldn't work off the top of my head. Maybe it'll at least get you started.
Depending on the array you can use array_walk or array_walk_recursive.
Something like this should work.
This is for 5.3+;
array_walk_recursive($posts, function(&$value) {
$value = Inflector::slug($value);
});
If you wanted to limit it to a certain field you could also do something like this:
array_walk_recursive($posts, function(&$value, $key) {
if ($key == 'title') {
$value = Inflector::slug($value);
}
});
I haven't used Cake in a while but like Rob Wilkerson said, you might find that the Set class could make lighter work of this.

Where do I define view functions in CakePHP?

I have a modifier procedure to show the "date" of an event.
if($event['Event']['is_multi_day']){
if( date('n',strtotime($event['Event']['start_day']) ) == date('n',strtotime($event['Event']['end_day'])) )
$date = date('j',strtotime($event['Event']['start_day'])).' - '.
date('j',strtotime($event['Event']['end_day'])).' '.
date('M',strtotime($event['Event']['end_day']));
else
$date = date('j',strtotime($event['Event']['start_day'])).' '.
date('M',strtotime($event['Event']['start_day'])).' - '.
date('j',strtotime($event['Event']['end_day'])).' '.
date('M',strtotime($event['Event']['end_day']));
}else{
$date = date('j M', strtotime($event['Event']['start_day']));
}
I have to include that code block in every page I display an event.
How do I define a function for this, which can be called from views I want?
Looks to me like you're going to be using this in a loop that displays a number of events and your code will be far from optimal in that situation.
I think you can reduce this line:
if( date('n',strtotime($event['Event']['start_day']) ) == date('n',strtotime($event['Event']['end_day'])) )
)
to:
if($event['Event']['start_day']==$event['Event']['end_day'])
(or something similar that compares the stored value without formatting. Formatting is for display purposes, not algorithmic comparison)
and this:
date('j',strtotime($event['Event']['end_day'])).' '.date('M',strtotime($event['Event']['end_day']));
to:
date('j M',strtotime($event['Event']['end_day']));
...and similar edits elsewhere. If this is in a loop, you need to reduce the number of unnecessary function calls and avoid concatenation of strings.
Personally, as this is a display function, I'd keep it on the view side of things (as opposed to the controller) and I'd probably do it as an element with passed parameters - see http://book.cakephp.org/view/560/Passing-Variables-into-an-Element
I would create a helper for this. For me it's more sensible rather than a component. If you using this data only to display it I believe that Helper is the proper solution. How to build custom helper
If it's raw data that you're manipulating (as shown) and you just want to return a value for display, I'd create a component and do it at the controller level. If you want to include presentation markup and/or logic, then an element is probably what you're looking for.

Resources