eZ Community » Forums » Discussions » Little Nemo in SlumberCode part 1:...
expandshrink

Sunday 18 March 2012 12:43:39 am - 7 replies

» Read full blog post

Introduction

First post in a series of "crazy ideas to explore at nighttime", this is dedicated to a new friend of mine: jQuery.

I never used that framework very much (I remain a backend coder at heart), but having been recently involved in whipping up some interactive and cool-looking web pages, I was impressed by the ease with which it allows to select sets of html elements and retrieve / alter their values.

The next (il)logical step was asking myself: can we reproduce such conciseness and ease of use in the eZ template language, where fetch functions are a staple? After all the "content/list" fetch function is used to select a set of nodes from a tree, with some filters applied. And, hey, nodes have attributes too, just like html elements!

Read on for more senseless drivel, erm, detailed analysis...

Sunday 18 March 2012 2:15:55 pm

just for the record, most of those selectors are actually CSS3 selectors (nothing specific to jQuery), see http://www.w3.org/TR/selectors/#selectors

CSS selectors are basically designed to easily query a HTML/XML tree. So if you have a tree containing objects with attributes, it's not surprising that the concept can fit happy.gif Emoticon You might also think of a syntax based on XPath that provides more features (you have functions in XPath) but it feels (and it is) way more complicated than syntax ala CSS selectors.

Sunday 18 March 2012 7:35:49 pm

@Damien I know most of those are just css selectors, I guess just not all of them. It is good to have a link to the css selectors spec though, so that we can strive not to implement anything that goes against it (eg. usage of "+" seems to be reserved for other stuff).

As for xpath, I never really tried to use it, but from reading here and there, it seems to me:

- based on a more sound mathematical structure than css selectors (which are all but universal in fact)

