joomla / joomla-cms

Home of the Joomla! Content Management System
https://www.joomla.org
GNU General Public License v2.0
4.77k stars 3.65k forks source link

[4.2.0] After upgrading from 4.1.5, listmodel with external database object still looks into joomla db object #38505

Closed FoTo50 closed 2 years ago

FoTo50 commented 2 years ago

Steps to reproduce the issue

I'm having a model in my component (jOpenSim) extended from ListModel but with an external database as db object (in my case extended from MysqliDriver).

After upgrading to 4.2.0 the method getListQuery() wants to find the (obviously not existing) tables in the Joomla DB for listing

Expected result

List of items of external database table

Actual result

Error message like "42S02, 1146, Table 'nameofJoomlaDB.externalTableName' doesn't exist"

System information (as much as possible)

running both (Joomla and external) on MariaDB 10.5.16 Switching Joomla DB from Mysqli to MySQL PDO didnt have any affect.

Additional comments

A "quickfix" for me was currently to add directly as first line in the method getListQuery(): if(method_exists($this,"setDatabase")) $this->setDatabase($externalDatabaseObject); right before getting the query object.

The if(method_exists($this,"setDatabase"))... was required to avoid the error "Call to undefined method ..::setDatabase()" in 4.1.5

richard67 commented 2 years ago

@laoneo It seems this comes from refactoring and db injection. Could you have a look? Thanks in advance.

laoneo commented 2 years ago

How did you set the specific database in 4.1 in the jOpenSim model?

FoTo50 commented 2 years ago

During __construct() I set it through a helper with $this->gridDB = $this->opensim->getGridDB()

later in the method getListQuery() I fetch the query object as

$query = $this->gridDB->getQuery(true);

but without the previous mentioned line before it, in 4.2.0 the query object still is trying to find the table in the Joomla database, while in 4.1.5 and previous it worked fine that way.

laoneo commented 2 years ago

Do you have some kind of stack trace, because when you work on the query it should not have any kind of reference to the model which has the other database.

FoTo50 commented 2 years ago

Maybe I should also mention, that same model also needs to deal with some component tables in the Joomla DB.

But these methods all use the "regular" way with $db = Factory::getDBO(); $query = $db->getQuery(true); and are not called at the moment when the view wants to initially display the external data for an overview

laoneo commented 2 years ago

We need to figure out where the access to the default table is done in the model to identify the root cause of the issue. For that I need to see where exactly the error happens. Do you have the source of the model publicly available?

FoTo50 commented 2 years ago

Well, more or less (semi public hehe). The latest RC of my component is https://jopensim.com/jopensim4/nightly/com_opensim.0.4.0.4_RC6.2022-08-10-13-55-21.zip where the 2 admin models for this case can be found in \administrator\components\com_opensim\src\Model\ (UsersModel.php and RegionsModel.php) ... in there still unchanged and working only in <= 4.1.5

FYI: I temporary changed the method getDatabase() from the basic abstract class DatabaseDriver for debugging and it surprisingly still returned the correct external database name right before and after calling getListQuery().

I suspect something with the actual ->getQuery() where it returns to parent when created with some - maybe now required - missing parameter ( ... maybe is this $options['factory'] ?)

BTW: the object for the external db is found in \administrator\components\com_opensim\src\Extension\jOpenSimGridDB.php

laoneo commented 2 years ago

Had a look on the code and you don't pass your own db object into the base class, either through the config array or setDbo. How should the base class, in your case ListModel, know what for a database to use? Relying only on overriding getDbo is error prone as the base class works on a different variable, before it was _db and now the one from the trait.

FoTo50 commented 2 years ago

Not sure how to understand (but sure willing to do so)

jOpenSimGridDB.php is created with the config ($options) array that way ... the object contains the external connection and works, even in 4.2.0

The model does not use the static Factory::getDbo method for getListQuery, but it's own to get the external object from jOpenSimGridDB.php to create the query object for it.

This even now in 4.2.0 works in models extended from e.g. AdminModel, but not from ListModel ... and there only in the method getListQuery()

laoneo commented 2 years ago

Can you please test the pr #https://github.com/joomla/joomla-cms/pull/38506. I'v illustrated there how you can do it better without storing the db in your own variable.

roland-d commented 2 years ago

Closing this now that we have a pull request.