Commit 542f9b0d authored by Jonathan.Wage's avatar Jonathan.Wage

Further model loading refactoring and refactored merge() in Doctrine_Record

parent 0ac4d757
......@@ -441,13 +441,13 @@ final class Doctrine
private static $_debug = false;
/**
* _loadedModels
* _loadedModelFiles
*
* Array of all the loaded models and the path to each one for autoloading
*
* @var array
*/
private static $_loadedModels = array();
private static $_loadedModelFiles = array();
/**
* _validators
......@@ -517,13 +517,44 @@ final class Doctrine
foreach ($it as $file) {
$e = explode('.', $file->getFileName());
if (end($e) === 'php' && strpos($file->getFileName(), '.inc') === false) {
self::$_loadedModels[$e[0]] = $file->getPathName();
self::$_loadedModelFiles[$e[0]] = $file->getPathName();
}
}
}
$loadedModels = array();
$modelFiles = array_keys(self::$_loadedModelFiles);
foreach ($modelFiles as $name) {
if (class_exists($name)) {
$declaredBefore = get_declared_classes();
if (self::isValidModelClass($name) && !in_array($name, $loadedModels)) {
$loadedModels[] = $name;
}
} else {
// Determine class names by the actual inclusion of the model file
// The possibility exists that the class name(s) contained in the model
// file is not the same as the actual model file name itself
if (isset(self::$_loadedModelFiles[$name])) {
require_once self::$_loadedModelFiles[$name];
$declaredAfter = get_declared_classes();
// Using array_slice since array_diff is broken is some versions
$foundClasses = array_slice($declaredAfter, count($declaredBefore) - 1);
if ($foundClasses) {
foreach ($foundClasses as $name) {
if (self::isValidModelClass($name) && !in_array($name, $loadedModels)) {
$loadedModels[] = $name;
}
}
}
}
}
}
}
return self::getLoadedModels(array_keys(self::$_loadedModels));
return self::filterInvalidModels($loadedModels);
}
/**
......@@ -541,57 +572,51 @@ final class Doctrine
{
if ($classes === null) {
$classes = get_declared_classes();
$classes = array_merge($classes, array_keys(self::$_loadedModels));
$classes = array_merge($classes, array_keys(self::$_loadedModelFiles));
}
$loadedModels = array();
return self::filterInvalidModels($classes);
}
/**
* filterInvalidModels
*
* Filter through an array of classes and return all the classes that are valid models
*
* @param classes Array of classes to filter through, otherwise uses get_declared_classes()
* @return array $loadedModels
*/
public static function filterInvalidModels($classes)
{
$validModels = array();
foreach ((array) $classes as $name) {
try {
$declaredBefore = get_declared_classes();
$class = new ReflectionClass($name);
if (self::isValidModelClass($class)) {
$loadedModels[] = $name;
}
} catch (Exception $e) {
// Determine class names by the actual inclusion of the model file
// The possibility exists that the class name(s) contained in the model
// file is not the same as the actual model file name itself
if (isset(self::$_loadedModels[$name])) {
try {
require_once self::$_loadedModels[$name];
$declaredAfter = get_declared_classes();
// Using array_slice since array_diff is broken is some versions
$foundClasses = array_slice($declaredAfter, count($declaredBefore)-1);
if ($foundClasses) {
foreach ($foundClasses as $name) {
$class = new ReflectionClass($name);
if (self::isValidModelClass($class)) {
$loadedModels[] = $name;
}
}
}
} catch (Exception $e) {
continue;
}
if (self::isValidModelClass($name) && !in_array($name, $validModels)) {
$validModels[] = $name;
}
}
return $validModels;
}
return $loadedModels;
}
/**
* isValidModelClass
*
* Checks whether a reflection class is a valid Doctrine model class
* Checks if what is passed is a valid Doctrine_Record
*
* @param class A reflection class to validate
* @param mixed $class Can be a string named after the class, an instance of the class, or an instance of the class reflected
* @return boolean
*/
public static function isValidModelClass($class)
{
if ($class instanceof Doctrine_Record) {
$class = get_class($class);
}
if (is_string($class) && class_exists($class)) {
$class = new ReflectionClass($class);
}
if ($class instanceof ReflectionClass) {
// Skip the following classes
// - abstract classes
......@@ -600,13 +625,14 @@ final class Doctrine
if (!$class->isAbstract() &&
$class->isSubClassOf('Doctrine_Record') &&
$class->hasMethod('setTableDefinition')) {
return true;
}
}
return false;
}
/**
* getConnectionByTableName
*
......@@ -1001,7 +1027,7 @@ final class Doctrine
return true;
}
$loadedModels = self::$_loadedModels;
$loadedModels = self::$_loadedModelFiles;
if (isset($loadedModels[$className]) && file_exists($loadedModels[$className])) {
require_once($loadedModels[$className]);
......
......@@ -670,12 +670,11 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
* @param string $array
* @return void
*/
public function fromArray($array)
public function fromArray($array, $deep = true)
{
$data = array();
foreach ($array as $rowKey => $row) {
$this[$rowKey]->fromArray($row);
$this[$rowKey]->fromArray($row, $deep);
}
}
......
......@@ -274,7 +274,7 @@ class Doctrine_Data
*/
public function purge($models = array())
{
$models = Doctrine::getLoadedModels($models);
$models = Doctrine::filterInvalidModels($models);
foreach ($models as $model)
{
......
......@@ -1124,7 +1124,7 @@ class Doctrine_Export extends Doctrine_Connection_Module
*/
public function exportClassesSql(array $classes)
{
$models = Doctrine::getLoadedModels($classes);
$models = Doctrine::filterInvalidModels($classes);
$sql = array();
......
......@@ -1174,7 +1174,7 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count
* @param boolean $deep - Return also the relations
* @return array
*/
public function toArray($deep = false, $prefixKey = false)
public function toArray($deep = true, $prefixKey = false)
{
$a = array();
......@@ -1184,10 +1184,12 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count
}
$a[$column] = $value;
}
if ($this->_table->getIdentifierType() == Doctrine::IDENTIFIER_AUTOINC) {
$i = $this->_table->getIdentifier();
$a[$i] = $this->getIncremented();
}
if ($deep) {
foreach ($this->_references as $key => $relation) {
if ( ! $relation instanceof Doctrine_Null) {
......@@ -1195,21 +1197,59 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count
}
}
}
return array_merge($a, $this->_values);
}
public function fromArray($array)
/**
* merge
*
* merges this record with an array of values
* or with another existing instance of this object
*
* @param mixed $data Data to merge. Either another instance of this model or an array
* @param bool $deep Bool value for whether or not to merge the data deep
* @return void
*/
public function merge($data, $deep = true)
{
if ($data instanceof $this) {
$array = $data->toArray($deep);
} else if (is_array($data)) {
$array = $data;
}
return $this->fromArray($array, $deep);
}
/**
* fromArray
*
* @param string $array
* @param bool $deep Bool value for whether or not to merge the data deep
* @return void
*/
public function fromArray($array, $deep = true)
{
if (is_array($array)) {
foreach ($array as $key => $value) {
if ($this->getTable()->hasRelation($key)) {
$this->$key->fromArray($value);
if ($this->getTable()->hasRelation($key) && $deep) {
$this->$key->fromArray($value, $deep);
} else if($this->getTable()->hasColumn($key)) {
$this->set($key, $value);
}
}
}
}
public function exportTo($type, $deep = false)
/**
* exportTo
*
* @param string $type
* @param string $deep
* @return void
*/
public function exportTo($type, $deep = true)
{
if ($type == 'array') {
return $this->toArray($deep);
......@@ -1217,6 +1257,15 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count
return Doctrine_Parser::dump($this->toArray($deep, true), $type);
}
}
/**
* importFrom
*
* @param string $type
* @param string $data
* @return void
* @author Jonathan H. Wage
*/
public function importFrom($type, $data)
{
if ($type == 'array') {
......@@ -1294,12 +1343,8 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count
*
* @return Doctrine_Record
*/
public function copy($deep = false)
public function copy($deep = true)
{
if ($deep) {
return $this->copyDeep();
}
$data = $this->_data;
if ($this->_table->getIdentifierType() === Doctrine::IDENTIFIER_AUTOINC) {
......@@ -1317,28 +1362,19 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count
}
}
return $ret;
}
/**
* copyDeep
* returns a copy of this object and all its related objects
*
* @return Doctrine_Record
*/
public function copyDeep() {
$copy = $this->copy();
if ($deep) {
foreach ($this->_references as $key => $value) {
if ($value instanceof Doctrine_Collection) {
foreach ($value as $record) {
$copy->{$key}[] = $record->copyDeep();
$rt->{$key}[] = $record->copy($deep);
}
} else {
$copy->set($key, $value->copyDeep());
$rt->set($key, $value->copy($deep));
}
}
}
return $copy;
return $ret;
}
/**
......@@ -1476,66 +1512,6 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count
$this->_references[$name] = $rel->fetchRelatedFor($this);
}
/**
* merge
* merges this record with an array of values
*
* @param array $values
* @return void
*/
public function merge(array $values)
{
foreach ($this->_table->getFieldNames() as $fieldName) {
try {
if (isset($values[$fieldName])) {
$this->set($fieldName, $values[$fieldName]);
}
} catch (Doctrine_Exception $e) {
// silence all exceptions
}
}
}
/**
* mergeDeep
* merges this record with an array of values
*
* @pre it is expected that the array keys representing a hasMany
* relationship are the keyColumn set with INDEXBY
*
* @param array $values
* @param $rmFromCollection if some records are not found in the array,
* they are removed from the collection<->relation
* @return void
*/
public function mergeDeep(array $values, $rmFromCollection = false)
{
$this->merge($values);
foreach ($values as $rel_name => $rel_data) {
if ($this->getTable()->hasRelation($rel_name)) {
$rel = $this->get($rel_name);
if ($rel instanceof Doctrine_Collection) {
foreach ($rel as $key => $record) {
if (isset($rel_data[$key])) {
$record->mergeDeep($rel_data[$key], $rmFromCollection);
unset($rel_data[$key]);
} elseif ($rmFromCollection) {
$rel->remove($key);
}
}
foreach ($rel_data as $key => $new_data) {
$new_record = $rel->getTable()->create();
$new_record->mergeDeep($new_data);
$rel->add($new_record, $key);
}
} else {
$rel->mergeDeep($rel_data);
}
}
}
}
/**
* call
*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment