Map Reduce help? also… *really* frustrated with the new ORM docs…

The 3.x ORM documentation is severely lacking considering the dramatic changes from 2.x

(1) There are no complete examples showing how to retrieve recordsets within a controller without using paginate(). It took me trial and error and a lot of piecing together of bits strewn about in the docs and the web to figure out how to make an actual find() call… and I still don’t understand how to use this thing and how it differs from the results of a paginate() call or why I can’t use a paginate() call in the same way as a find() call.

(2) The new ORM is a black box. Debug doesn’t work anymore so there’s no way to see what state it’s in. You can’t iterate through it anymore to add/edit/remove properties.

(3) Related to the above, if you want to add/edit/remove properties, the only way to do so now is to use Map Reduce… another black box. The documentation for this piece of kit is, realistically, almost totally usable. Sure, now I can copy the code from the docs and directly change ONE field in each record, provided it fits the format of the example. But nowhere is it explained how each argument is passed in or out of each of the functions, it’s not explained when the functions have to be used inside the controller method, it’s not explained what emit or emit intermediate does or how the two differ or even whether they are mandatory or not, it’s not explained what is native code for each function and what is custom to each example, it’s not explained how to apply map and reduce to multiple different fields in each record or how to create and add new fields to each record, it’s not explained whether you always need reduce or if you can achieve some things with just map… and it’s not explained how to pass your modified recordsets back to your view.

In the past, customizing recordsets was easy as pie… you pull a find(all) and iterate through each record, run your transformations or calculations on the necessary fields, then save the changes back to the actual record. Then set() your recordset back to your view just as it is in the docs. In other words, in between the cake magic of calling the database and the cake magic of handing off the data to your view, you, as a developer, had complete freedom to intercept the data and do whatever you wanted, no matter how arcane or complicated (hand off data to external functions and run advanced statistical analysis even) and everything would just work.

I’m hopeful that it’s all still wonderful and cakey-magicky-awesome like that, albeit just a little too black-boxy and undocumented.

tl;dr

Someone please point me to thorough documentation on cake’s Map Reduce, how it logically flows, what the inputs and outputs are, and with some nice semi-advanced use cases that show the entire controller code used.

Alternatively, tell me some other way to manually intercept and modify a recordset before handing it to my view (i.e. add/edit/remove individual fields to each record depending on the values of other fields)

1 Like

I agree that it can be difficult to find what you need in the docs, although half the time you end up seeing it after an hour right there, clear as day, and you ask yourself how you could possibly have missed it XD

But I would really love if there was a way to add user comments to parts of the documentation similar to php.net to clarify how to use particular tools. I’ve seen countless parts of the docs that are really hard to understand at first (conceptually), these could benefit greatly from practical examples, ideally from “regular” Cake users, because the core devs understand it too well, so they often skip things that are obvious to them (a flaw that we all share, haha).

In any case, I find that the new ORM is actually miles better than the Cake 2.0 one, although yes, it’s definitely more complex. But it’s possible to use it in a concise and effective manner once you get used to it.


For your first question, have you looked at http://book.cakephp.org/3.0/en/orm/query-builder.html ?
Almost everything related to finding records is explained there.

Basically, you can use $this->Articles->get($id) to quickly find a single entry by it’s ID.
You can use $this->Articles->find() combined with other selectors like where(), limit(), etc. to build custom queries.


Actually, using debug() to see what’s in the result isn’t a problem, but you need to use ->first(), ->all() or ->toArray() to execute your query. This is pretty important, since otherwise you’ll just be debugging the query instead of the results.


To manipulate specific fields you can use mutators in your model entity: http://book.cakephp.org/3.0/en/orm/entities.html#accessors-mutators

This allows you to globally manipulate fields either on display or on write, which is actually very comfortable. But it’s probably not flexible enough for some cases, so maybe you can show us a specific example of what you need.

Or you can always use something like $this->Articles->find()->hydrate(false)->toList() in order to just get a simple Array like in Cake 2.0 and you can then manipulate it the old fashioned way.

1 Like

A lot of leads to look into, thank you.

I did consider the hydrate false route when I read about it in the docs, but it feels so wrong. I want to jump on the 3.x bandwagon with both feet and not try to hack it back into 2.x. I know these things I want to do are possible, and likely simpler and better than before, but there’s just a few critical “aha” insights missing still :slight_smile:

Similarly, I was against learning and using the custom query builder. Something I normally avoided under 2.x as well since I wanted to use the framework the way it was intended.

I’ll check out these links and report back how it goes. Thank you!

We used to have comments on the docs. However, moderation became a huge issue as the comments were often inaccurate, misleading or should have been done as documentation edits.

Instead, we’ve tried to make the documentation easier to contribute to. Every page features an ‘edit’ button, which sends you to github’s editor where you can make the changes you think need to be made. I can understand that often you won’t have specific changes to make especially when documentation isn’t clear enough. But when you do have specific changes, a pull request is faster and simpler for everyone involved.

