From 80ecb2b28909626cf2da4153c658ea6702544415 Mon Sep 17 00:00:00 2001 From: camer0n Date: Thu, 27 Mar 2025 08:04:59 -0700 Subject: [PATCH] Improved testing of admin-ui search with custom handler. --- e107_handlers/admin_ui.php | 76 +++++++++++++++---- .../tests/unit/e_admin_controller_uiTest.php | 50 ++++++++---- 2 files changed, 98 insertions(+), 28 deletions(-) diff --git a/e107_handlers/admin_ui.php b/e107_handlers/admin_ui.php index 5162eb9e8..adceec6f3 100755 --- a/e107_handlers/admin_ui.php +++ b/e107_handlers/admin_ui.php @@ -3997,20 +3997,34 @@ class e_admin_controller_ui extends e_admin_controller //something like handleListUrlTypeFilter(); for custom handling of 'url_type' field name filters $method = 'handle'.$this->getRequest()->getActionName().$this->getRequest()->camelize($filter[0]).'Filter'; $args = array_slice($filter, 1); - + // fwrite(STDOUT, __LINE__ . " Searching custom method: " . $method . "\n"); e107::getMessage()->addDebug('Searching for custom filter method: ' .$method. '(' .implode(', ', $args). ')'); - - if(method_exists($this, $method)) // callback handling + if (method_exists($this, $method)) // method handling { - //return $this->$method($filter[1], $selected); selected? - // better approach - pass all values as method arguments - // NOTE - callbacks are allowed to return QUERY as a string, it'll be added in the WHERE clause + e107::getMessage()->addDebug('Executing filter callback ' . get_class($this) . '::' . $method . '(' . implode(', ', $args) . ')'); - e107::getMessage()->addDebug('Executing filter callback '.get_class($this).'::'.$method.'('.implode(', ', $args).')'); - - return call_user_func_array(array($this, $method), $args); + return call_user_func_array([$this, $method], $args); } + elseif (property_exists($this, $method)) // dynamic property handling + { + + // Debug information showing that the property was found + e107::getMessage()->addDebug('Accessing filter property ' . get_class($this) . '::$' . $method . ''); + + if (is_callable($this->$method)) + { + e107::getMessage()->addDebug('Executing callable property ' . get_class($this) . '::$' . $method . '(' . implode(', ', $args) . ')'); + + return call_user_func_array($this->$method, $args); + } + + // If not callable, return the property value as is (could be a query fragment or other data) + e107::getMessage()->addDebug('Returning property value from ' . get_class($this) . '::$' . $method . ''); + + return $this->$method; + } + $res = array($filter[0], $filter[1]); $this->_log('listQry Filtered by ' .$filter[0]. ' (' .$filter[1]. ')'); @@ -4889,6 +4903,26 @@ class e_admin_controller_ui extends e_admin_controller */ public function _modifyListQrySearch($listQry, $searchTerm, $filterOptions, string $tablePath, string $tableFrom, string $primaryName, $raw, $orderField, $qryAsc, $forceFrom, int $qryFrom, $forceTo, int $perPage, $qryField, $isfilter, $handleAction) { + +/* + e107::getMessage()->addDebug('listQry: ' . $listQry); + e107::getMessage()->addDebug('searchTerm: ' . $searchTerm); + e107::getMessage()->addDebug('filterOptions: ' . $filterOptions); + e107::getMessage()->addDebug('tablePath: ' . $tablePath); + e107::getMessage()->addDebug('handleAction: ' . $handleAction); + e107::getMessage()->addDebug('tableFrom: ' . $tableFrom); + e107::getMessage()->addDebug('primaryName: ' . $primaryName); + e107::getMessage()->addDebug('raw: ' . $raw); + e107::getMessage()->addDebug('orderField: ' . $orderField); + e107::getMessage()->addDebug('qryAsc: ' . $qryAsc); + e107::getMessage()->addDebug('forceFrom: ' . $forceFrom); + e107::getMessage()->addDebug('qryFrom: ' . $qryFrom); + e107::getMessage()->addDebug('forceTo: ' . $forceTo); + e107::getMessage()->addDebug('perPage: ' . $perPage); + e107::getMessage()->addDebug('qryField: ' . $qryField); + e107::getMessage()->addDebug('isfilter: ' . ($isfilter ? 'true' : 'false'));*/ + + $tp = e107::getParser(); $fields = $this->getFields(); $joinData = $this->getJoinData(); @@ -4905,6 +4939,7 @@ class e_admin_controller_ui extends e_admin_controller $searchQuery = $this->fixSearchWildcards($searchTerm); $searchFilter = $this->_parseFilterRequest($filterOptions); + $listQry = $this->listQry; // check for modification during parseFilterRequest(); if(E107_DEBUG_LEVEL == E107_DBG_SQLQUERIES) @@ -4960,7 +4995,7 @@ class e_admin_controller_ui extends e_admin_controller 'thisyear' => strtotime('+1 year', $filterValue), ]; - $end = isset($endOpts[$dateSearchType]) ? $endOpts[$dateSearchType] : time(); + $end = $endOpts[$dateSearchType] ?? time(); if(E107_DEBUG_LEVEL == E107_DBG_SQLQUERIES) { @@ -5043,16 +5078,26 @@ class e_admin_controller_ui extends e_admin_controller if($this->_isSearchField($var, $searchQuery)) { // Search for customer filter handler. - $cutomerSearchMethod = 'handle' . $handleAction . eHelper::camelize($key) . 'Search'; + $customSearchMethod = 'handle' . $handleAction . eHelper::camelize($key) . 'Search'; + $args = array($searchTerm); - e107::getMessage()->addDebug('Searching for custom search method: ' . $className . '::' . $cutomerSearchMethod . '(' . implode(', ', $args) . ')'); + e107::getMessage()->addDebug('Searching for custom search method: ' . $className . '::' . $customSearchMethod . '(' . implode(', ', $args) . ')'); - if(method_exists($this, $cutomerSearchMethod)) // callback handling + if (method_exists($this, $customSearchMethod)) // callback handling { - e107::getMessage()->addDebug('Executing custom search callback ' . $className . '::' . $cutomerSearchMethod . '(' . implode(', ', $args) . ')'); + e107::getMessage()->addDebug('Executing custom search callback ' . $className . '::' . $customSearchMethod . '(' . implode(', ', $args) . ')'); + + $filter[] = call_user_func_array([$this, $customSearchMethod], $args); + continue; + } + elseif (property_exists($this, $customSearchMethod)) // check for dynamic property + { + + e107::getMessage()->addDebug('Using custom search property ' . $className . '::$' . $customSearchMethod . ''); + + $filter[] = call_user_func_array($this->$customSearchMethod, $args); - $filter[] = call_user_func_array(array($this, $cutomerSearchMethod), $args); continue; } @@ -5120,6 +5165,7 @@ class e_admin_controller_ui extends e_admin_controller } + // fwrite(STDOUT, __LINE__ . print_r($filter,true) . "\n"); if(strpos($filterOptions, 'searchfield__') === 0) // search in specific field, so remove the above filters. diff --git a/e107_tests/tests/unit/e_admin_controller_uiTest.php b/e107_tests/tests/unit/e_admin_controller_uiTest.php index 6bac4e1da..866297826 100644 --- a/e107_tests/tests/unit/e_admin_controller_uiTest.php +++ b/e107_tests/tests/unit/e_admin_controller_uiTest.php @@ -9,26 +9,25 @@ */ + class e_admin_controller_uiTest extends \Codeception\Test\Unit { /** @var e_admin_controller_ui */ protected $ui; + protected $req; protected function _before() { - try { - $this->ui = $this->make('e_admin_controller_ui'); + $this->ui = $this->make(e_admin_controller_ui::class); + $this->req = $this->make(e_admin_request::class); } - catch(Exception $e) + catch (Exception $e) { - $this::fail("Couldn't load e_admin_controller_ui object"); + $this::fail("Couldn't load e_admin_controller_ui object: " . $e->getMessage()); } - - - } public function testJoinAlias() @@ -97,7 +96,7 @@ 'cal_by_cell' => 'cl.cal_by_cell', ); - $this->assertEquals($expected,$actual); + self::assertEquals($expected,$actual); } @@ -118,26 +117,29 @@ $perPage = 10; $qryField = null; $isfilter = false; - $handleAction = 'list'; + $handleAction = 'List'; $this->ui->setFields([ 'user_id' => array('title'=>'User ID', '__tableField' => 'u.user_id', 'type'=>'int', 'data'=>'int'), 'user_name' => array('title' => 'Name', '__tableField' => 'u.user_name', 'type' => 'text', 'data'=>'safestr'), // Display name 'user_login' => array('title' => 'Login','__tableField' => 'u.user_login', 'type' => 'text', 'data'=>'safestr'), // Real name (no real vetting) + 'user_phone' => array('title' => 'Phone','__tableField' => 'u.user_phone', 'search'=>true, 'type' => 'text', 'data'=>'safestr'), // Real name (no real vetting) + + ]); // Test single word search term. $result = $this->ui->_modifyListQrySearch($listQry, 'admin', $filterOptions, $tablePath, $tableFrom, $primaryName, $raw, $orderField, $qryAsc, $forceFrom, $qryFrom, $forceTo, $perPage, $qryField, $isfilter, $handleAction); - $expected = "SELECT u.* FROM `#user` WHERE 1 AND ( u.user_name LIKE '%admin%' OR u.user_login LIKE '%admin%' ) LIMIT 0, 10"; + $expected = "SELECT u.* FROM `#user` WHERE 1 AND ( u.user_name LIKE '%admin%' OR u.user_login LIKE '%admin%' OR u.user_phone LIKE '%admin%' ) LIMIT 0, 10"; $this::assertSame($expected, $result); // Test multiple word search term. $result = $this->ui->_modifyListQrySearch($listQry, 'firstname lastname', $filterOptions, $tablePath, $tableFrom, $primaryName, $raw, $orderField, $qryAsc, $forceFrom, $qryFrom, $forceTo, $perPage, $qryField, $isfilter, $handleAction); - $expected = "SELECT u.* FROM `#user` WHERE 1 AND (u.user_name LIKE '%firstname%' OR u.user_login LIKE '%firstname%') AND (u.user_name LIKE '%lastname%' OR u.user_login LIKE '%lastname%') LIMIT 0, 10"; + $expected = "SELECT u.* FROM `#user` WHERE 1 AND (u.user_name LIKE '%firstname%' OR u.user_login LIKE '%firstname%' OR u.user_phone LIKE '%firstname%') AND (u.user_name LIKE '%lastname%' OR u.user_login LIKE '%lastname%' OR u.user_phone LIKE '%lastname%') LIMIT 0, 10"; $this::assertSame($expected, $result); // Search term in quotes. - $expected = "SELECT u.* FROM `#user` WHERE 1 AND ( u.user_name LIKE '%firstname lastname%' OR u.user_login LIKE '%firstname lastname%' ) LIMIT 0, 10"; + $expected = "SELECT u.* FROM `#user` WHERE 1 AND ( u.user_name LIKE '%firstname lastname%' OR u.user_login LIKE '%firstname lastname%' OR u.user_phone LIKE '%firstname lastname%' ) LIMIT 0, 10"; // Double-quotes. $result = $this->ui->_modifyListQrySearch($listQry, '"firstname lastname"', $filterOptions, $tablePath, $tableFrom, $primaryName, $raw, $orderField, $qryAsc, $forceFrom, $qryFrom, $forceTo, $perPage, $qryField, $isfilter, $handleAction); @@ -149,9 +151,31 @@ // Single quote as apostophie. $result = $this->ui->_modifyListQrySearch($listQry, "burt's", $filterOptions, $tablePath, $tableFrom, $primaryName, $raw, $orderField, $qryAsc, $forceFrom, $qryFrom, $forceTo, $perPage, $qryField, $isfilter, $handleAction); - $expected = "SELECT u.* FROM `#user` WHERE 1 AND ( u.user_name LIKE '%burt's%' OR u.user_login LIKE '%burt's%' ) LIMIT 0, 10"; + $expected = "SELECT u.* FROM `#user` WHERE 1 AND ( u.user_name LIKE '%burt's%' OR u.user_login LIKE '%burt's%' OR u.user_phone LIKE '%burt's%' ) LIMIT 0, 10"; $this::assertSame($expected, $result); + + // Search Specific Field Test + + $this->req->setAction('List'); + $this->req->setQuery('searchquery', '5551234'); + $this->ui->setRequest($this->req); + + // Simulate a custom search handler for user_phone + $this->ui->handleListSearchfieldFilter = function ($field) + { + $search = $this->ui->getQuery('searchquery'); + return "u.user_phone LIKE '%custom_phone_" . $search . "%'"; + }; + + // Test custom search specifically for user_phone + $filterOptions = 'searchfield__user_phone'; + $result = $this->ui->_modifyListQrySearch($listQry, '5551234', $filterOptions, $tablePath, $tableFrom, $primaryName, $raw, $orderField, $qryAsc, $forceFrom, $qryFrom, $forceTo, $perPage, $qryField, $isfilter, $handleAction); + + // Expected result when the custom search handler is used + $expected = "SELECT u.* FROM `#user` WHERE 1 AND u.user_phone LIKE '%custom_phone_5551234%' LIMIT 0, 10"; + $this::assertSame($expected, $result); + } /* public function testGetSortParent()