diff --git a/api/components/com_banners/src/Controller/BannersController.php b/api/components/com_banners/src/Controller/BannersController.php index 1f1cf2393aec1..50b240926862a 100644 --- a/api/components/com_banners/src/Controller/BannersController.php +++ b/api/components/com_banners/src/Controller/BannersController.php @@ -35,4 +35,36 @@ class BannersController extends ApiController * @since 3.0 */ protected $default_view = 'banners'; + + /** + * Query filter parameters => model state mappings + * + * @var array + */ + protected $queryFilterModelStateMap = [ + 'category_id' => [ + 'name' => 'filter.category_id', + 'type' => 'INT' + ], + 'client_id' => [ + 'name' => 'filter.client_id', + 'type' => 'INT' + ], + 'level' => [ + 'name' => 'filter.level', + 'type' => 'INT' + ], + 'search' => [ + 'name' => 'filter.search', + 'type' => 'STRING' + ], + 'state' => [ + 'name' => 'filter.published', + 'type' => 'INT' + ], + 'language' => [ + 'name' => 'filter.language', + 'type' => 'STRING' + ], + ]; } diff --git a/api/components/com_banners/src/Controller/ClientsController.php b/api/components/com_banners/src/Controller/ClientsController.php index 6ea9f0eee9bb7..779262188abe7 100644 --- a/api/components/com_banners/src/Controller/ClientsController.php +++ b/api/components/com_banners/src/Controller/ClientsController.php @@ -35,4 +35,24 @@ class ClientsController extends ApiController * @since 3.0 */ protected $default_view = 'clients'; + + /** + * Query filter parameters => model state mappings + * + * @var array + */ + protected $queryFilterModelStateMap = [ + 'purchase_type' => [ + 'name' => 'filter.purchase_type', + 'type' => 'INT' + ], + 'search' => [ + 'name' => 'filter.search', + 'type' => 'STRING' + ], + 'state' => [ + 'name' => 'filter.published', + 'type' => 'INT' + ] + ]; } diff --git a/api/components/com_categories/src/Controller/CategoriesController.php b/api/components/com_categories/src/Controller/CategoriesController.php index e0c7b8d29ded1..c753646df2bc3 100644 --- a/api/components/com_categories/src/Controller/CategoriesController.php +++ b/api/components/com_categories/src/Controller/CategoriesController.php @@ -37,6 +37,38 @@ class CategoriesController extends ApiController */ protected $default_view = 'categories'; + /** + * Query filter parameters => model state mappings + * + * @var array + */ + protected $queryFilterModelStateMap = [ + 'access' => [ + 'name' => 'filter.access', + 'type' => 'INT' + ], + 'level' => [ + 'name' => 'filter.level', + 'type' => 'INT' + ], + 'tag' => [ + 'name' => 'filter.tag', + 'type' => 'INT' + ], + 'search' => [ + 'name' => 'filter.search', + 'type' => 'STRING' + ], + 'state' => [ + 'name' => 'filter.published', + 'type' => 'INT' + ], + 'language' => [ + 'name' => 'filter.language', + 'type' => 'STRING' + ], + ]; + /** * Method to allow extended classes to manipulate the data to be saved for an extension. * @@ -115,6 +147,7 @@ public function displayItem($id = null) return parent::displayItem($id); } + /** * Basic display of a list view * diff --git a/api/components/com_contact/src/Controller/ContactController.php b/api/components/com_contact/src/Controller/ContactController.php index 9fa2e2821ed33..9f2633d7e060a 100644 --- a/api/components/com_contact/src/Controller/ContactController.php +++ b/api/components/com_contact/src/Controller/ContactController.php @@ -54,6 +54,46 @@ class ContactController extends ApiController */ protected $default_view = 'contacts'; + /** + * Query filter parameters => model state mappings + * + * @var array + */ + protected $queryFilterModelStateMap = [ + 'access' => [ + 'name' => 'filter.access', + 'type' => 'INT' + ], + 'category_id' => [ + 'name' => 'filter.category_id', + 'type' => 'INT' + ], + 'level' => [ + 'name' => 'filter.level', + 'type' => 'INT' + ], + 'featured' => [ + 'name' => 'filter.featured', + 'type' => 'INT' + ], + 'tag' => [ + 'name' => 'filter.tag', + 'type' => 'STRING' + ], + 'search' => [ + 'name' => 'filter.search', + 'type' => 'STRING' + ], + 'state' => [ + 'name' => 'filter.published', + 'type' => 'INT' + ], + 'language' => [ + 'name' => 'filter.language', + 'type' => 'STRING' + ], + ]; + /** * Method to allow extended classes to manipulate the data to be saved for an extension. * @@ -65,6 +105,8 @@ class ContactController extends ApiController */ protected function preprocessSaveData(array $data): array { + $data = (array) json_decode($this->input->json->getRaw(), true); + foreach (FieldsHelper::getFields('com_contact.contact') as $field) { if (isset($data[$field->name])) diff --git a/api/components/com_content/src/Controller/ArticlesController.php b/api/components/com_content/src/Controller/ArticlesController.php index be6fa8de592d8..1bac2c3685a6e 100644 --- a/api/components/com_content/src/Controller/ArticlesController.php +++ b/api/components/com_content/src/Controller/ArticlesController.php @@ -39,44 +39,36 @@ class ArticlesController extends ApiController protected $default_view = 'articles'; /** - * Article list view amended to add filtering of data + * Query filter parameters => model state mappings * - * @return static A BaseController object to support chaining. - * - * @since 4.0.0 + * @var array */ - public function displayList() - { - $apiFilterInfo = $this->input->get('filter', [], 'array'); - $filter = InputFilter::getInstance(); - - if (array_key_exists('author', $apiFilterInfo)) - { - $this->modelState->set('filter.author_id', $filter->clean($apiFilterInfo['author'], 'INT')); - } - - if (array_key_exists('category', $apiFilterInfo)) - { - $this->modelState->set('filter.category_id', $filter->clean($apiFilterInfo['category'], 'INT')); - } - - if (array_key_exists('search', $apiFilterInfo)) - { - $this->modelState->set('filter.search', $filter->clean($apiFilterInfo['search'], 'STRING')); - } - - if (array_key_exists('state', $apiFilterInfo)) - { - $this->modelState->set('filter.published', $filter->clean($apiFilterInfo['state'], 'INT')); - } - - if (array_key_exists('language', $apiFilterInfo)) - { - $this->modelState->set('filter.language', $filter->clean($apiFilterInfo['language'], 'STRING')); - } - - return parent::displayList(); - } + protected $queryFilterModelStateMap = [ + 'access' => [ + 'name' => 'filter.access', + 'type' => 'INT' + ], + 'author_id' => [ + 'name' => 'filter.author_id', + 'type' => 'INT' + ], + 'category_id' => [ + 'name' => 'filter.category_id', + 'type' => 'INT' + ], + 'search' => [ + 'name' => 'filter.search', + 'type' => 'STRING' + ], + 'state' => [ + 'name' => 'filter.published', + 'type' => 'INT' + ], + 'language' => [ + 'name' => 'filter.language', + 'type' => 'STRING' + ], + ]; /** * Method to allow extended classes to manipulate the data to be saved for an extension. diff --git a/api/components/com_fields/src/Controller/FieldsController.php b/api/components/com_fields/src/Controller/FieldsController.php index d3611102f6714..9a1065dcae10d 100644 --- a/api/components/com_fields/src/Controller/FieldsController.php +++ b/api/components/com_fields/src/Controller/FieldsController.php @@ -36,6 +36,42 @@ class FieldsController extends ApiController */ protected $default_view = 'fields'; + /** + * Query filter parameters => model state mappings + * + * @var array + */ + protected $queryFilterModelStateMap = [ + 'access' => [ + 'name' => 'filter.access', + 'type' => 'INT' + ], + 'assigned_cat_ids' => [ + 'name' => 'filter.assigned_cat_ids', + 'type' => 'INT' + ], + 'group_id' => [ + 'name' => 'filter.group_id', + 'type' => 'INT' + ], + 'only_use_in_subform' => [ + 'name' => 'filter.only_use_in_subform', + 'type' => 'INT' + ], + 'search' => [ + 'name' => 'filter.search', + 'type' => 'STRING' + ], + 'state' => [ + 'name' => 'filter.published', + 'type' => 'INT' + ], + 'language' => [ + 'name' => 'filter.language', + 'type' => 'STRING' + ], + ]; + /** * Basic display of an item view * diff --git a/api/components/com_tags/src/Controller/TagsController.php b/api/components/com_tags/src/Controller/TagsController.php index dc3eb6555cb8e..7f7689c5fefad 100644 --- a/api/components/com_tags/src/Controller/TagsController.php +++ b/api/components/com_tags/src/Controller/TagsController.php @@ -35,4 +35,32 @@ class TagsController extends ApiController * @since 3.0 */ protected $default_view = 'tags'; + + /** + * Query filter parameters => model state mappings + * + * @var array + */ + protected $queryFilterModelStateMap = [ + 'access' => [ + 'name' => 'filter.access', + 'type' => 'INT' + ], + 'level' => [ + 'name' => 'filter.level', + 'type' => 'INT' + ], + 'state' => [ + 'name' => 'filter.published', + 'type' => 'INT' + ], + 'search' => [ + 'name' => 'filter.search', + 'type' => 'STRING' + ], + 'language' => [ + 'name' => 'filter.language', + 'type' => 'STRING' + ], + ]; } diff --git a/api/components/com_users/src/Controller/UsersController.php b/api/components/com_users/src/Controller/UsersController.php index 5fb528de733a8..129fd17de2679 100644 --- a/api/components/com_users/src/Controller/UsersController.php +++ b/api/components/com_users/src/Controller/UsersController.php @@ -41,6 +41,39 @@ class UsersController extends ApiController */ protected $default_view = 'users'; + /** + * Query filter parameters => model state mappings. + * Date ranges need special handling, which we will do in the displayList() override. + * + * @var array + */ + protected $queryFilterModelStateMap = [ + 'active' => [ + 'name' => 'filter.active', + 'type' => 'INT' + ], + 'excluded' => [ + 'name' => 'filter.excluded', + 'type' => 'INT' + ], + 'group' => [ + 'name' => 'filter.group', + 'type' => 'INT' + ], + 'groups' => [ + 'name' => 'filter.groups', + 'type' => 'INT' + ], + 'search' => [ + 'name' => 'filter.search', + 'type' => 'STRING' + ], + 'state' => [ + 'name' => 'filter.published', + 'type' => 'INT' + ], + ]; + /** * Method to allow extended classes to manipulate the data to be saved for an extension. * @@ -79,26 +112,6 @@ public function displayList() $apiFilterInfo = $this->input->get('filter', [], 'array'); $filter = InputFilter::getInstance(); - if (array_key_exists('state', $apiFilterInfo)) - { - $this->modelState->set('filter.state', $filter->clean($apiFilterInfo['state'], 'INT')); - } - - if (array_key_exists('active', $apiFilterInfo)) - { - $this->modelState->set('filter.active', $filter->clean($apiFilterInfo['active'], 'INT')); - } - - if (array_key_exists('groupid', $apiFilterInfo)) - { - $this->modelState->set('filter.group_id', $filter->clean($apiFilterInfo['groupid'], 'INT')); - } - - if (array_key_exists('search', $apiFilterInfo)) - { - $this->modelState->set('filter.search', $filter->clean($apiFilterInfo['search'], 'STRING')); - } - if (array_key_exists('registrationDateStart', $apiFilterInfo)) { $registrationStartInput = $filter->clean($apiFilterInfo['registrationDateStart'], 'STRING'); diff --git a/libraries/src/MVC/Controller/ApiController.php b/libraries/src/MVC/Controller/ApiController.php index 2827843af1aa0..55fefb1140bf3 100644 --- a/libraries/src/MVC/Controller/ApiController.php +++ b/libraries/src/MVC/Controller/ApiController.php @@ -19,6 +19,7 @@ use Joomla\CMS\MVC\Model\ListModel; use Joomla\CMS\MVC\View\JsonApiView; use Joomla\CMS\Object\CMSObject; +use Joomla\CMS\Filter\InputFilter; use Joomla\Input\Input; use Joomla\String\Inflector; use Tobscure\JsonApi\Exception\InvalidParameterException; @@ -79,6 +80,13 @@ class ApiController extends BaseController */ protected $modelState; + /** + * Query filter parameters => model state mappings + * + * @var array + */ + protected $modelFilterStateMap = []; + /** * Constructor. * @@ -215,6 +223,9 @@ public function displayList() $this->modelState->set($this->context . '.list.limit', $limit); } + // Set model filter state from request query. + $this->setModelFilterStateFromRequest(); + $viewType = $this->app->getDocument()->getType(); $viewName = $this->input->get('view', $this->default_view); $viewLayout = $this->input->get('layout', 'default', 'string'); @@ -575,4 +586,30 @@ protected function preprocessSaveData(array $data): array { return $data; } + + /** + * Method to set request filter parameters in model state. + * + * @param array $data An array of input data. + * + * @return void + */ + protected function setModelFilterStateFromRequest() + { + $apiFilterInfo = $this->input->get('filter', [], 'array'); + $filter = InputFilter::getInstance(); + + foreach ($this->modelFilterStateMap as $apiFilterName => $modelState) + { + if (!array_key_exists($apiFilterName, $apiFilterInfo) || trim($apiFilterInfo[$apiFilterName]) !== '') + { + continue; + } + + $this->modelState->set( + $modelState['name'], + $filter->clean($apiFilterInfo[$apiFilterName], $modelState['type']) + ); + } + } }