View Source

<p>So, now you have seen how to add commands to the zf tooling system. But what if you want to interact with a &quot;Project&quot;. I guess the bigger question is, what is a &quot;Project&quot;? In general, a &quot;project&quot; is a planned endeavor or an initiative. In the computer world, projects generally are a collection of resources. These resources can be files, directories, databases, schemas, images, styles, and more. </p>

<p>This same concept applies to Zend Framework projects. In ZF projects, you have controllers, actions, views, databases and so on and so forth. In terms of Zend_Tool, we need a way to track these types of resources - thus Zend_Tool_Project.</p>

<p>Zend_Tool_Project is capable of tracking project resources throughout the development of a project. So, for example, if in one command you created a controller, and in the next command you wish to create an action within that controller, Zend_Tool_Project is gonna have to <strong>know</strong> about the controller file you created so that you can (in the next action), be able to append that action to it. This is what keeps our projects up to date and <strong>stateful</strong>.</p>

<p>Another important point to understand about projects is that typically, resources are organized in a hierarchical fashion. With that in mind, Zend_Tool_Project is capable of serializing the current project into a internal representation that allows it to keep track of not only <strong>what</strong> resources are part of a project at any given time, but also <strong>where</strong> they are in relation to one another.</p>

<p>So, with that out of the way, lets get to the code. In the below example, we will create a provider that will expose a command called &quot;create mymodel&quot; which will be a very simple model in our existing project.</p>

<p>As you might recall from Part 1, we first need to create a provider which we will name &quot;My_ModelProvider&quot;. At this point, since our new provider will be Zend_Tool_Project specific, we will extend Zend_Tool_Project's special Provider Abstract. By extending this special provider abstract, we not only are implementing the Zend_Tool_Framework_Provider_Interface, but we are also gaining some common functionality for &quot;Projects&quot; that we will need.</p>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
class My_ModelProvider implements Zend_Tool_Project_Provider_Abstract
{

public function create($modelname = "Model")
{

}

}
]]></ac:plain-text-body></ac:macro>

<p>As you can see, this is all we need to have in order to expose a &quot;create&quot; method for our &quot;model&quot; provider. (Remember, this file will have to exist inside your include_path, at the location My/ModelProvider.php to be found by the Zend_Tool system.)</p>

<p>At this point we have a provider that can be dispatched and essentially won't do much of anything useful as you can see by the empty method body for create. Our next step is to provide that method body which will include some of our own custom logic as well as some logical that is specific to how <strong>new resources are integrated with existing projects</strong>.</p>

<p>Now is a good time to understand how projects are stored with respect to Zend_Tool_Project. To gain this insight, lets go back to our article on &lt;a href=&quot;&quot;&gt;getting started with Zend_Tool&lt;/a&gt;. After the step in that article where we have run &quot;zf create project&quot;, lets have a look at the hidden file that was created. It can be found inside the project directory with a name of &quot;.zfproject.xml&quot;. It should look like this:</p>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
<?xml version="1.0"?>
<projectProfile>
<projectDirectory>
<projectProfileFile/>
<applicationDirectory>
<apisDirectory enabled="false"/>
<configsDirectory/>
<controllersDirectory>
<controllerFile controllerName="index"/>
<controllerFile controllerName="error"/>
</controllersDirectory>
<layoutsDirectory enabled="false"/>
<modelsDirectory/>
<modulesDirectory enabled="false"/>
<viewsDirectory>
<viewScriptsDirectory>
<viewControllerScriptsDirectory forControllerName="index">
<viewScriptFile scriptName="index"/>
</viewControllerScriptsDirectory>
<viewControllerScriptsDirectory forControllerName="error">
<viewScriptFile scriptName="error"/>
</viewControllerScriptsDirectory>
</viewScriptsDirectory>
<viewHelpersDirectory/>
<viewFiltersDirectory enabled="false"/>
</viewsDirectory>
<bootstrapFile/>
</applicationDirectory>
<dataDirectory enabled="false">
<cacheDirectory enabled="false"/>
<searchIndexesDirectory enabled="false"/>
<localesDirectory enabled="false"/>
<logsDirectory enabled="false"/>
<sessionsDirectory enabled="false"/>
<uploadsDirectory enabled="false"/>
</dataDirectory>
<libraryDirectory>
<zfStandardLibraryDirectory/>
</libraryDirectory>
<publicDirectory>
<publicStylesheetsDirectory enabled="false"/>
<publicScriptsDirectory enabled="false"/>
<publicImagesDirectory enabled="false"/>
<publicIndexFile/>
<htaccessFile/>
</publicDirectory>
<providersDirectory enabled="false"/>
</projectDirectory>
</projectProfile>
]]></ac:plain-text-body></ac:macro>

