From 85862bbb9f29f39345f748c40b8056786c437ed2 Mon Sep 17 00:00:00 2001 From: Kyle Robinson Young Date: Mon, 19 Mar 2012 23:52:01 -0700 Subject: [PATCH] Lazy load models in shells. --- lib/Cake/Console/Shell.php | 75 ++++++++++++++++++------ lib/Cake/Test/Case/Console/ShellTest.php | 26 ++++++++ 2 files changed, 84 insertions(+), 17 deletions(-) diff --git a/lib/Cake/Console/Shell.php b/lib/Cake/Console/Shell.php index f2d316489..fc1508bfc 100644 --- a/lib/Cake/Console/Shell.php +++ b/lib/Cake/Console/Shell.php @@ -119,6 +119,13 @@ class Shell extends Object { */ public $uses = array(); +/** + * This shell's primary model class name, the first model in the $uses property + * + * @var string + */ + public $modelClass = null; + /** * Task Collection for the command, used to create Tasks. * @@ -177,7 +184,7 @@ class Shell extends Object { if ($this->tasks !== null && $this->tasks !== false) { $this->_mergeVars(array('tasks'), $parent, true); } - if ($this->uses !== null && $this->uses !== false) { + if (!empty($this->uses)) { $this->_mergeVars(array('uses'), $parent, false); } } @@ -223,32 +230,66 @@ class Shell extends Object { } /** - * If $uses = true - * Loads AppModel file and constructs AppModel class - * makes $this->AppModel available to subclasses - * If public $uses is an array of models will load those models + * If $uses is an array load each of the models in the array * * @return boolean */ protected function _loadModels() { - if (empty($this->uses)) { - return false; + if (is_array($this->uses)) { + list(, $this->modelClass) = pluginSplit(current($this->uses)); + foreach ($this->uses as $modelClass) { + $this->loadModel($modelClass); + } } - App::uses('ClassRegistry', 'Utility'); + return true; + } - $uses = is_array($this->uses) ? $this->uses : array($this->uses); - - $modelClassName = $uses[0]; - if (strpos($uses[0], '.') !== false) { - list($plugin, $modelClassName) = explode('.', $uses[0]); +/** + * Lazy loads models using the loadModel() method if declared in $uses + * + * @param string $name + * @return void + */ + public function __isset($name) { + if (is_array($this->uses)) { + foreach ($this->uses as $modelClass) { + list(, $class) = pluginSplit($modelClass); + if ($name === $class) { + return $this->loadModel($modelClass); + } + } } - $this->modelClass = $modelClassName; + } - foreach ($uses as $modelClass) { - list($plugin, $modelClass) = pluginSplit($modelClass, true); - $this->{$modelClass} = ClassRegistry::init($plugin . $modelClass); +/** + * Loads and instantiates models required by this shell. + * + * @param string $modelClass Name of model class to load + * @param mixed $id Initial ID the instanced model class should have + * @return mixed true when single model found and instance created, error returned if model not found. + * @throws MissingModelException if the model class cannot be found. + */ + public function loadModel($modelClass = null, $id = null) { + if ($modelClass === null) { + $modelClass = $this->modelClass; } + $this->uses = ($this->uses) ? (array)$this->uses : array(); + if (!in_array($modelClass, $this->uses)) { + $this->uses[] = $modelClass; + } + + list($plugin, $modelClass) = pluginSplit($modelClass, true); + if (!isset($this->modelClass)) { + $this->modelClass = $modelClass; + } + + $this->{$modelClass} = ClassRegistry::init(array( + 'class' => $plugin . $modelClass, 'alias' => $modelClass, 'id' => $id + )); + if (!$this->{$modelClass}) { + throw new MissingModelException($modelClass); + } return true; } diff --git a/lib/Cake/Test/Case/Console/ShellTest.php b/lib/Cake/Test/Case/Console/ShellTest.php index a4741476b..9b063dc7d 100644 --- a/lib/Cake/Test/Case/Console/ShellTest.php +++ b/lib/Cake/Test/Case/Console/ShellTest.php @@ -212,6 +212,32 @@ class ShellTest extends CakeTestCase { App::build(); } +/** + * testLoadModel method + * + * @return void + */ + public function testLoadModel() { + App::build(array( + 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS), + 'Model' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Model' . DS) + ), App::RESET); + + $Shell = new TestMergeShell(); + $this->assertEquals('Comment', $Shell->Comment->alias); + $this->assertInstanceOf('Comment', $Shell->Comment); + $this->assertEquals('Comment', $Shell->modelClass); + + CakePlugin::load('TestPlugin'); + $this->Shell->loadModel('TestPlugin.TestPluginPost'); + $this->assertTrue(isset($this->Shell->TestPluginPost)); + $this->assertInstanceOf('TestPluginPost', $this->Shell->TestPluginPost); + $this->assertEquals('TestPluginPost', $this->Shell->modelClass); + CakePlugin::unload('TestPlugin'); + + App::build(); + } + /** * testIn method *