+1 This is an awesome feature in K2, and would be great to do this kind of thing in core.
Best,
Matt Thomas Founder betweenbrain™ Lead Developer Construct Template Development Framework Phone: 203.632.9322 Twitter: @betweenbrain Github: https://github.com/betweenbrain
--
You received this message because you are subscribed to the Google Groups "Joomla! CMS Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to joomla-dev-cm...@googlegroups.com.
To post to this group, send an email to joomla-...@googlegroups.com.
Visit this group at http://groups.google.com/group/joomla-dev-cms?hl=en-GB.
For more options, visit https://groups.google.com/groups/opt_out.
Generally a valuable approach, but the wrong place.
A generic onBeforeQuery(JDatabaseQuery $query, string $context) in
JDatabase will do the same, plus offer much more opportunities.
@Andrew what kind of performance hit do you think adding these into JDatabase would give?I saw microseconds mentioned earlier. You presumably think longer?
Designing a com_content2 (or whatever!) is a fork in Joomla!'s heart.
Just adding onBeforeQuery in com_content's (or user or contact...) parts might be the good deal
Could increase performance (removing unused data from large queries)
But let's say we don't want more ugly architectures in Joomla ;) So why not using JModel and JTable for the events ?
Hi everyone,
I was wondering if anyone has given any additional thought to this idea? Given some of the recent discussions, I do wonder if having the ability to capture/manipulate queries would be helpful for fine tuning Joomla for different use cases.
Best,
Matt Thomas
@betweenbrain
http://matt-thomas.me/
http://betweenbrain.com/
https://github.com/betweenbrain
Sent from mobile. Please pardon any typos or brevity.
--
Am I missing something? I thought this was about list queries in models
and not about single items in JTable?
Hannes
Thank you for the helpful responses and examples. I will study that code. My current thinking is starting to expand beyond com_content, and it seems like using an Observer or Decorator pattern might be viable solutions, although I don't know enough about both, yet, to make a more informed comment.
Really, the basic idea is to provide a way to tap into any queries being run. As Neils described it "A generic onBeforeQuery(JDatabaseQuery $query, string $context) in JDatabase" is the core idea.
For example, I've been doing a lot of work with K2, which does support this idea with a plugin event, and have been making great use of a multiple category plugin for it. That plugin, for example, just modifies the query to add in multiple category support.
I feel that providing developers with the ability to tap into the queries could create some great opportunities.
Best,
Matt Thomas
@betweenbrain
http://matt-thomas.me/
http://betweenbrain.com/
https://github.com/betweenbrain
Sent from mobile. Please pardon any typos or brevity.
Hannes,
Maybe I better start a new thread to define the context more.
Best,
Matt Thomas
@betweenbrain
http://matt-thomas.me/
http://betweenbrain.com/
https://github.com/betweenbrain
Sent from mobile. Please pardon any typos or brevity.
To unsubscribe from this group and stop receiving emails from it, send an email to joomla-dev-cm...@googlegroups.com.
To post to this group, send an email to joomla-...@googlegroups.com.
Visit this group at http://groups.google.com/group/joomla-dev-cms.
For more options, visit https://groups.google.com/groups/opt_out.
Hi Matt,
Following is an attempt to try and answer your question based on architecture best practices including a conceptual proposal for a solution. Your question :
“Is having the ability to capture and/or manipulate database queries useful and is so how is this best implemented ?”
Two key requirements here, one the ability to capture queries and second the ability to manipulate queries.
I will first try to outline some of the concepts that adhere to this question, before moving on to discussing a potential solution.
There is nothing wrong with implementing an Inversion of Control mechanism (1) to make Joomla’s database layer more extendible. Inversion of Control is a key part of what makes a framework different from a library.
Inversion of Control is often referred to as the Hollywood principle (1) : Don't call us, we will call you and is a useful paradigm that assists in the development of code with high cohesion and low coupling that is easier to debug, maintain and test.
Inversion of Control can be implemented using various different patterns (note 1). In Joomla inversion of control is implemented primarily through the plugin system which is event driven and implements a topic based publisher/subscriber pattern. (note 2).
The concept of using a event driven plugin system as implemented in Joomla is also described by Fowler as Event Collaboration (6)
“Multiple components work together by communicating with each other by sending events when their internal state changes.”
Joomla limits event collaboration to collaboration between a component and one or more plugins, where the plugin can acted as a broker or proxy between different components or can work standalone.
An event driven architecture is not the only way to implement inversion of control. Many different paradigms exist that are implemented in various frameworks to allow for Inversion of Control, to name a few :
If we take a quick look at modern PHP frameworks we can see that in PHP, Event Driven Architectures are dominant core architectures for most frameworks. :
Symfony : Event Dispatcher
Zend : Event Manager
Typo3/Flow : Aspect oriented approach
Both Symfony and Zend implement an event driven architecture using a topic based, prioritized publisher/subscriber pattern which is similar to what Joomla does, be it that Zend and Symfony event queues are also prioritised and allow for the implementation of an Intercepting Filter (7), which Joomla does not.
Events are a great mechanism to extend a core architecture and allow to capture changes and react on them with high cohesion and low coupling. There is one thing they are not good at or intended for : manipulation of the underlying system. (note 3)
A better and more suited pattern to implement a solution that can manipulate the underlying data flow is using Commands and a Chain of Command (CoC) (note 4 and 5).
Following is a conceptual implementation of a Database::update() method that implements a Chain of Command using a prioritised, topic driven, command chain, together with a modifiable command that shows how a command can be used to set the modification date and user id.
public function update(KDatabaseQueryUpdate $query)
{
$context = $this->getContext();
$context->query = $query;
if ($this->getCommandChain()->run('before.update', $context, CONDITION_FALSE) !== false)
{
if (!empty($context->query->values))
{
//Execute the query
$context->result = $this->execute($context->query);
$context->affected = $this->_affected_rows;
$this->getCommandChain()->run('after.update', $context);
}
else $context->affected = false;
}
return $context->affected;
}
In the above code the actual execution method is being wrapped inside a command chain call, before the execute method is ran a ‘before.update’ command is run, after the execute method has been completed an ‘after.update’ command is run passing the number of affected rows through in the context.
class DatabaseCommandModifiable extends DatabaseCommand
{
protected function _beforeUpdate(KDatabaseContextInterface $context)
{
$query = $context->query;
if(isset($query->data->modified_by)) {
$query->data->modified_by = (int) $this->getUser()->getId();
}
if(isset($query->data->modified_on)) {
$query->data->modified_on = gmdate('Y-m-d H:i:s');
}
}
}
In the above code a modifiable command invoker will handle the before.update command setting the modified_on and modified_by database columns.
At first sight the above approach is very similar to an event dispatching implementation but the devil is in the details. The difference lies in the fact that the command chain is a prioritised chain of command invokers.
Each invoker is being called by it’s priority and the context is being passed from one to the next allowing each invoker to not only capture the command, but also modify the context before passing it on.
Above example shows how one can implement a inversion of control mechanism that allows to capture, modify and interrupt core application data flow.
Joomla can benefit from a command chain approach in each of it’s MVC layers, and also in it’s database layer. This would give developers a uniform approach to be able to extend, modify, interrupt data flow in models, views, controllers and on a database level.
Potential uses can be :
- logging
- caching
- authorisation
- validation
- ...
If a uniform approach is used documentation can be kept very limited. Developers would be able to entrust that the same implementation works for any extension build on the Joomla core which would further improve code re-use and interoperabulity between extensions.
1. Joomla has been steadily adding hard coded events to it’s core in past versions. There is a danger of introducing the ‘eventitish’ syndrome, eg using hard-coded events as the ‘go to’ solution for implementing Inversion of Control.
Both Drupal and Wordpress suffer from this and have many hundreds if not thousands hooks (a hook is a precedural form of an event mechniasm) in their core. Wordpress 3.6 counts no less then 1556 documented hooks.
A preferred approach to an event architecture would be a system that can generate events on various levels using an uniform event name syntax.
Example : on[Before/After][Component][Name][Type][Action]
Before/After - All actions have a before/after event
Component - The name of the component the event belongs to
Name - The name of the "entity" the event belongs to (e.g. the controller/table)
Type - The type of the "entity", e.g. Controller,
Action - The name of the action being run.
For example an event for adding an user would like like this : onAfterUsersUserControllerAdd()
Using this syntax, events can be generated dynamically and registered, without needing to have further documentation.
2. The Joomla’s event system is not always used only for notification purposes, and contains inconsistencies which add to the complexity of implementing events. Some of the events like onContentPrepare are used as data filters, others like onContentBeforeSave are used to be able interrupt the save operation.
Developers should be aware that this is not the intended use of an event architecture and not consider it the default. Other design patterns exist to solve this problem in a better way as discussed in the proposal above.
3. New features implemented in recent release and features being proposed have a high focus on extending com_content. While com_content indeed makes up a core part of Joomla, it’s only a single component build on top of the framework.
Developers should take care to implement design patterns in the core framework MVC architecture to maintain consistency. Failure to do so, will lead to an increase in code bloat, inconsistencies and further diverging of the codebases and implementations between major extensions which will lead to less interoperability between extensions.
1. There is some confusion these days over the meaning of inversion of control due to the rise of IoC containers; some people confuse the general principle with the specific styles of inversion of control (such as dependency injection) that these containers use.
2. There is some confusion in among Joomla developers that the Joomla event system uses an Observer pattern (3). This is not correct, Joomla uses a topic based Publish/Subscribe pattern, which is a sibling of a message queue paradigm (5).
- With an observer pattern an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes passing the object itself to the observer. An observer pattern is not message based.
- With a publish–subscribe pattern senders of messages, called publishers, send a message to a dispatcher which will dispatch the message to the interested subscribers.
The message itself is usually a string in a predefined format eg onBeforeQeury, and in most implementation additional data is also passed together with the message.
3. Zend and Symfony allow for manipulation of the event data and underlying system by implementing the intercepting filters pattern(7). Intercepting filters are key to be able to not only capture but also manipulate an event and the targeted object.
At present the Joomla CMS core does not have support for intercepting filters, and only allows to capture, not to manipulate. This is done by design and was a deliberate choice in Joomla 1.5 as the primarily goal of events is to notify, not to modify.
4. There are subtle differences between commands and events that might not seem obvious. Events clearly share most of the properties of commands - the ability to have their own lifetime, to be queued and executed, event reversal is the same as command undo.
Events, however, just communicate that something happened - with an event you let a system know that Y has happened. Another difference is that you think of broadcasting events to everyone who may be interested but sending commands only the a specific receiver. When it comes to actual behavior it doesn't really matter. The polymorphic reaction of a system to an X command need be no different to a Y event. Yet I think the naming does affect how people think about events and what kind of events they create.
Command is a classic pattern described in [Gang of Four]. You should also look at [hohpe-woolf] for the contrast between Command Message and Event Message.
5. The Chain of Command differs slightly from a Chain of Responsability pattern. In a Chain of Command the chain itself is reposible to move the pointer from one to the next command invoker when the chain is executed. In a chain of responsibility, the command invoker itself would call the next command invoker.
6. The Cocoa and Cocoa Touch frameworks, used for OS X and iOS applications respectively, actively use the chain-of-responsibility pattern for handling events.
Joomla can certainly benefit from adding more mechanism to allow for Inversion of Control, the ability to modify and capture queries is just one example where this can be useful. Inversion of Control will lead to increased flexibility and boost future innovation of Joomla as a web platform.
With the introduction of Inversion of Control come risks. The core application is effectively giving away control to extension developers, and with greater control comes greater responsibility. The question how much control you want to allow for is very relevant and should not be dismissed when making a choice on how to implement Inversion of Control in any architecture.
Different design patterns exist to implement Inversion of Control. A solid understanding of the differences, pro and con’s will be vital to be able to create a solid Inversion of Control driven architecture.
Finally there is a lot more that can be said about Inversion of Control, I have tried to capture the essence without going into to much detail.
I hope this helps, happy coding!
Johan
Inversion of Control : http://martinfowler.com/bliki/InversionOfControl.html
Hollywood principle : http://en.wikipedia.org/wiki/Hollywood_principle
Observer pattern : http://en.wikipedia.org/wiki/Observer_pattern
Publish/Subscribe : http://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern
Message queue : http://en.wikipedia.org/wiki/Message_queue
Event collaboration : http://martinfowler.com/eaaDev/EventCollaboration.html
Intercepting Filters : http://msdn.microsoft.com/en-us/library/ff647251.aspx
Visit this group at http://groups.google.com/group/joomla-dev-cms.
Hi Matt,
To answer your question : "What is the reasoning behind the design choice in Joomla 1.5 as the primarily goal of events to notify, not to modify. Do you feel that the reasoning behind that decision has since changed and that we, and or, Joomla is ready for Inversion of Control?"
Back in the days of the big refactoring of Joomla 1.5 the topic of Inversion of Control was not high on the agenda. The focus was almost completely on Separation of Concerns (ref 1) and creating a proper modularised framework (Note 1) together with the introducing of the MVC pattern to help improve and standardise component development best practices.
Inversion of Control is less about Separation of Concerns and more about offering the ability to implement common functionality that spans layers and tiers. This paradigm is also called Cross Cutting Concerns (ref 2) and typically supports operations such as logging, authorisation, caching, error handling, security, validation, internationalization and localization, business logic and workflows, …
Currently Joomla’s framework architecture does not offer a solid solution for developers to implement cross cutting concerns in their extensions. Some cross cutting concerns are being inverted through the use of plugins, like authorisation, authentication, search, editors, … but a standardised framework inversion of control to allow developers to deal more properly with cross cutting concerns is still missing.
The event and plugin system implementation originally found in Joomla 1.5 is a mix and match of a little bit of everything. We never made a deliberate choice to go either way with the system, mostly due to the fact that we didn’t really know how to do it and our hands where tied because we had to offer 100% compatibility with the legacy Mambo mambots implementation. (Note 2). The choices we made for Joomla 1.5 were :
Modularise the mosMambotHandler into two packages, improving the separation of concerns and making both more SOLID (ref 3)
Make the procedural mambots implementation the legacy approach and move to an OO approach for the new plugins, a plugin now extends from JPlugin.
Allow a plugin to handle multiple events.
Offer 100% compatibility with the legacy mambot system. Mambots should still be installable and work out of the box with legacy mode enabled.
The mambot code was refactored into following two packages :
1. A JEvent package : https://github.com/joomla/joomla-cms/tree/staging/libraries/joomla/event
2. A JPlugin package : https://github.com/joomla/joomla-cms/tree/staging/libraries/cms/plugin
The event package was originally based on a pure observer pattern and extended from there to implement a topic based publisher/subscriber pattern. (Note 3)
The refactored plugin system found in Joomla 1.5 is not pure notification based event system due to the fact that mambots were not pure event listeners either, they did a lot more. A design choice to make the event system a pure notification system was never and could never be made. Most mambots worked as Interception Filters, they received different arguments by reference and allowed to modify these arguments before passing them back.
Joomla already uses and has always used Inversion of Control even back to the Mambo days, without this concept Joomla wouldn't be extendable at all. Joomla's power and focus since it's birth has been to grow an extendable web application platform which has resulted in an eco-system of almost 8000 extensions.
The question is not if we are ready for Inversion of Control, the question to answer next is in what areas will more Inversion of Control be introduced, why, and most importantly how.
Using the current event system for this is possible, but it would be better to make a clear distinction between using events for notification purposes and additionally implementing a Chain of Command pattern to offer prioritised Interception Filters, and through this offer further Inversion of Control opportunities for extension developers.
Hope that helps. Happy coding!
Johan
1. Mambo didn’t have a framework at all. All the code was part of one big file called mambo.php all the core objects could be found in this file, our first job for Joomla 1.5 was to split this file up in a modularised framework.
2. Mambo had a so called mambot system. Mambots are what we now call plugins and already used a topic based publisher/subscriber pattern. Implementation was a little rough on the edges but it worked.
You can find the code for the mambots system in the old mambo svn branch on joomlacode. Search for 'mosMambotHandler' to find the actual implementation for the mambots. Mambots where completely procedural, and had a lot of similarities with 'hooks' in Drupal and Wordpress.
3. Since Joomla Platform 12.3 the event package no longer extends from JObserver and JObserverable. This is more correct as the event system is using a a topic based publish subscribe pattern, and not an observer pattern.
1. Seperation of concerns : http://en.wikipedia.org/wiki/Separation_of_concerns
2. Cross cutting concerns : http://en.wikipedia.org/wiki/Cross-cutting_concern
3. SOLID : http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)
Note : I have updated the Google Doc acoordingly with the information found in this reply. You can find it here : https://docs.google.com/document/d/1MsFW9GLbRv0juyqdbkD5bMBUmkk6ATnwcBklEaETQqE
Really, the basic idea is to provide a way to tap into any queries being run. As Neils described it "A generic onBeforeQuery(JDatabaseQuery $query, string $context) in JDatabase" is the core idea.