try for example to make that:
JDatabaseDriverMysqlix extends JDatabaseDriverMysqli to add a new method using with $db= = JFactory::getDBO();
It does not work. While a lot of things can be handled by override in Joomla, the database drivers are an exception. Why?
It should be possible to add a new method to a database driver using the standard Joomla db connection instead of creating a new connection.
Joomla 3.5 or 3.6 beta
Why that limit?
Sorry to ask silly question but I need JDatabaseDriver::getInstance()? So it is not possible to extend without creating an instance?
Well, for the same database connection with the same configuration for the full request you'd need to go through the getInstance method as it caches instances. That method also helps convert params over to the right structure (and that's ironically where the class name structure is enforced) so I'd suggest using it. Otherwise you can new JDatabaseDriverMysqlix
all you want and use that object.
@franzpeter With my little understanding, I think you are trying to add an extra method to JDatabaseDriverMysqli
that you'd use. For which you extended the same like
JDatabaseDriverMysqlix extends JDatabaseDriverMysqli
{
public function yourNewMethod()
{
// Your method code...
}
}
Now you want it to be available via JFactory::getDbo();
. Right?
If all this is not correct pardon me to ask for more explanation. Otherwise, here is what you need to do...
As correctly mentioned by Michael, the limiting factor is that the first ever chance to inject anything via plugin is too late to register a db path as the database would be already loaded and the worst cached in the factory.
DO the following:
1. Drop your class file at libraries/joomla/database/driver
as mysqlix.php
2. Select database type as mysqlix
in the global configuration.
OR the more hackish way:
Create a system plugin that immediately resets the JFactory cached instance and sets the new instance of your choice.
$options = array(
'driver' => 'mysqlix', // <== Your db driver class
'host' => $conf->get('host'),
'user' => $conf->get('user'),
'password' => $conf->get('password'),
'database' => $conf->get('db'),
'prefix' => $conf->get('dbprefix'),
);
JFactory::$database = JDatabaseDriver::getInstance($options);
This should work as $database
is a public property. Hope this helps.
@mbabker Shouldn't we have a custom lib path where such overrides may be dropped without entering the core compound?
Can't. How would you register those lookups? The first plugin event happens after the application is instantiated, which explicitly starts the session (making it hard to inject custom session handlers), and the session has a dependency to the database API for that metadata stuff (making it hard to inject custom database drivers), and the cache API is booted up because of cache use in JComponentHelper and JPluginHelper (making it hard to inject custom cache storage adapters), and a few other global services along the way (logging and event dispatcher are two but they aren't tied to JFactory).
If you create such a path lookup explicitly in the core, you're basically giving free reign to say something can overload a core class. We don't want that and we need to be moving to a more service driven approach. Which raises issue B in that there is a tight coupling across the application to a lot of services. See this gist as an example of the classes that get loaded into the system before the first plugin event is dispatched (this is after the plugins are imported and before the actual dispatch command).
Since this was just a flying thought, I cannot say how right now. I would think over it.
Still I guess there has to be some way such as allow JPATH_LIBRARIES_CUSTOM which would be looked up first for any defined class and if not found then the default core classes shall be loaded.
If it happens to be handler kind of classes such as the above db handler or a session handler that can be added to the list of available handlers.
I don't say this is the best solution, rather its an idea to start with.
To me it's a terrible solution. If you're going to default a JPATH_LIBRARIES_CUSTOM
to the front of the autoloader you're making a statement that Joomla explicitly supports AND encourages core classes to be overloaded and quite frankly this is a dangerous "feature" to support. What do you do when RegularLabs has overridden JModuleHelper
with Advanced Module Manager and someone else decides they want to customize the module handler? Or you get two extensions with conflicting versions of a database driver? Or someone overloads the core MVC layer? This is a pandora's box that spells nothing but trouble and the fact that core can already work with overloading implicitly is a terrible architectural issue that needs to be patched instead of expanded upon.
The "services" right now depend on rigid class name structures which are autoloaded or fallbacks to filesystem lookups in the core filesystem. Except for something like JHtml or JForm which have some different rules or mixed use cases. It's in part because core doesn't have proper service location.
You are right in all above statements. And we really should not (read, never) do exactly what I mentioned above out of the box. As I said, we need to think and do or not do what comes as best as a solution.
:-)
We already ship our IOC container. It could be implemented to allow
service location. It doesn't fix the issue of stuff being unoverrideable
due to when things are loaded, but for other API parts like JDocument,
JForm, JHttp, JInstaller, etc. it opens the door to a much cleaner way to
inject services.
On Wednesday, June 29, 2016, Izhar Aazmi notifications@github.com wrote:
You are right in all above statements. And we really should not (read,
never) do exactly what I mentioned above out of the box. As I said, we need
to think and do or not do what comes as best as a solution.:-)
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#10875 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AAWfoceMqFN5PoFZ9SC4-Sz9qjqKBYQYks5qQqCLgaJpZM4I5zxe
.
IOC container.
I don't know any about this. Can you please direct me to where I can educate myself.
@izharaazmi and mbabker: first of all thanks for the discussion.
The problem in case of Joomla is that coders are urged to use provided methods in case of database. Joomla is even limiting database methods common for mysqli or pdo to get used. If you have to handle with backward compatibility too, you are lost. Example: iterator. Is there since Joomla 3. At mean time existing methods which would provide clean backward compatiblitiy are set now as deprecated. All fetch methods are set as protected. Now if you would like to try to implement prepared statements - to give an example - with mysqli, you need to have access to a fetch method. So my question is: Is Drupal unsafer than Joomla? In Drupal you can access those methods. I doubt about that LoadAssoc for example is safer than the standard fetch method for mysqli, else Joomla would not use it:
protected function fetchAssoc($cursor = null)
{
return mysql_fetch_assoc($cursor ? $cursor : $this->cursor);
}
You write an additional function and that additional function is just executing a standard function. So why should it be safer. A prepared statement for example needs a fetch. It even would work if using fetch_assoc or fetch object or whatever. But no, Joomla has made it protected. Of course there is always the possibility to create an own db connection using a helper and write new code. Is that more safe? I doubt about.
@franzpeter Please understand that the Joomla provides an abstraction
layer via JDatabaseDriver
that allows you to bother about what data you
input and what data you want. While the mysqli result resource and any
other database drivers' result resource may all differently behave and the
methods to handle them differently named as well, they ultimately serves
one purpose that is get a record for you.
With this abstraction layer you are given the opportunity to care only what
you actually need rather what happens behind the scene for each specific
driver.
Such as fetchAssoc
requires a cursor object, that you should never bother
about at all. Why? Because that is not standard thing across all the
database types. Only standard is the record – an object, an array, a string
etc.
Hope that I did not misunderstood your concerns.
PS: If you still want to do it all by yourself Joomla doesn't stop you.
Just call $db->execute()
to get the cursor object for your query result.
Use it the way you want. Anything breaks, its your call.
And you mean while Drupal for example provides those things with less limit it is unsafer?
I don't know Drupal. It may be more safe than Joomla, or less, or probably the same. You know both, you can judge better :-)
It's a mix of different design approaches and different mentalities. Doesn't necessarily make one or the other "better" or "safer". The fetch*()
protected methods are considered design details in the Joomla database layer specifically used by other methods when loading data (so loadColumn()
as an example uses fetchArray()
which is a platform specific call on a cursor). Part of the thinking is to abstract out the high level general use cases for database interaction so you aren't worried about platform specifics or even differences in behavior between the three MySQL connectors. It does come at the expense of sometimes things not being as openly accessible as you would like
As for prepared statements specifically, as soon as I'm confident in the code changes as I make them in the framework package (see joomla-framework/database#38 for MySQLi support and joomla-framework/database@66035e4 for the PDO MySQL driver equivalents), those changes will be proposed to become a native part of the CMS' API (my plan is to do that PR once I add support to all the drivers).
I did a quick search through WordPress, Drupal, Doctrine, and Laravel's database code. From what I can find, none of the 5 projects (those plus Joomla) directly expose a method similar to our fetch*
protected methods (also most aren't supporting anything but PDO but that's another story). So I don't think our API structure is too far off but it does become a bit painful when you get into advanced scenarios.
@mbabker it looks like I can close this - can you confirm?
Close it.
Status | New | ⇒ | Closed |
Closed_Date | 0000-00-00 00:00:00 | ⇒ | 2016-08-05 15:45:11 |
Closed_By | ⇒ | brianteeman |
Closed - thanks everyone for your input
Create your
JDatabaseDriverMysqlix
class and it should work just fine so long as the class is loaded whenJDatabaseDriver::getInstance()
is called with your custom configuration.Note that without dropping your custom classes into a core autoloaded path or core hacking the bootup process, your custom drivers can't be used before the
onAfterInitialise
system event. During the application bootup process a database connection is opened due to the session processing code in the application class.Everything in this gist is what gets loaded during the bootup process.