}
}
+class PlDBNoSuchKeyException extends PlException
+{
+ public function __construct($key, PlDBTable $table)
+ {
+ parent::__construct('Erreur lors de l\'accès à la base de données',
+ 'No such key ' . $key . ' in table ' . $table->table);
+ }
+}
+
+
class PlDBIncompleteEntryDescription extends PlException
{
public function __construct($field, PlDBTable $table)
public $name;
public $inPrimaryKey;
- public $inUniqueKey;
- public $inKey;
public $type;
public $typeLength;
public $defaultValue;
public $autoIncrement;
+ private $validator;
+ private $formatter;
+
public function __construct(array $column)
{
$this->name = $column['Field'];
}
$this->allowNull = ($column['Null'] === 'YES');
$this->autoIncrement = (strpos($column['Extra'], 'auto_increment') !== false);
- $this->inPrimaryKey = ($column['Key'] === 'PRI');
- $this->inUniqueKey = $this->inPrimaryKey || ($column['Key'] === 'UNI');
- $this->inKey = $this->inUniqueKey || ($column['Key'] === 'MUL');
+ $this->inPrimaryKey = ($column['Key'] == 'PRI');
try {
$this->defaultValue = $this->format($column['Default']);
}
}
+ public function registerFormatter($class)
+ {
+ $this->formatter = $class;
+ }
+
+ public function registerValidator($class)
+ {
+ $this->validator = $class;
+ }
+
public function format($value, $badNullFallbackToDefault = false)
{
if (is_null($value)) {
return $this->defaultValue;
}
throw new PlDBBadValueException($value, $this, 'null not allowed');
+ }
+ if (!is_null($this->validator)) {
+ $class = $this->validator;
+ new $class($this, $value);
+ }
+ if (!is_null($this->formatter)) {
+ $class = $this->formatter;
+ $value = new $class($this, $value);
} else if ($this->type == 'enum') {
if (!$this->typeParameters->hasFlag($value)) {
throw new PlDBBadValueException($value, $this, 'invalid value for enum ' . $this->typeParameters->flags());
}
/* TODO: Check bounds */
return $value;
- } else if ($this->type == 'varchar') {
+ } else if (ends_with($this->type, 'char')) {
if (strlen($value) > $this->typeLength) {
throw new PlDBBadValueException($value, $this, 'value is expected to be at most ' . $this->typeLength . ' characters long, ' . strlen($value) . ' given');
}
return $value;
- } else if ($this->type == 'char') {
- if (strlen($value) != $this->typeLength) {
- throw new PlDBBadValueException($value, $this, 'value is expected to be ' . $this->typeLength . ' characters long, ' . strlen($value) . ' given');
- }
- return $value;
+ } else if (starts_with($this->type, 'date') || $this->type == 'timestamp') {
+ return new DateFieldFormatter($this, $value);
}
- /* TODO: Support data and times */
return $value;
}
}
+interface PlDBTableFieldValidator
+{
+ public function __construct(PlDBTableField $field, $value);
+}
+
+interface PlDBTableFieldFormatter extends PlDBTableFieldValidator, XDBFormat, PlExportable
+{
+}
+
+class DateFieldFormatter implements PlDBTableFieldFormatter
+{
+ private $datetime;
+ private $storageFormat;
+
+ public function __construct(PlDBTableField $field, $date)
+ {
+ $this->datetime = make_datetime($date);
+ if (is_null($this->datetime)) {
+ throw new PlDBBadValueException($date, $field, 'value is expected to be a date/time, ' . $date . ' given');
+ }
+ if ($field->type == 'date') {
+ $this->storageFormat = 'Y-m-d';
+ } else if ($field->type == 'datetime') {
+ $this->storageFormat = 'Y-m-d H:i:s';
+ } else {
+ $this->storageFormat = 'U';
+ }
+ }
+
+ public function format()
+ {
+ return XDB::escape($this->export());
+ }
+
+ public function date($format)
+ {
+ return $this->datetime->format($format);
+ }
+
+ public function export()
+ {
+ return $this->datetime->format($this->storageFormat);
+ }
+}
+
+class JSonFieldFormatter implements PlDBTableFieldFormatter, ArrayAccess
+{
+ private $data;
+
+ public function __construct(PlDBTableField $field, $data)
+ {
+ if (strpos($field->type, 'text') === false) {
+ throw new PlDBBadValueException($data, $field, 'json formatting requires a text field');
+ }
+
+ if (is_string($data)) {
+ $this->data = json_decode($data, true);
+ } else if (is_object($data)) {
+ if ($data instanceof PlExportable) {
+ $this->data = $data->export();
+ } else {
+ $this->data = json_decode(json_encode($data), true);
+ }
+ } else if (is_array($data)) {
+ $this->data = $data;
+ }
+
+ if (is_null($this->data)) {
+ throw new PlDBBadValueException($data, $field, 'cannot interpret data as json: ' . $data);
+ }
+ }
+
+ public function format()
+ {
+ return XDB::escape(json_encode($this->data));
+ }
+
+ public function export()
+ {
+ return $this->data;
+ }
+
+ public function offsetExists($offset)
+ {
+ return isset($this->data[$offset]);
+ }
+
+ public function offsetGet($offset)
+ {
+ return $this->data[$offset];
+ }
+
+ public function offsetSet($offset, $value)
+ {
+ $this->data[$offset] = $value;
+ }
+
+ public function offsetUnset($offset)
+ {
+ unset($this->data[$offset]);
+ }
+}
+
/** This class aims at providing a simple interface to interact with a single
* table of a database. It is implemented as a wrapper around XDB.
*/
class PlDBTable
{
+ const PRIMARY_KEY = 'PRIMARY';
+
public $table;
private $schema;
- private $keyFields;
+ private $primaryKey;
+ private $uniqueKeys;
+ private $multipleKeys;
private $mutableFields;
public function __construct($table)
$this->schema();
}
- private function parseSchema(PlIterator $schema)
+ private function parseSchema(PlIterator $schema, PlIterator $keys)
{
$this->schema = array();
- $this->keyFields = array();
+ $this->primaryKey = array();
+ $this->uniqueKeys = array();
+ $this->multipleKeys = array();
$this->mutableFields = array();
while ($column = $schema->next()) {
$field = new PlDBTableField($column);
$this->schema[$field->name] = $field;
- if ($field->inPrimaryKey) {
- $this->keyFields[] = $field->name;
- } else {
+ if (!$field->inPrimaryKey) {
$this->mutableFields[] = $field->name;
}
}
+ while ($column = $keys->next()) {
+ $name = $column['Key_name'];
+ $multiple = intval($column['Non_unique']) != 0;
+ $field = $column['Column_name'];
+ if ($multiple) {
+ if (!isset($this->multipleKeys[$name])) {
+ $this->multipleKeys[$name] = array();
+ }
+ $this->multipleKeys[$name][] = $field;
+ } else if ($name == self::PRIMARY_KEY) {
+ $this->primaryKey[] = $field;
+ } else {
+ if (!isset($this->uniqueKeys[$name])) {
+ $this->uniqueKeys[$name] = array();
+ }
+ $this->uniqueKeys[$name][] = $field;
+ }
+ }
}
{
if (!$this->schema) {
$schema = XDB::iterator('DESCRIBE ' . $this->table);
- $this->parseSchema($schema);
+ $keys = XDB::iterator('SHOW INDEX FROM ' . $this->table);
+ $this->parseSchema($schema, $keys);
}
return $this->schema;
}
return $this->field($field)->format($value);
}
+ public function registerFieldFormatter($field, $class)
+ {
+ return $this->field($field)->registerFormatter($class);
+ }
+
+ public function registerFieldValidator($field, $class)
+ {
+ return $this->field($field)->registerValidator($class);
+ }
+
+
public function defaultValue($field)
{
return $this->field($field)->defaultValue;
}
- public function primaryKey(PlDBTableEntry $entry)
+ private function hasKeyField(PlDBTableEntry $entry, array $fields)
+ {
+ foreach ($fields as $field) {
+ if (isset($entry->$field)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private function keyFields($keyName)
+ {
+ if ($keyName == self::PRIMARY_KEY) {
+ return $this->primaryKey;
+ } else if (isset($this->uniqueKeys[$keyName])) {
+ return $this->uniqueKeys[$keyName];
+ } else if (isset($this->multipleKeys[$keyName])) {
+ return $this->multipleKeys[$keyName];
+ }
+ throw new PlDBNoSuchKeyException($keyName, $this);
+ }
+
+ private function bestKeyFields(PlDBTableEntry $entry, $allowMultiple)
+ {
+ if ($this->hasKeyField($entry, $this->primaryKey)) {
+ return $this->primaryKey;
+ }
+ foreach ($this->uniqueKeys as $fields) {
+ if ($this->hasKeyField($entry, $fields)) {
+ return $fields;
+ }
+ }
+ if ($allowMultiple) {
+ foreach ($this->multipleKeys as $fields) {
+ if ($this->hasKeyField($entry, $fields)) {
+ return $fields;
+ }
+ }
+ }
+ return $this->primaryKey;
+ }
+
+ public function key(PlDBTableEntry $entry, array $keyFields)
{
$key = array();
- foreach ($this->keyFields as $field) {
+ foreach ($keyFields as $field) {
if (!isset($entry->$field)) {
throw new PlDBIncompleteEntryDescription($field, $this);
} else {
return implode('-', $key);
}
- private function buildKeyCondition(PlDBTableEntry $entry, $allowIncomplete)
+ public function primaryKey(PlDBTableEntry $entry)
+ {
+ return $this->key($this->keyFields(self::PRIMARY_KEY));
+ }
+
+ private function buildKeyCondition(PlDBTableEntry $entry, array $keyFields, $allowIncomplete)
{
$condition = array();
- foreach ($this->keyFields as $field) {
+ foreach ($keyFields as $field) {
if (!isset($entry->$field)) {
if (!$allowIncomplete) {
throw new PlDBIncompleteEntryDescription($field, $this);
{
$result = XDB::rawFetchOneAssoc('SELECT *
FROM ' . $this->table . '
- WHERE ' . $this->buildKeyCondition($entry, false));
+ WHERE ' . $this->buildKeyCondition($entry,
+ $this->bestKeyFields($entry, false),
+ false));
if (!$result) {
return false;
}
return $entry->fillFromDBData($result);
}
- public function iterateOnEntry(PlDBTableEntry $entry)
+ public function iterateOnCondition(PlDBTableEntry $entry, $condition, $sortField)
{
+ if (empty($sortField)) {
+ $sortField = $this->primaryKey;
+ }
+ if (!is_array($sortField)) {
+ $sortField = array($sortField);
+ }
+ $sort = ' ORDER BY ' . implode(', ', $sortField);
$it = XDB::rawIterator('SELECT *
FROM ' . $this->table . '
- WHERE ' . $this->buildKeyCondition($entry, true));
+ WHERE ' . $condition . '
+ ' . $sort);
return PlIteratorUtils::map($it, array($entry, 'cloneAndFillFromDBData'));
}
- public function updateEntry(PlDBTableEntry $entry)
+ public function iterateOnEntry(PlDBTableEntry $entry, $sortField)
{
- $values = array();
- foreach ($this->mutableFields as $field) {
- if ($entry->hasChanged($field)) {
- $values[] = XDB::format($field . ' = {?}', $entry->$field);
+ return $this->iterateOnCondition($entry,
+ $this->buildKeyCondition($entry,
+ $this->bestKeyFields($entry, true),
+ true),
+ $sortField);
+ }
+
+ const SAVE_INSERT_MISSING = 0x01;
+ const SAVE_UPDATE_EXISTING = 0x02;
+ const SAVE_IGNORE_DUPLICATE = 0x04;
+ public function saveEntries(array $entries, $flags)
+ {
+ $flags &= (self::SAVE_INSERT_MISSING | self::SAVE_UPDATE_EXISTING | self::SAVE_IGNORE_DUPLICATE);
+ Platal::assert($flags != 0, "Hey, the flags ($flags) here are so stupid, don't know what to do");
+ if ($flags == self::SAVE_UPDATE_EXISTING) {
+ foreach ($entries as $entry) {
+ $values = array();
+ foreach ($this->mutableFields as $field) {
+ if ($entry->hasChanged($field)) {
+ $values[] = XDB::format($field . ' = {?}', $entry->$field);
+ }
+ }
+ if (count($values) > 0) {
+ XDB::rawExecute('UPDATE ' . $this->table . '
+ SET ' . implode(', ', $values) . '
+ WHERE ' . $this->buildKeyCondition($entry,
+ $this->keyFields(self::PRIMARY_KEY),
+ false));
+ }
+ }
+ } else {
+ $fields = new PlFlagSet();
+ foreach ($entries as $entry) {
+ foreach ($this->schema as $field=>$type) {
+ if ($type->inPrimaryKey || $entry->hasChanged($field)) {
+ $fields->addFlag($field);
+ }
+ }
+ }
+ if (count($fields->export()) > 0) {
+ foreach ($entries as $entry) {
+ $v = array();
+ foreach ($fields as $field) {
+ $v[$field] = XDB::escape($entry->$field);
+ }
+ $values[] = '(' . implode(', ', $v) . ')';
+ }
+
+ $query = $this->table . ' (' . implode(', ', $fields->export()) . ')
+ VALUES ' . implode(",\n", $values);
+ if (($flags & self::SAVE_UPDATE_EXISTING)) {
+ $update = array();
+ foreach ($this->mutableFields as $field) {
+ if (isset($values[$field])) {
+ $update[] = "$field = VALUES($field)";
+ }
+ }
+ if (count($update) > 0) {
+ $query = 'INSERT INTO ' . $query;
+ $query .= "\n ON DUPLICATE KEY UPDATE " . implode(', ', $update);
+ } else {
+ $query = 'INSERT IGNORE INTO ' . $query;
+ }
+ } else if (($flags & self::SAVE_IGNORE_DUPLICATE)) {
+ $query = 'INSERT IGNORE INTO ' . $query;
+ } else {
+ $query = 'INSERT INTO ' . $query;
+ }
+ XDB::rawExecute($query);
+ if (count($entries) == 1) {
+ $id = XDB::insertId();
+ if ($id) {
+ $entry = end($entries);
+ foreach ($this->primaryKey as $field) {
+ if ($this->schema[$field]->autoIncrement) {
+ $entry->$field = $id;
+ break;
+ }
+ }
+ }
+ }
}
}
- if (count($values) > 0) {
- XDB::rawExecute('UPDATE ' . $this->table . '
- SET ' . implode(', ', $values) . '
- WHERE ' . $this->buildKeyCondition($entry, false));
+ }
+
+ public function deleteEntry(PlDBTableEntry $entry, $allowIncomplete)
+ {
+ XDB::rawExecute('DELETE FROM ' . $this->table . '
+ WHERE ' . $this->buildKeyCondition($entry,
+ $this->bestKeyFields($entry, $allowIncomplete),
+ $allowIncomplete));
+ }
+
+ public function exportEntry(PlDBTableEntry $entry)
+ {
+ $export = array();
+ foreach ($this->schema as $key=>$field) {
+ $value = $entry->$key;
+ if ($value instanceof PlExportable) {
+ $value = $value->export();
+ }
+ $export[$key] = $value;
}
+ return $export;
}
public static function get($name)
{
- var_dump('blah');
return new PlDBTable($name);
}
}
-class PlDBTableEntry extends PlAbstractIterable
+class PlDBTableEntry extends PlAbstractIterable implements PlExportable
{
private $table;
private $changed;
$this->changed = new PlFlagSet();
}
+ /** Register a custom formatter for a field.
+ *
+ * A formatter can be used to perform on-the-fly conversion from db storage to a user-friendly format.
+ * For example, if you have a textual field that contain json, you can use a JSonFieldFormatter on this
+ * field to perform automatic decoding when reading from the database (or when assigning the field)
+ * and automatic json_encoding when storing the object back to the db.
+ */
+ protected function registerFieldFormatter($field, $formatterClass)
+ {
+ $this->table->registerFieldFormatter($field, $formatterClass);
+ }
+
+ /** Register a custom validator for a field.
+ *
+ * A validator perform a pre-filter on the value of a field. As opposed to the formatters, it does
+ * not affects how the value is stored in the database.
+ */
+ protected function registerFieldValidator($field, $validatorClass)
+ {
+ $this->table->registerFieldValidator($field, $validatorClass);
+ }
+
/** This hook is called when the entry is going to be updated in the db.
*
* A typical usecase is a class that stores low-level representation of
return true;
}
+ /** This hook is called when the entry has been save in the database.
+ *
+ * It can be used to perform post-actions on save like storing extra data
+ * in database or sending a notification.
+ */
+ protected function postSave()
+ {
+ }
+
+ /** This hook is called when the entry is going to be deleted from the db.
+ *
+ * Default behavior is to call preSave().
+ *
+ * @return true in case of success.
+ */
+ protected function preDelete()
+ {
+ return $this->preSave();
+ }
+
/** This hook is called when the entry has just been fetched from the db.
*
* This is the counterpart of @ref preSave and a typical use-case is the conversion
return $this->postFetch();
}
+ public function copy(PlDBTableEntry $other)
+ {
+ Platal::assert($this->table == $other->table,
+ "Trying to fill an entry of table {$this->table->table} with content of {$other->table->table}.");
+ $this->changed = $other->changed;
+ $this->fetched = $other->fetched;
+ $this->data = $other->data;
+ }
+
public function cloneAndFillFromDBData(array $data)
{
$clone = clone $this;
return $this->table->fetchEntry($this);
}
- public function iterate()
+ public function iterate($sortField = null)
{
- return $this->table->iterateOnEntry($this);
+ return $this->table->iterateOnEntry($this, $sortField);
}
- public function save()
+ public function iterateOnCondition($condition, $sortField = null)
{
- if (!$this->preSave()) {
- return false;
+ return $this->table->iterateOnCondition($this, $condition, $sortField);
+ }
+
+ public function save($flags)
+ {
+ return self::saveBatch(array($this), $flags);
+ }
+
+ public function update($insertMissing = false)
+ {
+ $flags = PlDBTable::SAVE_UPDATE_EXISTING;
+ if ($insertMissing) {
+ $flags = PlDBTable::SAVE_INSERT_MISSING;
+ }
+ return $this->save($flags);
+ }
+
+ public function insert($allowUpdate = false)
+ {
+ $flags = PlDBTable::SAVE_INSERT_MISSING;
+ if ($allowUpdate) {
+ $flags |= PlDBTable::SAVE_UPDATE_EXISTING;
+ }
+ return $this->save($flags);
+ }
+
+ public function delete()
+ {
+ if (!$this->preDelete()) {
+ return 0;
+ }
+ return $this->table->deleteEntry($this, true);
+ }
+
+ public function export()
+ {
+ return $this->table->exportEntry($this);
+ }
+
+ protected static function saveBatch($entries, $flags)
+ {
+ $table = null;
+ foreach ($entries as $entry) {
+ if (is_null($table)) {
+ $table = $entry->table;
+ } else {
+ Platal::assert($table === $entry->table, "Cannot save batch of entries of different kinds");
+ }
+ if (!$entry->preSave()) {
+ return false;
+ }
+ }
+ $table->saveEntries($entries, $flags);
+ foreach ($entries as $entry) {
+ $entry->changed->clear();
+ $entry->postSave();
}
- $this->table->updateEntry($this);
- $this->changed->clear();
return true;
}
+
+ public static function insertBatch($entries, $allowUpdate = false)
+ {
+ $flags = PlDBTable::SAVE_INSERT_MISSING;
+ if ($allowUpdate) {
+ $flags |= PlDBTable::SAVE_UPDATE_EXISTING;
+ }
+ return self::saveBatch($entries, $flags);
+ }
}
// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
* descending order).
* The getSortTokens function is used to get actual ordering part of the query.
*/
-abstract class PlFilterOrder
+abstract class PlFilterOrder implements PlExportable
{
protected $desc = false;
public function __construct($desc = false)
$this->_tokens = null;
}
+ protected function buildExport($type)
+ {
+ $export = array('type' => $type);
+ if ($this->desc) {
+ $export['order'] = 'desc';
+ }
+ return $export;
+ }
+
+ public function export()
+ {
+ throw new Exception("This instance is not exportable");
+ }
+
public function toggleDesc()
{
$this->desc = !$this->desc;
$this->desc = $desc;
}
- public function buildSort(PlFilter &$pf)
+ public function buildSort(PlFilter $pf)
{
$sel = $this->getSortTokens($pf);
$this->_tokens = $sel;
}
/** This function must return the tokens to use for ordering
- * @param &$pf The PlFilter whose results must be ordered
+ * @param $pf The PlFilter whose results must be ordered
* @return The name of the field to use for ordering results
*/
- abstract protected function getSortTokens(PlFilter &$pf);
+ abstract protected function getSortTokens(PlFilter $pf);
}
// }}}
* the returned token will be used to group the values.
* It will always be called AFTER getSortTokens().
*/
- public function getGroupToken(PlFilter &$pf)
+ public function getGroupToken(PlFilter $pf)
{
return $this->_tokens;
}
$this->seed = $seed;
}
- protected function getSortTokens(PlFilter &$pf)
+ protected function getSortTokens(PlFilter $pf)
{
if ($this->seed == null) {
return 'RAND()';
return XDB::format('RAND({?})', $this->seed);
}
}
+
+ public function export()
+ {
+ $export = array('type' => 'random',);
+ if ($this->seed !== null)
+ $export['seed'] = $this->seed;
+ return $export;
+ }
}
// }}}
// {{{ interface PlFilterCondition
-interface PlFilterCondition
+interface PlFilterCondition extends PlExportable
{
const COND_TRUE = 'TRUE';
const COND_FALSE = 'FALSE';
- public function buildCondition(PlFilter &$pf);
+ public function buildCondition(PlFilter $pf);
}
// }}}
{
protected $child;
- public function __construct(&$child = null)
+ public function __construct($child = null)
{
if (!is_null($child) && ($child instanceof PlFilterCondition)) {
$this->setChild($child);
}
}
- public function setChild(PlFilterCondition &$cond)
+ public function setChild(PlFilterCondition $cond)
+ {
+ $this->child = $cond;
+ }
+
+ public function export()
{
- $this->child =& $cond;
+ return array('child' => $child->export());
}
}
// }}}
public function addChildren(array $conds)
{
- foreach ($conds as &$cond) {
+ foreach ($conds as $cond) {
if (!is_null($cond) && ($cond instanceof PlFilterCondition)) {
$this->addChild($cond);
}
}
}
- public function addChild(PlFilterCondition &$cond)
+ public function addChild(PlFilterCondition $cond)
{
- $this->children[] =& $cond;
+ $this->children[] = $cond;
}
protected function catConds(array $cond, $op, $fallback)
return '(' . implode(') ' . $op . ' (', $cond) . ')';
}
}
+
+ public function export()
+ {
+ $export = array();
+ foreach ($this->children as $child) {
+ $export[] = $child->export();
+ }
+ return array('children' => $export);
+ }
}
// }}}
// {{{ class PFC_True
class PFC_True implements PlFilterCondition
{
- public function buildCondition(PlFilter &$uf)
+ public function buildCondition(PlFilter $uf)
{
return self::COND_TRUE;
}
+
+ public function export()
+ {
+ return array('type' => 'true');
+ }
}
// }}}
// {{{ class PFC_False
class PFC_False implements PlFilterCondition
{
- public function buildCondition(PlFilter &$uf)
+ public function buildCondition(PlFilter $uf)
{
return self::COND_FALSE;
}
+
+ public function export()
+ {
+ return array('type' => 'false');
+ }
}
// }}}
// {{{ class PFC_Not
class PFC_Not extends PFC_OneChild
{
- public function buildCondition(PlFilter &$uf)
+ public function buildCondition(PlFilter $uf)
{
$val = $this->child->buildCondition($uf);
if ($val == self::COND_TRUE) {
return 'NOT (' . $val . ')';
}
}
+
+ public function export()
+ {
+ $export = parent::export();
+ $export['type'] = 'not';
+ return $export;
+ }
}
// }}}
// {{{ class PFC_And
class PFC_And extends PFC_NChildren
{
- public function buildCondition(PlFilter &$uf)
+ public function buildCondition(PlFilter $uf)
{
if (empty($this->children)) {
return self::COND_FALSE;
} else {
$true = self::COND_FALSE;
$conds = array();
- foreach ($this->children as &$child) {
+ foreach ($this->children as $child) {
$val = $child->buildCondition($uf);
if ($val == self::COND_TRUE) {
$true = self::COND_TRUE;
return $this->catConds($conds, 'AND', $true);
}
}
+
+ public function export() {
+ $export = parent::export();
+ $export['type'] = 'and';
+ return $export;
+ }
}
// }}}
// {{{ class PFC_Or
class PFC_Or extends PFC_NChildren
{
- public function buildCondition(PlFilter &$uf)
+ public function buildCondition(PlFilter $uf)
{
if (empty($this->children)) {
return self::COND_TRUE;
} else {
$true = self::COND_TRUE;
$conds = array();
- foreach ($this->children as &$child) {
+ foreach ($this->children as $child) {
$val = $child->buildCondition($uf);
if ($val == self::COND_TRUE) {
return self::COND_TRUE;
return $this->catConds($conds, 'OR', $true);
}
}
+
+ public function export() {
+ $export = parent::export();
+ $export['type'] = 'or';
+ return $export;
+ }
}
// }}}
// {{{ class PlFilter
-abstract class PlFilter
+abstract class PlFilter implements PlExportable
{
/** Filters objects matching the PlFilter
* @param $objects The objects to filter
*/
public abstract function filter(array $objects, $limit = null);
- public abstract function setCondition(PlFilterCondition &$cond);
+ public abstract function setCondition(PlFilterCondition $cond);
- public abstract function addSort(PlFilterOrder &$sort);
+ public abstract function addSort(PlFilterOrder $sort);
public abstract function getTotalCount();