Implemented the ModelBuild command

This commit is contained in:
Kévin Gomez 2013-10-31 21:05:29 +00:00
parent fbd439ff01
commit 88b2863fad
2 changed files with 267 additions and 1 deletions

View file

@ -19,6 +19,9 @@ use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
use Symfony\Component\HttpKernel\KernelInterface;
/**
@ -31,6 +34,11 @@ abstract class AbstractCommand extends ContainerAwareCommand
*/
protected $cacheDir = null;
/**
* @var Symfony\Component\HttpKernel\Bundle\BundleInterface
*/
protected $bundle = null;
/**
* {@inheritdoc}
*/
@ -64,6 +72,23 @@ abstract class AbstractCommand extends ContainerAwareCommand
return $this->runCommand($command, $params, $input, $output);
}
/**
* {@inheritdoc}
*/
protected function initialize(InputInterface $input, OutputInterface $output)
{
parent::initialize($input, $output);
$this->checkConfiguration();
if ($input->hasArgument('bundle') && '@' === substr($input->getArgument('bundle'), 0, 1)) {
$this->bundle = $this
->getContainer()
->get('kernel')
->getBundle(substr($input->getArgument('bundle'), 1));
}
}
protected function runCommand(Command $command, array $parameters, InputInterface $input, OutputInterface $output)
{
array_unshift($parameters, $this->getName());
@ -94,12 +119,126 @@ abstract class AbstractCommand extends ContainerAwareCommand
$fs->mkdir($this->cacheDir);
// collect all schemas
//$this->copySchemas($kernel, $this->cacheDir);
$this->copySchemas($kernel, $this->cacheDir);
// build.properties
$this->createBuildPropertiesFile($kernel, $this->cacheDir.'/build.properties');
}
/**
* @param KernelInterface $kernel The application kernel.
*/
protected function copySchemas(KernelInterface $kernel, $cacheDir)
{
$filesystem = new Filesystem();
if (!is_dir($cacheDir)) {
$filesystem->mkdir($cacheDir);
}
$base = ltrim(realpath($kernel->getRootDir().'/..'), DIRECTORY_SEPARATOR);
$finalSchemas = $this->getFinalSchemas($kernel, $this->bundle);
foreach ($finalSchemas as $schema) {
list($bundle, $finalSchema) = $schema;
$packagePrefix = $this->getPackagePrefix($bundle, $base);
$tempSchema = $bundle->getName().'-'.$finalSchema->getBaseName();
$this->tempSchemas[$tempSchema] = array(
'bundle' => $bundle->getName(),
'basename' => $finalSchema->getBaseName(),
'path' => $finalSchema->getPathname(),
);
$file = $cacheDir.DIRECTORY_SEPARATOR.$tempSchema;
$filesystem->copy((string) $finalSchema, $file, true);
// the package needs to be set absolute
// besides, the automated namespace to package conversion has
// not taken place yet so it needs to be done manually
$database = simplexml_load_file($file);
if (isset($database['package'])) {
// Do not use the prefix!
// This is used to override the package resulting from namespace conversion.
$database['package'] = $database['package'];
} elseif (isset($database['namespace'])) {
$database['package'] = $packagePrefix . str_replace('\\', '.', $database['namespace']);
} else {
throw new \RuntimeException(
sprintf('%s : Please define a `package` attribute or a `namespace` attribute for schema `%s`',
$bundle->getName(), $finalSchema->getBaseName())
);
}
// @todo
//if ($this->input && $this->input->hasOption('connection') && $this->input->getOption('connection')
// && $database['name'] != $this->input->getOption('connection')) {
// //we skip this schema because the connection name doesn't match the input value
// unset($this->tempSchemas[$tempSchema]);
// $filesystem->remove($file);
// continue;
//}
foreach ($database->table as $table) {
if (isset($table['package'])) {
$table['package'] = $table['package'];
} elseif (isset($table['namespace'])) {
$table['package'] = $packagePrefix . str_replace('\\', '.', $table['namespace']);
} else {
$table['package'] = $database['package'];
}
}
file_put_contents($file, $database->asXML());
}
}
/**
* Return a list of final schema files that will be processed.
*
* @param \Symfony\Component\HttpKernel\KernelInterface $kernel
*
* @return array
*/
protected function getFinalSchemas(KernelInterface $kernel, BundleInterface $bundle = null)
{
if (null !== $bundle) {
return $this->getSchemasFromBundle($bundle);
}
$finalSchemas = array();
foreach ($kernel->getBundles() as $bundle) {
$finalSchemas = array_merge($finalSchemas, $this->getSchemasFromBundle($bundle));
}
return $finalSchemas;
}
/**
* @param \Symfony\Component\HttpKernel\Bundle\BundleInterface
*/
protected function getSchemasFromBundle(BundleInterface $bundle)
{
$finalSchemas = array();
if (is_dir($dir = $bundle->getPath().'/Resources/config')) {
$finder = new Finder();
$schemas = $finder->files()->name('*schema.xml')->followLinks()->in($dir);
if (iterator_count($schemas)) {
foreach ($schemas as $schema) {
$logicalName = $this->transformToLogicalName($schema, $bundle);
$finalSchema = new \SplFileInfo($this->getFileLocator()->locate($logicalName));
$finalSchemas[(string) $finalSchema] = array($bundle, $finalSchema);
}
}
}
return $finalSchemas;
}
/**
* Translates a list of connection names to their DSN equivalents.
*
@ -145,4 +284,73 @@ abstract class AbstractCommand extends ContainerAwareCommand
$fs->touch($file);
}
}
/**
* @return \Symfony\Component\Config\FileLocatorInterface
*/
protected function getFileLocator()
{
return $this->getContainer()->get('file_locator');
}
/**
* @param \SplFileInfo $schema
* @param BundleInterface $bundle
* @return string
*/
protected function transformToLogicalName(\SplFileInfo $schema, BundleInterface $bundle)
{
$schemaPath = str_replace(
$bundle->getPath(). DIRECTORY_SEPARATOR . 'Resources' . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR,
'',
$schema->getRealPath()
);
return sprintf('@%s/Resources/config/%s', $bundle->getName(), $schemaPath);
}
/**
* Check the PropelConfiguration object.
*/
protected function checkConfiguration()
{
$parameters = $this->getContainer()->getParameter('propel.configuration');
if (0 === count($parameters)) {
throw new \RuntimeException('Propel should be configured (no database configuration found).');
}
}
/**
* Return the package prefix for a given bundle.
*
* @param Bundle $bundle
* @param string $baseDirectory The base directory to exclude from prefix.
*
* @return string
*/
protected function getPackagePrefix(Bundle $bundle, $baseDirectory = '')
{
$parts = explode(DIRECTORY_SEPARATOR, realpath($bundle->getPath()));
$length = count(explode('\\', $bundle->getNamespace())) * (-1);
$prefix = implode(DIRECTORY_SEPARATOR, array_slice($parts, 0, $length));
$prefix = ltrim(str_replace($baseDirectory, '', $prefix), DIRECTORY_SEPARATOR);
if (!empty($prefix)) {
$prefix = str_replace(DIRECTORY_SEPARATOR, '.', $prefix).'.';
}
return $prefix;
}
/**
* Return the current Propel cache directory.
*
* @return string The current Propel cache directory.
*/
protected function getCacheDir()
{
return $this->cacheDir;
}
}

View file

@ -0,0 +1,58 @@
<?php
/**
* This file is part of the PropelBundle package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
namespace Propel\PropelBundle\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* @author Kévin Gomez <contact@kevingomez.fr>
*/
class ModelBuildCommand extends AbstractCommand
{
/**
* {@inheritdoc}
*/
protected function configure()
{
parent::configure();
$this
->setName('propel:model:build')
->setDescription('Build the model classes based on Propel XML schemas')
->addArgument('bundle', InputArgument::OPTIONAL, 'The bundle to generate model classes from')
// @todo add the other arguments/options handled by the command
;
}
/**
* {@inheritdoc}
*/
protected function createSubCommandInstance()
{
return new \Propel\Generator\Command\SqlBuildCommand();
}
/**
* {@inheritdoc}
*/
protected function getSubCommandArguments(InputInterface $input)
{
$outputDir = realpath($this->getApplication()->getKernel()->getRootDir().'/../');
return array(
'--output-dir' => $outputDir,
);
}
}