Using the query builder, is how the ORM is intended to be used. Personally, I leverage custom finders extensively and only put the most basic of queries in my controllers. For example, I find code like:

$query = $this->Articles
  ->find('published')
  ->find('authoredBy', [$user->id]);

Simpler to read, write tests for and re-use than the equivalent ‘raw’ query builder code.

2 Likes

The specific situation I’m working with regards a table of products for sale. Each product has three “availability windows” which stipulate a range of months during which the product can be found at (three) different types of locations.

I planned to have the controller, then, parse the availability data in each of these 3 fields, check to see if the current month fell within the window for each, and then set three new booleans, one for each location: “available_now”.

Then in the view, I can add a simple badge to the product for each location where it is currently supposed to be available per the schedule (obviously this doesn’t account for inventory depletions or logistical mess ups… it’s just designed to flag the “should” aspect).

It looks like I could do this with virtual fields I suppose… or with something like a _getAccessibility($loc)… it hadn’t crossed my mind that this type of pre-view translation was model-level material.

What if there was something like a “request clarification” button? Those of us who are lost but have nothing to add could at least explain what we wish the documentation would spell out there.

Hmm, depending on how you precisely determine the availability it might actually be easiest to just create a helper method, which receives the relevant data or the full article entity and then returns the appropriate value, i.e.:

$this->Shop->getAvailability($article)

This would probably be the better solution if you’re only planning on using this in the views, otherwise yes, a virtual field might be superior.

1 Like

But have you tried using comment voting (a lá Youtube or StackOverflow) to facilitate self-moderation through the community? (promoting comments with positive votes and hiding comments with a certain amount of negative votes)

I don’t think that “unrefined” comments are necessarily bad, so long as there’s a way for the community to self-correct. Mistakes are an important part of the learning process and can be sometimes just as valuable in helping to understand a concept as a good documentation. But naturally, it would suck if misleading comments could be left unchallenged and would require constant intervention from moderators. So voting seems like a sensible solution, in theory at least.

The thing with the docs is that often times, more practical examples and more varied explanations could be helpful in understanding certain parts, but we don’t really want to litter the docs with too many of them, either.

For example, the docs briefly mention that you can add MultiAuth via custom finder methods, but never specifies how you would actually do it. To a Cake3 dev it might seem so obvious that it’s not even worth explaining further, but a beginner will be confused.

But… not explaining it in detail in the docs is probably the right choice, since if you’d try to explain everything the docs would become too heavy and slow to work with.

But a comment below the particular doc entry would be a perfect place for this kind of info. Or maybe “comment” is not the right term, I’m thinking more in terms of supplementary extensions to the docs.

In any case, there are a lot of practical things that users need to get done, that are only implicitly explained in the docs, one example that often pops up would be cells (it’s not immediately evident when to use them and what pros and cons they have, even with the example - it would be great if users could describe their own use cases and experiences).

It’s kind of a waste if people have to go to StackOverflow to find clarifications and get a good answer, but others don’t benefit from it as there’s no central place to look up these kinds of things.

However, I realize that there aren’t many projects that allow unofficial additions to the docs by the community, so maybe it’s one of those things that sounds better in theory than it actually works in practice :smiley:

Trying to create a url-safe string, I happened upon another curveball in the docs.

Although $this->text-truncate() works in my view, neither Text::slug() nor $this->text->slug() work in that same view.

What exactly do you mean by it’s not working? Error or not the expected result?

I’m not at my computer atm, but my recollection is that It’s throwing a method not defined error in one case and class not defined in the other.

Weird, I can definitely use Text::slug() in the controller (need to load it with “use Cake\Utility\Text;” though) and $this->Text->slug() works in the view right away.

Are you using the latest Cake 3 version? Because this method apparently has been implemented in 3.2.7. But I don’t really think that’s the problem, hmm…

1 Like

I have to eat my words.

I’m not sure what changed but $this->Text->slug() is working as expected now.

maybe size of T in text ? Text/text

I agree everithing that you write, my solution is extremely simple, for me 3.x doesn’t exist, because is extremely slow, undocumented and far away from the 2.x magic.

1 Like

What are you not able to find in the 3.x documentation that is easy to do in 2.x?

first, thank You much for your answer.
Pls understand me, i am a big fan of cakephp 2.x, and i try to learn to grow to 3.x.
One simple example: described also Stackoverflow, I try to migrate from 2.x to 3.4, with an url based language routing.
The language part is excelent developed, works like a charm.
When i try to use a paginator, i fail.
Now the paginator links are like /books/index?page=2&lang=en
How can I transform to be like /en/books/index?page=2
In case that Dispatcher Filters is the best solution or Middleware can I have any example.

I’ll answer your question on stackoverflow.