From c7768d882070ae9b902fe2f4575d7365c6b504de Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Wed, 27 May 2009 00:05:10 +0000 Subject: [PATCH] API CHANGE Added interface methods to CompositeDBField MINOR Documented CompositeDBField git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@77892 467b73ca-7a2a-4603-9d3b-597d59a354a9 --- core/model/fieldtypes/CompositeDBField.php | 167 +++++++++++++++++++++ 1 file changed, 167 insertions(+) diff --git a/core/model/fieldtypes/CompositeDBField.php b/core/model/fieldtypes/CompositeDBField.php index 82e6f1f42..802797f92 100644 --- a/core/model/fieldtypes/CompositeDBField.php +++ b/core/model/fieldtypes/CompositeDBField.php @@ -4,10 +4,177 @@ * This includes multi-value fields and transformed fields * * @todo Unittests for loading and saving composite values (see GIS module for existing similiar unittests) + * + * Example with a combined street name and number: + * +* class Street extends DBFields implements CompositeDBField() { +* protected $streetNumber; +* protected $streetName; +* protected $isChanged = false; +* static $composite_db = return array( +* "Number" => "Int", +* "Name" => "Text" +* ); +* +* function requireField() { +* DB::requireField($this->tableName, "{$this->name}Number", 'Int'); +* DB::requireField($this->tableName, "{$this->name}Name", 'Text'); +* } +* +* function writeToManipulation(&$manipulation) { +* if($this->getStreetName()) { +* $manipulation['fields']["{$this->name}Name"] = $this->prepValueForDB($this->getStreetName()); +* } else { +* $manipulation['fields']["{$this->name}Name"] = DBField::create('Varchar', $this->getStreetName())->nullValue(); +* } +* +* if($this->getStreetNumber()) { +* $manipulation['fields']["{$this->name}Number"] = $this->prepValueForDB($this->getStreetNumber()); +* } else { +* $manipulation['fields']["{$this->name}Number"] = DBField::create('Int', $this->getStreetNumber())->nullValue(); +* } +* } +* +* function addToQuery(&$query) { +* parent::addToQuery($query); +* $query->select[] = "{$this->name}Number"; +* $query->select[] = "{$this->name}Name"; +* } +* +* function setValue($value, $record = null, $markChanged=true) { +* if ($value instanceof Street && $value->hasValue()) { +* $this->setStreetName($value->getStreetName(), $markChanged); +* $this->setStreetNumber($value->getStreetNumber(), $markChanged); +* if($markChanged) $this->isChanged = true; +* } else if($record && isset($record[$this->name . 'Name']) && isset($record[$this->name . 'Number'])) { +* if($record[$this->name . 'Name'] && $record[$this->name . 'Number']) { +* $this->setStreetName($record[$this->name . 'Name'], $markChanged); +* $this->setStreetNumber($record[$this->name . 'Number'], $markChanged); +* } +* if($markChanged) $this->isChanged = true; +* } else if (is_array($value)) { +* if (array_key_exists('Name', $value)) { +* $this->setStreetName($value['Name'], $markChanged); +* } +* if (array_key_exists('Number', $value)) { +* $this->setStreetNumber($value['Number'], $markChanged); +* } +* if($markChanged) $this->isChanged = true; +* } +* } +* +* function setStreetNumber($val, $markChanged=true) { +* $this->streetNumber = $val; +* if($markChanged) $this->isChanged = true; +* } +* +* function setStreetName($val, $markChanged=true) { +* $this->streetName = $val; +* if($markChanged) $this->isChanged = true; +* } +* +* function getStreetNumber() { +* return $this->streetNumber; +* } +* +* function getStreetName() { +* return $this->streetName; +* } +* +* function isChanged() { +* return $this->isChanged; +* } +* +* function hasValue() { +* return ($this->getStreetName() || $this->getStreetNumber()); +* } +* } + * * * @package sapphire * @subpackage model */ interface CompositeDBField { + /** + * Similiar to {@link DataObject::$db}, + * holds an array of composite field names. + * Don't include the fields "main name", + * it will be prefixed in {@link requireField()}. + * + * @var array $composite_db + */ + //static $composite_db; + + /** + * Set the value of this field in various formats. + * Used by {@link DataObject->getField()}, {@link DataObject->setCastedField()} + * {@link DataObject->dbObject()} and {@link DataObject->write()}. + * + * As this method is used both for initializing the field after construction, + * and actually changing its values, it needs a {@link $markChanged} + * parameter. + * + * @param DBField|array $value + * @param array $record Map of values loaded from the database + * @param boolean $markChanged + */ + function setValue($value, $record = null, $markChanged = true); + + /** + * Used in constructing the database schema. + * Add any custom properties defined in {@link $composite_db}. + * Should make one or more calls to {@link DB::requireField()}. + */ + //abstract function requireField(); + + /** + * Add the custom internal values to an INSERT or UPDATE + * request passed through the ORM with {@link DataObject->write()}. + * Fields are added in $manipulation['fields']. Please ensure + * these fields are escaped for database insertion, as no + * further processing happens before running the query. + * Use {@link DBField->prepValueForDB()}. + * Ensure to write NULL or empty values as well to allow + * unsetting a previously set field. Use {@link DBField->nullValue()} + * for the appropriate type. + * + * @param array $manipulation + */ + function writeToManipulation(&$manipulation); + + /** + * Add all columns which are defined through {@link requireField()} + * and {@link $composite_db}, or any additional SQL that is required + * to get to these columns. Will mostly just write to the {@link SQLQuery->select} + * array. + * + * @param SQLQuery $query + */ + function addToQuery(&$query); + + /** + * Return array in the format of {@link $composite_db}. + * Used by {@link DataObject->hasOwnDatabaseField()}. + * @return array + */ + function compositeDatabaseFields(); + + /** + * Determines if the field has been changed since its initialization. + * Most likely relies on an internal flag thats changed when calling + * {@link setValue()} or any other custom setters on the object. + * + * @return boolean + */ + function isChanged(); + + /** + * Determines if any of the properties in this field have a value, + * meaning at least one of them is not NULL. + * + * @return boolean + */ + function hasValue(); + } \ No newline at end of file