Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[com_categories] - convert to prepared statement #27205

Merged
merged 25 commits into from
Jan 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 50 additions & 22 deletions administrator/components/com_categories/Field/CategoryeditField.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Joomla\CMS\Form\Field\ListField;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\Database\ParameterType;
use Joomla\Utilities\ArrayHelper;

/**
Expand Down Expand Up @@ -176,61 +177,73 @@ protected function getOptions()
$user = Factory::getUser();

$query = $db->getQuery(true)
->select('a.id AS value, a.title AS text, a.level, a.published, a.lft, a.language')
->from('#__categories AS a');
->select(
[
$db->quoteName('a.id', 'value'),
$db->quoteName('a.title', 'text'),
$db->quoteName('a.level'),
$db->quoteName('a.published'),
$db->quoteName('a.lft'),
$db->quoteName('a.language'),
]
)
->from($db->quoteName('#__categories', 'a'));

// Filter by the extension type
if ($this->element['parent'] == true || $jinput->get('option') == 'com_categories')
{
$query->where('(a.extension = ' . $db->quote($extension) . ' OR a.parent_id = 0)');
$query->where('(' . $db->quoteName('a.extension') . ' = :extension OR ' . $db->quoteName('a.parent_id') . ' = 0)')
->bind(':extension', $extension);
}
else
{
$query->where('(a.extension = ' . $db->quote($extension) . ')');
$query->where($db->quoteName('a.extension') . ' = :extension')
->bind(':extension', $extension);
}

// Filter language
if (!empty($this->element['language']))
{
if (strpos($this->element['language'], ',') !== false)
{
$language = implode(',', $db->quote(explode(',', $this->element['language'])));
$language = explode(',', $this->element['language']);
}
else
{
$language = $db->quote($this->element['language']);
$language = $this->element['language'];
}

$query->where($db->quoteName('a.language') . ' IN (' . $language . ')');
$query->whereIn($db->quoteName('a.language'), $language, ParameterType::STRING);
}

// Filter on the published state
$query->where('a.published IN (' . implode(',', ArrayHelper::toInteger($published)) . ')');
$state = ArrayHelper::toInteger($published);
$query->whereIn($db->quoteName('a.published'), $state);

// Filter categories on User Access Level
// Filter by access level on categories.
if (!$user->authorise('core.admin'))
{
$groups = implode(',', $user->getAuthorisedViewLevels());
$query->where('a.access IN (' . $groups . ')');
$groups = $user->getAuthorisedViewLevels();
$query->whereIn($db->quoteName('a.access'), $groups);
}

$query->order('a.lft ASC');
$query->order($db->quoteName('a.lft') . ' ASC');

// If parent isn't explicitly stated but we are in com_categories assume we want parents
if ($oldCat != 0 && ($this->element['parent'] == true || $jinput->get('option') == 'com_categories'))
{
// Prevent parenting to children of this item.
// To rearrange parents and children move the children up, not the parents down.
$query->join('LEFT', $db->quoteName('#__categories') . ' AS p ON p.id = ' . (int) $oldCat)
->where('NOT(a.lft >= p.lft AND a.rgt <= p.rgt)');

$rowQuery = $db->getQuery(true);
$rowQuery->select('a.id AS value, a.title AS text, a.level, a.parent_id')
->from('#__categories AS a')
->where('a.id = ' . (int) $oldCat);
$db->setQuery($rowQuery);
$row = $db->loadObject();
$query->join(
'LEFT',
$db->quoteName('#__categories', 'p'),
$db->quoteName('p.id') . ' = :oldcat'
)
->bind(':oldcat', $oldCat, ParameterType::INTEGER)
->where('NOT(' . $db->quoteName('a.lft') . ' >= ' . $db->quoteName('p.lft')
. ' AND ' . $db->quoteName('a.rgt') . ' <= ' . $db->quoteName('p.rgt') . ')'
);
}

// Get the options.
Expand Down Expand Up @@ -332,10 +345,25 @@ protected function getOptions()
}
}

if (($this->element['parent'] == true || $jinput->get('option') == 'com_categories')
&& (isset($row) && !isset($options[0]))
if ($oldCat != 0 && ($this->element['parent'] == true || $jinput->get('option') == 'com_categories')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the changes here and to the query below?

&& !isset($options[0])
&& isset($this->element['show_root']))
{
$rowQuery = $db->getQuery(true)
->select(
[
$db->quoteName('a.id', 'value'),
$db->quoteName('a.title', 'text'),
$db->quoteName('a.level'),
$db->quoteName('a.parent_id'),
]
)
->from($db->quoteName('#__categories', 'a'))
->where($db->quoteName('a.id') . ' = :aid')
->bind(':aid', $oldCat, ParameterType::INTEGER);
$db->setQuery($rowQuery);
$row = $db->loadObject();

if ($row->parent_id == '1')
{
$parent = new \stdClass;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Joomla\CMS\Language\LanguageHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Session\Session;
use Joomla\Database\ParameterType;

/**
* Supports a modal category picker.
Expand Down Expand Up @@ -119,7 +120,8 @@ function jSelectCategory_" . $this->id . "(id, title, object) {
$query = $db->getQuery(true)
->select($db->quoteName('title'))
->from($db->quoteName('#__categories'))
->where($db->quoteName('id') . ' = ' . (int) $value);
->where($db->quoteName('id') . ' = :value')
->bind(':value', $value, ParameterType::INTEGER);
$db->setQuery($query);

try
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Associations;
use Joomla\CMS\Table\Table;
use Joomla\Database\ParameterType;

/**
* Categories helper.
Expand All @@ -35,20 +36,21 @@ public static function getAssociations($pk, $extension = 'com_content')
$langAssociations = Associations::getAssociations($extension, '#__categories', 'com_categories.item', $pk, 'id', 'alias', '');
$associations = array();
$user = Factory::getUser();
$groups = implode(',', $user->getAuthorisedViewLevels());
$groups = $user->getAuthorisedViewLevels();

foreach ($langAssociations as $langAssociation)
{
// Include only published categories with user access
$arrId = explode(':', $langAssociation->id);
$assocId = $arrId[0];
$db = Factory::getDbo();
$arrId = explode(':', $langAssociation->id);
$assocId = (int) $arrId[0];
$db = Factory::getDbo();

$query = $db->getQuery(true)
->select($db->quoteName('published'))
->from($db->quoteName('#__categories'))
->where('access IN (' . $groups . ')')
->where($db->quoteName('id') . ' = ' . (int) $assocId);
->whereIn($db->quoteName('access'), $groups)
->where($db->quoteName('id') . ' = :associd')
->bind(':associd', $assocId, ParameterType::INTEGER);

$result = (int) $db->setQuery($query)->loadResult();

Expand Down
108 changes: 81 additions & 27 deletions administrator/components/com_categories/Model/CategoriesModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Joomla\CMS\Language\Associations;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\MVC\Model\ListModel;
use Joomla\Database\ParameterType;

/**
* Categories Component Categories Model
Expand Down Expand Up @@ -167,70 +168,105 @@ protected function getListQuery()
', a.language'
)
);
$query->from('#__categories AS a');
$query->from($db->quoteName('#__categories', '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');
$query->select(
[
$db->quoteName('l.title', 'language_title'),
$db->quoteName('l.image', 'language_image'),
]
)
->join(
'LEFT',
$db->quoteName('#__languages', 'l'),
$db->quoteName('l.lang_code') . ' = ' . $db->quoteName('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');
$query->select($db->quoteName('uc.name', 'editor'))
->join(
'LEFT',
$db->quoteName('#__users', 'uc'),
$db->quoteName('uc.id') . ' = ' . $db->quoteName('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');
$query->select($db->quoteName('ag.title', 'access_level'))
->join(
'LEFT',
$db->quoteName('#__viewlevels', 'ag'),
$db->quoteName('ag.id') . ' = ' . $db->quoteName('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');
$query->select($db->quoteName('ua.name', 'author_name'))
->join(
'LEFT',
$db->quoteName('#__users', 'ua'),
$db->quoteName('ua.id') . ' = ' . $db->quoteName('a.created_user_id')
);

// Join over the associations.
$assoc = $this->getAssoc();

if ($assoc)
{
$query->select('COUNT(asso2.id)>1 as association')
->join('LEFT', '#__associations AS asso ON asso.id = a.id AND asso.context=' . $db->quote('com_categories.item'))
->join('LEFT', '#__associations AS asso2 ON asso2.key = asso.key')
->join(
'LEFT',
$db->quoteName('#__associations', 'asso'),
$db->quoteName('asso.id') . ' = ' . $db->quoteName('a.id')
. ' AND ' . $db->quoteName('asso.context') . ' = ' . $db->quote('com_categories.item')
)
->join(
'LEFT',
$db->quoteName('#__associations', 'asso2'),
$db->quoteName('asso2.key') . ' = ' . $db->quoteName('asso.key')
)
->group('a.id, l.title, uc.name, ag.title, ua.name');
}

// Filter by extension
if ($extension = $this->getState('filter.extension'))
{
$query->where('a.extension = ' . $db->quote($extension));
$query->where($db->quoteName('a.extension') . ' = :extension')
->bind(':extension', $extension);
}

// Filter on the level.
if ($level = $this->getState('filter.level'))
if ($level = (int) $this->getState('filter.level'))
{
$query->where('a.level <= ' . (int) $level);
$query->where($db->quoteName('a.level') . ' <= :level')
->bind(':level', $level, ParameterType::INTEGER);
}

// Filter by access level.
if ($access = $this->getState('filter.access'))
if ($access = (int) $this->getState('filter.access'))
{
$query->where('a.access = ' . (int) $access);
$query->where($db->quoteName('a.access') . ' = :access')
->bind(':access', $access, ParameterType::INTEGER);
}

// Implement View Level Access
if (!$user->authorise('core.admin'))
{
$groups = implode(',', $user->getAuthorisedViewLevels());
$query->where('a.access IN (' . $groups . ')');
$groups = $user->getAuthorisedViewLevels();
$query->whereIn($db->quoteName('a.access'), $groups);
}

// Filter by published state
$published = (string) $this->getState('filter.published');

if (is_numeric($published))
{
$query->where('a.published = ' . (int) $published);
$published = (int) $published;
$query->where($db->quoteName('a.published') . ' = :published')
->bind(':published', $published, ParameterType::INTEGER);
}
elseif ($published === '')
{
$query->where('(a.published IN (0, 1))');
$query->whereIn($db->quoteName('a.published'), [0, 1]);
}

// Filter by search in title
Expand All @@ -240,32 +276,50 @@ protected function getListQuery()
{
if (stripos($search, 'id:') === 0)
{
$query->where('a.id = ' . (int) substr($search, 3));
$search = (int) substr($search, 3);
$query->where($db->quoteName('a.id') . ' = :search')
->bind(':search', $search, ParameterType::INTEGER);
}
else
{
$search = $db->quote('%' . str_replace(' ', '%', $db->escape(trim($search), true) . '%'));
$query->where('(a.title LIKE ' . $search . ' OR a.alias LIKE ' . $search . ' OR a.note LIKE ' . $search . ')');
$search = '%' . str_replace(' ', '%', trim($search)) . '%';
$query->extendWhere(
'AND',
[
$db->quoteName('a.title') . ' LIKE :title',
$db->quoteName('a.alias') . ' LIKE :alias',
$db->quoteName('a.note') . ' LIKE :note',
],
'OR'
)
->bind(':title', $search)
->bind(':alias', $search)
->bind(':note', $search);
}
}

// Filter on the language.
if ($language = $this->getState('filter.language'))
{
$query->where('a.language = ' . $db->quote($language));
$query->where($db->quoteName('a.language') . ' = :language')
->bind(':language', $language);
}

// Filter by a single tag.
$tagId = $this->getState('filter.tag');

if (is_numeric($tagId))
{
$query->where($db->quoteName('tagmap.tag_id') . ' = ' . (int) $tagId)
$tagId = (int) $tagId;
$typeAlias = $extension . '.category';
$query->where($db->quoteName('tagmap.tag_id') . ' = :tagid')
->bind(':tagid', $tagId, ParameterType::INTEGER)
->join(
'LEFT', $db->quoteName('#__contentitem_tag_map', 'tagmap')
. ' ON ' . $db->quoteName('tagmap.content_item_id') . ' = ' . $db->quoteName('a.id')
. ' AND ' . $db->quoteName('tagmap.type_alias') . ' = ' . $db->quote($extension . '.category')
);
. ' AND ' . $db->quoteName('tagmap.type_alias') . ' = :typealias'
)
->bind(':typealias', $typeAlias);
}

// Add the list ordering clause
Expand Down
Loading