mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02: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@60276 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
124a6e3934
commit
bf9f349210
@ -62,6 +62,16 @@ abstract class DataFormatter extends Object {
|
|||||||
*/
|
*/
|
||||||
protected $outputContentType = null;
|
protected $outputContentType = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to set totalSize properties on the output
|
||||||
|
* of {@link convertDataObjectSet()}, shows the
|
||||||
|
* total number of records without the "limit" and "offset"
|
||||||
|
* GET parameters. Useful to implement pagination.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $totalSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a DataFormatter object suitable for handling the given file extension.
|
* Get a DataFormatter object suitable for handling the given file extension.
|
||||||
*
|
*
|
||||||
@ -182,6 +192,20 @@ abstract class DataFormatter extends Object {
|
|||||||
return $this->outputContentType;
|
return $this->outputContentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $size
|
||||||
|
*/
|
||||||
|
public function setTotalSize($size) {
|
||||||
|
$this->totalSize = (int)$size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getTotalSize() {
|
||||||
|
return $this->totalSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all fields on the object which should be shown
|
* Returns all fields on the object which should be shown
|
||||||
* in the output. Can be customised through {@link self::setCustomFields()}.
|
* in the output. Can be customised through {@link self::setCustomFields()}.
|
||||||
|
@ -90,7 +90,14 @@ class JSONDataFormatter extends DataFormatter {
|
|||||||
foreach($set as $item) {
|
foreach($set as $item) {
|
||||||
if($item->canView()) $jsonParts[] = $this->convertDataObject($item);
|
if($item->canView()) $jsonParts[] = $this->convertDataObject($item);
|
||||||
}
|
}
|
||||||
return "[\n" . implode(",\n", $jsonParts) . "\n]";
|
$json = "{\n";
|
||||||
|
$json .= 'totalSize: ';
|
||||||
|
$json .= (is_numeric($this->totalSize)) ? $this->totalSize : 'null';
|
||||||
|
$json .= ",\n";
|
||||||
|
$json .= "items: [\n" . implode(",\n", $jsonParts) . "\n]\n";
|
||||||
|
$json .= "}\n";
|
||||||
|
|
||||||
|
return $json;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function convertStringToArray($strData) {
|
public function convertStringToArray($strData) {
|
||||||
|
@ -140,7 +140,7 @@ class RestfulServer extends Controller {
|
|||||||
* @param String $relation
|
* @param String $relation
|
||||||
* @return String The serialized representation of the requested object(s) - usually XML or JSON.
|
* @return String The serialized representation of the requested object(s) - usually XML or JSON.
|
||||||
*/
|
*/
|
||||||
protected function getHandler($className, $id, $relation) {
|
protected function getHandler($className, $id, $relationName) {
|
||||||
$sort = array(
|
$sort = array(
|
||||||
'sort' => $this->request->getVar('sort'),
|
'sort' => $this->request->getVar('sort'),
|
||||||
'dir' => $this->request->getVar('dir')
|
'dir' => $this->request->getVar('dir')
|
||||||
@ -150,44 +150,45 @@ class RestfulServer extends Controller {
|
|||||||
'limit' => $this->request->getVar('limit')
|
'limit' => $this->request->getVar('limit')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$params = $this->request->getVars();
|
||||||
|
|
||||||
$responseFormatter = $this->getResponseDataFormatter();
|
$responseFormatter = $this->getResponseDataFormatter();
|
||||||
if(!$responseFormatter) return $this->unsupportedMediaType();
|
if(!$responseFormatter) return $this->unsupportedMediaType();
|
||||||
|
|
||||||
|
// $obj can be either a DataObject or a DataObjectSet,
|
||||||
|
// depending on the request
|
||||||
if($id) {
|
if($id) {
|
||||||
$obj = DataObject::get_by_id($className, $id);
|
// Format: /api/v1/<MyClass>/<ID>
|
||||||
|
$query = $this->getObjectQuery($className, $id, $params);
|
||||||
|
$obj = singleton($className)->buildDataObjectSet($query->execute());
|
||||||
if(!$obj) return $this->notFound();
|
if(!$obj) return $this->notFound();
|
||||||
|
$obj = $obj->First();
|
||||||
if(!$obj->canView()) return $this->permissionFailure();
|
if(!$obj->canView()) return $this->permissionFailure();
|
||||||
|
|
||||||
if($relation) {
|
// Format: /api/v1/<MyClass>/<ID>/<Relation>
|
||||||
if($relationClass = $obj->many_many($relation)) {
|
if($relationName) {
|
||||||
$query = $obj->getManyManyComponentsQuery($relation);
|
$query = $this->getObjectRelationQuery($obj, $params, $sort, $limit, $relationName);
|
||||||
} elseif($relationClass = $obj->has_many($relation)) {
|
if($query === false) return $this->notFound();
|
||||||
$query = $obj->getComponentsQuery($relation);
|
$obj = singleton($className)->buildDataObjectSet($query->execute());
|
||||||
} elseif($relationClass = $obj->has_one($relation)) {
|
|
||||||
$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 $this->notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
// get all results
|
|
||||||
$obj = $this->search($relationClass, $this->request->getVars(), $sort, $limit, $query);
|
|
||||||
if(!$obj) $obj = new DataObjectSet();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$obj = $this->search($className, $this->request->getVars(), $sort, $limit);
|
// Format: /api/v1/<MyClass>
|
||||||
|
$query = $this->getObjectsQuery($className, $params, $sort, $limit);
|
||||||
|
$obj = singleton($className)->buildDataObjectSet($query->execute());
|
||||||
|
|
||||||
// show empty serialized result when no records are present
|
// show empty serialized result when no records are present
|
||||||
if(!$obj) $obj = new DataObjectSet();
|
if(!$obj) $obj = new DataObjectSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->getResponse()->addHeader('Content-Type', $responseFormatter->getOutputContentType());
|
$this->getResponse()->addHeader('Content-Type', $responseFormatter->getOutputContentType());
|
||||||
|
|
||||||
if($obj instanceof DataObjectSet) return $responseFormatter->convertDataObjectSet($obj);
|
if($obj instanceof DataObjectSet) {
|
||||||
else return $responseFormatter->convertDataObject($obj);
|
$responseFormatter->setTotalSize($query->unlimitedRowCount());
|
||||||
|
return $responseFormatter->convertDataObjectSet($obj);
|
||||||
|
} else {
|
||||||
|
return $responseFormatter->convertDataObject($obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -202,7 +203,7 @@ class RestfulServer extends Controller {
|
|||||||
* @param array $params
|
* @param array $params
|
||||||
* @return DataObjectSet
|
* @return DataObjectSet
|
||||||
*/
|
*/
|
||||||
protected function search($className, $params = null, $sort = null, $limit = null, $existingQuery = null) {
|
protected function getSearchQuery($className, $params = null, $sort = null, $limit = null, $existingQuery = null) {
|
||||||
if(singleton($className)->hasMethod('getRestfulSearchContext')) {
|
if(singleton($className)->hasMethod('getRestfulSearchContext')) {
|
||||||
$searchContext = singleton($className)->{'getRestfulSearchContext'}();
|
$searchContext = singleton($className)->{'getRestfulSearchContext'}();
|
||||||
} else {
|
} else {
|
||||||
@ -210,7 +211,7 @@ class RestfulServer extends Controller {
|
|||||||
}
|
}
|
||||||
$query = $searchContext->getQuery($params, $sort, $limit, $existingQuery);
|
$query = $searchContext->getQuery($params, $sort, $limit, $existingQuery);
|
||||||
|
|
||||||
return singleton($className)->buildDataObjectSet($query->execute());
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -355,6 +356,61 @@ class RestfulServer extends Controller {
|
|||||||
return $obj;
|
return $obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a single DataObject by ID,
|
||||||
|
* through a request like /api/v1/<MyClass>/<MyID>
|
||||||
|
*
|
||||||
|
* @param string $className
|
||||||
|
* @param int $id
|
||||||
|
* @param array $params
|
||||||
|
* @return SQLQuery
|
||||||
|
*/
|
||||||
|
protected function getObjectQuery($className, $id, $params) {
|
||||||
|
$baseClass = ClassInfo::baseDataClass($className);
|
||||||
|
return singleton($className)->buildSQL(
|
||||||
|
"`$baseClass`.ID = {$id}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param DataObject $obj
|
||||||
|
* @param array $params
|
||||||
|
* @param int|array $sort
|
||||||
|
* @param int|array $limit
|
||||||
|
* @return SQLQuery
|
||||||
|
*/
|
||||||
|
protected function getObjectsQuery($className, $params, $sort, $limit) {
|
||||||
|
return $this->getSearchQuery($className, $params, $sort, $limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param DataObject $obj
|
||||||
|
* @param array $params
|
||||||
|
* @param int|array $sort
|
||||||
|
* @param int|array $limit
|
||||||
|
* @param string $relationName
|
||||||
|
* @return SQLQuery|boolean
|
||||||
|
*/
|
||||||
|
protected function getObjectRelationQuery($obj, $params, $sort, $limit, $relationName) {
|
||||||
|
if($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);
|
||||||
|
}
|
||||||
|
|
||||||
protected function permissionFailure() {
|
protected function permissionFailure() {
|
||||||
// return a 401
|
// return a 401
|
||||||
$this->getResponse()->setStatusCode(403);
|
$this->getResponse()->setStatusCode(403);
|
||||||
|
@ -96,7 +96,8 @@ class XMLDataFormatter extends DataFormatter {
|
|||||||
Controller::curr()->getResponse()->addHeader("Content-type", "text/xml");
|
Controller::curr()->getResponse()->addHeader("Content-type", "text/xml");
|
||||||
$className = $set->class;
|
$className = $set->class;
|
||||||
|
|
||||||
$xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<$className>\n";
|
$xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||||
|
$xml .= (is_numeric($this->totalSize)) ? "<$className totalSize=\"{$this->totalSize}\">\n" : "<$className>\n";
|
||||||
foreach($set as $item) {
|
foreach($set as $item) {
|
||||||
if($item->canView()) $xml .= $this->convertDataObjectWithoutHeader($item);
|
if($item->canView()) $xml .= $this->convertDataObjectWithoutHeader($item);
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ require_once(MANIFEST_FILE);
|
|||||||
|
|
||||||
if(isset($_GET['debugmanifest'])) Debug::show(file_get_contents(MANIFEST_FILE));
|
if(isset($_GET['debugmanifest'])) Debug::show(file_get_contents(MANIFEST_FILE));
|
||||||
|
|
||||||
if(!isset(Director::$environment_type) && $envType) Director::set_environment_type($envType);
|
//if(!isset(Director::$environment_type) && $envType) Director::set_environment_type($envType);
|
||||||
|
|
||||||
// Load error handlers
|
// Load error handlers
|
||||||
Debug::loadErrorHandlers();
|
Debug::loadErrorHandlers();
|
||||||
|
@ -11,7 +11,12 @@
|
|||||||
* This is loaded into the TEMP_FOLDER define on start up
|
* This is loaded into the TEMP_FOLDER define on start up
|
||||||
*/
|
*/
|
||||||
function getTempFolder() {
|
function getTempFolder() {
|
||||||
$cachefolder = "silverstripe-cache" . str_replace(array("/",":", "\\"),"-", substr($_SERVER['SCRIPT_FILENAME'], 0, strlen($_SERVER['SCRIPT_FILENAME']) - strlen('/sapphire/main.php')));
|
if(preg_match('/^(.*)\/sapphire\/[^\/]+$/', $_SERVER['SCRIPT_FILENAME'], $matches)) {
|
||||||
|
$cachefolder = "silverstripe-cache" . str_replace(array(' ',"/",":", "\\"),"-", $matches[1]);
|
||||||
|
} else {
|
||||||
|
$cachefolder = "silverstripe-cache";
|
||||||
|
}
|
||||||
|
|
||||||
$ssTmp = dirname(dirname($_SERVER['SCRIPT_FILENAME'])) . "/silverstripe-cache";
|
$ssTmp = dirname(dirname($_SERVER['SCRIPT_FILENAME'])) . "/silverstripe-cache";
|
||||||
if(@file_exists($ssTmp)) {
|
if(@file_exists($ssTmp)) {
|
||||||
return $ssTmp;
|
return $ssTmp;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
/**
|
/**
|
||||||
* Define a constant for the name of the manifest file
|
* Define a constant for the name of the manifest file
|
||||||
*/
|
*/
|
||||||
define("MANIFEST_FILE", TEMP_FOLDER . "/manifest" . str_replace(array(' ','\\','/',':'),"_", $_SERVER['SCRIPT_FILENAME']));
|
define("MANIFEST_FILE", TEMP_FOLDER . "/manifest-" . str_replace('.php','',basename($_SERVER['SCRIPT_FILENAME'])));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ManifestBuilder class generates the manifest file and keeps it fresh.
|
* The ManifestBuilder class generates the manifest file and keeps it fresh.
|
||||||
|
@ -80,6 +80,13 @@ class HTTPResponse extends Object {
|
|||||||
return $this->statusCode;
|
return $this->statusCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this HTTP response is in error
|
||||||
|
*/
|
||||||
|
function isError() {
|
||||||
|
return $this->statusCode && ($this->statusCode < 200 || $this->statusCode > 399);
|
||||||
|
}
|
||||||
|
|
||||||
function setBody($body) {
|
function setBody($body) {
|
||||||
$this->body = $body;
|
$this->body = $body;
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ class RequestHandlingData extends ViewableData {
|
|||||||
foreach($this->stat('url_handlers') as $rule => $action) {
|
foreach($this->stat('url_handlers') as $rule => $action) {
|
||||||
if(isset($_REQUEST['debug_request'])) Debug::message("Testing '$rule' with '" . $request->remaining() . "' on $this->class");
|
if(isset($_REQUEST['debug_request'])) Debug::message("Testing '$rule' with '" . $request->remaining() . "' on $this->class");
|
||||||
if($params = $request->match($rule, true)) {
|
if($params = $request->match($rule, true)) {
|
||||||
if(isset($_REQUEST['debug_request'])) Debug::message("Rule '$rule' matched on $this->class");
|
if(isset($_REQUEST['debug_request'])) Debug::message("Rule '$rule' matched to action '$action' on $this->class");
|
||||||
|
|
||||||
// Actions can reference URL parameters, eg, '$Action/$ID/$OtherID' => '$Action',
|
// Actions can reference URL parameters, eg, '$Action/$ID/$OtherID' => '$Action',
|
||||||
if($action[0] == '$') $action = $params[substr($action,1)];
|
if($action[0] == '$') $action = $params[substr($action,1)];
|
||||||
@ -86,6 +86,11 @@ class RequestHandlingData extends ViewableData {
|
|||||||
return $this->httpError(403, "Action '$action' isn't allowed on class $this->class");
|
return $this->httpError(403, "Action '$action' isn't allowed on class $this->class");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($result instanceof HTTPResponse && $result->isError()) {
|
||||||
|
if(isset($_REQUEST['debug_request'])) Debug::message("Rule resulted in HTTP error; breaking");
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
// If we return a RequestHandlingData, call handleRequest() on that, even if there is no more URL to parse.
|
// If we return a RequestHandlingData, call handleRequest() on that, even if there is no more URL to parse.
|
||||||
// It might have its own handler. However, we only do this if we haven't just parsed an empty rule ourselves,
|
// It might have its own handler. However, we only do this if we haven't just parsed an empty rule ourselves,
|
||||||
// to prevent infinite loops
|
// to prevent infinite loops
|
||||||
|
@ -2630,7 +2630,7 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
|||||||
* User defined permissions for search result table by ModelAdmin to act on.
|
* User defined permissions for search result table by ModelAdmin to act on.
|
||||||
* Such as print search
|
* Such as print search
|
||||||
*/
|
*/
|
||||||
public static $results_permissions = null;
|
public static $results_permissions = array();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,8 +24,7 @@ class PrimaryKey extends Int {
|
|||||||
public function scaffoldFormField($title = null) {
|
public function scaffoldFormField($title = null) {
|
||||||
$objs = DataObject::get($this->object->class);
|
$objs = DataObject::get($this->object->class);
|
||||||
|
|
||||||
$first = $objs->First();
|
$titleField = (singleton($this->object->class)->hasField('Title')) ? "Title" : "Name";
|
||||||
$titleField = isset($first->Title) ? "Title" : "Name";
|
|
||||||
|
|
||||||
$map = ($objs) ? $objs->toDropdownMap("ID", $titleField) : false;
|
$map = ($objs) ? $objs->toDropdownMap("ID", $titleField) : false;
|
||||||
|
|
||||||
|
@ -23,6 +23,10 @@ table.CMSList td {
|
|||||||
border-style:none;
|
border-style:none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.TableListField table.data td.nolabel{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
table.TableField th,
|
table.TableField th,
|
||||||
table.TableListField th,
|
table.TableListField th,
|
||||||
.TableListField table.data th,
|
.TableListField table.data th,
|
||||||
@ -114,7 +118,7 @@ table.CMSList tbody td.checkbox {
|
|||||||
table.TableField tbody tr.over td,
|
table.TableField tbody tr.over td,
|
||||||
.TableListField table.data tbody tr.over td,
|
.TableListField table.data tbody tr.over td,
|
||||||
table.CMSList tbody td.over td{
|
table.CMSList tbody td.over td{
|
||||||
background-color: #FFC;
|
background-color: #FF6600;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.TableField tbody tr.current td,
|
table.TableField tbody tr.current td,
|
||||||
|
@ -12,11 +12,17 @@ class TaskRunner extends Controller {
|
|||||||
|
|
||||||
function index() {
|
function index() {
|
||||||
$tasks = ClassInfo::subclassesFor('BuildTask');
|
$tasks = ClassInfo::subclassesFor('BuildTask');
|
||||||
echo "<ul>";
|
if(Director::is_cli()) {
|
||||||
foreach($tasks as $task) {
|
echo "Tasks available:\n\n";
|
||||||
echo "<li><a href=\"$task\">$task</a></li>";
|
foreach($tasks as $task) echo " * $task: sake dev/tasks/$task\n";
|
||||||
|
} else {
|
||||||
|
echo "<h1>Tasks available</h1>\n";
|
||||||
|
echo "<ul>";
|
||||||
|
foreach($tasks as $task) {
|
||||||
|
echo "<li><a href=\"$task\">$task</a></li>\n";
|
||||||
|
}
|
||||||
|
echo "</ul>";
|
||||||
}
|
}
|
||||||
echo "</ul>";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function runTask($request) {
|
function runTask($request) {
|
||||||
@ -29,6 +35,8 @@ class TaskRunner extends Controller {
|
|||||||
if (!$task->isDisabled()) $task->run($request);
|
if (!$task->isDisabled()) $task->run($request);
|
||||||
} else {
|
} else {
|
||||||
echo "Build task '$TaskName' not found.";
|
echo "Build task '$TaskName' not found.";
|
||||||
|
if(class_exists($TaskName)) echo " It isn't a subclass of BuildTask.";
|
||||||
|
echo "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ class CheckboxSetField extends OptionsetField {
|
|||||||
|
|
||||||
$this->disabled ? $disabled = " disabled=\"disabled\"" : $disabled = "";
|
$this->disabled ? $disabled = " disabled=\"disabled\"" : $disabled = "";
|
||||||
|
|
||||||
$options .= "<li class=\"$extraClass\"><input id=\"$itemID\" name=\"$this->name[]\" type=\"checkbox\" value=\"$key\"$checked $disabled class=\"checkbox\" /> <label for=\"$itemID\">$value</label></li>\n";
|
$options .= "<li class=\"$extraClass\"><input id=\"$itemID\" name=\"$this->name[$key]\" type=\"checkbox\" value=\"$key\"$checked $disabled class=\"checkbox\" /> <label for=\"$itemID\">$value</label></li>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -185,44 +185,6 @@ JS;
|
|||||||
return $this->renderWith($this->template);
|
return $this->renderWith($this->template);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns non-paginated items.
|
|
||||||
* Please use Items() for pagination.
|
|
||||||
* This function is called whenever a complete result-set is needed,
|
|
||||||
* so even if a single record is displayed in a popup, we need the results
|
|
||||||
* to make pagination work.
|
|
||||||
*
|
|
||||||
* @todo Merge with more efficient querying of TableListField
|
|
||||||
*/
|
|
||||||
function sourceItems() {
|
|
||||||
if($this->sourceItems) {
|
|
||||||
return $this->sourceItems;
|
|
||||||
}
|
|
||||||
|
|
||||||
$limitClause = "";
|
|
||||||
if($this->pageSize) {
|
|
||||||
$limitClause = "{$this->pageSize}";
|
|
||||||
} else {
|
|
||||||
$limitClause = "0";
|
|
||||||
}
|
|
||||||
if(isset($_REQUEST['ctf'][$this->Name()]['start']) && is_numeric($_REQUEST['ctf'][$this->Name()]['start'])) {
|
|
||||||
$SQL_start = intval($_REQUEST['ctf'][$this->Name()]['start']);
|
|
||||||
$limitClause .= " OFFSET {$SQL_start}";
|
|
||||||
}
|
|
||||||
|
|
||||||
$sort = $this->sourceSort;
|
|
||||||
if(isset($_REQUEST['ctf'][$this->Name()]['sort'])) {
|
|
||||||
$sort = Convert::raw2sql($_REQUEST['ctf'][$this->Name()]['sort']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->sourceItems = DataObject::get($this->sourceClass, $this->sourceFilter, $sort, $this->sourceJoin, $limitClause);
|
|
||||||
$this->unpagedSourceItems = DataObject::get($this->sourceClass, $this->sourceFilter, $sort, $this->sourceJoin);
|
|
||||||
|
|
||||||
$this->totalCount = ($this->unpagedSourceItems) ? $this->unpagedSourceItems->TotalItems() : null;
|
|
||||||
|
|
||||||
return $this->sourceItems;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sourceClass() {
|
function sourceClass() {
|
||||||
return $this->sourceClass;
|
return $this->sourceClass;
|
||||||
}
|
}
|
||||||
|
@ -1045,6 +1045,8 @@ class TableListField_Item extends ViewableData {
|
|||||||
function Fields() {
|
function Fields() {
|
||||||
$list = $this->parent->FieldList();
|
$list = $this->parent->FieldList();
|
||||||
foreach($list as $fieldName => $fieldTitle) {
|
foreach($list as $fieldName => $fieldTitle) {
|
||||||
|
$value = "";
|
||||||
|
|
||||||
// This supports simple FieldName syntax
|
// This supports simple FieldName syntax
|
||||||
if(strpos($fieldName,'.') === false) {
|
if(strpos($fieldName,'.') === false) {
|
||||||
$value = ($this->item->val($fieldName)) ? $this->item->val($fieldName) : $this->item->$fieldName;
|
$value = ($this->item->val($fieldName)) ? $this->item->val($fieldName) : $this->item->$fieldName;
|
||||||
|
@ -272,5 +272,5 @@ TableListRecord.prototype = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TableListRecord.applyTo('div.TableListField tr');
|
TableListRecord.applyTo('div.TableListField tr');
|
||||||
TableListField.applyTo('div.TableListField');
|
TableListField.applyTo('div.TableListField');
|
||||||
|
@ -114,18 +114,14 @@ class SearchContext extends Object {
|
|||||||
$SQL_sort = (!empty($sort)) ? Convert::raw2sql($sort) : singleton($this->modelClass)->stat('default_sort');
|
$SQL_sort = (!empty($sort)) ? Convert::raw2sql($sort) : singleton($this->modelClass)->stat('default_sort');
|
||||||
$query->orderby($SQL_sort);
|
$query->orderby($SQL_sort);
|
||||||
foreach($searchParams as $key => $value) {
|
foreach($searchParams as $key => $value) {
|
||||||
/*We add $value!='' here to not include a filter like this: $fieldname like '%%', which abviously filter out some
|
$key = str_replace('__', '.', $key);
|
||||||
records with the $fieldname set to null. and this is not the search intention.
|
if($filter = $this->getFilter($key)) {
|
||||||
*/
|
$filter->setModel($this->modelClass);
|
||||||
if ($value != '0'&&$value!='') {
|
$filter->setValue($value);
|
||||||
$key = str_replace('__', '.', $key);
|
if(! $filter->isEmpty()) {
|
||||||
$filter = $this->getFilter($key);
|
|
||||||
if ($filter) {
|
|
||||||
$filter->setModel($this->modelClass);
|
|
||||||
$filter->setValue($value);
|
|
||||||
$filter->apply($query);
|
$filter->apply($query);
|
||||||
}
|
}
|
||||||
//}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
|
@ -28,5 +28,8 @@ class EndsWithFilter extends SearchFilter {
|
|||||||
$query->where($this->getDbName(), "RLIKE", "{$this->getValue()}$");
|
$query->where($this->getDbName(), "RLIKE", "{$this->getValue()}$");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isEmpty() {
|
||||||
|
return $this->getValue() == null || $this->getValue() == '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
@ -21,11 +21,12 @@ class ExactMatchFilter extends SearchFilter {
|
|||||||
* @return unknown
|
* @return unknown
|
||||||
*/
|
*/
|
||||||
public function apply(SQLQuery $query) {
|
public function apply(SQLQuery $query) {
|
||||||
if($this->getValue()) {
|
$query = $this->applyRelation($query);
|
||||||
$query = $this->applyRelation($query);
|
return $query->where("{$this->getDbName()} = '{$this->getValue()}'");
|
||||||
return $query->where("{$this->getDbName()} = '{$this->getValue()}'");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isEmpty() {
|
||||||
|
return $this->getValue() == null || $this->getValue() == '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
@ -13,22 +13,23 @@
|
|||||||
class ExactMatchMultiFilter extends SearchFilter {
|
class ExactMatchMultiFilter extends SearchFilter {
|
||||||
|
|
||||||
public function apply(SQLQuery $query) {
|
public function apply(SQLQuery $query) {
|
||||||
if($this->getValue()) {
|
$query = $this->applyRelation($query);
|
||||||
$query = $this->applyRelation($query);
|
$values = explode(',',$this->getValue());
|
||||||
$values = explode(',',$this->getValue());
|
if(! $values) return false;
|
||||||
if(!$values) return false;
|
for($i = 0; $i < count($values); $i++) {
|
||||||
|
if(! is_numeric($values[$i])) {
|
||||||
for($i=0; $i<count($values); $i++) {
|
// @todo Fix string replacement to only replace leading and tailing quotes
|
||||||
if(!is_numeric($values[$i])) {
|
$values[$i] = str_replace("'", '', $values[$i]);
|
||||||
// @todo Fix string replacement to only replace leading and tailing quotes
|
$values[$i] = Convert::raw2sql($values[$i]);
|
||||||
$values[$i] = str_replace("'", '', $values[$i]);
|
|
||||||
$values[$i] = Convert::raw2sql($values[$i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$SQL_valueStr = "'" . implode("','", $values) . "'";
|
|
||||||
return $query->where("{$this->getDbName()} IN ({$SQL_valueStr})");
|
|
||||||
}
|
}
|
||||||
|
$SQL_valueStr = "'" . implode("','", $values) . "'";
|
||||||
|
|
||||||
|
return $query->where("{$this->getDbName()} IN ({$SQL_valueStr})");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isEmpty() {
|
||||||
|
return $this->getValue() == null || $this->getValue() == '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
@ -32,5 +32,8 @@ class FulltextFilter extends SearchFilter {
|
|||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isEmpty() {
|
||||||
|
return $this->getValue() == null || $this->getValue() == '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
24
search/filters/GreaterThanFilter.php
Normal file
24
search/filters/GreaterThanFilter.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Selects numerical/date content greater than the input
|
||||||
|
*
|
||||||
|
* @todo documentation
|
||||||
|
*
|
||||||
|
* @package sapphire
|
||||||
|
* @subpackage search
|
||||||
|
*/
|
||||||
|
class GreaterThanFilter extends SearchFilter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return $query
|
||||||
|
*/
|
||||||
|
public function apply(SQLQuery $query) {
|
||||||
|
$query = $this->applyRelation($query);
|
||||||
|
return $query->where("{$this->getDbName()} > '{$this->getValue()}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isEmpty() {
|
||||||
|
return $this->getValue() == null || $this->getValue() == '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
24
search/filters/LessThanFilter.php
Normal file
24
search/filters/LessThanFilter.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Selects numerical/date content smaller than the input
|
||||||
|
*
|
||||||
|
* @todo documentation
|
||||||
|
*
|
||||||
|
* @package sapphire
|
||||||
|
* @subpackage search
|
||||||
|
*/
|
||||||
|
class LessThanFilter extends SearchFilter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return $query
|
||||||
|
*/
|
||||||
|
public function apply(SQLQuery $query) {
|
||||||
|
$query = $this->applyRelation($query);
|
||||||
|
return $query->where("{$this->getDbName()} < '{$this->getValue()}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isEmpty() {
|
||||||
|
return $this->getValue() == null || $this->getValue() == '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
@ -17,5 +17,8 @@ class PartialMatchFilter extends SearchFilter {
|
|||||||
return $query->where("{$this->getDbName()} LIKE '%{$this->getValue()}%'");
|
return $query->where("{$this->getDbName()} LIKE '%{$this->getValue()}%'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isEmpty() {
|
||||||
|
return $this->getValue() == null || $this->getValue() == '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
@ -139,5 +139,19 @@ abstract class SearchFilter extends Object {
|
|||||||
*/
|
*/
|
||||||
abstract public function apply(SQLQuery $query);
|
abstract public function apply(SQLQuery $query);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if a field has a value,
|
||||||
|
* and that the filter should be applied.
|
||||||
|
* Relies on the field being populated with
|
||||||
|
* {@link setValue()}
|
||||||
|
*
|
||||||
|
* @usedby SearchContext
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function isEmpty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
23
search/filters/SmallerThanFilter.php
Normal file
23
search/filters/SmallerThanFilter.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Selects numerical/date content smaller than the input
|
||||||
|
*
|
||||||
|
* @todo documentation
|
||||||
|
*
|
||||||
|
* @package sapphire
|
||||||
|
* @subpackage search
|
||||||
|
*/
|
||||||
|
class SmallerThanFilter extends SearchFilter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return $query
|
||||||
|
*/
|
||||||
|
public function apply(SQLQuery $query) {
|
||||||
|
if($this->getValue()) {
|
||||||
|
$query = $this->applyRelation($query);
|
||||||
|
return $query->where("{$this->getDbName()} < '{$this->getValue()}'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
@ -28,5 +28,8 @@ class StartsWithFilter extends SearchFilter {
|
|||||||
$query->where("LOCATE('{$this->getValue()}', {$this->getDbName()}) = 1");
|
$query->where("LOCATE('{$this->getValue()}', {$this->getDbName()}) = 1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isEmpty() {
|
||||||
|
return $this->getValue() == null || $this->getValue() == '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
@ -13,17 +13,19 @@
|
|||||||
class StartsWithMultiFilter extends SearchFilter {
|
class StartsWithMultiFilter extends SearchFilter {
|
||||||
|
|
||||||
public function apply(SQLQuery $query) {
|
public function apply(SQLQuery $query) {
|
||||||
if($this->getValue()) {
|
$query = $this->applyRelation($query);
|
||||||
$query = $this->applyRelation($query);
|
$values = explode(',', $this->getValue());
|
||||||
$values = explode(',',$this->getValue());
|
|
||||||
|
|
||||||
foreach($values as $value) {
|
foreach($values as $value) {
|
||||||
$SQL_value = Convert::raw2sql(str_replace("'", '', $value));
|
$SQL_value = Convert::raw2sql(str_replace("'", '', $value));
|
||||||
$matches[] = "{$this->getDbName()} LIKE '$SQL_value%'";
|
$matches[] = "{$this->getDbName()} LIKE '$SQL_value%'";
|
||||||
}
|
|
||||||
return $query->where(implode(" OR ", $matches));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $query->where(implode(" OR ", $matches));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isEmpty() {
|
||||||
|
return $this->getValue() == null || $this->getValue() == '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
@ -16,6 +16,9 @@ class SubstringFilter extends SearchFilter {
|
|||||||
return $query->where("LOCATE('{$this->getValue()}', {$this->getDbName()}) != 0");
|
return $query->where("LOCATE('{$this->getValue()}', {$this->getDbName()}) != 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isEmpty() {
|
||||||
|
return $this->getValue() == null || $this->getValue() == '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
Loading…
Reference in New Issue
Block a user