1

I'm calling the following query to retrieve records and the primary table data elements are all included, but the JOIN elements of data are not included. Any suggestions what I'm missing?

private function getRecordsOfMbrs($endDate)
{
    $db    = $this->getDatabase();
    $query = $db->getQuery(true);
    $query->select('a.*, b.title, b.term_type, b.term_dur, u.name, u.email');
    $query->from($db->quoteName('#__mycomponent_records', 'a'));
    $query->join('LEFT', $db->quoteName('#__mycomponent_rectypes', 'b') . ' ON ' . $db->quoteName('b.id') . ' = ' . (int) $db->quoteName('a.type_id'));
    $query->join('LEFT', $db->quoteName('#__users', 'u') . ' ON ' . $db->quoteName('u.id') . ' = ' . (int) $db->quoteName('a.user_id'));
    $query->where($db->quoteName('a.end_date') . ' = ' . $db->quote($endDate));
    $query->where($db->quoteName('a.state') . ' = ' . (int) 2);
    $db->setQuery($query);
    try {
        $recMbrs = $db->loadObjectList();
        $this->logTask('Retrieved records for members.', 'notice');
        return $recMbrs;
    } catch (RuntimeException $e) {
        $this->logTask($e->getMessage());
        return Status::KNOCKOUT;
    }
}

If I use this query in the database directly, all is returned as expected.

SELECT a.*, b.title, b.term_type, b.term_dur, u.name, u.email
FROM `uj2k9_mycomponent_records` a
LEFT JOIN `uj2k9_mycomponent_rectypes` b ON b.id = a.type_id
LEFT JOIN `uj2k9_users` u ON u.id = a.user_id
WHERE a.end_date = '2024-04-24'
AND a.state = 2
2
  • Why does it make any sense at all to quote a column name (a string composed of letters, a dot, and an underscore THEN cast that string as an integer?!? Why not just hardcode the value 0 there? Surely you need to remove the (int) casting, right? From what I see, every use of (int) in your script is either unnecessary or actively doing harm. This is what is called a "footgun". To be honest, there is no part of your query building process that benefits from calling quoteName(). I recommend removing all of these code bloating calls. Commented May 21 at 23:23

2 Answers 2

2

You are casting the column name to integer in PHP, which always results in 0:

(int) $db->quoteName('a.type_id')

This results in query like this:

LEFT JOIN `uj2k9_mycomponent_rectypes` b ON b.id = 0

If you need to cast column values, use $query->castAs():

$query->castAs('INT', $db->quoteName('a.type_id'))
1

Your script is doing several things that it doesn't need to and a few things that are actively harmful to your process. Casting a column name to an integer doesn't make any sense, but I suspect you are just trying to implement some security measure that you've read elsewhere but in a different context.

Not only do you not need to cast a hardcoded integer as an integer, it damages your query to cast column names as integers.

Here's a rewrite where I've removed all of the non-helpful calls of quoteName(). The script becomes functional and also profoundly easier to read for humans.

private function getRecordsOfMbrs(string $endDate)
{
    $db = $this->getDatabase();
    $query = $db->getQuery(true)
        ->select('a.*, b.title, b.term_type, b.term_dur, u.name, u.email')
        ->from('#__mycomponent_records a')
        ->join('LEFT', '#__mycomponent_rectypes b ON b.id = a.type_id')
        ->join('LEFT', '#__users u ON u.id = a.user_id')
        ->where('a.end_date = ' . $db->quote($endDate))
        ->where('a.state = 2');
    $db->setQuery($query);
    try {
        $this->logTask('Retrieved records for members.', 'notice');
        return $db->loadObjectList();
    } catch (RuntimeException $e) {
        $this->logTask($e->getMessage());
        return Status::KNOCKOUT;
    }
}
7
  • Thanks Mick, I've not picked up on the $query->leftJoin() way of doing joins before so this is very helpful. I thought using the quoteName() was the preferred way to encase tables and fields? Commented May 23 at 0:13
  • It is the overly cautious advice given to all Joomlers to cover the high volume of "developers" who are novices with insufficient knowledge of security practices and how to write valid SQL queries. I assure you there is no vulnerability in this case. Commented May 23 at 1:03
  • @GlennArkell That could be because the method doesn't exist. There is no leftJoin() method on Joomla\Database\QueryInterface. Your IDE should warn you about that.
    – Sharky
    Commented May 23 at 5:17
  • @Sharky was it removed? There are many old posts on JSE that used it. joomla.stackexchange.com/search?q=leftJoin Commented May 23 at 5:19
  • 1
    Documentation is wrong in that it treats Joomla\Database\DatabaseAwareTrait::getDatabase() as returning a concrete Joomla\Database\DatabaseDriver class when it's actually typehinted to return Joomla\Database\DatabaseInterface. In turn, DatabaseDriver::getQuery() is documented as returning DatabaseQuery while DatabaseInterface::getQuery() returns QueryInterface. leftJoin() and other shortcut methods are present on DatabaseQuery class but not on the QueryInterface interface. These methods will not be added to the interface. They will be completely removed at some point.
    – Sharky
    Commented May 23 at 6:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.