- not really friendly (this might be a biased opinion though, since css selectors I've used for ages)

Wednesday 21 March 2012 7:11:43 pm

+1

Loving the idea. As far as I'm concerned, it's not that less readable than the default fetch functions, you just need to get used to use it.

I also see great auto-completion plugins for our IDE, plus it might help new comers to use this query builder (how would you name it ?).

Let me know if you want me to join your forces.

Cheers,

Arnaud

Monday 16 April 2012 2:51:54 pm

@Arnaud great to have you onboard, a team of 2 is surely enough to get this started.

Before I rush off to github, let's agree on a name for this baby: "ezquery", and "ezselector" being the 1st 2 that come to my mind.

As for the rest:

- template operators "q" (query) and "qc" (query count) [alternative: "f" and "fc", but it looks like it's fottbla related blunk.gif Emoticon ]

- components: a parser of the "q" string; 2 backends that translate the parsed representation into requests to current and ezp-net content models; optional an in-built cache so that calling "q" many times over with the same parameters does not destroy your performances

- choice: we should agree in detail about the syntax we support. It can be imho either more jquery-like or more ez-like (using one way to denote matching on attributes and another one, generic, to match everything else)

Tuesday 17 April 2012 2:37:46 pm

Quote from Gaetano Giunta :

@Arnaud great to have you onboard, a team of 2 is surely enough to get this started.

Before I rush off to github, let's agree on a name for this baby: "ezquery", and "ezselector" being the 1st 2 that come to my mind.

As for the rest:

- template operators "q" (query) and "qc" (query count) [alternative: "f" and "fc", but it looks like it's fottbla related blunk.gif Emoticon ]

- components: a parser of the "q" string; 2 backends that translate the parsed representation into requests to current and ezp-net content models; optional an in-built cache so that calling "q" many times over with the same parameters does not destroy your performances

- choice: we should agree in detail about the syntax we support. It can be imho either more jquery-like or more ez-like (using one way to denote matching on attributes and another one, generic, to match everything else)

ezquery sounds good

I like the backend implementation and I see at least 3 backends :

  • a request parser, aware of the selectors syntax listed above
  • query builder for ezp 4 versions
  • query builder for ezp-next

Regarding the query operator, there's a need to configurate (via a kind of dependency injection) the query builder before making the request. I mean that we might want to fetch different types of entity such as content nodes, objects, etc. Plus, why we need that ? If we follow the jQuery concept, the # selector will be used used together with an ID value and that's the issue. A content object has 2 ids : his node_id and his contentobject_id. We could think of a "#" selector used with a node_id and "##" with the contentobject_id, but... well, what I have in mind looks like :

{def $ezq_config = qconfig( 'node', 'v2' )
       $items = q( $ezq_config, "#2" )}

That way, 'node' might be used to select which backends are used. We could also have default request parser and query builder, and they should be extendable so anybody could create its own backend and provide it as an extension happy.gif Emoticon

Furthermore (writing and thinking at the same time...), I would like the q() operator not to return the results directly, but I'd prefer something like an eZQueryObject with attributes we can inspect within a template :

  • q(...).results => an array containing the results
  • q(...).config => return the eZQueryConfig object (the one returned by qconfig())
  • q(...).backends => return information about the backends
  • q(...).errors 
  • ....

Then usage might looks like :

{def $ezq_config = qconfig( 'node', 'v2' )
       $ezq = q( $ezq_config, "#2" )
       $items = $ezq.results} 

What do you think ?

I suggest that you start a github project called ezquery and that we use the wiki to write down our ideas, concepts, etc before writing a single piece of code (I know you Gaetano !!! happy.gif Emoticon)

Cheers,

Arnaud

Modified on Tuesday 17 April 2012 2:39:18 pm by Arnaud Lafon

Tuesday 17 April 2012 7:27:21 pm

Mmm, lots of bread on the table my friend...

  1. is the q() operator meant to be an universal selector or just a "node" selector? I thought just a bit about this in the past, and came to the conclusion that using it to select something which is not a (set of) node is overkill. We could select objects, users, whatever, but the "fetch content/list" is imho the workhorse of eZPublish: the most used fetch function and the one which has most parameters. We could of course support selection by remote_id (and remote_object_id as well): in both cases the function would return a set instead of a single node, but it would be easy to use nonetheless
  2. about your syntax example, I'd reverse it, make config optional and stick it 2nd place. We should try to make almost everything work by just using the string in the 1st param - in fact we could do away with 2nd param if we add extra switches in the 1st one
  3. about what is returned: I have played around with building "magic" template objects, especially when trying to map xml files to tpl data. And the "dynamic nature" of attributes which make up a template object can be used to a great deal to play magic tricks, similar to what jquery does:
    • q() returns an object of class eZQueryResultSet (in php terms)
    • when calling .name on it ( or ->attribute('name') ), the call is forwarded to the node in the set (if there's only one. what to do if there's many?)
    • when calling .count on it, the number of elements in the set is returned
    • I think we might even get away with accessing set elements by .0, .1 notation
    • etc...

One thing I do not want to loose is the ease for writing this line:

 {q('#2').name} has {q('#2').children|count} children

Tuesday 24 April 2012 10:17:03 am

Hi Gaetano,

I definitely agree with you when it comes to keep it simple (following your last piece of template code). 

  1. is the q() operator meant to be universal ? Well I don't know. I first thought that It could be very useful to simplify the fetch functions, but your approach saying that it's just a "node" selector is also a good one. What I really would like is that it has to be extended as suggested by the multiple backends approach (see point 2)
  2. making the config optional and stick in 2nd place => works for me ! And keep in mind that the configuration object could be used to set different backends.
  3. flash of genius :
  • why not making eZQueryResultSet implement the PHP Iterator ?
  • eZQueryResultSet might also expose magic functions such as 
    • q().reverse : returns another eZQueryResultSet but starting from the end
    • q().last : returns the last element
    • q().first : alias of q() when iterating the first item
    • q().count : returns how many nodes were fetched
    • q().elements (or q().results or anything else) : returns all the results as an array

Last but not least, we forgot a very important feature to be implemented : limiting the query result set with offset and limit parameters. My opinion is that these parameters should be set using the configuration object (as the 2nd operator's parameter) because using it in the query string would be too much... 

Regarding the configuration object, we should also be able to create it on the fly using a hash :

{def $limit = 10}
The {$limit} first articles below your root node are :
<ul>
     {foreach q("#2 .article", hash('limit',10)) as $node}
     <li>{$node.name|wash}</li>
     {/foreach} 
</ul> 

Note the iterator concept happy.gif Emoticon

Modified on Tuesday 24 April 2012 12:34:39 pm by Arnaud Lafon

expandshrink

You must be logged in to post messages in this topic!

36 542 Users on board!

Forums menu