<?php
+use \PFF\HtmlBuilder\Tag as Tag;
+
class IPF_Admin_Model extends IPF_Admin_Component
{
public $modelName;
return IPF_ORM::getTable($this->modelName);
}
- private function query($searchValue)
+ private function query($searchValue, $filters)
{
if (method_exists($this->modelName, 'ordering')) {
$m = new $this->modelName;
$q->addWhere($wh, $whv);
}
+ foreach ($filters as $f)
+ $f->applyToQuery($q);
+
return $q;
}
- public function ListItemsQuery($searchValue, $page, $pageSize)
+ protected function getItems($searchValue, $filters, $page, $pageSize)
{
$idColumn = $this->table()->getIdentifier();
$result = array();
- foreach ($this->query($searchValue)->limit($pageSize)->offset(($page - 1) * $pageSize)->execute() as $o) {
+ foreach ($this->query($searchValue, $filters)->limit($pageSize)->offset(($page - 1) * $pageSize)->execute() as $o) {
$id = $o->__get($idColumn);
$result[$id] = $o;
}
return $result;
}
- public function ListItemsQueryCount($searchValue)
+ protected function itemsCount($searchValue, $filters)
{
- return $this->query($searchValue)->count();
+ return $this->query($searchValue, $filters)->count();
}
public function getObjectByID($id)
return null;
}
+ /* filters */
+
+ protected function _listFilters()
+ {
+ return array();
+ }
+
+ public function listFilters()
+ {
+ $filters = array();
+ foreach ($this->_listFilters() as $f) {
+ if (is_string($f))
+ $f = new IPF_Admin_Model_RelationFilter($this->modelName, $f);
+
+ $filters[] = $f;
+ }
+ return $filters;
+ }
+
public function reorder($ids)
{
if (!$this->_orderable())
}
}
+abstract class IPF_Admin_Model_Filter implements IPF_Admin_ListFilter
+{
+ abstract function applyToQuery($q);
+
+ protected $title, $paramName;
+
+ function title()
+ {
+ return $this->title;
+ }
+
+ protected function link($params, $value, $title)
+ {
+ if ($value !== null)
+ $params[$this->paramName] = $value;
+ else
+ unset($params[$this->paramName]);
+
+ return Tag::a()
+ ->attr('href', '?'.IPF_HTTP_URL::generateParams($params, false))
+ ->append($title);
+ }
+}
+
+class IPF_Admin_Model_RelationFilter extends IPF_Admin_Model_Filter
+{
+ private $relation, $selected = null;
+
+ function __construct($modelName, $relName)
+ {
+ $this->relation = IPF_ORM::getTable($modelName)->getRelation($relName);
+ $this->title = 'By '.IPF_Utils::humanTitle($relName);
+
+ $this->paramName = 'filter_'.$this->relation['local'];
+ }
+
+ function setParams($params)
+ {
+ $this->selected = \PFF\Arr::get($params, $this->paramName);
+ }
+
+ function applyToQuery($q)
+ {
+ // check ???
+ if ($this->selected)
+ $q->addWhere($this->relation['local'].' = ?', array($this->selected));
+ }
+
+ function render($extraParams)
+ {
+ $ul = Tag::ul();
+
+ // reset filter
+ $ul->append(Tag::li()
+ ->toggleClass('selected', !$this->selected)
+ ->append($this->link($extraParams, null, __('All'))));
+
+ // query related
+ $table = IPF_ORM::getTable($this->relation['class']);
+
+ $query = $table->createQuery();
+ if ($table->getOrdering()) {
+ $query->orderBy(implode(', ', $table->getOrdering()));
+ } elseif ($table->hasTemplate('IPF_ORM_Template_Orderable')) {
+ $query->orderBy($table->getTemplate('IPF_ORM_Template_Orderable')->getColumnName());
+ }
+
+ $foreign = $this->relation['foreign'];
+ foreach ($query->execute() as $val) {
+ $id = $val[$foreign];
+ $name = (string)$val;
+
+ $ul->append(Tag::li()
+ ->toggleClass('selected', $this->selected == $id)
+ ->append($this->link($extraParams, $id, $name)));
+ }
+
+ return $ul->html();
+ }
+}
+
+class IPF_Admin_Model_OwnedFilter extends IPF_Admin_Model_Filter
+{
+ private $column, $selected = null;
+
+ function __construct($modelName, $column, $title)
+ {
+ $this->column = $column;
+ $this->title = $title;
+ $this->paramName = 'filter_'.$this->column;
+ }
+
+ function setParams($params)
+ {
+ $this->selected = \PFF\Arr::get($params, $this->paramName);
+ }
+
+ function applyToQuery($q)
+ {
+ // check ???
+ if ($this->selected)
+ $q->addWhere($this->column.' = ?', array($this->selected));
+ }
+
+ function render($extraParams)
+ {
+ $ul = Tag::ul();
+
+ // reset filter
+ $ul->append(Tag::li()
+ ->toggleClass('selected', !$this->selected)
+ ->append($this->link($extraParams, null, __('All'))));
+
+ foreach (User::query()->fetchAll() as $val) {
+ $id = $val->id;
+ $name = (string)$val;
+
+ $ul->append(Tag::li()
+ ->toggleClass('selected', $this->selected == $id)
+ ->append($this->link($extraParams, $id, $name)));
+ }
+
+ return $ul->html();
+ }
+}
+
+class BooleanFilter extends IPF_Admin_Model_Filter
+{
+ private $column, $trueTitle, $falseTitle, $selected;
+
+ public function __construct($column, $title, $trueTitle='Yes', $falseTitle='No')
+ {
+ $this->column = $column;
+ $this->title = $title;
+ $this->trueTitle = $trueTitle;
+ $this->falseTitle = $falseTitle;
+
+ $this->paramName = 'filter_'.$column;
+ }
+
+ function setParams($params)
+ {
+ $this->selected = \PFF\Arr::get($params, $this->paramName);
+ }
+
+ function render($extraParams)
+ {
+ return Tag::ul(null,
+ Tag::li()
+ ->toggleClass('selected', $this->selected !== 'y' && $this->selected !== 'n')
+ ->append($this->link($extraParams, null, __('All'))),
+ Tag::li()
+ ->toggleClass('selected', $this->selected === 'y')
+ ->append($this->link($extraParams, 'y', $this->trueTitle)),
+ Tag::li()
+ ->toggleClass('selected', $this->selected === 'n')
+ ->append($this->link($extraParams, 'n', $this->falseTitle)));
+ }
+
+ function applyToQuery($q)
+ {
+ switch ($this->selected) {
+ case 'y':
+ $query->addWhere($this->column);
+ break;
+ case 'n':
+ $query->addWhere('NOT '.$this->column);
+ break;
+ }
+ }
+}
+
+class DateHierarchyListFilter extends IPF_Admin_Model_Filter
+{
+ private $model, $name;
+ private $day, $month, $year;
+
+ function __construct($title, $modelName, $fieldName)
+ {
+ $this->title = $title;
+ $this->modelName = $modelName;
+ $this->name = $fieldName;
+
+ $this->paramName = $fieldName;
+ }
+
+ function setParams($params)
+ {
+ $date = \PFF\Arr::get($params, $this->paramName, '');
+ $matches = array();
+ if (preg_match('/(\d{4})-(\d{2})-(\d{2})/', $date, $matches)) {
+ $this->year = intval($matches[1]);
+ $this->month = intval($matches[2]);
+ $this->day = intval($matches[3]);
+ }
+ }
+
+ function render($extraParams)
+ {
+ $ul = Tag::ul();
+
+ $ul->append(Tag::li()
+ ->toggleClass('selected', !$this->year)
+ ->append($this->link($extraParams, null, __('All'))));
+
+ if ($this->year)
+ $ul->append($this->renderChoice($extraParams, $this->year, 0, 0, $this->year)->addClass('selected'));
+
+ if ($this->month)
+ $ul->append($this->renderChoice($extraParams, $this->year, $this->month, 0, $this->monthName($this->month))->addClass('selected'));
+
+ if ($this->day)
+ $ul->append($this->renderChoice($extraParams, $this->year, $this->month, $this->day, $this->day)->addClass('selected'));
+
+ if ($this->day) {
+ } elseif ($this->month) {
+ $days = $this->choices('DAY(' . $this->name . ')',
+ 'YEAR(' . $this->name . ')', $this->year,
+ 'MONTH(' . $this->name . ')', $this->month);
+ foreach ($days as $day) {
+ $ul->append($this->renderChoice($extraParams, $this->year, $this->month, $day, $day));
+ }
+ } elseif ($this->year) {
+ $months = $this->choices('MONTH(' . $this->name . ')',
+ 'YEAR(' . $this->name . ')', $this->year);
+ foreach ($months as $month) {
+ $ul->append($this->renderChoice($extraParams, $this->year, $month, 0, $this->monthName($month)));
+ }
+ } else {
+ $years = $this->choices('YEAR(' . $this->name . ')');
+ foreach ($years as $year) {
+ $ul->append($this->renderChoice($extraParams, $year, 0, 0, $year));
+ }
+ }
+
+ return $ul->html();
+ }
+
+ function applyToQuery($q)
+ {
+ if ($this->day)
+ $q->addWhere('DAY(' . $this->name . ') = ?', array($this->day));
+ if ($this->month)
+ $q->addWhere('MONTH(' . $this->name . ') = ?', array($this->month));
+ if ($this->year)
+ $q->addWhere('YEAR(' . $this->name . ') = ?', array($this->year));
+ }
+
+ private function choices(/* $what, [$expr, $value, ...]*/)
+ {
+ $args = func_get_args();
+ $what = array_shift($args);
+
+ $q = IPF_ORM_Query::create()
+ ->from($this->modelName)
+ ->select($what . ' AS value')
+ ->groupBy('1')
+ ->orderBy('1');
+
+ while ($args) {
+ $expr = array_shift($args);
+ $value = array_shift($args);
+
+ $q->addWhere($expr . ' = ?', array($value));
+ }
+ return \PFF\Arr::create($q->fetchArray())->pluck('value')->arr();
+ }
+
+ private function renderChoice($extraParams, $year, $month, $day, $label)
+ {
+ return Tag::li(null,
+ $this->link($extraParams, sprintf('%04d-%02d-%02d', $year, $month, $day), $label));
+ }
+
+ protected function monthName($month)
+ {
+ return date('F', mktime(0, 0, 0, $month, 1));
+ }
+}
+
<?php
-abstract class BaseListFilter
+interface IPF_Admin_ListFilter
{
- public $name;
-
- function __construct($title, $choices)
- {
- $this->choices = $choices;
- $this->title = $title;
- }
-
- function IsChoice($id)
- {
- foreach ($this->choices as $ch)
- if ($ch['id'] == $id)
- return true;
- return false;
- }
-
- function selected()
- {
- foreach ($this->choices as $ch)
- if (($ch['id'] != '') && ($ch['selected']===true))
- return true;
- return false;
- }
-
- abstract function SetSelect($request);
- abstract function FilterQuery($request, $query);
-}
-
-class ListFilter extends BaseListFilter
-{
- function __construct($local, $foreign, $choices, $title)
- {
- parent::__construct($title, $choices);
- $this->local = $local;
- $this->foreign = $foreign;
- }
-
- function SetSelect($request)
- {
- /* nothing to do */
- }
-
- function FilterQuery($request, $query)
- {
- $param_name = 'filter_'.$this->local;
- if (isset($request->GET[$param_name])){
- $id = $request->GET[$param_name];
- if ($this->IsChoice($id)){
- $query->addWhere($this->local.'='.$id);
- }
- }
- }
-}
-
-class BooleanFilter extends BaseListFilter
-{
- private $column;
-
- public function __construct($column, $title, $trueTitle='Yes', $falseTitle='No')
- {
- $this->name = $column;
- $this->column = $column;
- parent::__construct($title, array(
- array(
- 'id' => null,
- 'param_key' => 'filter_'.$this->column,
- 'param_value' => null,
- 'name' => 'All',
- 'selected' => true,
- ),
- array(
- 'id' => 'y',
- 'param_key' => 'filter_'.$this->column,
- 'param_value' => 'y',
- 'name' => $trueTitle,
- 'selected' => false,
- ),
- array(
- 'id' => 'n',
- 'param_key' => 'filter_'.$this->column,
- 'param_value' => 'n',
- 'name' => $falseTitle,
- 'selected' => false,
- ),
- ));
- }
-
- public function SetSelect($request)
- {
- switch (\PFF\Arr::get($request->GET, 'filter_'.$this->column)) {
- case 'y':
- $this->choices[1]['selected'] = true;
- break;
- case 'n':
- $this->choices[2]['selected'] = true;
- break;
- default:
- $this->choices[0]['selected'] = true;
- }
- }
-
- public function FilterQuery($request, $query)
- {
- switch (\PFF\Arr::get($request->GET, 'filter_'.$this->column)) {
- case 'y':
- $query->addWhere($this->column);
- break;
- case 'n':
- $query->addWhere('NOT '.$this->column);
- break;
- }
- }
-}
-
-class ListTreeFilter extends BaseListFilter{
- function __construct($name, $title, $model, $fields){
- $this->name = $name;
- $choices = array();
- $choices[] = array(
- 'id'=>null,
- 'param_key'=>'filter_'.$this->name,
- 'param_value'=>null,
- 'name'=>'All',
- 'original_name'=>'All',
- 'selected'=>false,
- 'level'=>0,
- );
- $levels = array();
-
- $mrels = $model->getTable()->getRelations();
- $this->fields = array();
- foreach($fields as $fname){
- if (array_key_exists($fname, $mrels)){
- $n = count($this->fields);
- if ($n==0)
- $parent_key = null;
- else
- $parent_key = $this->fields[$n-1]['local'];
- $this->fields[] = array(
- 'name'=>$fname,
- 'local'=>$mrels[$fname]->getLocal(),
- 'parent_key'=>$parent_key,
- 'class'=>$mrels[$fname]->getClass(),
- 'objects'=>$this->_getObjects($mrels[$fname]->getClass()),
- );
- }
- }
- $this->_collectTreeRecursive($choices);
- parent::__construct($title, $choices);
- }
-
- protected function _getObjects($modelName)
- {
- return IPF_ORM_Query::create()
- ->from($modelName)
- ->orderby('ord')
- ->execute();
- }
-
- protected function _collectTreeRecursive(&$choices,$level=0,$parent_id=null,$valname=''){
- foreach($this->fields[$level]['objects'] as $o){
- if ($level>0){
- $foreign = $this->fields[$level]['parent_key'];
- if ($parent_id!=$o->$foreign)
- continue;
- }
- $this->_addObject($o, $choices, $level, $valname);
- if ($level<(count($this->fields)-1)){
- $this->_collectTreeRecursive($choices,$level+1,$o->id,$valname.$o->id.'.');
- }
- }
- }
-
- protected function _addObject($o, &$choices, $level, $valname)
- {
- $name = str_repeat("-", $level).$o->name;
- $id = $valname.$o->id;
-
- $choices[] = array(
- 'id'=>$id,
- 'param_key'=>'filter_'.$this->name,
- 'param_value'=>$id,
- 'original_name'=>$o->name,
- 'name'=>$name,
- 'selected'=>false,
- 'level'=>$level,
- );
- }
- function SetSelect($request){
- $sel_id = @$request->GET['filter_'.$this->name];
- foreach($this->choices as &$ch){
- $ch['selected']= ($sel_id==$ch['id']);
- }
- }
-
- function FilterQuery($request,$q){
- $param_name = 'filter_'.$this->name;
- if (isset($request->GET[$param_name])){
- $id = $request->GET[$param_name];
- if ($this->IsChoice($id)){
- $l = explode(".",$id);
- $wh = array();
- for($i=0; $i<count($this->fields); $i++){
- if ($i>=(count($l)))
- $wh[] = $this->fields[$i]['local'].' IS NULL';
- else
- $wh[] = $this->fields[$i]['local'].'='.$l[$i];
- }
- $dql = '';
- foreach($wh as $w){
- if ($dql!='')
- $dql .= ' AND ';
- $dql .= $w;
- }
- $q->addWhere($dql);
- }
- }
- }
-}
-
-class DateHierarchyListFilter extends BaseListFilter {
- public $model, $name;
-
- function __construct($title, $modelName, $fieldName) {
- parent::__construct($title, array());
- $this->modelName = $modelName;
- $this->name = $fieldName;
- }
-
- private function loadChoices($funcKey, $funcValue, $current) {
- $vals = IPF_ORM_Query::create()
- ->select($funcKey . '(' . $this->name . ') as k')
- ->addSelect($funcValue . '(' . $this->name . ') as v')
- ->from($this->modelName)
- ->groupBy('1')
- ->orderBy('1')
- ->fetchArray();
- foreach ($vals as $r) {
- $v = $r['k'];
- $this->choices[] = array(
- 'name' => $r['v'],
- 'selected' => $current == $v,
- 'param_key' => 'filter_' . $this->name,
- 'param_value' => sprintf($this->getFormat(), $v),
- );
- }
- }
-
- private function addChoices($q, $format) {
- $vals = $q
- ->from($this->modelName)
- ->groupBy('1')
- ->orderBy('1')
- ->fetchArray();
- foreach ($vals as $r) {
- $v = $r['k'];
- $this->choices[] = array(
- 'name' => $r['v'],
- 'selected' => false,
- 'param_key' => 'filter_' . $this->name,
- 'param_value' => sprintf($format, $v),
- );
- }
- }
-
- private $day, $month, $year;
-
- private function getFormat() {
- if ($this->day) {
- return '';
- } elseif ($this->month) {
- return sprintf('%04d-%02d-', $this->year, $this->month) . '-%02d';
- } elseif ($this->year) {
- return sprintf('%04d-', $this->year) . '%02d-00';
- } else {
- return '%04d-00-00';
- }
- }
-
- function SetSelect($request) {
- $date = @$request->GET['filter_' . $this->name];
- if (preg_match('/(\d{4})-(\d{2})-(\d{2})/', $date, $matches)) {
- $this->year = intval($matches[1]);
- $this->month = intval($matches[2]);
- $this->monthName = date('F', mktime(0, 0, 0, $this->month, 1));
- $this->day = intval($matches[3]);
- }
-
- $this->choices = array(
- array(
- 'name' => 'All',
- 'selected' => !$this->year,
- 'param_key' => 'filter_' . $this->name,
- 'param_value' => null,
- ),
- );
-
- if ($this->year) {
- $this->choices[] = array(
- 'name' => $this->year,
- 'selected' => true,
- 'param_key' => 'filter_' . $this->name,
- 'param_value' => $this->year . '-00-00',
- );
- }
-
- if ($this->month) {
- $this->choices[] = array(
- 'name' => $this->monthName,
- 'selected' => true,
- 'param_key' => 'filter_' . $this->name,
- 'param_value' => sprintf('%04d-%02d-00', $this->year, $this->month),
- );
- }
-
- if ($this->day) {
- $this->choices[] = array(
- 'name' => $this->day,
- 'selected' => true,
- 'param_key' => 'filter_' . $this->name,
- 'param_value' => sprintf('%04d-%02d-%02d', $this->year, $this->month, $this->day),
- );
- }
-
- if ($this->day) {
- } elseif ($this->month) {
- $q = IPF_ORM_Query::create()
- ->select('DAY(' . $this->name . ') as k')
- ->addSelect('DAY(' . $this->name . ') as v')
- ->addWhere('YEAR(' . $this->name . ') = ?', array($this->year))
- ->addWhere('MONTH(' . $this->name . ') = ?', array($this->month));
- $this->addChoices($q, sprintf('%04d-%02d', $this->year, $this->month) . '-%02d');
- } elseif ($this->year) {
- $q = IPF_ORM_Query::create()
- ->select('MONTH(' . $this->name . ') as k')
- ->addSelect('MONTHNAME(' . $this->name . ') as v')
- ->addWhere('YEAR(' . $this->name . ') = ?', array($this->year));
- $this->addChoices($q, sprintf('%04d', $this->year) . '-%02d-00');
- } else {
- $q = IPF_ORM_Query::create()
- ->select('YEAR(' . $this->name . ') as k')
- ->addSelect('YEAR(' . $this->name . ') as v');
- $this->addChoices($q, '%04d-00-00');
- }
- }
-
- function FilterQuery($request, $q) {
- if ($this->day)
- $q->addWhere('DAY(' . $this->name . ') = ?', array($this->day));
- if ($this->month)
- $q->addWhere('MONTH(' . $this->name . ') = ?', array($this->month));
- if ($this->year)
- $q->addWhere('YEAR(' . $this->name . ') = ?', array($this->year));
- }
+ function title();
+ function setParams($params);
+ function render($extraParams);
}
abstract class IPF_Admin_Component
}
}
- protected function _listFilters()
- {
- return array();
- }
-
protected function _setupEditForm($form)
{
$this->_setupForm($form);
return $this->header;
}
- public abstract function ListItemsQuery($searchValue, $page, $pageSize);
- public abstract function ListItemsQueryCount($searchValue);
+ protected abstract function getItems($searchValue, $filters, $page, $pageSize);
+ protected abstract function itemsCount($searchValue, $filters);
public abstract function getObjectByID($id);
public abstract function saveObject($form, $object);
public abstract function deleteObject($object);
public function ListItems($request)
{
$searchValue = @$request->GET['q'];
- $this->filters = array();
- // $this->_GetFilters($request);
+
+ $filters = $this->listFilters();
+ foreach ($filters as $f)
+ $f->setParams($request->GET);
$currentPage = (int)@$request->GET['page'];
if (!$currentPage)
$currentPage = 1;
- $count = $this->ListItemsQueryCount($searchValue);
- $objects = $this->ListItemsQuery($searchValue, $currentPage, $this->perPage);
+ $count = $this->itemsCount($searchValue, $filters);
+ $objects = $this->getItems($searchValue, $filters, $currentPage, $this->perPage);
$this->ListItemsHeader();
'current_page' => $currentPage,
'classname'=>$this->verbose_name(),
'title_add'=>$this->titleAdd(),
- 'filters'=>$this->filters,
+ 'filters' => $filters,
'is_search' => $this->searcheable(),
'search_value' => $searchValue,
);
return $this->renderToResponse($this->_getListTemplate(), $context, $request);
}
- protected function _ListFilterQuery($request)
- {
- foreach($this->filters as $f){
- $f->FilterQuery($request,$this->q);
- }
- }
-
- protected function _GetFilters($request)
+ public function listFilters()
{
- $this->filters = array();
- $rels = $this->model->getTable()->getRelations();
- foreach($this->_listFilters() as $f){
- if (is_string($f)){
- $local = $rels[$f]['local'];
- $foreign = $rels[$f]['foreign'];
- $sel_id = @$request->GET['filter_'.$local];
- $choices = array();
- $choices[] = array(
- 'id' => null,
- 'param_key' => 'filter_'.$local,
- 'param_value' => null,
- 'name' => 'All',
- 'selected' => ($sel_id==''),
- );
-
- $table = IPF_ORM::getTable($rels[$f]['class']);
-
- $query = $table->createQuery();
- if ($table->getOrdering()) {
- $query->orderBy(implode(', ', $table->getOrdering()));
- } elseif ($table->hasTemplate('IPF_ORM_Template_Orderable')) {
- $query->orderBy($table->getTemplate('IPF_ORM_Template_Orderable')->getColumnName());
- }
-
- foreach ($query->execute() as $val) {
- $selected = false;
- $id = $val[$foreign];
- if ($sel_id==$id)
- $selected = true;
- $choices[] = array(
- 'id' => $id,
- 'param_key' => 'filter_'.$local,
- 'param_value' => $id,
- 'name' => (string)$val,
- 'selected' => $selected,
- );
- }
- $this->filters[$f] = new ListFilter($local, $foreign, $choices, 'By '.IPF_Utils::humanTitle($f));
- } else {
- $f->SetSelect($request);
- $this->filters[$f->name] = $f;
- }
- }
+ return array();
}
public function _orderable()