mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
(merged from branches/roa. use "svn log -c <changeset> -g <module-svn-path>" for detailed commit message)
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@60204 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
e25f44604f
commit
9ac464cc57
@ -81,7 +81,7 @@ Director::addRules(10, array(
|
||||
'images/$Action/$Class/$ID/$Field' => 'Image_Uploader',
|
||||
'' => 'RootURLController',
|
||||
'sitemap.xml' => 'GoogleSitemap',
|
||||
'api/v1/$ClassName/$ID' => 'RestfulServer',
|
||||
'api/v1/$ClassName/$ID/$Relation' => 'RestfulServer',
|
||||
'dev/$Action/$NestedAction' => 'DevelopmentAdmin'
|
||||
));
|
||||
|
||||
|
@ -42,16 +42,33 @@ class RestfulServer extends Controller {
|
||||
if(!isset($this->urlParams['ClassName'])) return $this->notFound();
|
||||
$className = $this->urlParams['ClassName'];
|
||||
$id = (isset($this->urlParams['ID'])) ? $this->urlParams['ID'] : null;
|
||||
$relation = (isset($this->urlParams['Relation'])) ? $this->urlParams['Relation'] : null;
|
||||
|
||||
// This is a little clumsy and should be improved with the new TokenisedURL that's coming
|
||||
if(strpos($relation,'.') !== false) list($relation, $extension) = explode('.', $relation, 2);
|
||||
else if(strpos($id,'.') !== false) list($id, $extension) = explode('.', $id, 2);
|
||||
else if(strpos($className,'.') !== false) list($className, $extension) = explode('.', $className, 2);
|
||||
else $extension = null;
|
||||
|
||||
// Determine mime-type from extension
|
||||
$contentMap = array(
|
||||
'xml' => 'text/xml',
|
||||
'json' => 'text/json',
|
||||
'js' => 'text/json',
|
||||
'xhtml' => 'text/html',
|
||||
'html' => 'text/html',
|
||||
);
|
||||
$contentType = isset($contentMap[$extension]) ? $contentMap[$extension] : 'text/xml';
|
||||
|
||||
switch($requestMethod) {
|
||||
case 'GET':
|
||||
return $this->getHandler($className, $id);
|
||||
return $this->getHandler($className, $id, $relation, $contentType);
|
||||
|
||||
case 'PUT':
|
||||
return $this->putHandler($className, $id);
|
||||
return $this->putHandler($className, $id, $relation, $contentType);
|
||||
|
||||
case 'DELETE':
|
||||
return $this->deleteHandler($className, $id);
|
||||
return $this->deleteHandler($className, $id, $relation, $contentType);
|
||||
|
||||
case 'POST':
|
||||
}
|
||||
@ -83,46 +100,67 @@ class RestfulServer extends Controller {
|
||||
* - static $api_access must be set. This enables the API on a class by class basis
|
||||
* - $obj->canView() must return true. This lets you implement record-level security
|
||||
*/
|
||||
protected function getHandler($className, $id) {
|
||||
$obj = DataObject::get_by_id($className, $id);
|
||||
if(!$obj) {
|
||||
return $this->notFound();
|
||||
}
|
||||
|
||||
// TO DO - inspect that Accept header as well. $_GET['accept'] can still be checked, as it's handy for debugging
|
||||
$contentType = isset($_GET['accept']) ? $_GET['accept'] : 'text/xml';
|
||||
|
||||
if($obj->stat('api_access') && $obj->canView()) {
|
||||
switch($contentType) {
|
||||
case "text/xml":
|
||||
$this->getResponse()->addHeader("Content-type", "text/xml");
|
||||
return $this->dataObjectAsXML($obj);
|
||||
|
||||
case "text/json":
|
||||
$this->getResponse()->addHeader("Content-type", "text/json");
|
||||
return $this->dataObjectAsJSON($obj);
|
||||
|
||||
case "text/html":
|
||||
case "application/xhtml+xml":
|
||||
$this->getResponse()->addHeader("Content-type", "text/json");
|
||||
return $this->dataObjectAsXHTML($obj);
|
||||
protected function getHandler($className, $id, $relation, $contentType) {
|
||||
if($id) {
|
||||
$obj = DataObject::get_by_id($className, $id);
|
||||
if(!$obj) {
|
||||
return $this->notFound();
|
||||
}
|
||||
|
||||
if(!$obj->stat('api_access') || !$obj->canView()) {
|
||||
return $this->permissionFailure();
|
||||
}
|
||||
|
||||
if($relation) {
|
||||
if($obj->hasMethod($relation)) $obj = $obj->$relation();
|
||||
else return $this->notFound();
|
||||
}
|
||||
|
||||
} else {
|
||||
return $this->permissionFailure();
|
||||
$obj = DataObject::get($className, "");
|
||||
if(!singleton($className)->stat('api_access')) {
|
||||
return $this->permissionFailure();
|
||||
}
|
||||
}
|
||||
|
||||
// TO DO - inspect that Accept header as well. $_GET['accept'] can still be checked, as it's handy for debugging
|
||||
switch($contentType) {
|
||||
case "text/xml":
|
||||
$this->getResponse()->addHeader("Content-type", "text/xml");
|
||||
if($obj instanceof DataObjectSet) return $this->dataObjectSetAsXML($obj);
|
||||
else return $this->dataObjectAsXML($obj);
|
||||
|
||||
case "text/json":
|
||||
//$this->getResponse()->addHeader("Content-type", "text/json");
|
||||
if($obj instanceof DataObjectSet) return $this->dataObjectSetAsJSON($obj);
|
||||
else return $this->dataObjectAsJSON($obj);
|
||||
|
||||
case "text/html":
|
||||
case "application/xhtml+xml":
|
||||
if($obj instanceof DataObjectSet) return $this->dataObjectSetAsXHTML($obj);
|
||||
else return $this->dataObjectAsXHTML($obj);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an XML representation of the given DataObject.
|
||||
*/
|
||||
protected function dataObjectAsXML(DataObject $obj) {
|
||||
protected function dataObjectAsXML(DataObject $obj, $includeHeader = true) {
|
||||
$className = $obj->class;
|
||||
$id = $obj->ID;
|
||||
$objHref = Director::absoluteURL(self::$api_base . "$obj->class/$obj->ID");
|
||||
|
||||
$json = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<$className>\n";
|
||||
$json = "";
|
||||
if($includeHeader) $json .= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||
$json .= "<$className href=\"$objHref.xml\">\n";
|
||||
foreach($obj->db() as $fieldName => $fieldType) {
|
||||
$json .= "<$fieldName>" . Convert::raw2xml($obj->$fieldName) . "</$fieldName>\n";
|
||||
if(is_object($obj->$fieldName)) {
|
||||
$json .= $obj->$fieldName->toXML();
|
||||
} else {
|
||||
$json .= "<$fieldName>" . Convert::raw2xml($obj->$fieldName) . "</$fieldName>\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach($obj->has_one() as $relName => $relClass) {
|
||||
$fieldName = $relName . 'ID';
|
||||
@ -131,27 +169,26 @@ class RestfulServer extends Controller {
|
||||
} else {
|
||||
$href = Director::absoluteURL(self::$api_base . "$className/$id/$relName");
|
||||
}
|
||||
$json .= "<$relName linktype=\"has_one\" href=\"$href\" id=\"{$obj->$fieldName}\" />\n";
|
||||
$json .= "<$relName linktype=\"has_one\" href=\"$href.xml\" id=\"{$obj->$fieldName}\" />\n";
|
||||
}
|
||||
|
||||
foreach($obj->has_many() as $relName => $relClass) {
|
||||
$json .= "<$relName linktype=\"has_many\">\n";
|
||||
$json .= "<$relName linktype=\"has_many\" href=\"$objHref/$relName.xml\">\n";
|
||||
$items = $obj->$relName();
|
||||
foreach($items as $item) {
|
||||
//$href = Director::absoluteURL(self::$api_base . "$className/$id/$relName/$item->ID");
|
||||
$href = Director::absoluteURL(self::$api_base . "$relClass/$item->ID");
|
||||
$json .= "<$relClass href=\"$href\" id=\"{$item->ID}\" />\n";
|
||||
$json .= "<$relClass href=\"$href.xml\" id=\"{$item->ID}\" />\n";
|
||||
}
|
||||
$json .= "</$relName>\n";
|
||||
}
|
||||
|
||||
foreach($obj->many_many() as $relName => $relClass) {
|
||||
$json .= "<$relName linktype=\"many_many\">\n";
|
||||
$json .= "<$relName linktype=\"many_many\" href=\"$objHref/$relName.xml\">\n";
|
||||
$items = $obj->$relName();
|
||||
foreach($items as $item) {
|
||||
//$href = Director::absoluteURL(self::$api_base . "$className/$id/$relName/$item->ID");
|
||||
$href = Director::absoluteURL(self::$api_base . "$relClass/$item->ID");
|
||||
$json .= "<$relClass href=\"$href\" id=\"{$item->ID}\" />\n";
|
||||
$json .= "<$relClass href=\"$href.xml\" id=\"{$item->ID}\" />\n";
|
||||
}
|
||||
$json .= "</$relName>\n";
|
||||
}
|
||||
@ -161,6 +198,20 @@ class RestfulServer extends Controller {
|
||||
return $json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an XML representation of the given DataObject.
|
||||
*/
|
||||
protected function dataObjectSetAsXML(DataObjectSet $set) {
|
||||
$className = $set->class;
|
||||
|
||||
$json = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<$className>\n";
|
||||
foreach($set as $item) {
|
||||
if($item->canView()) $json .= $this->dataObjectAsXML($item, false);
|
||||
}
|
||||
$json .= "</$className>";
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an XML representation of the given DataObject.
|
||||
@ -171,7 +222,11 @@ class RestfulServer extends Controller {
|
||||
|
||||
$json = "{\n className : \"$className\",\n";
|
||||
foreach($obj->db() as $fieldName => $fieldType) {
|
||||
$jsonParts[] = "$fieldName : \"" . Convert::raw2js($obj->$fieldName) . "\"";
|
||||
if(is_object($obj->$fieldName)) {
|
||||
$jsonParts[] = "$fieldName : " . $obj->$fieldName->toJSON();
|
||||
} else {
|
||||
$jsonParts[] = "$fieldName : \"" . Convert::raw2js($obj->$fieldName) . "\"";
|
||||
}
|
||||
}
|
||||
|
||||
foreach($obj->has_one() as $relName => $relClass) {
|
||||
@ -181,7 +236,7 @@ class RestfulServer extends Controller {
|
||||
} else {
|
||||
$href = Director::absoluteURL(self::$api_base . "$className/$id/$relName");
|
||||
}
|
||||
$jsonParts[] = "$relName : { className : \"$relClass\", href : \"$href\", id : \"{$obj->$fieldName}\" }";
|
||||
$jsonParts[] = "$relName : { className : \"$relClass\", href : \"$href.json\", id : \"{$obj->$fieldName}\" }";
|
||||
}
|
||||
|
||||
foreach($obj->has_many() as $relName => $relClass) {
|
||||
@ -190,7 +245,7 @@ class RestfulServer extends Controller {
|
||||
foreach($items as $item) {
|
||||
//$href = Director::absoluteURL(self::$api_base . "$className/$id/$relName/$item->ID");
|
||||
$href = Director::absoluteURL(self::$api_base . "$relClass/$item->ID");
|
||||
$jsonInnerParts[] = "{ className : \"$relClass\", href : \"$href\", id : \"{$obj->$fieldName}\" }";
|
||||
$jsonInnerParts[] = "{ className : \"$relClass\", href : \"$href.json\", id : \"{$obj->$fieldName}\" }";
|
||||
}
|
||||
$jsonParts[] = "$relName : [\n " . implode(",\n ", $jsonInnerParts) . " \n ]";
|
||||
}
|
||||
@ -201,13 +256,26 @@ class RestfulServer extends Controller {
|
||||
foreach($items as $item) {
|
||||
//$href = Director::absoluteURL(self::$api_base . "$className/$id/$relName/$item->ID");
|
||||
$href = Director::absoluteURL(self::$api_base . "$relClass/$item->ID");
|
||||
$jsonInnerParts[] = " { className : \"$relClass\", href : \"$href\", id : \"{$obj->$fieldName}\" }";
|
||||
$jsonInnerParts[] = " { className : \"$relClass\", href : \"$href.json\", id : \"{$obj->$fieldName}\" }";
|
||||
}
|
||||
$jsonParts[] = "$relName : [\n " . implode(",\n ", $jsonInnerParts) . "\n ]";
|
||||
}
|
||||
|
||||
return "{\n " . implode(",\n ", $jsonParts) . "\n}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an XML representation of the given DataObject.
|
||||
*/
|
||||
protected function dataObjectSetAsJSON(DataObjectSet $set) {
|
||||
$jsonParts = array();
|
||||
foreach($set as $item) {
|
||||
if($item->canView()) $jsonParts[] = $this->dataObjectAsJSON($item);
|
||||
}
|
||||
return "[\n" . implode(",\n", $jsonParts) . "\n]";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for object delete
|
||||
*/
|
||||
|
@ -145,5 +145,13 @@ class ClassInfo {
|
||||
global $_ALL_CLASSES;
|
||||
return (isset($_ALL_CLASSES['implementors'][$interfaceName])) ? $_ALL_CLASSES['implementors'][$interfaceName] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given class implements the given interface
|
||||
*/
|
||||
static function classImplements($className, $interfaceName) {
|
||||
global $_ALL_CLASSES;
|
||||
return isset($_ALL_CLASSES['implementors'][$interfaceName]) ? in_array($className, $_ALL_CLASSES['implementors'][$interfaceName]) : false;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
@ -557,6 +557,14 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
|
||||
if(($this->ID && is_numeric($this->ID)) && !$forceInsert) {
|
||||
$dbCommand = 'update';
|
||||
|
||||
// Update the changed array with references to changed obj-fields
|
||||
foreach($this->record as $k => $v) {
|
||||
if(is_object($v) && $v->isChanged()) {
|
||||
$this->changed[$k] = true;
|
||||
}
|
||||
}
|
||||
|
||||
} else{
|
||||
$dbCommand = 'insert';
|
||||
|
||||
@ -1022,7 +1030,7 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
*
|
||||
* @return array The database fields
|
||||
*/
|
||||
public function db() {
|
||||
public function db($component = null) {
|
||||
$classes = ClassInfo::ancestry($this);
|
||||
$good = false;
|
||||
$items = array();
|
||||
@ -1035,7 +1043,15 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
}
|
||||
continue;
|
||||
}
|
||||
eval("\$items = array_merge((array){$class}::\$db, (array)\$items);");
|
||||
|
||||
if($component) {
|
||||
$candidate = eval("return isset({$class}::\$db[\$component]) ? {$class}::\$db[\$component] : null;");
|
||||
if($candidate) {
|
||||
return $candidate;
|
||||
}
|
||||
} else {
|
||||
eval("\$items = array_merge((array){$class}::\$db, (array)\$items);");
|
||||
}
|
||||
}
|
||||
|
||||
return $items;
|
||||
@ -1176,8 +1192,7 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
public function scaffoldFormFields() {
|
||||
$fields = new FieldSet();
|
||||
|
||||
foreach($this->inheritedDatabaseFields() as $fieldName => $fieldType) {
|
||||
|
||||
foreach($this->db() as $fieldName => $fieldType) {
|
||||
// @todo Pass localized title
|
||||
// commented out, to be less of a pain in the ass
|
||||
//$fields->addFieldToTab('Root.Main', $this->dbObject($fieldName)->scaffoldFormField());
|
||||
@ -1243,6 +1258,22 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
* @return mixed The field value
|
||||
*/
|
||||
protected function getField($field) {
|
||||
// If we already have an object in $this->record, then we should just return that
|
||||
if(isset($this->record[$field]) && is_object($this->record[$field])) return $this->record[$field];
|
||||
|
||||
// Otherwise, we need to determine if this is a complex field
|
||||
$fieldClass = $this->db($field);
|
||||
if($fieldClass && ClassInfo::classImplements($fieldClass, 'CompositeDBField')) {
|
||||
$helperPair = $this->castingHelperPair($field);
|
||||
$constructor = $helperPair['castingHelper'];
|
||||
$fieldName = $field;
|
||||
$fieldObj = eval($constructor);
|
||||
if(isset($this->record[$field])) $fieldObj->setValue($this->record[$field], $this->record);
|
||||
$this->record[$field] = $fieldObj;
|
||||
|
||||
return $this->record[$field];
|
||||
}
|
||||
|
||||
return isset($this->record[$field]) ? $this->record[$field] : null;
|
||||
}
|
||||
|
||||
@ -1293,28 +1324,36 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
* @param mixed $val New field value
|
||||
*/
|
||||
function setField($fieldName, $val) {
|
||||
$defaults = $this->stat('defaults');
|
||||
// if a field is not existing or has strictly changed
|
||||
if(!isset($this->record[$fieldName]) || $this->record[$fieldName] !== $val) {
|
||||
// TODO Add check for php-level defaults which are not set in the db
|
||||
// TODO Add check for hidden input-fields (readonly) which are not set in the db
|
||||
if(
|
||||
// Only existing fields
|
||||
$this->fieldExists($fieldName)
|
||||
// Catches "0"==NULL
|
||||
&& (isset($this->record[$fieldName]) && (intval($val) != intval($this->record[$fieldName])))
|
||||
// Main non type-based check
|
||||
&& (isset($this->record[$fieldName]) && $this->record[$fieldName] != $val)
|
||||
) {
|
||||
// Non-strict check fails, so value really changed, e.g. "abc" != "cde"
|
||||
$this->changed[$fieldName] = 2;
|
||||
} else {
|
||||
// Record change-level 1 if only the type changed, e.g. 0 !== NULL
|
||||
$this->changed[$fieldName] = 1;
|
||||
}
|
||||
|
||||
// value is always saved back when strict check succeeds
|
||||
// Situation 1: Passing a DBField
|
||||
if($val instanceof DBField) {
|
||||
$val->Name = $fieldName;
|
||||
$this->record[$fieldName] = $val;
|
||||
|
||||
// Situation 2: Passing a literal
|
||||
} else {
|
||||
$defaults = $this->stat('defaults');
|
||||
// if a field is not existing or has strictly changed
|
||||
if(!isset($this->record[$fieldName]) || $this->record[$fieldName] !== $val) {
|
||||
// TODO Add check for php-level defaults which are not set in the db
|
||||
// TODO Add check for hidden input-fields (readonly) which are not set in the db
|
||||
if(
|
||||
// Only existing fields
|
||||
$this->fieldExists($fieldName)
|
||||
// Catches "0"==NULL
|
||||
&& (isset($this->record[$fieldName]) && (intval($val) != intval($this->record[$fieldName])))
|
||||
// Main non type-based check
|
||||
&& (isset($this->record[$fieldName]) && $this->record[$fieldName] != $val)
|
||||
) {
|
||||
// Non-strict check fails, so value really changed, e.g. "abc" != "cde"
|
||||
$this->changed[$fieldName] = 2;
|
||||
} else {
|
||||
// Record change-level 1 if only the type changed, e.g. 0 !== NULL
|
||||
$this->changed[$fieldName] = 1;
|
||||
}
|
||||
|
||||
// value is always saved back when strict check succeeds
|
||||
$this->record[$fieldName] = $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1334,7 +1373,7 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
$castingHelper = $this->castingHelper($fieldName);
|
||||
if($castingHelper) {
|
||||
$fieldObj = eval($castingHelper);
|
||||
$fieldObj->setVal($val);
|
||||
$fieldObj->setValue($val);
|
||||
$fieldObj->saveInto($this);
|
||||
} else {
|
||||
$this->$fieldName = $val;
|
||||
@ -1349,7 +1388,7 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
* @return boolean True if the given field exists
|
||||
*/
|
||||
public function hasField($field) {
|
||||
return array_key_exists($field, $this->record);
|
||||
return array_key_exists($field, $this->record) || $this->fieldExists($field);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1486,14 +1525,17 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
* @return DBField The field as a DBField object
|
||||
*/
|
||||
public function dbObject($fieldName) {
|
||||
return $this->obj($fieldName);
|
||||
/*
|
||||
$helperPair = $this->castingHelperPair($fieldName);
|
||||
$constructor = $helperPair['castingHelper'];
|
||||
|
||||
if($obj = eval($constructor)) {
|
||||
$obj->setVal($this->$fieldName, $this->record);
|
||||
$obj->setValue($this->$fieldName, $this->record);
|
||||
}
|
||||
|
||||
return $obj;
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1560,18 +1602,34 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
// Build our intial query
|
||||
$query = new SQLQuery($select, "`$baseClass`", $filter, $sort);
|
||||
|
||||
// Add SQL for multi-value fields on the base table
|
||||
$databaseFields = $this->databaseFields();
|
||||
if($databaseFields) foreach($databaseFields as $k => $v) {
|
||||
if(!in_array($k, array('ClassName', 'LastEdited', 'Created'))) {
|
||||
if(ClassInfo::classImplements($v, 'CompositeDBField')) {
|
||||
$this->obj($k)->addToQuery($query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Join all the tables
|
||||
if($tableClasses) {
|
||||
foreach($tableClasses as $tableClass) {
|
||||
$query->from[$tableClass] = "LEFT JOIN `$tableClass` ON `$tableClass`.ID = `$baseClass`.ID";
|
||||
$query->select[] = "`$tableClass`.*";
|
||||
// ask each $db field on the specific table for alterations to the query
|
||||
$uninheritedDbFields = singleton($tableClass)->uninherited('db',true);
|
||||
if($uninheritedDbFields) foreach($uninheritedDbFields as $fieldName => $fieldType) {
|
||||
singleton($tableClass)->obj($fieldName)->addToQuery($query);
|
||||
|
||||
// Add SQL for multi-value fields
|
||||
$SNG = singleton($tableClass);
|
||||
foreach($SNG->databaseFields() as $k => $v) {
|
||||
if(!in_array($k, array('ClassName', 'LastEdited', 'Created'))) {
|
||||
if(ClassInfo::classImplements($v, 'CompositeDBField')) {
|
||||
$SNG->obj($k)->addToQuery($query);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$query->select[] = "`$baseClass`.ID";
|
||||
$query->select[] = "if(`$baseClass`.ClassName,`$baseClass`.ClassName,'$baseClass') AS RecordClassName";
|
||||
|
||||
|
@ -1,8 +1,14 @@
|
||||
<?php
|
||||
/**
|
||||
* Single field in the database.
|
||||
* Every field from the database is represented as a sub-class of DBField. In addition to supporting
|
||||
* the creation of the field in the database,
|
||||
* Every field from the database is represented as a sub-class of DBField.
|
||||
*
|
||||
* <h2>Multi-value DBField objects</h2>
|
||||
* Sometimes you will want to make DBField classes that don't have a 1-1 match to database fields. To do this, there are a
|
||||
* number of fields for you to overload.
|
||||
* - Overload {@link writeToManipulation} to add the appropriate references to the INSERT or UPDATE command
|
||||
* - Overload {@link addToQuery} to add the appropriate items to a SELECT query's field list
|
||||
* - Add appropriate accessor methods
|
||||
*
|
||||
* @package sapphire
|
||||
* @subpackage model
|
||||
@ -38,8 +44,30 @@ abstract class DBField extends ViewableData {
|
||||
return $dbField;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
function setVal($value, $record = null) {
|
||||
return $this->setValue($value);
|
||||
return $this->setValue($value, $record);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of this field.
|
||||
* The name should never be altered, but it if was never given a name in the first place you can set a name.
|
||||
* If you try an alter the name a warning will be thrown.
|
||||
*/
|
||||
function setName($name) {
|
||||
if($this->name) {
|
||||
user_error("DBField::setName() shouldn't be called once a DBField already has a name. It's partially immutable - it shouldn't be altered after it's given a value.", E_USER_WARNING);
|
||||
}
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this field
|
||||
*/
|
||||
function getName() {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -92,7 +120,9 @@ abstract class DBField extends ViewableData {
|
||||
*
|
||||
* @param Query $query
|
||||
*/
|
||||
function addToQuery(&$query) {}
|
||||
function addToQuery(&$query) {
|
||||
|
||||
}
|
||||
|
||||
function setTable($tableName) {
|
||||
$this->tableName = $tableName;
|
||||
|
@ -91,7 +91,6 @@ class SearchContext extends Object {
|
||||
public function getQuery($searchParams) {
|
||||
$q = new SQLQuery("*", $this->modelClass);
|
||||
$this->processFilters($q);
|
||||
|
||||
return $q;
|
||||
}
|
||||
|
||||
@ -162,7 +161,8 @@ class SearchContext extends Object {
|
||||
$fields = array_filter($fields, array($this,'clearEmptySearchFields'));
|
||||
$length = count($fields);
|
||||
foreach($fields as $key=>$val) {
|
||||
if ($val != '') {
|
||||
// Array values come from more complex fields - for now let's just disable searching on them
|
||||
if (!is_array($val) && $val != '') {
|
||||
$filter .= "`$key`='$val'";
|
||||
} else {
|
||||
$length--;
|
||||
|
Loading…
x
Reference in New Issue
Block a user