diff --git a/app_controller.php b/app_controller.php index ebeee34..14ab045 100644 --- a/app_controller.php +++ b/app_controller.php @@ -185,25 +185,21 @@ class AppController extends Controller { // Unserialize our complex structure of fields // This SHOULD always be set, except when debugging - if (isset($params['fields'])) - $params['fields'] = unserialize($params['fields']); - else - $params['fields'] = array($this->{$this->modelClass}->alias - .'.'. - $this->{$this->modelClass}->primarKey); + if (isset($params['post'])) + $params['post'] = unserialize($params['post']); - // Unserialize the list of ids, if present. - if (isset($params['custom'])) - $params['custom'] = unserialize($params['custom']); + + // This SHOULD always be set, except when debugging + if (!isset($params['post']['fields'])) + $params['post']['fields'] = array($this->{$this->modelClass}->alias + .'.'. + $this->{$this->modelClass}->primaryKey); + + // Make sure the action parameter at least exists, and + // promote it to the top level (since it drives the operation). + if (isset($params['post']['action'])) + $params['action'] = $params['post']['action']; else - $params['custom'] = null; - - // Unserialize the list of ids, if present. - if (isset($params['idlist'])) - $params['idlist'] = unserialize($params['idlist']); - - // Make sure the action parameter at least exists - if (!isset($params['action'])) $params['action'] = null; } @@ -227,12 +223,14 @@ class AppController extends Controller { function gridDataCount(&$params, &$model) { // Establish the tables and conditions for counting - $query = array_intersect_key($this->gridDataCountTables($params, $model), + $query = array_intersect_key($this->gridDataCountTableSet($params, $model), array('link'=>1, 'contain'=>1)); - // Add in the conditions and grouping - $query['conditions'] = $this->gridDataCountConditions($params, $model); - $query['group'] = $this->gridDataCountGroup($params, $model); + // Conditions for the count + $query['conditions'] = $this->gridDataCountConditionSet($params, $model); + + // Grouping (which would not be typical) + $query['group'] = $this->gridDataCountGroup($params, $model); // DEBUG PURPOSES ONLY! $params['count_query'] = $query; @@ -250,11 +248,29 @@ class AppController extends Controller { return $this->gridDataTables($params, $model); } + function gridDataCountTableSet(&$params, &$model) { + // Preliminary set of tables + $query = array_intersect_key($this->gridDataCountTables($params, $model), + array('link'=>1, 'contain'=>1)); + + // Perform filtering based on user request: $params['post']['filter'] + return array_intersect_key($this->gridDataFilterTables($params, $model, $query), + array('link'=>1, 'contain'=>1)); + } + function gridDataCountConditions(&$params, &$model) { // Same conditions for counting as for retreiving return $this->gridDataConditions($params, $model); } + function gridDataCountConditionSet(&$params, &$model) { + // Conditions for the count + $conditions = $this->gridDataCountConditions($params, $model); + + // Perform filtering based on user request: $params['post']['filter'] + return $this->gridDataFilterConditions($params, $model, $conditions); + } + function gridDataCountGroup(&$params, &$model) { // Grouping will screw up the count, since it // causes the results to be split into chunks @@ -265,6 +281,101 @@ class AppController extends Controller { } + /************************************************************************** + ************************************************************************** + ************************************************************************** + * gridData FILTERING + */ + + function gridDataFilterTables(&$params, &$model, $query) { + if (isset($query['link'])) + $link = 'link'; + else + $link = 'contain'; + + if (empty($params['post']['filter'])) + return $query; + + foreach ($params['post']['filter'] AS $filter => $value) { + if (preg_match("/\./", $filter)) { + list($tbl, $id) = explode(".", $filter); + } + elseif (preg_match('/^(.*)_(id)$/', $filter, $matches)) { + list($tbl, $id) = array_slice($matches, 1); + } + else { + $tbl = $filter; + $id = null; + } + + $table = $this->gridDataFilterTable($params, $model, $tbl); + if (!$table || $table == $model->alias) + continue; + + // If the table is already part of the query, don't replace it + if (isset($query[$link][$table])) + continue; + + $query[$link][$table] + = $this->gridDataFilterTableConfig($params, $model, $table); + } + + return $query; + } + + function gridDataFilterConditions(&$params, &$model, $conditions) { + if (empty($params['post']['filter'])) + return $conditions; + + foreach ($params['post']['filter'] AS $filter => $value) { + if (preg_match("/\./", $filter)) { + list($tbl, $id) = explode(".", $filter); + } + elseif (preg_match('/^(.*)_(id)$/', $filter, $matches)) { + list($tbl, $id) = array_slice($matches, 1); + } + else { + $tbl = $filter; + $id = null; + } + + $table = $this->gridDataFilterTable($params, $model, $tbl); + if (!$table) + continue; + + $key = $this->gridDataFilterTableKey($params, $model, $table, $id); + if (!$key) + continue; + + $conditions[] + = $this->gridDataFilterTableCondition($params, $model, $table, $key, $value); + } + + return $conditions; + } + + function gridDataFilterTable(&$params, &$model, $table) { + return Inflector::camelize($table); + } + + function gridDataFilterTableConfig(&$params, &$model, $table) { + return array('fields' => array()); + } + + function gridDataFilterTableKey(&$params, &$model, $table, $id) { + // REVISIT : 20090722 + // When $id is null, we could instantiate the table, + // and use the _actual_ primary key. However, I don't + // expect that functionality to be used, and will just + // stick with 'id' for now. + return $id ? $id : 'id'; + } + + function gridDataFilterTableCondition(&$params, &$model, $table, $key, $value) { + return array("{$table}.{$key}" => $value); + } + + /************************************************************************** ************************************************************************** * gridData PAGINATION @@ -282,6 +393,7 @@ class AppController extends Controller { return compact('record_count', 'limit', 'page', 'start', 'total'); } + /************************************************************************** ************************************************************************** * gridData RETREIVAL @@ -289,19 +401,25 @@ class AppController extends Controller { function gridDataRecords(&$params, &$model, $pagination) { // Establish the tables for this query - $query = array_intersect_key($this->gridDataTables($params, $model), + $query = array_intersect_key($this->gridDataTableSet($params, $model), array('link'=>1, 'contain'=>1)); - // Add in the conditions and grouping - $query['conditions'] = $this->gridDataConditions($params, $model); - $query['group'] = $this->gridDataGroup($params, $model); + // Specify the fields for the query + $query['fields'] = $this->gridDataFields($params, $model); - // Grab the actual records taking pagination into account + // Conditions of the query + $query['conditions'] = $this->gridDataConditionSet($params, $model); + + // Data record grouping + $query['group'] = $this->gridDataGroup($params, $model); + + // The subset of data based on pagination + $query['limit'] = $this->gridDataLimit($params, $model, $pagination['start'], $pagination['limit']); + + // Ordering based on user request $query['order'] = $this->gridDataOrder($params, $model, isset($params['sidx']) ? $params['sidx'] : null, isset($params['sord']) ? $params['sord'] : null); - $query['limit'] = $this->gridDataLimit($params, $model, $pagination['start'], $pagination['limit']); - $query['fields'] = $this->gridDataFields($params, $model); // DEBUG PURPOSES ONLY! $params['query'] = $query; @@ -317,6 +435,19 @@ class AppController extends Controller { return array('contain' => false); } + function gridDataTableSet(&$params, &$model) { + // Preliminary set of tables + $query = array_intersect_key($this->gridDataTables($params, $model), + array('link'=>1, 'contain'=>1)); + + // Perform filtering based on user request: $params['post']['filter'] + $query = array_intersect_key($this->gridDataFilterTables($params, $model, $query), + array('link'=>1, 'contain'=>1)); + + return $query; + } + + function gridDataConditions(&$params, &$model) { $searches = array(); @@ -368,6 +499,14 @@ class AppController extends Controller { return $conditions; } + function gridDataConditionSet(&$params, &$model) { + // Conditions for record retrieval + $conditions = $this->gridDataConditions($params, $model); + + // Perform filtering based on user request: $params['post']['filter'] + return $this->gridDataFilterConditions($params, $model, $conditions); + } + function gridDataFields(&$params, &$model) { return null; } @@ -436,7 +575,7 @@ class AppController extends Controller { // in SQL. But, it works for now, so what the heck... $subtotals = array(); - foreach ($params['fields'] AS $field) { + foreach ($params['post']['fields'] AS $field) { if (preg_match('/subtotal-(.*)$/', $field, $matches)) $subtotals[] = array('field' => $matches[1], 'name' => $field, @@ -541,7 +680,7 @@ class AppController extends Controller { $id_field = 'grid_id'; foreach ($records AS $record) { $this->gridDataOutputRecord($params, $model, $record, - $record[$id_field], $params['fields']); + $record[$id_field], $params['post']['fields']); } } diff --git a/views/elements/jqGrid.ctp b/views/elements/jqGrid.ctp index 1715759..67310b4 100644 --- a/views/elements/jqGrid.ctp +++ b/views/elements/jqGrid.ctp @@ -69,36 +69,30 @@ $url = $html->url(array('controller' => $controller, // Create extra parameters that jqGrid will pass to our // controller whenever data is requested. // 'fields' will allow the controller to return only the -// requested fields, and in the right order. Since fields -// is a complex structure (an array), we'll need to -// serialize it first for transport over HTTP. +// requested fields, and in the right order. $postData = array(); -$postData['fields'] = serialize(array_map(create_function('$col', - 'return $col["index"];'), - array_values($jqGridColumns))); +$postData['fields'] = array_map(create_function('$col', + 'return $col["index"];'), + array_values($jqGridColumns)); // Determine if we're to be using a custom list, or if // the data will simply be action based. if (isset($custom_ids)) { if (!isset($action)) $action = 'idlist'; - $postData['idlist'] = serialize($custom_ids); -} -elseif (!isset($action)) { - $action = null; + $postData['idlist'] = $custom_ids; } -if (isset($custom_post_data)) { - $postData['custom'] = serialize($custom_post_data); -} - -// 'action' will ensure that the controller provides the -// correct subset of data -$postData['action'] = $action; - -if (isset($nolinks)) { +if (isset($nolinks)) $postData['nolinks'] = true; -} + +// 'action' will ensure that the controller does the right thing +// 'filter' allows the app controller to automagic filter +// 'custom' is for use solely by derived controllers +$postData['action'] = isset($action) ? $action : null; +$postData['filter'] = isset($filter) ? $filter : null; +$postData['custom'] = isset($custom_post_data) ? $custom_post_data : null; + // Perform column customizations. // This will largely be based off of the 'formatter' parameter, @@ -196,7 +190,9 @@ $jqGrid_setup = array_merge (array('mtype' => 'GET', 'datatype' => 'xml', 'url' => $url, - 'postData' => $postData, + // Since postData is a complex structure (an array), we'll + // need to serialize it first for transport over HTTP. + 'postData' => array('post' => serialize($postData)), 'colNames' => array_keys($jqGridColumns), 'colModel' => array('--special' => $jqGridColumns), 'height' => $height,