diff --git a/api/RestfulServer.php b/api/RestfulServer.php index 63ad99b16..1f2e39410 100644 --- a/api/RestfulServer.php +++ b/api/RestfulServer.php @@ -98,7 +98,7 @@ class RestfulServer extends Controller { $member = $this->authenticate(); // handle different HTTP verbs - if($this->request->isGET()) return $this->getHandler($className, $id, $relation); + if($this->request->isGET() || $this->request->isHEAD()) return $this->getHandler($className, $id, $relation); if($this->request->isPOST()) return $this->postHandler($className, $id, $relation); if($this->request->isPUT()) return $this->putHandler($className, $id, $relation); if($this->request->isDELETE()) return $this->deleteHandler($className, $id, $relation); @@ -186,6 +186,9 @@ class RestfulServer extends Controller { if($obj instanceof DataObjectSet) { $responseFormatter->setTotalSize($query->unlimitedRowCount()); return $responseFormatter->convertDataObjectSet($obj); + } else if(!$obj) { + $responseFormatter->setTotalSize(0); + return $responseFormatter->convertDataObjectSet(new DataObjectSet()); } else { return $responseFormatter->convertDataObject($obj); } @@ -394,22 +397,22 @@ class RestfulServer extends Controller { * @return SQLQuery|boolean */ protected function getObjectRelationQuery($obj, $params, $sort, $limit, $relationName) { - if($relationClass = $obj->many_many($relationName)) { + if($obj->hasMethod("{$relationName}Query")) { + // @todo HACK Switch to ComponentSet->getQuery() once we implement it (and lazy loading) + $query = $obj->{"{$relationName}Query"}(null, $sort, null, $limit); + $relationClass = $obj->{"{$relationName}Class"}(); + } elseif($relationClass = $obj->many_many($relationName)) { $query = $obj->getManyManyComponentsQuery($relationName); } elseif($relationClass = $obj->has_many($relationName)) { $query = $obj->getComponentsQuery($relationName); } elseif($relationClass = $obj->has_one($relationName)) { $query = null; - } elseif($obj->hasMethod("{$relation}Query")) { - // @todo HACK Switch to ComponentSet->getQuery() once we implement it (and lazy loading) - $query = $obj->{"{$relation}Query"}(null, $sort, null, $limit); - $relationClass = $obj->{"{$relation}Class"}(); } else { return false; } // get all results - return $this->getSearchQuery($relationClass, $params, $sort, $limit); + return $this->getSearchQuery($relationClass, $params, $sort, $limit, $query); } protected function permissionFailure() { diff --git a/api/XMLDataFormatter.php b/api/XMLDataFormatter.php index 6dfcdc4df..ae74f0010 100644 --- a/api/XMLDataFormatter.php +++ b/api/XMLDataFormatter.php @@ -42,6 +42,8 @@ class XMLDataFormatter extends DataFormatter { $json = "<$className href=\"$objHref.xml\">\n"; foreach($this->getFieldsForObj($obj) as $fieldName => $fieldType) { $fieldValue = $obj->$fieldName; + if(!mb_check_encoding($fieldValue,'utf-8')) $fieldValue = "(data is badly encoded)"; + if(is_object($fieldValue) && is_subclass_of($fieldValue, 'Object') && $fieldValue->hasMethod('toXML')) { $json .= $fieldValue->toXML(); } else { diff --git a/core/control/HTTPRequest.php b/core/control/HTTPRequest.php index a0b15cbf9..3cf32378e 100644 --- a/core/control/HTTPRequest.php +++ b/core/control/HTTPRequest.php @@ -67,6 +67,10 @@ class HTTPRequest extends Object implements ArrayAccess { function isDELETE() { return $this->httpMethod == 'DELETE'; } + + function isHEAD() { + return $this->httpMethod == 'HEAD'; + } function setBody($body) { $this->body = $body; diff --git a/core/model/DataObject.php b/core/model/DataObject.php index f86a4ca71..4aacb4df3 100644 --- a/core/model/DataObject.php +++ b/core/model/DataObject.php @@ -1025,7 +1025,6 @@ class DataObject extends ViewableData implements DataObjectInterface { if($componentClass) { $query = $this->getManyManyComponentsQuery($componentName, $filter, $sort, $join, $limit); - $records = $query->execute(); $result = $this->buildDataObjectSet($records, "ComponentSet", $query, $componentBaseClass); if($result) $result->parseQueryLimit($query); // for pagination support @@ -1078,6 +1077,22 @@ class DataObject extends ViewableData implements DataObjectInterface { ); array_unshift($query->select, "`$table`.*"); + // FIXME: We were having database crashing troubles with GIS content being accessed from with the link + // tracking join. In order to fix it, we're altering the query just for this many-many relation. + // The more long-term fix to this is to let developers specify which data columns they are actually interested + // in, and thereby optimise the query in a more loosely coupled fashion. + if($table == "SiteTree_LinkTracking") { + $filteredSelect = array(); + foreach($query->select as $item) { + if(strpos($item,'SiteTree') !== false) $filteredSelect[] = $item; + } + $query->select = $filteredSelect; + $query->from = array( + "SiteTree" => $query->from["SiteTree"], + $query->from[0], + ); + } + if($filter) $query->where[] = $filter; if($join) $query->from[] = $join; @@ -1548,7 +1563,7 @@ class DataObject extends ViewableData implements DataObjectInterface { } } - foreach($fields as $name => $level) { + if ($fields) foreach($fields as $name => $level) { if(!isset($this->original[$name])) continue; $changedFields[$name] = array( 'before' => $this->original[$name], diff --git a/dev/CsvBulkLoader.php b/dev/CsvBulkLoader.php index 5f16d77a2..36f3f5d10 100644 --- a/dev/CsvBulkLoader.php +++ b/dev/CsvBulkLoader.php @@ -188,7 +188,8 @@ class CsvBulkLoader extends BulkLoader { if(is_string($duplicateCheck)) { $SQL_fieldName = Convert::raw2sql($duplicateCheck); if(!isset($record[$fieldName])) { - user_error("CsvBulkLoader:processRecord: Couldn't find duplicate identifier '{$fieldName}' in columns", E_USER_ERROR); + return false; + //user_error("CsvBulkLoader:processRecord: Couldn't find duplicate identifier '{$fieldName}' in columns", E_USER_ERROR); } $SQL_fieldValue = $record[$fieldName]; $existingRecord = DataObject::get_one($this->objectClass, "`$SQL_fieldName` = '{$SQL_fieldValue}'"); diff --git a/templates/EditableFormFieldOption.ss b/templates/EditableFormFieldOption.ss index 1a6abd905..4ec89718c 100755 --- a/templates/EditableFormFieldOption.ss +++ b/templates/EditableFormFieldOption.ss @@ -2,13 +2,13 @@ <% if isReadonly %> <% _t('LOCKED', 'These fields cannot be modified') %> $DefaultSelect - + <% _t('LOCKED', 'These fields cannot be modified') %> <% else %> <% _t('DRAG', 'Drag to rearrange order of fields') %> $DefaultSelect - + <% _t('DELETE', 'Remove this option') %> <% end_if %>