+++ /dev/null
-<?php
-
-use \PFF\HtmlBuilder\Text as Text;
-use \PFF\HtmlBuilder\Tag as Tag;
-
-class IPF_Admin_Model extends IPF_Admin_Component
-{
- public $modelName;
-
- public function __construct($modelName)
- {
- $this->modelName = $modelName;
- }
-
- public function verbose_name()
- {
- return IPF_Utils::humanTitle($this->modelName);
- }
-
- public function slug()
- {
- return strtolower($this->modelName);
- }
-
- private function table()
- {
- return IPF_ORM::getTable($this->modelName);
- }
-
- protected function query($searchValue, $filters)
- {
- if (method_exists($this->modelName, 'ordering')) {
- $m = new $this->modelName;
- $ord = $m->ordering();
- } elseif ($this->table()->getOrdering()) {
- $ord = implode(', ', $this->table()->getOrdering());
- } elseif ($this->table()->hasTemplate('IPF_ORM_Template_Orderable')) {
- $ord = $this->table()->getTemplate('IPF_ORM_Template_Orderable')->getColumnName();
- } else {
- $ord = '1 desc';
- }
-
- $q = IPF_ORM_Query::create()->from($this->modelName)->orderby($ord);
-
- if ($searchValue) {
- $wh = array();
- $whv = array();
- foreach ($this->_searchFields() as $f) {
- $wh[] = $f.' like ?';
- $whv[] = '%'.$searchValue.'%';
- }
- $q->addWhere($wh, $whv);
- }
-
- foreach ($filters as $f)
- $f->applyToQuery($q);
-
- return $q;
- }
-
- protected function getItems($searchValue, $filters, $page, $pageSize)
- {
- $idColumn = $this->table()->getIdentifier();
-
- $result = array();
- foreach ($this->query($searchValue, $filters)->limit($pageSize)->offset(($page - 1) * $pageSize)->execute() as $o) {
- $id = $o->__get($idColumn);
- $result[$id] = $o;
- }
- return $result;
- }
-
- protected function itemsCount($searchValue, $filters)
- {
- return $this->query($searchValue, $filters)->count();
- }
-
- public function getObjectByID($id)
- {
- return $this->table()->find($id);
- }
-
- public function searcheable()
- {
- return count($this->_searchFields()) > 0;
- }
-
- protected function _searchFields()
- {
- return array();
- }
-
- public function list_display()
- {
- return $this->table()->getColumnNames();
- }
-
- public function renderCell($object, $column)
- {
- $value = $object->$column;
- switch ($object->getTable()->getTypeOf($column)) {
- case 'boolean':
- return $value
- ? '<span class="positive">✔</span>'
- : '<span class="negative">✘</span>';
- case 'timestamp':
- return Text::escape(IPF_Utils::formatDate($value));
- default:
- return Text::escape($value);
- }
- }
-
- protected function columnTitle($column)
- {
- $columns = $this->table()->getColumns();
- if (array_key_exists($column, $columns) && array_key_exists('verbose', $columns[$column]))
- return $columns[$column]['verbose'];
- else
- return parent::columnTitle($column);
- }
-
- public function _orderable()
- {
- return $this->_orderableColumn() !== null;
- }
-
- public function _orderableColumn()
- {
- if (method_exists($this, 'list_order'))
- return $this->list_order();
- elseif ($this->table()->hasTemplate('IPF_ORM_Template_Orderable'))
- return $this->table()->getTemplate('IPF_ORM_Template_Orderable')->getColumnName();
- else
- 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())
- return false;
-
- $ord_field = $this->_orderableColumn();
-
- $table = IPF_ORM::getTable($this->modelName);
- $conn = $table->getConnection();
-
- $idColumn = $table->getIdentifier();
- if (is_array($idColumn))
- $idColumn = $idColumn[0];
-
- $questions = str_repeat('?,', count($ids)-1) . '?';
- $query = 'SELECT ' . $conn->quoteIdentifier($ord_field) .
- ' FROM ' . $conn->quoteIdentifier($table->getTableName()) .
- ' WHERE ' . $conn->quoteIdentifier($idColumn) . ' IN (' . $questions . ')' .
- ' ORDER BY ' . $conn->quoteIdentifier($ord_field);
- $ords = $conn->fetchColumn($query, $ids);
-
- $i = 0;
- foreach ($ids as $id) {
- $item = $table->find($id);
- $item[$ord_field] = $ords[$i];
- $item->save();
- $i++;
- }
-
- return true;
- }
-
- /* edit */
-
- protected function _getForm($model, $data)
- {
- $extra = array(
- 'user_fields' => $this->fields(),
- 'inlines' => $this->inlines(),
- );
- return new IPF_Admin_ModelForm($data, $model, $this->modelName, $extra);
- }
-
- public function inlines()
- {
- return array();
- }
-
- public function saveObject($form, $model)
- {
- $model = $form->save();
- $idColumn = $this->table()->getIdentifier();
- return array($model->$idColumn, $model);
- }
-
- public function deleteObject($model)
- {
- $model->delete();
- }
-
- public function fields()
- {
- return null;
- }
-}
-
-class IPF_Admin_ModelForm extends IPF_Form_Model
-{
- private $inlines = array();
-
- function __construct($data=null, $model=null, $modelName='', $extra=array())
- {
- if ($model) {
- // edit
- $extra['model'] = $model;
- $extra['initial'] = $this->getFormData($model);
- } else {
- // add
- $extra['model'] = new $modelName;
- }
-
- parent::__construct($data, $extra);
- }
-
- function initFields($extra=array())
- {
- parent::initFields($extra);
-
- if ($extra['inlines']) {
- $this->field_groups[] = array('fields' => array_keys($this->fields));
- foreach ($extra['inlines'] as $inlineClassName) {
- $this->inlines[] = new $inlineClassName($extra['model']);
- }
- }
-
- foreach ($this->inlines as $inline) {
- $name = $inline->getModelName();
- $this->fields[$name] = $inline->createField();
-
- $this->field_groups[] = array(
- 'label' => $inline->getLegend(),
- 'fields' => array($name),
- );
- }
- }
-
- private function getFormData($o)
- {
- $data = $o->getData();
- foreach ($o->getTable()->getRelations() as $rname => $rel) {
- $fields = $this->fields();
- if (!$fields || in_array($rname, $fields)) {
- if ($rel->getType() == IPF_ORM_Relation::MANY_AGGREGATE) {
- $data[$rname] = array();
- foreach ($rel->fetchRelatedFor($o) as $ri) {
- $data[$rname][] = $ri->pk();
- }
- }
- }
- }
-
- foreach ($this->inlines() as $inlineName => $inlineClassName) {
- $inlineInstance = new $inlineClassName($o, null);
-
- $objs = array();
- foreach ($inlineInstance->getObjects() as $io) {
- $d = $io->getData();
- $d['id'] = $io->pk();
- $objs[] = $d;
- }
- $data[$inlineName] = $objs;
- }
-
- return $data;
- }
-
- function save($commit=true)
- {
- $model = parent::save($commit);
-
- foreach ($this->inlines as $inline) {
- $this->saveInlineObject($inline, $model);
- }
-
- return $model;
- }
-
- private function saveInlineObject($inline, $model)
- {
- $objIndex = array();
- foreach ($inline->getObjects() as $obj)
- $objIndex[$obj->pk()] = $obj;
-
- $modelName = $inline->getModelName();
- $fk_local = $inline->getFkLocal();
-
- foreach ($this->cleaned_data[$modelName] as $objData) {
- if (array_key_exists('id', $objData) && array_key_exists($objData['id'], $objIndex)) {
- $obj = $objIndex[$objData['id']];
- if (isset($objData['is_remove'])) {
- $obj->delete();
- } else {
- $obj->synchronizeWithArray($objData);
- $obj->save();
- }
- } else {
- $objData[$fk_local] = $model->id;
- $obj = new $modelName;
- $obj->synchronizeWithArray($objData);
- $obj->save();
- }
- }
- }
-}
-
-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));
- }
-}
-
+++ /dev/null
-<?php
-
-abstract class IPF_Admin_ModelInline
-{
- public $parentModel = null;
- public $orderby = 'id';
-
- function __construct($parentModel)
- {
- $this->parentModel = $parentModel;
- }
-
- abstract function getModelName();
-
- public function getApplication()
- {
- foreach (IPF_Project::getInstance()->appList() as $app)
- foreach (IPF_Legacy_ORM_App::appModelList($app) as $model)
- if ($model == $this->getModelName())
- return $app;
- return null;
- }
-
- function getAddNum()
- {
- return 4;
- }
-
- function getLegend()
- {
- return $this->getModelName();
- }
-
- function getFkName()
- {
- foreach($this->getTable()->getRelations() as $rel) {
- if ($rel->getClass()==get_class($this->parentModel))
- return $rel->getAlias();
- }
- throw new IPF_Exception(__('Cannot get fkName for '.$this->getModelName()));
- }
-
- function getFkLocal()
- {
- foreach($this->getTable()->getRelations() as $rel) {
- if ($rel->getClass() == get_class($this->parentModel))
- return $rel->getLocal();
- }
- throw new IPF_Exception(__('Cannot get fkLocal for '.$this->getModelName()));
- }
-
- function getObjects()
- {
- if (!$this->parentModel->exists())
- return array();
-
- $query = IPF_ORM_Query::create()
- ->from($this->getModelName())
- ->where($this->getFkLocal().'='.$this->parentModel->id);
-
- $o = $this->_orderableColumn();
- if ($o)
- $query->orderby($o);
- else
- $query->orderby($this->orderby);
-
- return $query->execute();
- }
-
- public function _orderable()
- {
- return $this->_orderableColumn() !== null;
- }
-
- public function _orderableColumn()
- {
- if ($this->getTable()->hasTemplate('IPF_ORM_Template_Orderable'))
- return $this->getTable()->getTemplate('IPF_ORM_Template_Orderable')->getColumnName();
- else
- return null;
- }
-
- private function getTable()
- {
- return IPF_ORM::getTable($this->getModelName());
- }
-
- public function createField()
- {
- $exclude = array(
- $this->getFkName(),
- $this->getFkLocal(),
- );
- $o = $this->_orderableColumn();
- if ($o)
- $exclude[] = $o;
-
- $fields = array();
- foreach (IPF_Form_Model::suggestFields($this->getTable(), null, $exclude, null) as $field) {
- list($n, $f) = $field;
- $fields[$n] = $f;
- }
-
- return new IPF_Form_Field_Set(array(
- 'fields' => $fields,
- 'addCount' => $this->getAddNum(),
- ));
- }
-}
-
--- /dev/null
+<?php
+
+use \PFF\HtmlBuilder\Text as Text;
+use \PFF\HtmlBuilder\Tag as Tag;
+
+class IPF_Admin_Model extends IPF_Admin_Component
+{
+ public $modelName;
+
+ public function __construct($modelName)
+ {
+ $this->modelName = $modelName;
+ }
+
+ public function verbose_name()
+ {
+ return IPF_Utils::humanTitle($this->modelName);
+ }
+
+ public function slug()
+ {
+ return strtolower($this->modelName);
+ }
+
+ private function table()
+ {
+ return IPF_ORM::getTable($this->modelName);
+ }
+
+ protected function query($searchValue, $filters)
+ {
+ if (method_exists($this->modelName, 'ordering')) {
+ $m = new $this->modelName;
+ $ord = $m->ordering();
+ } elseif ($this->table()->getOrdering()) {
+ $ord = implode(', ', $this->table()->getOrdering());
+ } elseif ($this->table()->hasTemplate('IPF_ORM_Template_Orderable')) {
+ $ord = $this->table()->getTemplate('IPF_ORM_Template_Orderable')->getColumnName();
+ } else {
+ $ord = '1 desc';
+ }
+
+ $q = IPF_ORM_Query::create()->from($this->modelName)->orderby($ord);
+
+ if ($searchValue) {
+ $wh = array();
+ $whv = array();
+ foreach ($this->_searchFields() as $f) {
+ $wh[] = $f.' like ?';
+ $whv[] = '%'.$searchValue.'%';
+ }
+ $q->addWhere($wh, $whv);
+ }
+
+ foreach ($filters as $f)
+ $f->applyToQuery($q);
+
+ return $q;
+ }
+
+ protected function getItems($searchValue, $filters, $page, $pageSize)
+ {
+ $idColumn = $this->table()->getIdentifier();
+
+ $result = array();
+ foreach ($this->query($searchValue, $filters)->limit($pageSize)->offset(($page - 1) * $pageSize)->execute() as $o) {
+ $id = $o->__get($idColumn);
+ $result[$id] = $o;
+ }
+ return $result;
+ }
+
+ protected function itemsCount($searchValue, $filters)
+ {
+ return $this->query($searchValue, $filters)->count();
+ }
+
+ public function getObjectByID($id)
+ {
+ return $this->table()->find($id);
+ }
+
+ public function searcheable()
+ {
+ return count($this->_searchFields()) > 0;
+ }
+
+ protected function _searchFields()
+ {
+ return array();
+ }
+
+ public function list_display()
+ {
+ return $this->table()->getColumnNames();
+ }
+
+ public function renderCell($object, $column)
+ {
+ $value = $object->$column;
+ switch ($object->getTable()->getTypeOf($column)) {
+ case 'boolean':
+ return $value
+ ? '<span class="positive">✔</span>'
+ : '<span class="negative">✘</span>';
+ case 'timestamp':
+ return Text::escape(IPF_Utils::formatDate($value));
+ default:
+ return Text::escape($value);
+ }
+ }
+
+ protected function columnTitle($column)
+ {
+ $columns = $this->table()->getColumns();
+ if (array_key_exists($column, $columns) && array_key_exists('verbose', $columns[$column]))
+ return $columns[$column]['verbose'];
+ else
+ return parent::columnTitle($column);
+ }
+
+ public function _orderable()
+ {
+ return $this->_orderableColumn() !== null;
+ }
+
+ public function _orderableColumn()
+ {
+ if (method_exists($this, 'list_order'))
+ return $this->list_order();
+ elseif ($this->table()->hasTemplate('IPF_ORM_Template_Orderable'))
+ return $this->table()->getTemplate('IPF_ORM_Template_Orderable')->getColumnName();
+ else
+ 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())
+ return false;
+
+ $ord_field = $this->_orderableColumn();
+
+ $table = IPF_ORM::getTable($this->modelName);
+ $conn = $table->getConnection();
+
+ $idColumn = $table->getIdentifier();
+ if (is_array($idColumn))
+ $idColumn = $idColumn[0];
+
+ $questions = str_repeat('?,', count($ids)-1) . '?';
+ $query = 'SELECT ' . $conn->quoteIdentifier($ord_field) .
+ ' FROM ' . $conn->quoteIdentifier($table->getTableName()) .
+ ' WHERE ' . $conn->quoteIdentifier($idColumn) . ' IN (' . $questions . ')' .
+ ' ORDER BY ' . $conn->quoteIdentifier($ord_field);
+ $ords = $conn->fetchColumn($query, $ids);
+
+ $i = 0;
+ foreach ($ids as $id) {
+ $item = $table->find($id);
+ $item[$ord_field] = $ords[$i];
+ $item->save();
+ $i++;
+ }
+
+ return true;
+ }
+
+ /* edit */
+
+ protected function _getForm($model, $data)
+ {
+ $extra = array(
+ 'user_fields' => $this->fields(),
+ 'inlines' => $this->inlines(),
+ );
+ return new IPF_Admin_ModelForm($data, $model, $this->modelName, $extra);
+ }
+
+ public function inlines()
+ {
+ return array();
+ }
+
+ public function saveObject($form, $model)
+ {
+ $model = $form->save();
+ $idColumn = $this->table()->getIdentifier();
+ return array($model->$idColumn, $model);
+ }
+
+ public function deleteObject($model)
+ {
+ $model->delete();
+ }
+
+ public function fields()
+ {
+ return null;
+ }
+}
+
+class IPF_Admin_ModelForm extends IPF_Form_Model
+{
+ private $inlines = array();
+
+ function __construct($data=null, $model=null, $modelName='', $extra=array())
+ {
+ if ($model) {
+ // edit
+ $extra['model'] = $model;
+ $extra['initial'] = $this->getFormData($model);
+ } else {
+ // add
+ $extra['model'] = new $modelName;
+ }
+
+ parent::__construct($data, $extra);
+ }
+
+ function initFields($extra=array())
+ {
+ parent::initFields($extra);
+
+ if ($extra['inlines']) {
+ $this->field_groups[] = array('fields' => array_keys($this->fields));
+ foreach ($extra['inlines'] as $inlineClassName) {
+ $this->inlines[] = new $inlineClassName($extra['model']);
+ }
+ }
+
+ foreach ($this->inlines as $inline) {
+ $name = $inline->getModelName();
+ $this->fields[$name] = $inline->createField();
+
+ $this->field_groups[] = array(
+ 'label' => $inline->getLegend(),
+ 'fields' => array($name),
+ );
+ }
+ }
+
+ private function getFormData($o)
+ {
+ $data = $o->getData();
+ foreach ($o->getTable()->getRelations() as $rname => $rel) {
+ $fields = $this->fields();
+ if (!$fields || in_array($rname, $fields)) {
+ if ($rel->getType() == IPF_ORM_Relation::MANY_AGGREGATE) {
+ $data[$rname] = array();
+ foreach ($rel->fetchRelatedFor($o) as $ri) {
+ $data[$rname][] = $ri->pk();
+ }
+ }
+ }
+ }
+
+ foreach ($this->inlines() as $inlineName => $inlineClassName) {
+ $inlineInstance = new $inlineClassName($o, null);
+
+ $objs = array();
+ foreach ($inlineInstance->getObjects() as $io) {
+ $d = $io->getData();
+ $d['id'] = $io->pk();
+ $objs[] = $d;
+ }
+ $data[$inlineName] = $objs;
+ }
+
+ return $data;
+ }
+
+ function save($commit=true)
+ {
+ $model = parent::save($commit);
+
+ foreach ($this->inlines as $inline) {
+ $this->saveInlineObject($inline, $model);
+ }
+
+ return $model;
+ }
+
+ private function saveInlineObject($inline, $model)
+ {
+ $objIndex = array();
+ foreach ($inline->getObjects() as $obj)
+ $objIndex[$obj->pk()] = $obj;
+
+ $modelName = $inline->getModelName();
+ $fk_local = $inline->getFkLocal();
+
+ foreach ($this->cleaned_data[$modelName] as $objData) {
+ if (array_key_exists('id', $objData) && array_key_exists($objData['id'], $objIndex)) {
+ $obj = $objIndex[$objData['id']];
+ if (isset($objData['is_remove'])) {
+ $obj->delete();
+ } else {
+ $obj->synchronizeWithArray($objData);
+ $obj->save();
+ }
+ } else {
+ $objData[$fk_local] = $model->id;
+ $obj = new $modelName;
+ $obj->synchronizeWithArray($objData);
+ $obj->save();
+ }
+ }
+ }
+}
+
+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));
+ }
+}
+
--- /dev/null
+<?php
+
+abstract class IPF_Admin_ModelInline
+{
+ public $parentModel = null;
+ public $orderby = 'id';
+
+ function __construct($parentModel)
+ {
+ $this->parentModel = $parentModel;
+ }
+
+ abstract function getModelName();
+
+ public function getApplication()
+ {
+ foreach (IPF_Project::getInstance()->appList() as $app)
+ foreach (IPF_Legacy_ORM_App::appModelList($app) as $model)
+ if ($model == $this->getModelName())
+ return $app;
+ return null;
+ }
+
+ function getAddNum()
+ {
+ return 4;
+ }
+
+ function getLegend()
+ {
+ return $this->getModelName();
+ }
+
+ function getFkName()
+ {
+ foreach($this->getTable()->getRelations() as $rel) {
+ if ($rel->getClass()==get_class($this->parentModel))
+ return $rel->getAlias();
+ }
+ throw new IPF_Exception(__('Cannot get fkName for '.$this->getModelName()));
+ }
+
+ function getFkLocal()
+ {
+ foreach($this->getTable()->getRelations() as $rel) {
+ if ($rel->getClass() == get_class($this->parentModel))
+ return $rel->getLocal();
+ }
+ throw new IPF_Exception(__('Cannot get fkLocal for '.$this->getModelName()));
+ }
+
+ function getObjects()
+ {
+ if (!$this->parentModel->exists())
+ return array();
+
+ $query = IPF_ORM_Query::create()
+ ->from($this->getModelName())
+ ->where($this->getFkLocal().'='.$this->parentModel->id);
+
+ $o = $this->_orderableColumn();
+ if ($o)
+ $query->orderby($o);
+ else
+ $query->orderby($this->orderby);
+
+ return $query->execute();
+ }
+
+ public function _orderable()
+ {
+ return $this->_orderableColumn() !== null;
+ }
+
+ public function _orderableColumn()
+ {
+ if ($this->getTable()->hasTemplate('IPF_ORM_Template_Orderable'))
+ return $this->getTable()->getTemplate('IPF_ORM_Template_Orderable')->getColumnName();
+ else
+ return null;
+ }
+
+ private function getTable()
+ {
+ return IPF_ORM::getTable($this->getModelName());
+ }
+
+ public function createField()
+ {
+ $exclude = array(
+ $this->getFkName(),
+ $this->getFkLocal(),
+ );
+ $o = $this->_orderableColumn();
+ if ($o)
+ $exclude[] = $o;
+
+ $fields = array();
+ foreach (IPF_Form_Model::suggestFields($this->getTable(), null, $exclude, null) as $field) {
+ list($n, $f) = $field;
+ $fields[$n] = $f;
+ }
+
+ return new IPF_Form_Field_Set(array(
+ 'fields' => $fields,
+ 'addCount' => $this->getAddNum(),
+ ));
+ }
+}
+