Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Init models in constructor with shells #572

Closed
wants to merge 1 commit into from

4 participants

@shama

This commit will initialize models set by $uses in the __construct() in shells. Currently you must call initialize() in order to use models in a shell.

I did not find any test cases nor tickets directly showing the current behavior is the desired behavior. The docs indicate this change is the desired behavior. Thus I assume the current behavior is incorrect and this commit will fix it.

@rchavik
Collaborator

Rather than loading them immediately, perhaps we could implement lazy loading in Shells ala Controllers etc ?

@shama

@rchavik That is a better idea :)
Would that make this a 2.2 change? As loadModel() and $modelClass would be added to Shell?

@markstory
Owner

I don't see where in the shell docs it says the models will be initialized in the constructor. However, I do think that having a constructor create a complete object without the need for additional callbacks is a good change.

@shama

Pull request updated: models are now lazily loaded in shells. Doesn't break BC. Unsure if this is a feature or a fix. Just let me know if it should go into 2.2 instead.

@lorenzo
Owner

@shama any chance you can rebase this for 2.4?

@shama shama referenced this pull request
Merged

Lazy load models in shells #1147

@shama

New PR rebased against 2.4 here: #1147 Thanks @lorenzo!

@shama shama closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 20, 2012
  1. @shama

    Lazy load models in shells

    shama authored
This page is out of date. Refresh to see the latest.
Showing with 90 additions and 21 deletions.
  1. +64 −21 lib/Cake/Console/Shell.php
  2. +26 −0 lib/Cake/Test/Case/Console/ShellTest.php
View
85 lib/Cake/Console/Shell.php
@@ -111,6 +111,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.
*
* @var TaskCollection
@@ -176,8 +183,10 @@ public function __construct($stdout = null, $stderr = null, $stdin = null) {
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);
+ list($plugin, $modelClass) = pluginSplit($this->uses[0], true);
+ $this->modelClass = $modelClass;
}
}
@@ -222,38 +231,72 @@ protected function _welcome() {
}
/**
- * 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 ($this->uses === null || $this->uses === false) {
- return;
- }
- App::uses('ClassRegistry', 'Utility');
-
- if ($this->uses !== true && !empty($this->uses)) {
- $uses = is_array($this->uses) ? $this->uses : array($this->uses);
-
- $modelClassName = $uses[0];
- if (strpos($uses[0], '.') !== false) {
- list($plugin, $modelClassName) = explode('.', $uses[0]);
+ if (is_array($this->uses)) {
+ $this->modelClass = null;
+ foreach ($this->uses as $modelClass) {
+ $this->loadModel($modelClass);
}
- $this->modelClass = $modelClassName;
+ return true;
+ }
+ return false;
+ }
- foreach ($uses as $modelClass) {
- list($plugin, $modelClass) = pluginSplit($modelClass, true);
- $this->{$modelClass} = ClassRegistry::init($plugin . $modelClass);
+/**
+ * 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($plugin, $class) = pluginSplit($modelClass, true);
+ if ($name === $class) {
+ return $this->loadModel($modelClass);
+ }
}
- return true;
}
return false;
}
/**
+ * 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) {
+ return false;
+ }
+
+ $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;
+ }
+
+/**
* Loads tasks defined in public $tasks
*
* @return boolean
View
26 lib/Cake/Test/Case/Console/ShellTest.php
@@ -195,6 +195,32 @@ public function testInitialize() {
}
/**
+ * 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
*
* @return void
Something went wrong with that request. Please try again.