ENHANCEMENT: Improved performance of admin/assets area.

BUGFIX: Fixed bug in 'sake interactive' error handling.
BUGFIX: Fixed bugs with MSSQL and Windows support.
API CHANGE: Added FormAction::setButtonContent()

git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@80782 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Sam Minnee 2009-07-01 22:27:18 +00:00
parent aaef41a122
commit f41e2b474c
10 changed files with 90 additions and 74 deletions

View File

@ -33,7 +33,7 @@ class Convert extends Object {
foreach($val as $k => $v) $val[$k] = self::raw2att($v);
return $val;
} else {
return str_replace(array('&','"',"'",'<','>'), array('&amp;','&quot;','&apos;','&lt;','&gt;'), $val);
return str_replace(array('&','"',"'",'<','>'), array('&amp;','&quot;','&#39;','&lt;','&gt;'), $val);
}
}
@ -71,7 +71,7 @@ class Convert extends Object {
foreach($val as $k => $v) $val[$k] = self::raw2xml($v);
return $val;
} else {
return str_replace(array('&','<','>',"\n",'"',"'"), array('&amp;','&lt;','&gt;','<br />','&quot;','&apos;'), $val);
return str_replace(array('&','<','>',"\n",'"',"'"), array('&amp;','&lt;','&gt;','<br />','&quot;','&#39;'), $val);
}
}
@ -133,7 +133,7 @@ class Convert extends Object {
// More complex text needs to use html2raw instead
if(strpos($val,'<') !== false) return self::html2raw($val);
$converted = str_replace(array('&amp;','&lt;','&gt;','&quot;','&apos;'), array('&','<','>','"',"'"), $val);
$converted = str_replace(array('&amp;','&lt;','&gt;','&quot;','&apos;', '&#39;'), array('&','<','>','"',"'", "'"), $val);
$converted = ereg_replace('&#[0-9]+;', '', $converted);
return $converted;
}
@ -335,4 +335,4 @@ class Convert extends Object {
}
?>
?>

View File

@ -194,7 +194,9 @@ class Session {
if(!session_id() && !headers_sent()) {
session_set_cookie_params(self::$timeout, Director::baseURL());
session_start();
// @ is to supress win32 warnings/notices when session wasn't cleaned up properly
// There's nothing we can do about this, because it's an operating system function!
@session_start();
}
}

View File

