J4 Issue ?
avatar brianteeman
brianteeman
21 Jan 2020

I see some queries are like

$query->join('LEFT', '#__categories AS c ON c.id = a.catid');

and others are like

$query->join('LEFT', $db->quoteName('#__categories') . ' AS c ON c.id = a.catid');

Are they all supposed to be like the second?

avatar brianteeman brianteeman - open - 21 Jan 2020
avatar joomla-cms-bot joomla-cms-bot - change - 21 Jan 2020
Labels Added: ?
avatar joomla-cms-bot joomla-cms-bot - labeled - 21 Jan 2020
avatar mbabker
mbabker - comment - 21 Jan 2020

Realistically, quoted identifiers (table and column names mainly) are only essential if you're using reserved keywords inside of a query. But, Joomla seems to have a thing for quoting everything possible so people spend less time thinking about whether quoting is necessary. So yes, for consistency it probably should be quoted, but no it is not mandatory.

avatar mbabker
mbabker - comment - 21 Jan 2020

And if you really wanted to get obsessive about it, the right line would look something like this:

// Using sprintf because there's way too much concatenation otherwise
// Results in LEFT JOIN `#__categories` AS c ON `c`.`id` = `a`.`catid` for MySQL
$query->join('LEFT', sprintf('%s AS c ON %s = %s', $db->quoteName('#__categories'), $db->quoteName('c.id'), $db->quoteName('a.catid'));
avatar alikon
alikon - comment - 21 Jan 2020

less readable that way at my eyes, i would prefer

$query->join(
'LEFT',
 $db->quoteName('#__categories', 'c'), 
 $db->quoteName('c.id') .' = '. $db->quoteName('a.catid')
);

but just my personal taste

avatar brianteeman
brianteeman - comment - 21 Jan 2020

I always think that the code in joomla should serve as a good example to extension developers and site builders. Most know nothing about php code they just know about joomla code - and then like me not very much and need to learn by example.

It really does look very odd when you get mixed styles in the same query

$query->select(
$this->getState(
'list.select',
'DISTINCT a.id, a.title, a.name, a.checked_out, a.checked_out_time, a.note' .
', a.state, a.access, a.created_time, a.created_user_id, a.ordering, a.language' .
', a.fieldparams, a.params, a.type, a.default_value, a.context, a.group_id' .
', a.label, a.description, a.required'
)
);
$query->from('#__fields AS a');
// Join over the language
$query->select('l.title AS language_title, l.image AS language_image')
->join('LEFT', $db->quoteName('#__languages') . ' AS l ON l.lang_code = a.language');
// Join over the users for the checked out user.
$query->select('uc.name AS editor')->join('LEFT', '#__users AS uc ON uc.id=a.checked_out');
// Join over the asset groups.
$query->select('ag.title AS access_level')->join('LEFT', '#__viewlevels AS ag ON ag.id = a.access');
// Join over the users for the author.
$query->select('ua.name AS author_name')->join('LEFT', '#__users AS ua ON ua.id = a.created_user_id');
// Join over the field groups.
$query->select('g.title AS group_title, g.access as group_access, g.state AS group_state, g.note as group_note');
$query->join('LEFT', '#__fields_groups AS g ON g.id = a.group_id');
// Filter by context
if ($context = $this->getState('filter.context'))
{
$query->where($db->quoteName('a.context') . ' = :context')
->bind(':context', $context);
}
// Filter by access level.
if ($access = $this->getState('filter.access'))
{
if (is_array($access))
{
$access = ArrayHelper::toInteger($access);
$query->whereIn($db->quoteName('a.access'), $access);
}
else
{
$access = (int) $access;
$query->where($db->quoteName('a.access') . ' = :access')
->bind(':access', $access, ParameterType::INTEGER);
}
}

avatar mbabker
mbabker - comment - 21 Jan 2020

less readable that way at my eyes, i would prefer [snip]

Can't get that one without a hard B/C break in the API (splitting the existing second param into two separate parameters, one for the table name and one for the join condition). You're right it's more readable, but realistically the ship has sailed already on having a query builder API that is also human eye friendly.

avatar alikon
alikon - comment - 21 Jan 2020

@brianteeman
good point indeed,
and mostly my fault triyng to convert SQL to prepared statement, in a fast way

@mbabker
not sure why you call an hard B/C break

this is a much more clean example maybe

// Get the associated contact items
$db = Factory::getDbo();
$query = $db->getQuery(true)
->select(
[
$db->quoteName('c.id'),
$db->quoteName('c.name', 'title'),
$db->quoteName('l.sef', 'lang_sef'),
$db->quoteName('lang_code'),
$db->quoteName('cat.title', 'category_title'),
$db->quoteName('l.image'),
$db->quoteName('l.title', 'language_title'),
]
)
->from($db->quoteName('#__contact_details', 'c'))
->join('LEFT', $db->quoteName('#__categories', 'cat'), $db->quoteName('cat.id') . ' = ' . $db->quoteName('c.catid'))
->join('LEFT', $db->quoteName('#__languages', 'l'), $db->quoteName('c.language') . ' = ' . $db->quoteName('l.lang_code'))
->whereIn($db->quoteName('c.id'), array_values($associations))
->where($db->quoteName('c.id') . ' != :id')
->bind(':id', $contactid, ParameterType::INTEGER);
$db->setQuery($query);

avatar mbabker
mbabker - comment - 21 Jan 2020

Oh, nevermind. Apparently this has already changed (with only part of the hard B/C break).

The signature in 3.x is:

public function join($type, $conditions);

In 4.0, after joomla-framework/database#143, the signature is:

public function join($type, $table, $condition = null);

So the way you suggested works.

There is a B/C break in the changed signature if anyone has custom query builder classes, but it's not B/C breaking to users of the API since the base class is accounting for both the old usage and new usage (basically since the $condition parameter is nullable it avoids the worst breaking change that could be made, and that's what I was worried about happening).

avatar alikon alikon - change - 23 Jan 2020
Labels Added: J4 Issue
avatar alikon alikon - labeled - 23 Jan 2020
avatar richard67 richard67 - change - 27 Jan 2020
Status New Confirmed
avatar brianteeman
brianteeman - comment - 6 Feb 2020

Closing as my question was answered

avatar brianteeman brianteeman - close - 6 Feb 2020
avatar brianteeman brianteeman - change - 6 Feb 2020
Status Confirmed Closed
Closed_Date 0000-00-00 00:00:00 2020-02-06 23:05:30
Closed_By brianteeman

Add a Comment

Login with GitHub to post a comment