New Query Builder (includes support for attributes)
Permalink 3 users found helpfulDescription
Simple library that will construct database queries for you. Includes functions for getting attribute information with the query.
Why on earth would anyone need another query builder?
While working on a project, I had a lot of list queries that also needed attribute information. It seemed a complete waste of processing power and an obscene number of extra queries to get attribute information for every user in a certain group when I know a good old join would do the trick. Thus became this library.
How do I use it?
Place it in your root library folder, or package library folder and reference it (I use it in packages usually). I've included 3 real life demo subclasses to show how it works. Additionally, images shows a subquery trick for getting fileversion info.
Final note:
I'd love any input on this, good and bad. The best way to make software better is to get outside opinions, and I'd like to hear yours!
The software package can be accessed at github, with sample classes to show usage:
https://github.com/cryophallion/c5-QueryBuilder...
Happy coding!
I'll try to add explanations on more of the tables/queries, and a summary rundown on what the examples are trying to do in the readme.
It IS a big class, it almost needed to be with so many different things that may be needed (for example, I WAS imploding with AND until only a week ago, when I ran into the possible need for an OR query, at which point I had to rip that all apart).
I think this is something that could be generalized and built into the existing PageList, Page, and Attribute classes. Each attribute could be configured for 'prefetchability', where it would return a LEFT JOIN that the PageList could use when fetching. You call PageList while setting $pl->prefetchAttribute('attribute_handle'), and that would load the value into Page. If $page->getAttribute('attribute_handle') has a prefetch value stored, it'd load that prefetched value, otherwise just run along its regular getAttribute() codepath.
As a plus, that PageList::get() could be cleaned up at the same time, so all that foreach(DatabaseItemList::get()) logic it does to load the Pages from the DIL, to instead load all the Pages in one big query. Should be a massive perf improvement for any sites with big page lists, especially those with remote DBs.
https://github.com/Remo/concrete5/commit/c7d335a49b96204a3a6b8b60cd1...
I mean, I happened to need to deal with two of the three attribute types, but that was more coincidental than anything else.
My method is best for a single page, data driven website style, which is exactly what the code was crafted for. I had an event need, pro-events didn't fit their needs, so I had to create my own.
What's key to this is the flexibility. It can work with any attribute type (including user created ones). It can filter really easily (which is great for me since this site has lots of search filter options). So, for people who want to use this as part of a data driven style site, this is a major timesaver (excepting the minimal time needed to understand the code).
I'm still learning the "C5 way" of doing things, but for this, an extensible, robust, and flexible query builder seemed the right choice. It's great for those member list blocks that seem to be needed on so many sites.
I'm sure the gurus on here have a better idea of how to deal with this in the C5 internals. I'm sure I could hack it, but it seems people like remo are already doing it, and they know the code way better than I do. Hence why my pull requests all are form centric for now....
Side note: I see that prepared statements are used in the PageList workaround. That works for that situation, but in this one, there are so many filter variables, so generated sql is the only way to deal with it.
Hey Kirk,
I don't think there's an easy way to combine clauses in the way you
describe. I think you need to either create your own SQL string (as you
suggested), or you could run two different PageList queries and combine
the results at the end.
The latter approach (combining two query results) would be simpler, but
if you are relying on the pagination feature then it won't work well
with that. But if you don't need pagination, you can just run two
separate PageList things... one for all the pagetypes *other than*
'blog_post' (which you'd probably need to do by making multiple calls to
$pl->filterByCollectionTypeHandle() for each other pagetype), then one
that combines 'blog_post' with user id. Then after you have the two
results (via $pl->get()), combine the two arrays via php's array_merge()
function.
Now that I've written all that out, it actually doesn't sound so simple
anymore :) So if you want to go the SQL route, you do this:
$safeUIDs = array_map <http://www.php.net/array_map>('intval', $userIDsArray); //ensure all UID's are integers, otherwise we're vulnerable to SQL injection attacks!
$safeUIDString = implode <http://www.php.net/implode>(',', $safeUIDs);
$where = "(pt.ctHandle <> 'blog_post' OR (pt.ctHandle = 'blog_post' AND (p1.uID IN ({$safeUIDString}) OR p2.uID IN ({$safeUIDString}))))";
$pl->filter(false, $where);
Hope that helps!
http://www.concrete5.org/community/forums/customizing_c5/how-to-do-...
On 06/04/2014 00:44, concrete5 Community wrote:
I made this for a project, but my hope is that it will help others struggling with this kind of issue who doesn't want to have to do all the background work (or who wants to come up with some cool tweak to make it better).
Much like I use jordanlev's great crud class (on the same site actually), I want this class to be free to use. I mean, if someone wants to pay me, great, but let's be honest, not likely to happen :)
Making it GPL would mean that anything that integrates on top of this also needs a free option (EDIT: and may also preclude this code ever making it into the core).
Browsing through the main class code I could see this is a necessarily big class. It pulls queries together that are spread over so many classes in the c5 core.
Also, I did a major rework of all the example classes today, cleaning out extraneous code that was making it harder to understand, and documenting things to make it clearer. Additionally, I added a db.xml file to show the example classes table structure.
Let me know if that makes things cleaner! Thanks for your input!
http://www.concrete5.org/community/forums/customizing_c5/how-i-lowe...
I think you may have been working in parallel and come up with similar solutions.
I can sort of follow what is going on, but would feel more confident working with this if the examples contained comments to explain the what and why of all the configuration tables they are setting up to build a query.