@ -262,8 +262,14 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
$this->class = get_class($this);
foreach($record as $k => $v) {
if($v) {
if($k == 'Created' || $k == 'LastEdited') {
$fieldtype = 'SSDatetime';
} else {
$fieldtype = $this->db($k);
}
// MSSQLDatabase::date() uses datetime for the data type for "Date" and "SSDatetime"
switch($this->db($k)) {
switch($fieldtype) {
case "Date":
$v = preg_replace('/:[0-9][0-9][0-9]([ap]m)$/i', ' \\1', $v);
$record[$k] = date('Y-m-d', strtotime($v));

View File

@ -429,66 +429,18 @@ class Hierarchy extends DataObjectDecorator {
$stageChildren = $this->owner->stageChildren(true);
$this->_cache_allChildrenIncludingDeleted = $stageChildren;
$this->owner->extend("augmentAllChildrenIncludingDeleted", $stageChildren, $context);
// Add live site content, if required.
// Add live site content that doesn't exist on the stage site, if required.
if($this->owner->hasExtension('Versioned')) {
// Get all the requisite data, and index it
$liveChildren = $this->owner->liveChildren(true);
if(isset($stageChildren)) {
foreach($stageChildren as $child) {
$idxStageChildren[$child->ID] = $child;
}
}
if(isset($liveChildren)) {
// Next, go through the live children. Only some of these will be listed
$liveChildren = $this->owner->liveChildren(true, true);
if($liveChildren) {
foreach($liveChildren as $child) {
$idxLiveChildren[$child->ID] = $child;
}
}
DataObject::disable_subclass_access();
if($idxStageChildren) {
$foundInLive = Versioned::get_by_stage( $baseClass, 'Live', "\"{$baseClass}\".\"ID\" IN (" . implode(",", array_keys($idxStageChildren)) . ")", "" );
}
if($idxLiveChildren) {
$foundInStage = Versioned::get_by_stage( $baseClass, 'Stage', "\"{$baseClass}\".\"ID\" IN (" . implode(",", array_keys($idxLiveChildren)) . ")", "" );
}
DataObject::enable_subclass_access();
if(isset($foundInLive)) {
foreach($foundInLive as $child) {
$idxFoundInLive[$child->ID] = $child;
}
}
if(isset($foundInStage)) {
foreach($foundInStage as $child) {
$idxFoundInStage[$child->ID] = $child;
}
}
$this->_cache_allChildrenIncludingDeleted = new DataObjectSet();
// First, go through the stage children. They will all be listed but may be different colours
if($stageChildren) {
foreach($stageChildren as $child) {
$this->_cache_allChildrenIncludingDeleted->push($child);
}
}
// Next, go through the live children. Only some of these will be listed
if($liveChildren) {
foreach($liveChildren as $child) {
// Not found on stage = deleted page. Anything else is ignored
if(!isset($idxFoundInStage[$child->ID])) {
$this->_cache_allChildrenIncludingDeleted->push($child);
}
}
}
}
$this->owner->extend("augmentAllChildrenIncludingDeleted", $stageChildren, $context);
} else {
user_error("Hierarchy::AllChildren() Couldn't determine base class for '{$this->owner->class}'", E_USER_ERROR);
@ -529,7 +481,10 @@ class Hierarchy extends DataObjectDecorator {
$extraFilter = $showAll ? '' : " AND \"ShowInMenus\"=1";
$baseClass = ClassInfo::baseDataClass($this->owner->class);
$staged = DataObject::get($baseClass, "\"{$baseClass}\".\"ParentID\" = " . (int)$this->owner->ID . " AND \"{$baseClass}\".\"ID\" != " . (int)$this->owner->ID . $extraFilter, "");
$staged = DataObject::get($baseClass, "\"{$baseClass}\".\"ParentID\" = "
. (int)$this->owner->ID . " AND \"{$baseClass}\".\"ID\" != " . (int)$this->owner->ID
. $extraFilter, "");
if(!$staged) $staged = new DataObjectSet();
$this->owner->extend("augmentStageChildren", $staged, $showAll);
return $staged;
@ -538,12 +493,28 @@ class Hierarchy extends DataObjectDecorator {
/**
* Return children from the live site, if it exists.
* @param boolean $showAll Include all of the elements, even those not shown in the menus.
* @param boolean $onlyDeletedFromStage Only return items that have been deleted from stage
* @return DataObjectSet
*/
public function liveChildren($showAll = false) {
public function liveChildren($showAll = false, $onlyDeletedFromStage = false) {
$extraFilter = $showAll ? '' : " AND \"ShowInMenus\"=1";
$join = "";
$baseClass = ClassInfo::baseDataClass($this->owner->class);
return Versioned::get_by_stage($baseClass, "Live", "\"{$baseClass}\".\"ParentID\" = " . (int)$this->owner->ID . " AND \"{$baseClass}\".\"ID\" != " . (int)$this->owner->ID. $extraFilter, "");
if($onlyDeletedFromStage) {
// Note that the lack of double-quotes around $baseClass are the only thing preventing
// it from being rewritten to {$baseClass}_Live. This is brittle, won't work in
// postgres, and will need to be fixed *somehow*. Also, this code should probably be
// refactored to be pushed into Versioned somehow; perhaps a "doesn't exist on stage X"
// option for get_by_stage.
$join = "LEFT JOIN {$baseClass} ON {$baseClass}.\"ID\" = \"{$baseClass}\".\"ID\"";
$extraFilter .= " AND {$baseClass}.\"ID\" IS NULL";
}
return Versioned::get_by_stage($baseClass, "Live", "\"{$baseClass}\".\"ParentID\" = "
. (int)$this->owner->ID . " AND \"{$baseClass}\".\"ID\" != " . (int)$this->owner->ID
. $extraFilter, null, $join);
}
/**

View File

@ -442,7 +442,12 @@ class Versioned extends DataObjectDecorator {
$oldStage = Versioned::$reading_stage;
Versioned::$reading_stage = $toStage;
$conn = DB::getConn();
if($conn->hasMethod('allowPrimaryKeyEditing')) $conn->allowPrimaryKeyEditing($baseClass, true);
$from->write();
if($conn->hasMethod('allowPrimaryKeyEditing')) $conn->allowPrimaryKeyEditing($baseClass, false);
$from->destroy();
Versioned::$reading_stage = $oldStage;

View File

@ -123,7 +123,7 @@ class Date extends DBField {
*/
function Ago() {
if($this->value) {
if(time() > strtotime($this->value)) {
if(strtotime($this->value) == time() || time() > strtotime($this->value)) {
return sprintf(
_t(
'Date.TIMEDIFFAGO',

View File

@ -44,7 +44,9 @@ class HTMLText extends Text {
/* Catch warnings thrown by loadHTML and turn them into a failure boolean rather than a SilverStripe error */
set_error_handler(create_function('$no, $str', 'throw new Exception("HTML Parse Error: ".$str);'), E_ALL);
try { $res = $doc->loadHTML('<meta content="text/html; charset=utf-8" http-equiv="Content-type"/>' . $this->value); }
// Nonbreaking spaces get converted into weird characters, so strip them
$value = str_replace('&nbsp;', ' ', $this->value);
try { $res = $doc->loadHTML('<meta content="text/html; charset=utf-8" http-equiv="Content-type"/>' . $value); }
catch (Exception $e) { $res = false; }
restore_error_handler();

View File

@ -24,7 +24,7 @@ define('30719',E_ALL);
*/
class SapphireREPL extends Controller {
private function error_handler( $errno, $errstr, $errfile, $errline, $errctx ) {
public function error_handler( $errno, $errstr, $errfile, $errline, $errctx ) {
// Ignore unless important error
if ( ($errno & ~( 2048 | 8192 | 16384 )) == 0 ) return ;
// Otherwise throw exception to handle in REPL loop

View File

@ -191,11 +191,15 @@ class Folder extends File {
if($oldFile == $file && $i > 2) user_error("Couldn't fix $file with $i", E_USER_ERROR);
}
if(file_exists($tmpFile['tmp_name']) && copy($tmpFile['tmp_name'], "$base/$file")) {
//$fullFilename = "$base/$file";
$fullFilename = $base . DIRECTORY_SEPARATOR . str_replace(array("\\","/") , DIRECTORY_SEPARATOR, $file );
if(file_exists($tmpFile['tmp_name']) && copy($tmpFile['tmp_name'], $fullFilename)) {
// Update with the new image
return $this->constructChild(basename($file));
} else {
user_error("Folder::addUploadToFolder: Couldn't copy '$tmpFile[tmp_name]' to '$file'", E_USER_ERROR);
if(!file_exists($tmpFile['tmp_name'])) user_error("Folder::addUploadToFolder: '$tmpFile[tmp_name]' doesn't exist", E_USER_ERROR);
else user_error("Folder::addUploadToFolder: Couldn't copy '$tmpFile[tmp_name]' to '$fullFilename'", E_USER_ERROR);
return false;
}
}
@ -260,7 +264,18 @@ class Folder extends File {
* Returns true if this folder has children
*/
public function hasChildren() {
return $this->ID && $this->myChildren() && $this->myChildren()->Count() > 0;
return (bool)DB::query("SELECT COUNT(*) FROM \"File\" WHERE ParentID = "
. (int)$this->ID)->value();
}
/**
* Returns true if this folder has children
*/
public function hasChildFolders() {
$SQL_folderClasses = Convert::raw2sql(ClassInfo::subclassesFor('Folder'));
return (bool)DB::query("SELECT COUNT(*) FROM \"File\" WHERE ParentID = " . (int)$this->ID
. " AND \"ClassName\" IN ('" . implode("','", $SQL_folderClasses) . "')")->value();
}
/**
@ -311,7 +326,6 @@ class Folder extends File {
*/
function getCMSFields() {
$nameField = ($this->ID > 0) ? new TextField("Name") : new HiddenField("Name");
$fileList = new AssetTableField(
$this,
"Files",
@ -350,10 +364,10 @@ class Folder extends File {
new LiteralField("UploadIframe",
$this->getUploadIframe()
)
),
)/*,
new Tab("UnusedFiles", _t('Folder.UNUSEDFILESTAB', "Unused files"),
new Folder_UnusedAssetsField($this)
)
)*/
),
new HiddenField("ID")
);
@ -422,6 +436,12 @@ class Folder extends File {
HTML;
}
/**
* Get the children of this folder that are also folders.
*/
function ChildFolders() {
return DataObject::get("Folder", "ParentID = " . (int)$this->ID);
}
}
class Folder_UnusedAssetsField extends CompositeField {

View File

@ -19,6 +19,16 @@ class FormAction extends FormField {
*/
public $useButtonTag = false;
private $buttonContent = null;
/**
* Add content inside a button field.
*/
function setButtonContent($content) {
$this->buttonContent = (string) $content;
}
/**
* Create a new action button.
* @param action The method to call when the button is clicked
@ -74,7 +84,7 @@ class FormAction extends FormField {
$attributes['class'] = $attributes['class'] . ' disabled';
}
return $this->createTag('button', $attributes, $this->attrTitle());
return $this->createTag('button', $attributes, $this->buttonContent ? $this->buttonContent : $this->attrTitle());
} else {
$attributes = array(
'class' => 'action' . ($this->extraClass() ? $this->extraClass() : ''),
@ -117,4 +127,4 @@ class FormAction_WithoutLabel extends FormAction {
return null;
}
}
?>
?>