CakePHP: Use Inflector Class over whole array - cakephp

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.

Related

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.

Map as return type of #MatrixParameter

The Rest-api we are building we need some sort of filtering system to prevent too much (useless) data to be transfered to our client. The use of #MatrixParameter seems like a nice solution since this allows a readable way to filter on multiple 'levels' of the URI
However in our api we have fields our clients would like to filter on which are not defined on compile time (and can be different per client). This makes is infeasable to speficy these fields on the #matrixParam annotation.
So i was hoping there would be some way to use a Map as receiving 'bean' object
ie: when i do a GET on
https://api.example.com/rest/filtered_get;param1=value1;param2=value2/optional/continuation/of/uri/
would end up with in map containing param1,param2 as keys and value1 and value2 as values
#Get()
#Path("filtered_get")
public Response getter(#matrixParam("") HashMap<String, String/Object>parameters) {
//doStuffWiththeParameters;
}
The Service is being implemented with cxf
I think i have this figured out.
The trick is to use the PathSegment variable
usinge the code like so:
#Path("/filter{reference_to_pathParam}")
public RestEntityService<T> search(#PathParam("reference_to_pathParam") PathSegment p) {
MultiValuedMap<String,String> matrix = p.getMatrixParameters();
// doStuff with the matrix parameters
}
allows you to use unspecified matrix parameters in your URI like:
https://api.example.com/rest/../filter;field=value;field2=value2/rest/of/the/URI/
and get those fields in the matrix (map)
Note that i'm using a explicit pathsegment for this filter. This is because if i would use something like #path("/{filter}") as annotation it would interfere with other selectors using pathparameters.
Not marking this as answer yet because i dont know if there might be better/cleaner ways to do this.

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.

Redundant ModelName in CakePHP find Results

I am trying to get rid of the redundant model names in the results array returned by the find method in CakePHP. As it is now, if I were to do something like $results = $this->Model->find('all'), I would have to access a result field by $results[Model][fieldName] instead of $results[fieldName].
I understand that having the model name in the array has benefits but I am trying to build an api so I need to json encode the array. With the model name included I get something hideous like:
[{"Model":{"field":"blah","field":"blah"}},{"Model":{"field":"blah","field":"blah"}}]
I want something more elegant like:
[{"field":"blah","field":"blah"},{"field":"blah","field":"blah"}]
Any ideas?
In your controller, instead of serializing the results of the find, serialise a level deeper.
Assuming CakePHP 2:
$things = $this->Thing->find('all');
$things = Set::extract('/Thing/.', $things);
Now your results should be free of the extra level in your JSON.
The alternative, lengthy way of doing it is to for loop over the results:
foreach ($things as $k => &$v) {
$v = $v['Thing']
}
After that, your $things will have removed the extra level of keys.
For later versions of Cake, use $things = Set::extract($things, '{n}.Thing');

EXTJS - How to verify if element exists?

I need to know if a boxComponent exists in a ext formPanel in order to take some actions... Is there some way to know that?
something like this:
if(getElementById("boxId") != 'undefined' ){
alert('exists');
}
The common pattern that most people use is this:
var myBoxCmp = Ext.getCmp('cmpId');
if(myBoxCmp){
myBoxCmp.doSomething();
}
Same thing for Elements:
var el = Ext.get('elId');
if(el){
el.doSomething();
}
You can also use methods like Container.findById, but if you have an id (assuming it is unique, which it should be) just use getCmp.
EDIT: Several years have passed since this original answer, and nowadays getCmp is generally frowned upon as a code smell and should typically be avoided in applications (promotes global references, which generally indicate poor design when they are required). It's typically better to use controller references (if using MVC) or the various ComponentQuery or Container methods to reference related components (e.g. down, child, getComponent, etc.)
I just do it the extjs way and i prefer not to use getElementById() which is a native js method and may cause incompatibility issues in diffrenet browsers:
if (!Ext.getCmp('componentid')) {
alert('boxId is empty');
}
You can use Ext.get('boxId'). It returns null if the object doesn't exist and returns an Ext.Element object.
Using getElementById would probably be much faster though. Do you have any specific objection against it?
Use the Ext.isEmpty(object) method.
if(Ext.isEmpty(getElementById("boxId")) {
alert('boxId is empty');
}
function openView(cid) {
shortName = cid.substr(cid.lastIndexOf(".")+1, cid.length);
if(Ext.get(shortName) == null) Ext.create(cid);
Ext.Viewport.setActiveItem(Ext.getCmp(shortName));
}
This function opens a view like
openView('MyApp.view.Oeffnungszeiten');
and if the View exists it accesses the old instance

Resources