<p>This file represents how Zend_Tool_Project manages resources in a hierarchical fashion. For the purposes of our example, we want to be able to add our new &quot;Models&quot; into the &quot;ModelsDirectory&quot; of this project. In addition, we want to make sure that our project understands the context of these new resources. What is meant by &quot;context&quot; is so that our project understands what &quot;role&quot; this new resources plays within our project. For example, first and foremost, our &quot;Model&quot; resource is a file, so the project knows that this can be written to disk when asked to. Also, it understand that its a &quot;Model&quot; resource, and can have some custom logic assigned to it so that is <strong>acts</strong> like a Model with respect to other resources.</p>

<p>To be able to assign a context to these resources when they are created, we will also need to create a context class that we can use.</p>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
<?php

require_once 'Zend/Tool/Project/Context/Filesystem/Directory.php';

class Example_MyModelFileContext extends Zend_Tool_Project_Context_Filesystem_File
{
// proteted property to hold the actual models name
protected $_modelName = null;

// this is the name of the context (you will see this written as the node name of the project file)
public function getName()
{
return 'ModelFile';
}

// anything returned here will be "Attributes" of the context and persisted throughout all project interactions
public function getPersistentParameters()
{
return array('modelName' => $this->_modelName);
}

// this is an accessor for setting the modelName
public function setModelName($modelName)
{
$this->_modelName = $modelName;
$this->_filesystemName = $modelName . '.php';
}

// this is an accessor for getting the modelname
public function getModelName()
{
return $this->_modelName;
}

}
]]></ac:plain-text-body></ac:macro>

<p>Now that we have a context, we can start interacting with our project when our create method is called. Lets walk through the code sample below line by line (there will be comments before each line).</p>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
class My_ModelProvider implements Zend_Tool_Project_Provider_Abstract
{

public function create($modelname = "Model")
{

// find where we need to write these new model files
// a graph is the serialized structure as objects
$projectGraph = $this->_loadProjectProfile();

// Now, lets create a new node within our project that will be defined
// by the context we created previously under the existing 'modelsDirectory'
try {
$modelFileNode = $this->_createNodeUnder('modelsDirectory');
} catch (Exception $e) {
throw new Zend_Tool_Framework_Exception('This project doesnt have a models directory');
}

// lets give our new model its name provided by the caller.
$modelFileNode->setModelName($modelname);

echo 'Creating model file for ' . $modelName . PHP_EOL;
$modelFileNode->create();

// call out to our local method for putting "code" into our new model file within
// our project
$this->_createMyModelContents($modelFileNode->getPath(), $modelname);

$this->_storeProfile();
}

protected function _createMyModelContents($path, $modelName)
{
$contents = <<<EOS
class {$modelName}
{

protected \$_data = null;

public function setData(\$data)
{
\$this->_data = \$data;
return \$this;
}

public function getData()
{
return \$this->_data;
}

}

EOS;

file_put_contents($path, $contents);

}

}
]]></ac:plain-text-body></ac:macro>

<p>Now that we have those two file in place, its just a matter or running the command:</p>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
zf create model --modelname Foo
]]></ac:plain-text-body></ac:macro>

<p>And there you go, now you have created both a provider and a project context so that you can add custom resources to an existing project!</p>