Merged changes from 2.2.2-assets - everything except the asset refactoring

git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@60468 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Sam Minnee 2008-08-12 02:51:33 +00:00
parent b5001bc906
commit 0bd9bc4ff8
34 changed files with 188 additions and 67 deletions

View File

@ -92,11 +92,9 @@ if(isset($_FILE_TO_URL_MAPPING)) {
}
$testPath = dirname($testPath);
}
}
if(ManifestBuilder::staleManifest()){
ManifestBuilder::compileManifest();
}

View File

@ -11,6 +11,9 @@ abstract class CliController extends Controller {
}
function index() {
// Always re-compile the manifest (?flush=1)
ManifestBuilder::compileManifest();
foreach( ClassInfo::subclassesFor( $this->class ) as $subclass ) {
echo $subclass;

16
cli/HourlyTask.php Normal file
View File

@ -0,0 +1,16 @@
<?php
/**
* @package sapphire
* @subpackage cron
*/
/**
* Classes that must be run hourly extend this class
* @package sapphire
* @subpackage cron
*/
class HourlyTask extends ScheduledTask {
}
?>

View File

@ -127,8 +127,10 @@ class ClassInfo {
*/
static function ancestry($class, $onlyWithTables = false) {
global $_ALL_CLASSES;
if(!is_string($class)) $class = $class->class;
if(is_object($class)) $class = $class->class;
else if(!is_string($class)) user_error("Bad class value " . var_export($class, true) . " passed to ClassInfo::ancestry()", E_USER_WARNING);
$items = $_ALL_CLASSES['parents'][$class];
$items[$class] = $class;
if($onlyWithTables) foreach($items as $item) {

View File

@ -87,8 +87,8 @@ function getClassFile($className) {
function singleton($className) {
static $_SINGLETONS;
if(!isset($className)) user_error("singleton() Called without a class", E_USER_ERROR);
if(!class_exists($className)) user_error("Bad class to singleton() - $className", E_USER_ERROR);
if(!isset($_SINGLETONS[$className])) {
if(!class_exists($className)) user_error("Bad class to singleton() - $className", E_USER_ERROR);
$_SINGLETONS[$className] = Object::strong_create($className,null, true);
if(!$_SINGLETONS[$className]) user_error("singleton() Unknown class '$className'", E_USER_ERROR);
}

View File

@ -146,11 +146,15 @@ class Object {
* Returns true if the given method exists.
*/
public function hasMethod($methodName) {
if(method_exists($this, $methodName)) return true;
$methodName = strtolower($methodName);
if(!isset($this->class)) $this->class = get_class($this);
/*
if(!isset(Object::$builtInMethods['_set'][$this->class])) $this->buildMethodList();
if(isset(Object::$builtInMethods[$this->class][$methodName])) return true;
*/
if(isset(Object::$extraMethods[$this->class][$methodName])) return true;
return false;
}
@ -257,7 +261,7 @@ class Object {
$methodNames[strtolower($name)] = $name;
}
Object::$builtInMethods[$this->class] = $methodNames;
Object::$builtInMethods['_set'][$this->class] = true ;
Object::$builtInMethods['_set'][$this->class] = true;
}
/**
@ -442,7 +446,9 @@ class Object {
* @return DataObjectDecorator The instance of the extension
*/
public function extInstance($name) {
return $this->extension_instances[$name];
if(isset($this->extension_instances[$name])) {
return $this->extension_instances[$name];
}
}
/**
@ -584,4 +590,4 @@ class Object {
return $data;
}
}
?>
?>

View File

@ -220,6 +220,7 @@ class Requirements {
Requirements::$css = array();
Requirements::$customScript = array();
Requirements::$customCSS = array();
Requirements::$customHeadTags = "";
}
}

View File

@ -79,7 +79,7 @@ class ViewableData extends Object implements IteratorAggregate {
$trimmedName = substr($methodName,1);
$this->createMethod($trimmedName, "return \$obj->cachedCall('$methodName', '$trimmedName', \$args);");
}
}
}
parent::defineMethods();
}
@ -206,8 +206,7 @@ class ViewableData extends Object implements IteratorAggregate {
* @param array
*/
public function buildCastingHelperCache(&$cache) {
$class = $this->class;
$class = $this->class ? $this->class : get_class($this);
$classes = ClassInfo::ancestry($class);
foreach($classes as $componentClass) {

View File

@ -293,6 +293,11 @@ class Director {
}
$s = (isset($_SERVER['SSL']) || isset($_SERVER['HTTPS'])) ? 's' : '';
if(!isset($_SERVER['HTTP_HOST'])) {
user_error("Director::protocolAndHost() lacks sufficient information - HTTP_HOST not set.", E_USER_WARNING);
}
return "http$s://" . $_SERVER['HTTP_HOST'];
}

View File

@ -72,6 +72,16 @@ class DB {
*/
static function query($sql, $errorLevel = E_USER_ERROR) {
DB::$lastQuery = $sql;
/* debug helper for query efficiency
if(substr(strtolower($sql),0,6) == 'select') {
$product = 1;
foreach(DB::$globalConn->query("explain " . $sql, $errorLevel) as $explainRow) {
if($explainRow['rows']) $product *= $explainRow['rows'];
}
if($product > 100)
Debug::message("Cartesian product $product for SQL: $sql");
} */
return DB::$globalConn->query($sql, $errorLevel);
}

View File

@ -679,13 +679,13 @@ class DataObject extends ViewableData implements DataObjectInterface {
}
}
$this->extend('augmentWrite', $manipulation);
// New records have their insert into the base data table done first, so that they can pass the
// generated ID on to the rest of the manipulation
if(isset($isNewRecord) && $isNewRecord && isset($manipulation[$baseTable])) {
$manipulation[$baseTable]['command'] = 'update';
}
DB::manipulate($manipulation);
if(isset($isNewRecord) && $isNewRecord) {
@ -1901,7 +1901,7 @@ class DataObject extends ViewableData implements DataObjectInterface {
}
}
// Join all the tables
if($tableClasses) {
if($tableClasses && self::$subclass_access) {
foreach($tableClasses as $tableClass) {
$query->from[$tableClass] = "LEFT JOIN `$tableClass` ON `$tableClass`.ID = `$baseClass`.ID";
$query->select[] = "`$tableClass`.*";
@ -2519,7 +2519,21 @@ class DataObject extends ViewableData implements DataObjectInterface {
*/
protected static $context_obj = null;
/*
* @ignore
*/
private static $subclass_access = true;
/**
* Temporarily disable subclass access in data object qeur
*/
static function disable_subclass_access() {
self::$subclass_access = false;
}
static function enable_subclass_access() {
self::$subclass_access = true;
}
//-------------------------------------------------------------------------------------------//
/**

View File

@ -33,6 +33,9 @@ abstract class DataObjectDecorator extends Extension {
* @todo Rename to "loadExtraStaticFields", as it decorates more than database related fields.
*/
function loadExtraDBFields() {
// Don't apply DB fields if the parent object has this extension too
if(singleton(get_parent_class($this->owner))->extInstance($this->class)) return;
$fields = $this->extraDBFields();
$className = $this->owner->class;
@ -104,4 +107,4 @@ abstract class DataObjectDecorator extends Extension {
}
}
?>
?>

View File

@ -6,7 +6,7 @@
*/
/**
* This class represents a set of {@link ViewableData} subclasses (mostly {@link DataObject} or {@link ArrayData}.
* This class represents a set of {@link ViewableData} subclasses (mostly {@link DataObject} or {@link ArrayData}).
* It is used by the ORM-layer of Silverstripe to return query-results from {@link SQLQuery}.
* @package sapphire
* @subpackage model
@ -436,8 +436,10 @@ class DataObjectSet extends ViewableData implements IteratorAggregate {
* @param DataObjectSet $anotherSet Set to mege onto this set.
*/
public function merge($anotherSet){
foreach($anotherSet->items as $item){
$this->push($item);
if($anotherSet) {
foreach($anotherSet->items as $item){
$this->push($item);
}
}
}
@ -573,7 +575,8 @@ class DataObjectSet extends ViewableData implements IteratorAggregate {
* @return array
*/
public function map($key = "ID", $value = "Title", $includeBlank=null) {
$map = array();
/* Don't do this, add this locally.
* Reasons: 1: In some case this blank value don't/mustn't present.
2: In some case, this balnk value should be customised, such as (Select from below)

View File

@ -651,4 +651,4 @@ abstract class Query extends Object implements Iterator {
abstract function seek($rowNum);
}
?>
?>

View File

@ -161,7 +161,7 @@ class DatabaseAdmin extends Controller {
array_shift($dataClasses);
if(!$quiet) {
echo '<p><b>Creating database tables</b></p>';
echo '\n<p><b>Creating database tables</b></p>\n\n';
}
$conn->beginSchemaUpdate();
@ -169,7 +169,7 @@ class DatabaseAdmin extends Controller {
$SNG = singleton($dataClass);
if($testMode || !($SNG instanceof TestOnly)) {
if(!$quiet) {
echo "<li>$dataClass</li>";
echo "<li>$dataClass</li>\n";
}
$SNG->requireTable();
}
@ -180,7 +180,7 @@ class DatabaseAdmin extends Controller {
if($populate) {
if(!$quiet) {
echo '<p><b>Creating database records</b></p>';
echo '\n<p><b>Creating database records</b></p>\n\n';
}
foreach($dataClasses as $dataClass) {
@ -188,7 +188,7 @@ class DatabaseAdmin extends Controller {
if(strpos($dataClass,'Test_') === false) {
if(!$quiet) {
echo "<li>$dataClass</li>";
echo "<li>$dataClass</li>\n";
}
singleton($dataClass)->requireDefaultRecords();
@ -268,4 +268,4 @@ class DatabaseAdmin extends Controller {
}
?>
?>

View File

@ -85,9 +85,6 @@ class ErrorPage extends Page {
* @param boolean $createNewVersion Set this to true to create a new version number. By default, the existing version number will be copied over.
*/
function publish($fromStage, $toStage, $createNewVersion = false) {
// Temporarily log out when producing this page
$loggedInMember = Member::currentUser();
Session::clear("loggedInAs");
$alc_enc = isset($_COOKIE['alc_enc']) ? $_COOKIE['alc_enc'] : null;
Cookie::set('alc_enc', null);
@ -111,7 +108,6 @@ class ErrorPage extends Page {
Versioned::reading_stage($oldStage);
// Log back in
if($loggedInMember) Session::set("loggedInAs", $loggedInMember->ID);
if(isset($alc_enc)) Cookie::set('alc_enc', $alc_enc);
return $this->extension_instances['Versioned']->publish($fromStage, $toStage, $createNewVersion);

View File

@ -408,6 +408,7 @@ class Hierarchy extends DataObjectDecorator {
}
}
DataObject::disable_subclass_access();
if(isset($idxStageChildren)) {
$foundInLive = Versioned::get_by_stage( $baseClass, 'Live', "`{$baseClass}`.`ID` IN (" . implode(",", array_keys($idxStageChildren)) . ")", "" );
}
@ -415,6 +416,7 @@ class Hierarchy extends DataObjectDecorator {
if(isset($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) {

View File

@ -65,6 +65,8 @@ class SQLQuery extends Object {
*/
public $delete = false;
private $replacements = array();
/**
* The logical connective used to join WHERE clauses. Defaults to AND.
* @var string
@ -352,6 +354,8 @@ class SQLQuery extends Object {
* @param string $new The new text.
*/
function replaceText($old, $new) {
$this->replacements[] = array($old, $new);
/*
if($this->select) foreach($this->select as $i => $item)
$this->select[$i] = str_replace($old, $new, $item);
@ -374,6 +378,7 @@ class SQLQuery extends Object {
foreach($this->having as $i => $item)
$this->having[$i] = str_replace($old, $new, $item);
}
*/
}
/**
@ -406,6 +411,10 @@ class SQLQuery extends Object {
if($this->orderby) $text .= " ORDER BY " . $this->orderby;
if($this->limit) $text .= " LIMIT " . $this->limit;
foreach($this->replacements as $replacement) {
$text = str_replace($replacement[0], $replacement[1], $text);
}
return $text;
}

View File

@ -91,7 +91,8 @@ class SiteTree extends DataObject {
static $indexes = array(
"SearchFields" => "fulltext (Title, MenuTitle, Content, MetaTitle, MetaDescription, MetaKeywords)",
"TitleSearchFields" => "fulltext (Title)"
"TitleSearchFields" => "fulltext (Title)",
"URLSegment" => true,
);
static $has_many = array(
@ -361,7 +362,12 @@ class SiteTree extends DataObject {
*
* @var int
*/
protected static $currentPageID;
private static $currentPageID;
/**
* Records the URL segment that was used to set the current page ID
*/
private static $currentPageIDSetFromURLSegment;
/**
@ -369,8 +375,10 @@ class SiteTree extends DataObject {
* the cached answers.
*/
protected function prepareCurrentAndSection() {
if(!self::$currentPageID) {
if(!self::$currentPageID || Director::urlParam('URLSegment') != self::$currentPageIDSetFromURLSegment) {
self::$currentPageID = Director::currentPage() ? Director::currentPage()->ID : null;
self::$currentPageIDSetFromURLSegment = Director::urlParam('URLSegment');
if(!isset(self::$currentPageID)) {
self::$currentPageID = -1;
$nextID = (Director::currentPage() && isset(Director::currentPage()->Parent->ID))
@ -1220,6 +1228,7 @@ class SiteTree extends DataObject {
return $fields;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Get the actions available in the CMS for this page - eg Save, Publish.
@ -1251,6 +1260,34 @@ class SiteTree extends DataObject {
return new DataObjectSet($actions);
}
/**
* Publish this page
*/
function doPublish() {
$original = Versioned::get_one_by_stage("SiteTree", "Live", "`SiteTree`.`ID` = $this->ID");
// Handle activities undertaken by decorators
$this->extend('onBeforePublish', $original);
$this->AssignedToID = 0;
$this->RequestedByID = 0;
$this->Status = "Published";
//$this->PublishedByID = Member::currentUser()->ID;
$this->write();
$this->publish("Stage", "Live");
GoogleSitemap::ping();
// Fix the sort order for this page's siblings
DB::query("UPDATE SiteTree_Live
INNER JOIN SiteTree ON SiteTree_Live.ID = SiteTree.ID
SET SiteTree_Live.Sort = SiteTree.Sort
WHERE SiteTree_Live.ParentID = " . sprintf('%d', $this->ParentID));
// Handle activities undertaken by decorators
$this->extend('onAfterPublish', $original);
}
/**

View File

@ -39,4 +39,4 @@ class SSDatetime extends Date {
}
}
?>
?>

View File

@ -159,7 +159,7 @@ class Text extends DBField {
* Caution: Not XML/HTML-safe - does not respect closing tags.
*/
function BigSummary($maxWords = 50, $plain = 1) {
$result = "";
// get first sentence?
// this needs to be more robust
if($plain) $data = Convert::xml2raw( $this->value, true );

View File

@ -27,7 +27,7 @@ class Time extends DBField {
}
function _12Hour( $parts ) {
function 12Hour( $parts ) {
$hour = $parts[1];
$min = $parts[2];
$half = $parts[3];

View File

@ -11,6 +11,8 @@
width: 20px;
float : left;
height:100px;
overflow-y:scroll;
}
.SelectionGroup li div.field {

View File

@ -22,8 +22,10 @@ class Filesystem extends Object {
/**
* Remove a directory and all subdirectories and files
* @param $contentsOnly If this is true then the contents of the folder will be removed but not the folder itself
*/
static function removeFolder($folder) {
static function removeFolder( $folder, $contentsOnly = false ) {
// remove a file encountered by a recursive call.
if( !is_dir( $folder ) || is_link($folder) )
unlink( $folder );
@ -36,7 +38,8 @@ class Filesystem extends Object {
self::removeFolder( $folder.'/'.$file );
closedir($dir);
rmdir($folder);
if(!$contentsOnly) rmdir($folder);
}
}
@ -134,4 +137,4 @@ class Filesystem extends Object {
}
?>
?>

View File

@ -39,7 +39,7 @@ class Folder extends File {
}
function userCanUse() {
if( Member::currentUser()->_isAdmin() )
if( Member::currentUser()->isAdmin() )
return true;
$useGroups = $this->CanUse();
@ -55,7 +55,7 @@ class Folder extends File {
}
function userCanEdit() {
if( Member::currentUser()->_isAdmin() )
if( Member::currentUser()->isAdmin() )
return true;
$useGroups = $this->CanEdit();

View File

@ -81,7 +81,6 @@ class Form extends RequestHandlingData {
* @param actions All of the action buttons in the form - a {@link FieldSet} of {@link FormAction} objects
*/
function __construct($controller, $name, FieldSet $fields, FieldSet $actions, $validator = null) {
parent::__construct();
foreach($fields as $field) $field->setForm($this);
@ -91,6 +90,8 @@ class Form extends RequestHandlingData {
$this->actions = $actions;
$this->controller = $controller;
$this->name = $name;
if(!$this->controller) user_error("$this->class form created without a controller", E_USER_ERROR);
// Form validation
if($validator) {
@ -122,6 +123,8 @@ class Form extends RequestHandlingData {
if(isset($errorInfo['message']) && isset($errorInfo['type'])) {
$this->setMessage($errorInfo['message'],$errorInfo['type']);
}
$this->security = self::$default_security;
}
static $url_handlers = array(
@ -910,6 +913,16 @@ class Form extends RequestHandlingData {
$this->security = false;
}
private static $default_security = true;
/**
* Disable security tokens for every form on this site.
*/
static function disable_all_security_tokens() {
self::$default_security = false;
}
/**
* Returns true if security is enabled - that is if the SecurityID
* should be included and checked on this form.
@ -998,4 +1011,4 @@ class Form_FieldMap extends Object {
function __call($method, $args = null) {
return $this->form->dataFieldByName($method);
}
}
}

View File

@ -233,7 +233,7 @@ function HtmlEditorField_dataValue_processImage($parts) {
$image = Image::find(urldecode($src));
// If we have an image, insert the resampled one into the src attribute; otherwise, leave the img src alone.
if($image) {
if($image && $image->getWidth() != $width && $image->getHeight != $height) {
// If we have an image, generate the resized image.
$resizedImage = $image->getFormattedImage("ResizedImage",$width, $height);
$parts[$partSource['src="']] = $resizedImage->getRelativePath() ;

View File

@ -167,7 +167,7 @@ class TableField extends TableListField {
// Load the data in to a temporary form (for correct field types)
$fieldset = $this->FieldSetForRow();
if($fieldset){
$form = new Form(null, null, $fieldset, new FieldSet());
$form = new Form($this, null, $fieldset, new FieldSet());
$form->loadDataFrom($item);
// Add the item to our new DataObjectSet, with a wrapper class.
$output->push(new TableField_Item($item, $this, $form, $this->fieldTypes));
@ -351,7 +351,7 @@ class TableField extends TableListField {
}
}
$form = new Form(null, null, $fieldset, new FieldSet());
$form = new Form($this, null, $fieldset, new FieldSet());
if($dataObjects) {
foreach ($dataObjects as $objectid => $fieldValues) {
@ -745,4 +745,4 @@ class TableField_Item extends TableListField_Item {
}
?>
?>

View File

@ -1240,4 +1240,4 @@ class TableListField_Item extends ViewableData {
}
?>
?>

View File

@ -511,8 +511,8 @@ $lang['en_US']['Security']['ALREADYLOGGEDIN'] = 'You don\'t have access to this
$lang['en_US']['Security']['LOGGEDOUT'] = 'You have been logged out. If you would like to log in again, enter your credentials below.';
$lang['en_US']['Security']['LOGIN'] = 'Log in';
$lang['en_US']['Security']['LOSTPASSWORDHEADER'] = 'Lost Password';
$lang['en_US']['Security']['NOTERESETPASSWORD'] = 'Enter your e-mail address and we will send you a link with which you can reset your password';
$lang['en_US']['Security']['BUTTONSEND'] = 'Send me the password reset link';
$lang['en_US']['Security']['NOTERESETPASSWORD'] = 'Enter your email address to be sent a password reset link.';
$lang['en_US']['Security']['BUTTONSEND'] = 'Send Password Reset Link';
$lang['en_US']['Security']['PASSWORDSENTHEADER'] = 'Password reset link sent to \'%s\'';
$lang['en_US']['Security']['PASSWORDSENTTEXT'] = 'Thank you! The password reset link has been sent to \'%s\'.';
$lang['en_US']['Security']['CHANGEPASSWORDHEADER'] = 'Change your password';

View File

@ -33,7 +33,9 @@ class SearchForm extends Form {
// Hayden: Sorry if I've got it mixed up, but on the results or not found pages, the
// RelativeLink seems to be empty and it packs a sad
$formController = isset($_GET['formController']) ? $_GET['formController'] : null;
if( !$formController ) $formController = $controller->RelativeLink();
if( !$formController ) {
$formController = $controller->RelativeLink();
}
$fields->push(new HiddenField("formController", null, $formController));
// $fields->push(new HiddenField("formController", null, $controller->RelativeLink()));

View File

@ -601,7 +601,7 @@ class Member extends DataObject {
* only right name for this?
* @todo Is {@link Group}::CanCMSAdmin not deprecated?
*/
function _isAdmin() {
function isAdmin() {
if($groups = $this->Groups()) {
foreach($groups as $group) {
if($group->CanCMSAdmin)
@ -611,21 +611,13 @@ class Member extends DataObject {
return Permission::check('ADMIN');
}
/**
* Check if the user is an administrator
*
* Alias for {@link _isAdmin()} because the method is used in both ways
* all over the framework.
*
* @return Returns TRUE if this user is an administrator.
* @see _isAdmin()
*/
public function isAdmin() {
return $this->_isAdmin();
function _isAdmin() {
user_error("Deprecated. Use isAdmin() instead", E_USER_NOTICE);
return $this->isAdmin();
}
function _isCMSUser() {
function isCMSUser() {
if($groups = $this->Groups()) {
foreach($groups as $group) {
if($group->CanCMS)
@ -634,6 +626,11 @@ class Member extends DataObject {
}
}
function _isCMSUser() {
user_error("Deprecated. Use isCMSUser() instead", E_USER_NOTICE);
return $this->isCMSUser();
}
//------------------- HELPER METHODS -----------------------------------//

View File

@ -7,4 +7,4 @@
$Field
<% end_control %>
</fieldset>
</form>
</form>

View File

@ -1,4 +1,4 @@
<p><% _t('HELLO', 'Hi') %> $FirstName,</p>
<p><% _t('TEXT1', 'Here\'s is your') %> <a href="$PasswordResetLink"><% _t('TEXT2', 'password reset link') %></a> <% _t('TEXT3', 'for') %> $BaseHref</p>
<p><% _t('TEXT1', 'Here is your') %> <a href="$PasswordResetLink"><% _t('TEXT2', 'password reset link') %></a> <% _t('TEXT3', 'for') %> $BaseHref.</p>