mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-09-19 16:06:32 +02:00
aeccb8b8e0
API: Deprecate SS_Datetime. The DBField subclasses are have all been renamed to start with “DB” and be in the SilverStripe\Model\FieldType namespace. To keep DataObject definitions concise, the original short variations of their names are preserved as service definitions. Most of the field generation code doesn’t need to change, but where field classes are referenced directly, changes will be needed. SS_Datetime, which is commonly referenced outside the model system itself, has been preserved as a subclass of DBDatetime. This has been marked as deprecated and can be removed in SilverStripe 5. A few places that referred to $db and $casting values weren’t using the Injector to instantiate the relevant classes. This meant that the remapping we have created as part of moving classes into a namespace didn’t work.
279 lines
6.5 KiB
PHP
279 lines
6.5 KiB
PHP
<?php
|
|
|
|
namespace SilverStripe\Model\FieldType;
|
|
|
|
use DB;
|
|
use Object;
|
|
use DataObject;
|
|
|
|
/**
|
|
* Apply this interface to any {@link DBField} that doesn't have a 1-1 mapping with a database field.
|
|
* 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:
|
|
* <code>
|
|
* class Street extends DBComposite {
|
|
* private static $composite_db = return array(
|
|
* "Number" => "Int",
|
|
* "Name" => "Text"
|
|
* );
|
|
* }
|
|
* </code>
|
|
*
|
|
* @package framework
|
|
* @subpackage model
|
|
*/
|
|
abstract class DBComposite extends DBField {
|
|
|
|
/**
|
|
* 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()}.
|
|
*
|
|
* @config
|
|
* @var array
|
|
*/
|
|
private static $composite_db = array();
|
|
|
|
/**
|
|
* Either the parent dataobject link, or a record of saved values for each field
|
|
*
|
|
* @var array|DataObject
|
|
*/
|
|
protected $record = array();
|
|
|
|
/**
|
|
* Write all nested fields into a manipulation
|
|
*
|
|
* @param array $manipulation
|
|
*/
|
|
public function writeToManipulation(&$manipulation) {
|
|
foreach($this->compositeDatabaseFields() as $field => $spec) {
|
|
// Write sub-manipulation
|
|
$fieldObject = $this->dbObject($field);
|
|
$fieldObject->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 SQLSelect->select}
|
|
* array.
|
|
*
|
|
* @param SQLSelect $query
|
|
*/
|
|
public function addToQuery(&$query) {
|
|
parent::addToQuery($query);
|
|
|
|
foreach($this->compositeDatabaseFields() as $field => $spec) {
|
|
$table = $this->getTable();
|
|
$key = $this->getName() . $field;
|
|
if($table) {
|
|
$query->selectField("\"{$table}\".\"{$key}\"");
|
|
} else {
|
|
$query->selectField("\"{$key}\"");
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return array in the format of {@link $composite_db}.
|
|
* Used by {@link DataObject->hasOwnDatabaseField()}.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function compositeDatabaseFields() {
|
|
return $this->config()->composite_db;
|
|
}
|
|
|
|
|
|
public function isChanged() {
|
|
// When unbound, use the local changed flag
|
|
if(! ($this->record instanceof DataObject) ) {
|
|
return $this->isChanged;
|
|
}
|
|
|
|
// Defer to parent record
|
|
foreach($this->compositeDatabaseFields() as $field => $spec) {
|
|
$key = $this->getName() . $field;
|
|
if($this->record->isChanged($key)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Composite field defaults to exists only if all fields have values
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function exists() {
|
|
// By default all fields
|
|
foreach($this->compositeDatabaseFields() as $field => $spec) {
|
|
$fieldObject = $this->dbObject($field);
|
|
if(!$fieldObject->exists()) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public function requireField() {
|
|
foreach($this->compositeDatabaseFields() as $field => $spec){
|
|
$key = $this->getName() . $field;
|
|
DB::requireField($this->tableName, $key, $spec);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Assign the given value.
|
|
* If $record is assigned to a dataobject, this field becomes a loose wrapper over
|
|
* the records on that object instead.
|
|
*
|
|
* {@see ViewableData::obj}
|
|
*
|
|
* @param mixed $value
|
|
* @param mixed $record Parent object to this field, which could be a DataObject, record array, or other
|
|
* @param bool $markChanged
|
|
*/
|
|
public function setValue($value, $record = null, $markChanged = true) {
|
|
$this->isChanged = $markChanged;
|
|
|
|
// When given a dataobject, bind this field to that
|
|
if($record instanceof DataObject) {
|
|
$this->bindTo($record);
|
|
$record = null;
|
|
}
|
|
|
|
foreach($this->compositeDatabaseFields() as $field => $spec) {
|
|
// Check value
|
|
if($value instanceof DBComposite) {
|
|
// Check if saving from another composite field
|
|
$this->setField($field, $value->getField($field));
|
|
|
|
} elseif(isset($value[$field])) {
|
|
// Check if saving from an array
|
|
$this->setField($field, $value[$field]);
|
|
}
|
|
|
|
// Load from $record
|
|
$key = $this->getName() . $field;
|
|
if(is_array($record) && isset($record[$key])) {
|
|
$this->setField($field, $record[$key]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Bind this field to the dataobject, and set the underlying table to that of the owner
|
|
*
|
|
* @param DataObject $dataObject
|
|
*/
|
|
public function bindTo($dataObject) {
|
|
$this->record = $dataObject;
|
|
}
|
|
|
|
public function saveInto($dataObject) {
|
|
foreach($this->compositeDatabaseFields() as $field => $spec) {
|
|
// Save into record
|
|
$key = $this->getName() . $field;
|
|
$dataObject->setField($key, $this->getField($field));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* get value of a single composite field
|
|
*
|
|
* @param string $field
|
|
* @return mixed
|
|
*/
|
|
public function getField($field) {
|
|
// Skip invalid fields
|
|
$fields = $this->compositeDatabaseFields();
|
|
if(!isset($fields[$field])) {
|
|
return null;
|
|
}
|
|
|
|
// Check bound object
|
|
if($this->record instanceof DataObject) {
|
|
$key = $this->getName().$field;
|
|
return $this->record->getField($key);
|
|
}
|
|
|
|
// Check local record
|
|
if(isset($this->record[$field])) {
|
|
return $this->record[$field];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public function hasField($field) {
|
|
$fields = $this->compositeDatabaseFields();
|
|
return isset($fields[$field]);
|
|
}
|
|
|
|
/**
|
|
* Set value of a single composite field
|
|
*
|
|
* @param string $field
|
|
* @param mixed $value
|
|
* @param bool $markChanged
|
|
*/
|
|
public function setField($field, $value, $markChanged = true) {
|
|
// Skip non-db fields
|
|
if(!$this->hasField($field)) {
|
|
return;
|
|
}
|
|
|
|
// Set changed
|
|
if($markChanged) {
|
|
$this->isChanged = true;
|
|
}
|
|
|
|
// Set bound object
|
|
if($this->record instanceof DataObject) {
|
|
$key = $this->getName() . $field;
|
|
return $this->record->setField($key, $value);
|
|
}
|
|
|
|
// Set local record
|
|
$this->record[$field] = $value;
|
|
}
|
|
|
|
/**
|
|
* Get a db object for the named field
|
|
*
|
|
* @param string $field Field name
|
|
* @return DBField|null
|
|
*/
|
|
public function dbObject($field) {
|
|
$fields = $this->compositeDatabaseFields();
|
|
if(!isset($fields[$field])) {
|
|
return null;
|
|
}
|
|
|
|
// Build nested field
|
|
$key = $this->getName() . $field;
|
|
$spec = $fields[$field];
|
|
$fieldObject = Object::create_from_string($spec, $key);
|
|
$fieldObject->setValue($this->getField($field), null, false);
|
|
return $fieldObject;
|
|
}
|
|
|
|
public function castingHelper($field) {
|
|
$fields = $this->compositeDatabaseFields();
|
|
if(isset($fields[$field])) {
|
|
return $fields[$field];
|
|
}
|
|
|
|
|
|
parent::castingHelper($field);
|
|
}
|
|
|
|
}
|