Skip to content

Commit

Permalink
[com_categories] - convert to prepared statement (#27205)
Browse files Browse the repository at this point in the history
Co-authored-by: Quy <quy@fluxbb.org>
  • Loading branch information
2 people authored and HLeithner committed Jan 6, 2020
1 parent 5d03525 commit 1557ec2
Show file tree
Hide file tree
Showing 6 changed files with 238 additions and 97 deletions.
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')
&& !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

0 comments on commit 1557ec2

Please sign in to comment.