diff --git a/core/Extension.php b/core/Extension.php
new file mode 100644
index 000000000..6c53ec98e
--- /dev/null
+++ b/core/Extension.php
@@ -0,0 +1,24 @@
+owner = $owner;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/core/model/DataObject.php b/core/model/DataObject.php
index 88260429e..bff4cff67 100644
--- a/core/model/DataObject.php
+++ b/core/model/DataObject.php
@@ -39,11 +39,6 @@ class DataObject extends Controller {
*/
protected $components;
- /**
- * This DataObjects extensions, eg Versioned.
- * @var array
- */
- protected $extension_instances = array();
/**
* True if this DataObject has been destroyed.
@@ -95,14 +90,6 @@ class DataObject extends Controller {
HTTP::register_modification_date($record['LastEdited']);
}
- // Set up the extensions
- if($extensions = $this->stat('extensions')) {
- foreach($extensions as $extension) {
- $instance = eval("return new $extension;");
- $instance->setOwner($this);
- $this->extension_instances[$instance->class] = $instance;
- }
- }
parent::__construct();
// Must be called after parent constructor
@@ -126,15 +113,16 @@ class DataObject extends Controller {
/**
* Create a duplicate of this node.
- * It will create the duplicate in the database.
+ *
+ * @param $doWrite Perform a write() operation before returning the object. If this is true, it will create the duplicate in the database.
*
* @return DataObject A duplicate of this node. The exact type will be the type of this node.
*/
- function duplicate() {
+ function duplicate($doWrite = true) {
$className = $this->class;
$clone = new $className( $this->record );
$clone->ID = 0;
- $clone->write();
+ if($doWrite) $clone->write();
return $clone;
}
@@ -175,14 +163,14 @@ class DataObject extends Controller {
*/
function defineMethods() {
if($this->class == 'DataObject') return;
-
- if($this->extension_instances) foreach($this->extension_instances as $i => $instance) {
- $this->addMethodsFrom('extension_instances', $i);
- // Define the extra db fields
+ parent::defineMethods();
+
+ // Define the extra db fields
+ if($this->extension_instances) foreach($this->extension_instances as $i => $instance) {
$instance->loadExtraDBFields();
}
-
+
// Set up accessors for joined items
if($manyMany = $this->many_many()) {
foreach($manyMany as $relationship => $class) {
@@ -201,8 +189,6 @@ class DataObject extends Controller {
$this->addWrapperMethod($relationship, 'getComponent');
}
}
-
- parent::defineMethods();
}
/**
@@ -312,6 +298,9 @@ class DataObject extends Controller {
*/
protected function onBeforeWrite() {
$this->brokenOnWrite = false;
+
+ $dummy = null;
+ $this->extend('augmentBeforeWrite', $dummy);
}
/**
@@ -1304,56 +1293,6 @@ class DataObject extends Controller {
return $query;
}
- /**
- * Run the given function on all of this object's extensions
- *
- * @param string $funcName The name of the function.
- * @param mixed $arg An Argument to be passed to each of the extension functions.
- */
- public function extend($funcName, &$arg) {
- if($this->extension_instances) {
- foreach($this->extension_instances as $extension) {
- if($extension->hasMethod($funcName)) {
- $extension->$funcName($arg);
- }
- }
- }
- }
-
- /**
- * Get an extension on this DataObject
- *
- * @param string $name Classname of the Extension (e.g. 'Versioned')
- *
- * @return DataObjectDecorator The instance of the extension
- */
- public function getExtension($name) {
- return $this->extension_instances[$name];
- }
-
- /**
- * Returns true if the given extension class is attached to this object
- *
- * @param string $requiredExtension Classname of the extension
- *
- * @return boolean True if the given extension class is attached to this object
- */
- public function hasExtension($requiredExtension) {
- return isset($this->extension_instances[$requiredExtension]) ? true : false;
- }
-
- /**
- * Add an extension to the given object.
- * This can be used to add extensions to built-in objects, such as role decorators on Member
- */
- public static function add_extension($className, $extensionName) {
- Object::addStaticVars($className, array(
- 'extensions' => array(
- $extensionName,
- ),
- ));
- }
-
/**
* Get a bunch of fields in a list - a
of - name: value
*
@@ -1470,6 +1409,11 @@ class DataObject extends Controller {
* Flush the cached results for get_one()
*/
public function flushCache() {
+ if($this->class == 'DataObject') {
+ DataObject::$cache_get_one = array();
+ return;
+ }
+
$classes = ClassInfo::ancestry($this->class);
foreach($classes as $class) {
// If someone else has called get_one and flushCache() is called, then that object will be destroyed.
@@ -1540,7 +1484,7 @@ class DataObject extends Controller {
$tableClasses = ClassInfo::dataClassesFor($callerClass);
$baseClass = array_shift($tableClasses);
- return DataObject::get_one($callerClass,"`$baseClass`.ID = $id");
+ return DataObject::get_one($callerClass,"`$baseClass`.`ID` = $id");
} else {
user_error("DataObject::get_by_id passed a non-numeric ID #$id", E_USER_WARNING);
}
@@ -1695,13 +1639,34 @@ class DataObject extends Controller {
public function isInDB() {
return is_numeric( $this->ID ) && $this->ID > 0;
}
+
+ /**
+ * Sets a 'context object' that can be used to provide hints about how to process a particular get / get_one request.
+ * In particular, DataObjectDecorators can use this to amend queries more effectively.
+ * Care must be taken to unset the context object after you're done with it, otherwise you will have a stale context,
+ * which could cause horrible bugs.
+ */
+ public static function set_context_obj($obj) {
+ if($obj && self::$context_obj) user_error("Dataobject::set_context_obj called when there is already a context.", E_USER_WARNING);
+ self::$context_obj = $obj;
+ }
+
+ /**
+ * Retrieve the current context object.
+ */
+ public static function context_obj() {
+ return self::$context_obj;
+ }
+
+ protected static $context_obj = null;
+
//-------------------------------------------------------------------------------------------//
/**
* Database field definitions.
* This is a map from field names to field type. The field
- * type should be a class that extends DBField.
+ * type should be a class that extends .
* @var array
*/
public static $db = null;
@@ -1788,18 +1753,5 @@ class DataObject extends Controller {
* @var string
*/
public static $default_sort = null;
-
- /**
- * Extensions to be used on this DataObject. An array of extension names
- * and parameters eg:
- *
- * static $extensions = array(
- * "Hierarchy",
- * "Versioned('Stage', 'Live')",
- * );
- *
- * @var array
- */
- public static $extensions = null;
}
?>
diff --git a/core/model/DataObjectDecorator.php b/core/model/DataObjectDecorator.php
index dfcee161b..f43fc4e4c 100755
--- a/core/model/DataObjectDecorator.php
+++ b/core/model/DataObjectDecorator.php
@@ -9,20 +9,7 @@
* Plug-ins for additional functionality in your DataObjects.
* DataObject decorators add extra functionality to your data objects.
*/
-abstract class DataObjectDecorator extends Object {
- /**
- * The DataObject that owns this decorator.
- * @var DataObject
- */
- protected $owner;
-
- /**
- * Set the owner of this decorator.
- * @param DataObject $owner
- */
- function setOwner(DataObject $owner) {
- $this->owner = $owner;
- }
+abstract class DataObjectDecorator extends Extension {
/**
* Load the extra database fields defined in extraDBFields.
@@ -43,12 +30,16 @@ abstract class DataObjectDecorator extends Object {
* Edit the given query object to support queries for this extension.
* @param SQLQuery $query Query to augment.
*/
- abstract function augmentSQL(SQLQuery &$query);
+ function augmentSQL(SQLQuery &$query) {
+
+ }
/**
* Update the database schema as required by this extension.
*/
- abstract function augmentDatabase();
+ function augmentDatabase() {
+
+ }
/**
* Define extra database fields.
diff --git a/core/model/SiteTree.php b/core/model/SiteTree.php
index 4b3f69e17..7cc32db53 100644
--- a/core/model/SiteTree.php
+++ b/core/model/SiteTree.php
@@ -100,8 +100,8 @@ class SiteTree extends DataObject {
* if you need such behaviour.
* @return SiteTree The duplicated object.
*/
- public function duplicate() {
- $page = parent::duplicate();
+ public function duplicate($doWrite = true) {
+ $page = parent::duplicate($doWrite);
$page->CheckedPublicationDifferences = $page->AddedToStage = true;
return $page;
}
@@ -459,6 +459,8 @@ class SiteTree extends DataObject {
$this->URLSegment = $segment;
}
+ DataObject::set_context_obj($this);
+
// Ensure URLSegment is unique
$idFilter = $this->ID ? " AND `SiteTree`.ID <> '$this->ID'" : '';
$count = 1;
@@ -466,6 +468,8 @@ class SiteTree extends DataObject {
$count++;
$this->URLSegment = ereg_replace('-[0-9]+$','', $this->URLSegment) . "-$count";
}
+
+ DataObject::set_context_obj(null);
// If the URLSegment has been changed, rewrite links
if(isset($this->changed['URLSegment']) && $this->changed['URLSegment']) {
@@ -483,6 +487,7 @@ class SiteTree extends DataObject {
parent::onBeforeWrite();
}
+
/**
* Generate a URL segment based on the title provided.
* @param string $title Page title.