Compare commits
No commits in common. "1.2.1" and "4.0" have entirely different histories.
14
.gitignore
vendored
14
.gitignore
vendored
|
@ -1,5 +1,9 @@
|
||||||
Model/*/map
|
# Propel2 generated base classes, those are environment dependent
|
||||||
Model/*/om
|
/Model/Base
|
||||||
vendor
|
/Model/Map
|
||||||
composer.lock
|
/Model/**/Base
|
||||||
composer.phar
|
/Model/**/Map
|
||||||
|
|
||||||
|
# Composer
|
||||||
|
/vendor
|
||||||
|
/composer.lock
|
||||||
|
|
35
.travis.yml
35
.travis.yml
|
@ -1,16 +1,33 @@
|
||||||
|
sudo: false
|
||||||
|
|
||||||
language: php
|
language: php
|
||||||
|
|
||||||
php:
|
php:
|
||||||
- 5.3
|
- 7.0
|
||||||
- 5.4
|
- 7.1
|
||||||
- 5.5
|
- 7.2
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- $HOME/.composer/cache/files
|
||||||
|
|
||||||
|
env:
|
||||||
|
- SYMFONY_VERSION="^3.0"
|
||||||
|
- SYMFONY_VERSION="^4.0"
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
allow_failures:
|
fast_finish: true
|
||||||
- php: 5.5
|
|
||||||
|
|
||||||
before_script:
|
exclude:
|
||||||
- curl -s http://getcomposer.org/installer | php
|
- php: 7.0
|
||||||
- php composer.phar --dev install
|
env: SYMFONY_VERSION="^4.0"
|
||||||
|
|
||||||
script: phpunit --coverage-text
|
before_install:
|
||||||
|
- composer self-update
|
||||||
|
- if [ "${SYMFONY_VERSION}" != "" ]; then composer require --no-update "symfony/symfony:${SYMFONY_VERSION}"; fi;
|
||||||
|
|
||||||
|
install:
|
||||||
|
- composer update ${COMPOSER_FLAGS} --prefer-source
|
||||||
|
|
||||||
|
script:
|
||||||
|
- vendor/bin/phpunit --colors
|
||||||
|
|
|
@ -8,97 +8,55 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Command;
|
namespace Propel\Bundle\PropelBundle\Command;
|
||||||
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
|
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\ArrayInput;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
use Symfony\Component\Filesystem\Filesystem;
|
use Symfony\Component\Filesystem\Filesystem;
|
||||||
use Symfony\Component\Finder\Finder;
|
|
||||||
use Symfony\Component\HttpKernel\KernelInterface;
|
|
||||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||||
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
||||||
|
use Symfony\Component\HttpKernel\KernelInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for Propel commands.
|
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||||
*
|
|
||||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
|
||||||
* @author William DURAND <william.durand1@gmail.com>
|
|
||||||
*/
|
*/
|
||||||
abstract class AbstractCommand extends ContainerAwareCommand
|
abstract class AbstractCommand extends ContainerAwareCommand
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Additional Phing args to add in specialized commands.
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $additionalPhingArgs = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Temporary XML schemas used on command execution.
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $tempSchemas = array();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $cacheDir = null;
|
protected $cacheDir = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Phing output.
|
* @var \Symfony\Component\HttpKernel\Bundle\BundleInterface
|
||||||
* @string
|
|
||||||
*/
|
|
||||||
protected $buffer = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Symfony\Component\HttpKernel\Bundle\BundleInterface
|
|
||||||
*/
|
*/
|
||||||
protected $bundle = null;
|
protected $bundle = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Boolean
|
|
||||||
*/
|
|
||||||
private $alreadyWroteConnection = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @var InputInterface
|
* @var InputInterface
|
||||||
*/
|
*/
|
||||||
protected $input;
|
protected $input;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the package prefix for a given bundle.
|
* @var OutputInterface
|
||||||
*
|
|
||||||
* @param Bundle $bundle
|
|
||||||
* @param string $baseDirectory The base directory to exclude from prefix.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
protected function getPackagePrefix(Bundle $bundle, $baseDirectory = '')
|
protected $output;
|
||||||
{
|
|
||||||
$parts = explode(DIRECTORY_SEPARATOR, realpath($bundle->getPath()));
|
|
||||||
$length = count(explode('\\', $bundle->getNamespace())) * (-1);
|
|
||||||
|
|
||||||
$prefix = implode(DIRECTORY_SEPARATOR, array_slice($parts, 0, $length));
|
use FormattingHelpers;
|
||||||
$prefix = ltrim(str_replace($baseDirectory, '', $prefix), DIRECTORY_SEPARATOR);
|
|
||||||
|
|
||||||
if (!empty($prefix)) {
|
|
||||||
$prefix = str_replace(DIRECTORY_SEPARATOR, '.', $prefix).'.';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $prefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
protected function initialize(InputInterface $input, OutputInterface $output)
|
protected function initialize(InputInterface $input, OutputInterface $output)
|
||||||
{
|
{
|
||||||
parent::initialize($input, $output);
|
$kernel = $this->getApplication()->getKernel();
|
||||||
|
|
||||||
$this->input = $input;
|
$this->input = $input;
|
||||||
|
$this->output = $output;
|
||||||
$this->checkConfiguration();
|
$this->cacheDir = $kernel->getCacheDir().'/propel';
|
||||||
|
|
||||||
if ($input->hasArgument('bundle') && '@' === substr($input->getArgument('bundle'), 0, 1)) {
|
if ($input->hasArgument('bundle') && '@' === substr($input->getArgument('bundle'), 0, 1)) {
|
||||||
$this->bundle = $this
|
$this->bundle = $this
|
||||||
|
@ -109,112 +67,42 @@ abstract class AbstractCommand extends ContainerAwareCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call a Phing task.
|
* Create all the files needed by Propel's commands.
|
||||||
*
|
|
||||||
* @param string $taskName A Propel task name.
|
|
||||||
* @param array $properties An array of properties to pass to Phing.
|
|
||||||
*/
|
*/
|
||||||
protected function callPhing($taskName, $properties = array())
|
protected function setupBuildTimeFiles()
|
||||||
{
|
{
|
||||||
$kernel = $this->getApplication()->getKernel();
|
$kernel = $this->getApplication()->getKernel();
|
||||||
|
|
||||||
if (isset($properties['propel.schema.dir'])) {
|
$fs = new Filesystem();
|
||||||
$this->cacheDir = $properties['propel.schema.dir'];
|
$fs->mkdir($this->cacheDir);
|
||||||
} else {
|
|
||||||
$this->cacheDir = $kernel->getCacheDir().'/propel';
|
|
||||||
|
|
||||||
$filesystem = new Filesystem();
|
|
||||||
$filesystem->remove($this->cacheDir);
|
|
||||||
$filesystem->mkdir($this->cacheDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// collect all schemas
|
||||||
$this->copySchemas($kernel, $this->cacheDir);
|
$this->copySchemas($kernel, $this->cacheDir);
|
||||||
|
|
||||||
// build.properties
|
// propel.json
|
||||||
$this->createBuildPropertiesFile($kernel, $this->cacheDir.'/build.properties');
|
$this->createPropelConfigurationFile($this->cacheDir.'/propel.json');
|
||||||
|
|
||||||
// buildtime-conf.xml
|
|
||||||
$this->createBuildTimeFile($this->cacheDir.'/buildtime-conf.xml');
|
|
||||||
|
|
||||||
// Verbosity
|
|
||||||
$bufferPhingOutput = $this->getContainer()->getParameter('kernel.debug');
|
|
||||||
|
|
||||||
// Phing arguments
|
|
||||||
$args = $this->getPhingArguments($kernel, $this->cacheDir, $properties);
|
|
||||||
|
|
||||||
// Add any arbitrary arguments last
|
|
||||||
foreach ($this->additionalPhingArgs as $arg) {
|
|
||||||
if (in_array($arg, array('verbose', 'debug'))) {
|
|
||||||
$bufferPhingOutput = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$args[] = '-'.$arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
$args[] = $taskName;
|
|
||||||
|
|
||||||
// Enable output buffering
|
|
||||||
Phing::setOutputStream(new \OutputStream(fopen('php://output', 'w')));
|
|
||||||
Phing::setErrorStream(new \OutputStream(fopen('php://output', 'w')));
|
|
||||||
Phing::startup();
|
|
||||||
Phing::setProperty('phing.home', getenv('PHING_HOME'));
|
|
||||||
|
|
||||||
ob_start();
|
|
||||||
|
|
||||||
$phing = new Phing();
|
|
||||||
$returnStatus = true; // optimistic way
|
|
||||||
|
|
||||||
try {
|
|
||||||
$phing->execute($args);
|
|
||||||
$phing->runBuild();
|
|
||||||
|
|
||||||
$this->buffer = ob_get_contents();
|
|
||||||
|
|
||||||
// Guess errors
|
|
||||||
if (strstr($this->buffer, 'failed. Aborting.') ||
|
|
||||||
strstr($this->buffer, 'Failed to execute') ||
|
|
||||||
strstr($this->buffer, 'failed for the following reason:')) {
|
|
||||||
$returnStatus = false;
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$returnStatus = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($bufferPhingOutput) {
|
|
||||||
ob_end_clean();
|
|
||||||
} else {
|
|
||||||
ob_end_flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $returnStatus;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param KernelInterface $kernel The application kernel.
|
* @param KernelInterface $kernel The application kernel.
|
||||||
|
* @param string $cacheDir The directory in which the schemas will
|
||||||
|
* be copied.
|
||||||
*/
|
*/
|
||||||
protected function copySchemas(KernelInterface $kernel, $cacheDir)
|
protected function copySchemas(KernelInterface $kernel, $cacheDir)
|
||||||
{
|
{
|
||||||
$filesystem = new Filesystem();
|
$filesystem = new Filesystem();
|
||||||
|
|
||||||
if (!is_dir($cacheDir)) {
|
|
||||||
$filesystem->mkdir($cacheDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
$base = ltrim(realpath($kernel->getRootDir().'/..'), DIRECTORY_SEPARATOR);
|
|
||||||
|
|
||||||
$finalSchemas = $this->getFinalSchemas($kernel, $this->bundle);
|
$finalSchemas = $this->getFinalSchemas($kernel, $this->bundle);
|
||||||
foreach ($finalSchemas as $schema) {
|
foreach ($finalSchemas as $schema) {
|
||||||
|
/** @var null|Bundle $bundle */
|
||||||
list($bundle, $finalSchema) = $schema;
|
list($bundle, $finalSchema) = $schema;
|
||||||
$packagePrefix = $this->getPackagePrefix($bundle, $base);
|
|
||||||
|
|
||||||
$tempSchema = $bundle->getName().'-'.$finalSchema->getBaseName();
|
if ($bundle) {
|
||||||
$this->tempSchemas[$tempSchema] = array(
|
$file = $cacheDir.DIRECTORY_SEPARATOR.'bundle-'.$bundle->getName().'-'.$finalSchema->getBaseName();
|
||||||
'bundle' => $bundle->getName(),
|
} else {
|
||||||
'basename' => $finalSchema->getBaseName(),
|
$file = $cacheDir.DIRECTORY_SEPARATOR.'app-'.$finalSchema->getBaseName();
|
||||||
'path' => $finalSchema->getPathname(),
|
}
|
||||||
);
|
|
||||||
|
|
||||||
$file = $cacheDir.DIRECTORY_SEPARATOR.$tempSchema;
|
|
||||||
$filesystem->copy((string) $finalSchema, $file, true);
|
$filesystem->copy((string) $finalSchema, $file, true);
|
||||||
|
|
||||||
// the package needs to be set absolute
|
// the package needs to be set absolute
|
||||||
|
@ -227,27 +115,47 @@ abstract class AbstractCommand extends ContainerAwareCommand
|
||||||
// This is used to override the package resulting from namespace conversion.
|
// This is used to override the package resulting from namespace conversion.
|
||||||
$database['package'] = $database['package'];
|
$database['package'] = $database['package'];
|
||||||
} elseif (isset($database['namespace'])) {
|
} elseif (isset($database['namespace'])) {
|
||||||
$database['package'] = $packagePrefix . str_replace('\\', '.', $database['namespace']);
|
if ($bundle) {
|
||||||
|
$database['package'] = $this->getPackageFromBundle($bundle, (string)$database['namespace']);
|
||||||
|
} else {
|
||||||
|
$database['package'] = $this->getPackageFromApp((string)$database['namespace']);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new \RuntimeException(
|
throw new \RuntimeException(
|
||||||
sprintf('%s : Please define a `package` attribute or a `namespace` attribute for schema `%s`',
|
sprintf(
|
||||||
$bundle->getName(), $finalSchema->getBaseName())
|
'%s : Please define a `package` attribute or a `namespace` attribute for schema `%s`',
|
||||||
|
$bundle ? $bundle->getName() : 'App',
|
||||||
|
$finalSchema->getBaseName()
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->input && $this->input->hasOption('connection') && $this->input->getOption('connection')
|
if ($this->input->hasOption('connection')) {
|
||||||
&& $database['name'] != $this->input->getOption('connection')) {
|
$connections = $this->input->getOption('connection') ?: array($this->getDefaultConnection());
|
||||||
//we skip this schema because the connection name doesn't match the input value
|
|
||||||
unset($this->tempSchemas[$tempSchema]);
|
if (!in_array((string) $database['name'], $connections)) {
|
||||||
$filesystem->remove($file);
|
// we skip this schema because the connection name doesn't
|
||||||
continue;
|
// match the input values
|
||||||
|
$filesystem->remove($file);
|
||||||
|
$this->output->writeln(sprintf(
|
||||||
|
'<info>Skipped schema %s due to database name missmatch (%s not in [%s]).</info>',
|
||||||
|
$finalSchema->getPathname(),
|
||||||
|
$database['name'],
|
||||||
|
implode(',', $connections)
|
||||||
|
));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($database->table as $table) {
|
foreach ($database->table as $table) {
|
||||||
if (isset($table['package'])) {
|
if (isset($table['package'])) {
|
||||||
$table['package'] = $table['package'];
|
$table['package'] = $table['package'];
|
||||||
} elseif (isset($table['namespace'])) {
|
} elseif (isset($table['namespace'])) {
|
||||||
$table['package'] = $packagePrefix . str_replace('\\', '.', $table['namespace']);
|
if ($bundle) {
|
||||||
|
$table['package'] = $this->getPackageFromBundle($bundle, (string)$table['namespace']);
|
||||||
|
} else {
|
||||||
|
$table['package'] = $this->getPackageFromApp((string)$table['namespace']);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$table['package'] = $database['package'];
|
$table['package'] = $database['package'];
|
||||||
}
|
}
|
||||||
|
@ -260,167 +168,204 @@ abstract class AbstractCommand extends ContainerAwareCommand
|
||||||
/**
|
/**
|
||||||
* Return a list of final schema files that will be processed.
|
* Return a list of final schema files that will be processed.
|
||||||
*
|
*
|
||||||
* @param \Symfony\Component\HttpKernel\KernelInterface $kernel
|
* @param KernelInterface $kernel The application kernel.
|
||||||
|
* @param BundleInterface $bundle If given, only the bundle's schemas will
|
||||||
|
* be returned.
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array A list of schemas.
|
||||||
*/
|
*/
|
||||||
protected function getFinalSchemas(KernelInterface $kernel, BundleInterface $bundle = null)
|
protected function getFinalSchemas(KernelInterface $kernel, BundleInterface $bundle = null)
|
||||||
{
|
{
|
||||||
if (null !== $bundle) {
|
if (null !== $bundle) {
|
||||||
return $this->getSchemasFromBundle($bundle);
|
return $this->getSchemaLocator()->locateFromBundle($bundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
$finalSchemas = array();
|
return $this->getSchemaLocator()->locateFromBundlesAndConfiguration($kernel->getBundles());
|
||||||
foreach ($kernel->getBundles() as $bundle) {
|
|
||||||
$finalSchemas = array_merge($finalSchemas, $this->getSchemasFromBundle($bundle));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $finalSchemas;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \Symfony\Component\HttpKernel\Bundle\BundleInterface
|
* Run a Symfony command.
|
||||||
|
*
|
||||||
|
* @param Command $command The command to run.
|
||||||
|
* @param array $parameters An array of parameters to give to the command.
|
||||||
|
* @param InputInterface $input An InputInterface instance
|
||||||
|
* @param OutputInterface $output An OutputInterface instance
|
||||||
|
*
|
||||||
|
* @return int The command return code.
|
||||||
*/
|
*/
|
||||||
protected function getSchemasFromBundle(BundleInterface $bundle)
|
protected function runCommand(Command $command, array $parameters, InputInterface $input, OutputInterface $output)
|
||||||
{
|
{
|
||||||
$finalSchemas = array();
|
// add the command's name to the parameters
|
||||||
|
array_unshift($parameters, $this->getName());
|
||||||
|
|
||||||
if (is_dir($dir = $bundle->getPath().'/Resources/config')) {
|
// merge the default parameters
|
||||||
$finder = new Finder();
|
$extraParameters = [
|
||||||
$schemas = $finder->files()->name('*schema.xml')->followLinks()->in($dir);
|
'--verbose' => $input->getOption('verbose')
|
||||||
|
];
|
||||||
|
|
||||||
if (iterator_count($schemas)) {
|
if ($command->getDefinition()->hasOption('schema-dir')) {
|
||||||
foreach ($schemas as $schema) {
|
$extraParameters['--schema-dir'] = $this->cacheDir;
|
||||||
$logicalName = $this->transformToLogicalName($schema, $bundle);
|
}
|
||||||
$finalSchema = new \SplFileInfo($this->getFileLocator()->locate($logicalName));
|
|
||||||
|
|
||||||
$finalSchemas[(string) $finalSchema] = array($bundle, $finalSchema);
|
if ($command->getDefinition()->hasOption('config-dir')) {
|
||||||
}
|
$extraParameters['--config-dir'] = $this->cacheDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parameters = array_merge($extraParameters, $parameters);
|
||||||
|
|
||||||
|
if ($input->hasOption('platform')) {
|
||||||
|
if ($platform = $input->getOption('platform') ?: $this->getPlatform()) {
|
||||||
|
$parameters['--platform'] = $platform;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $finalSchemas;
|
$command->setApplication($this->getApplication());
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// and run the sub-command
|
||||||
* @param \SplFileInfo $file
|
return $command->run(new ArrayInput($parameters), $output);
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function getRelativeFileName(\SplFileInfo $file)
|
|
||||||
{
|
|
||||||
return substr(str_replace(realpath($this->getContainer()->getParameter('kernel.root_dir') . '/../'), '', $file), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a 'build.properties' file.
|
|
||||||
*
|
|
||||||
* @param KernelInterface $kernel The application kernel.
|
|
||||||
* @param string $file Should be 'build.properties'.
|
|
||||||
*/
|
|
||||||
protected function createBuildPropertiesFile(KernelInterface $kernel, $file)
|
|
||||||
{
|
|
||||||
$filesystem = new Filesystem();
|
|
||||||
$buildPropertiesFile = $kernel->getRootDir().'/config/propel.ini';
|
|
||||||
|
|
||||||
if (file_exists($buildPropertiesFile)) {
|
|
||||||
$filesystem->copy($buildPropertiesFile, $file);
|
|
||||||
} else {
|
|
||||||
$filesystem->touch($file);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an XML file which represents propel.configuration
|
* Create an XML file which represents propel.configuration
|
||||||
*
|
*
|
||||||
* @param string $file Should be 'buildtime-conf.xml'.
|
* @param string $file Should be 'propel.json'.
|
||||||
*/
|
*/
|
||||||
protected function createBuildTimeFile($file)
|
protected function createPropelConfigurationFile($file)
|
||||||
{
|
{
|
||||||
$container = $this->getContainer();
|
$propelConfig = $this->getContainer()->getParameter('propel.configuration');
|
||||||
|
|
||||||
if (!$container->has('propel.configuration')) {
|
//needed because because Propel2's configuration tree is a bit different
|
||||||
throw new \InvalidArgumentException('Could not find Propel configuration.');
|
//propel.runtime.logging is PropelBundle feature only.
|
||||||
}
|
unset($propelConfig['runtime']['logging']);
|
||||||
|
|
||||||
$xml = strtr(<<<EOT
|
$config = array(
|
||||||
<?xml version="1.0"?>
|
'propel' => $propelConfig
|
||||||
<config>
|
);
|
||||||
<propel>
|
|
||||||
<datasources default="%default_connection%">
|
|
||||||
|
|
||||||
EOT
|
file_put_contents($file, json_encode($config, JSON_PRETTY_PRINT));
|
||||||
, array('%default_connection%' => $container->getParameter('propel.dbal.default_connection')));
|
|
||||||
|
|
||||||
$propelConfiguration = $container->get('propel.configuration');
|
|
||||||
foreach ($propelConfiguration['datasources'] as $name => $datasource) {
|
|
||||||
$xml .= strtr(<<<EOT
|
|
||||||
<datasource id="%name%">
|
|
||||||
<adapter>%adapter%</adapter>
|
|
||||||
<connection>
|
|
||||||
<dsn>%dsn%</dsn>
|
|
||||||
<user>%username%</user>
|
|
||||||
<password>%password%</password>
|
|
||||||
</connection>
|
|
||||||
</datasource>
|
|
||||||
|
|
||||||
EOT
|
|
||||||
, array(
|
|
||||||
'%name%' => $name,
|
|
||||||
'%adapter%' => $datasource['adapter'],
|
|
||||||
'%dsn%' => $datasource['connection']['dsn'],
|
|
||||||
'%username%' => $datasource['connection']['user'],
|
|
||||||
'%password%' => isset($datasource['connection']['password']) ? $datasource['connection']['password'] : '',
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
$xml .= <<<EOT
|
|
||||||
</datasources>
|
|
||||||
</propel>
|
|
||||||
</config>
|
|
||||||
EOT;
|
|
||||||
|
|
||||||
file_put_contents($file, $xml);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an array of properties as key/value pairs from an input file.
|
* Translates a list of connection names to their DSN equivalents.
|
||||||
*
|
*
|
||||||
* @param string $file A file properties.
|
* @param array $connections The names.
|
||||||
* @return array An array of properties as key/value pairs.
|
*
|
||||||
|
* @return array
|
||||||
*/
|
*/
|
||||||
protected function getProperties($file)
|
protected function getConnections(array $connections)
|
||||||
{
|
{
|
||||||
$properties = array();
|
$dsnList = array();
|
||||||
|
foreach ($connections as $connection) {
|
||||||
if (false === $lines = @file($file)) {
|
$dsnList[] = sprintf('%s=%s', $connection, $this->getDsn($connection));
|
||||||
throw new \Exception(sprintf('Unable to parse contents of "%s".', $file));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($lines as $line) {
|
return $dsnList;
|
||||||
$line = trim($line);
|
}
|
||||||
|
|
||||||
if ('' == $line || in_array($line[0], array('#', ';'))) {
|
/**
|
||||||
continue;
|
* Get the data (host, user, ...) for a given connection.
|
||||||
}
|
*
|
||||||
|
* @param string $name The connection name.
|
||||||
$pos = strpos($line, '=');
|
*
|
||||||
$property = trim(substr($line, 0, $pos));
|
* @return array The connection data.
|
||||||
$value = trim(substr($line, $pos + 1));
|
*/
|
||||||
|
protected function getConnectionData($name)
|
||||||
if ("true" === $value) {
|
{
|
||||||
$value = true;
|
$knownConnections = $this->getContainer()->getParameter('propel.configuration');
|
||||||
} elseif ("false" === $value) {
|
if (!isset($knownConnections['database']['connections'][$name])) {
|
||||||
$value = false;
|
throw new \InvalidArgumentException(sprintf('Unknown connection "%s"', $name));
|
||||||
}
|
|
||||||
|
|
||||||
$properties[$property] = $value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $properties;
|
return $knownConnections['database']['connections'][$name];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the DSN for a given connection.
|
||||||
|
*
|
||||||
|
* @param string $connectionName The connection name.
|
||||||
|
*
|
||||||
|
* @return string The DSN.
|
||||||
|
*/
|
||||||
|
protected function getDsn($connectionName)
|
||||||
|
{
|
||||||
|
$connection = $this->getConnectionData($connectionName);
|
||||||
|
// Add user and password to dsn string
|
||||||
|
$dsn = explode(';', $connection['dsn']);
|
||||||
|
if (isset($connection['user'])) {
|
||||||
|
$dsn[] = 'user=' . urlencode($connection['user']);
|
||||||
|
}
|
||||||
|
if (isset($connection['password'])) {
|
||||||
|
$dsn[] = 'password=' . urlencode($connection['password']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode(';', $dsn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Symfony\Component\Config\FileLocatorInterface
|
||||||
|
*/
|
||||||
|
protected function getSchemaLocator()
|
||||||
|
{
|
||||||
|
return $this->getContainer()->get('propel.schema_locator');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $namespace
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function getPackageFromApp($namespace)
|
||||||
|
{
|
||||||
|
if ('\\' === $namespace[0]) {
|
||||||
|
$namespace = substr($namespace, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 === stripos($namespace, 'App\\')) {
|
||||||
|
$namespace = substr($namespace, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'src.'.str_replace('\\', '.', $namespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Bundle $bundle
|
||||||
|
* @param string $namespace
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function getPackageFromBundle(Bundle $bundle, $namespace)
|
||||||
|
{
|
||||||
|
//find relative path from namespace to bundle->getNamespace()
|
||||||
|
$baseNamespace = (new \ReflectionClass($bundle))->getNamespaceName();
|
||||||
|
if (0 === strpos($namespace, $baseNamespace)) {
|
||||||
|
//base namespace fits
|
||||||
|
//eg.
|
||||||
|
// Base: Jarves/JarvesBundle => Jarves
|
||||||
|
// Model namespace: Jarves\Model
|
||||||
|
// strpos(Jarves\Model, Jarves) === 0
|
||||||
|
// $namespaceDiff = Model
|
||||||
|
|
||||||
|
$namespaceDiff = substr($namespace, strlen($baseNamespace) + 1);
|
||||||
|
|
||||||
|
$bundlePath = realpath($bundle->getPath()) . '/' . str_replace('\\', '/', $namespaceDiff);
|
||||||
|
$appPath = realpath($this->getApplication()->getKernel()->getRootDir() . '/..');
|
||||||
|
|
||||||
|
$path = static::getRelativePath($bundlePath, $appPath);
|
||||||
|
|
||||||
|
return str_replace('/', '.', $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
//does not match or its a absolute path, so return it without suffix
|
||||||
|
if ('\\' === $namespace[0]) {
|
||||||
|
$namespace = substr($namespace, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str_replace('\\', '.', $namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the current Propel cache directory.
|
* Return the current Propel cache directory.
|
||||||
|
*
|
||||||
* @return string The current Propel cache directory.
|
* @return string The current Propel cache directory.
|
||||||
*/
|
*/
|
||||||
protected function getCacheDir()
|
protected function getCacheDir()
|
||||||
|
@ -429,47 +374,29 @@ EOT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \Symfony\Component\Config\FileLocatorInterface
|
* Returns a relative path from $path to $current.
|
||||||
*/
|
|
||||||
protected function getFileLocator()
|
|
||||||
{
|
|
||||||
return $this->getContainer()->get('file_locator');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get connection by checking the input option named 'connection'.
|
|
||||||
* Returns the default connection if no option specified or an exception
|
|
||||||
* if the specified connection doesn't exist.
|
|
||||||
*
|
*
|
||||||
* @param InputInterface $input
|
* @param string $from
|
||||||
* @param OutputInterface $output
|
* @param string $to relative to this
|
||||||
* @throw \InvalidArgumentException If the connection does not exist.
|
*
|
||||||
* @return array
|
* @return string relative path without trailing slash
|
||||||
*/
|
*/
|
||||||
protected function getConnection(InputInterface $input, OutputInterface $output)
|
public static function getRelativePath($from, $to)
|
||||||
{
|
{
|
||||||
$propelConfiguration = $this->getContainer()->get('propel.configuration');
|
$from = '/' . trim($from, '/');
|
||||||
$name = $input->getOption('connection') ?: $this->getContainer()->getParameter('propel.dbal.default_connection');
|
$to = '/' . trim($to, '/');
|
||||||
|
|
||||||
if (isset($propelConfiguration['datasources'][$name])) {
|
if (0 === $pos = strpos($from, $to)) {
|
||||||
$defaultConfig = $propelConfiguration['datasources'][$name];
|
return substr($from, strlen($to) + ('/' === $to ? 0 : 1));
|
||||||
} else {
|
|
||||||
throw new \InvalidArgumentException(sprintf('Connection named %s doesn\'t exist', $name));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (false === $this->alreadyWroteConnection) {
|
$result = '';
|
||||||
$output->writeln(sprintf('Use connection named <comment>%s</comment> in <comment>%s</comment> environment.',
|
while ($to && false === strpos($from, $to)) {
|
||||||
$name, $this->getApplication()->getKernel()->getEnvironment())
|
$result .= '../';
|
||||||
);
|
$to = substr($to, 0, strrpos($to, '/'));
|
||||||
$this->alreadyWroteConnection = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// prevent errors
|
return !$to /*we reached root*/ ? $result . substr($from, 1) : $result. substr($from, strlen($to) + 1);
|
||||||
if (!isset($defaultConfig['connection']['password'])) {
|
|
||||||
$defaultConfig['connection']['password'] = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return array($name, $defaultConfig);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -480,10 +407,10 @@ EOT;
|
||||||
*/
|
*/
|
||||||
protected function parseDbName($dsn)
|
protected function parseDbName($dsn)
|
||||||
{
|
{
|
||||||
preg_match('#dbname=([a-zA-Z0-9\_]+)#', $dsn, $matches);
|
preg_match('#(dbname|Database)=([a-zA-Z0-9\_]+)#', $dsn, $matches);
|
||||||
|
|
||||||
if (isset($matches[1])) {
|
if (isset($matches[2])) {
|
||||||
return $matches[1];
|
return $matches[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
// e.g. SQLite
|
// e.g. SQLite
|
||||||
|
@ -491,158 +418,37 @@ EOT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check the PropelConfiguration object.
|
* Returns the name of the migrations table.
|
||||||
*/
|
|
||||||
protected function checkConfiguration()
|
|
||||||
{
|
|
||||||
$parameters = $this->getContainer()->get('propel.configuration')->getParameters();
|
|
||||||
|
|
||||||
if (!isset($parameters['datasources']) || 0 === count($parameters['datasources'])) {
|
|
||||||
throw new \RuntimeException('Propel should be configured (no database configuration found).');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write Propel output as summary based on a Regexp.
|
|
||||||
*
|
*
|
||||||
* @param OutputInterface $output The output object.
|
|
||||||
* @param string $taskname A task name
|
|
||||||
*/
|
|
||||||
protected function writeSummary(OutputInterface $output, $taskname)
|
|
||||||
{
|
|
||||||
foreach (explode("\n", $this->buffer) as $line) {
|
|
||||||
if (false !== strpos($line, '[' . $taskname . ']')) {
|
|
||||||
$arr = preg_split('#\[' . $taskname . '\] #', $line);
|
|
||||||
$info = $arr[1];
|
|
||||||
|
|
||||||
if ('"' === $info[0]) {
|
|
||||||
$info = sprintf('<info>%s</info>', $info);
|
|
||||||
}
|
|
||||||
|
|
||||||
$output->writeln($info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Comes from the SensioGeneratorBundle.
|
|
||||||
* @see https://github.com/sensio/SensioGeneratorBundle/blob/master/Command/Helper/DialogHelper.php#L52
|
|
||||||
*
|
|
||||||
* @param OutputInterface $output The output.
|
|
||||||
* @param string $text A text message.
|
|
||||||
* @param string $style A style to apply on the section.
|
|
||||||
*/
|
|
||||||
protected function writeSection(OutputInterface $output, $text, $style = 'bg=blue;fg=white')
|
|
||||||
{
|
|
||||||
$output->writeln(array(
|
|
||||||
'',
|
|
||||||
$this->getHelperSet()->get('formatter')->formatBlock($text, $style, true),
|
|
||||||
'',
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders an error message if a task has failed.
|
|
||||||
*
|
|
||||||
* @param OutputInterface $output The output.
|
|
||||||
* @param string $taskName A task name.
|
|
||||||
* @param Boolean $more Whether to add a 'more details' message or not.
|
|
||||||
*/
|
|
||||||
protected function writeTaskError($output, $taskName, $more = true)
|
|
||||||
{
|
|
||||||
$moreText = $more ? ' To get more details, run the command with the "--verbose" option.' : '';
|
|
||||||
|
|
||||||
return $this->writeSection($output, array(
|
|
||||||
'[Propel] Error',
|
|
||||||
'',
|
|
||||||
'An error has occured during the "' . $taskName . '" task process.' . $moreText
|
|
||||||
), 'fg=white;bg=red');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param OutputInterface $output The output.
|
|
||||||
* @param string $filename The filename.
|
|
||||||
*/
|
|
||||||
protected function writeNewFile(OutputInterface $output, $filename)
|
|
||||||
{
|
|
||||||
$output->writeln('>> <info>File+</info> ' . $filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param OutputInterface $output The output.
|
|
||||||
* @param string $directory The directory.
|
|
||||||
*/
|
|
||||||
protected function writeNewDirectory(OutputInterface $output, $directory)
|
|
||||||
{
|
|
||||||
$output->writeln('>> <info>Dir+</info> ' . $directory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ask confirmation from the user.
|
|
||||||
*
|
|
||||||
* @param OutputInterface $output The output.
|
|
||||||
* @param string $question A given question.
|
|
||||||
* @param string $default A default response.
|
|
||||||
*/
|
|
||||||
protected function askConfirmation(OutputInterface $output, $question, $default = null)
|
|
||||||
{
|
|
||||||
return $this->getHelperSet()->get('dialog')->askConfirmation($output, $question, $default);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param \SplFileInfo $schema
|
|
||||||
* @param BundleInterface $bundle
|
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function transformToLogicalName(\SplFileInfo $schema, BundleInterface $bundle)
|
protected function getMigrationsTable()
|
||||||
{
|
{
|
||||||
$schemaPath = str_replace(
|
$config = $this->getContainer()->getParameter('propel.configuration');
|
||||||
$bundle->getPath(). DIRECTORY_SEPARATOR . 'Resources' . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR,
|
|
||||||
'',
|
|
||||||
$schema->getRealPath()
|
|
||||||
);
|
|
||||||
|
|
||||||
return sprintf('@%s/Resources/config/%s', $bundle->getName(), $schemaPath);
|
return $config['migrations']['tableName'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compiles arguments/properties for the Phing process.
|
* Returns the name of the default connection.
|
||||||
* @return array
|
*
|
||||||
|
* @return string
|
||||||
*/
|
*/
|
||||||
private function getPhingArguments(KernelInterface $kernel, $workingDirectory, $properties)
|
protected function getDefaultConnection()
|
||||||
{
|
{
|
||||||
$args = array();
|
$config = $this->getContainer()->getParameter('propel.configuration');
|
||||||
|
|
||||||
// Default properties
|
return !empty($config['generator']['defaultConnection']) ? $config['generator']['defaultConnection'] : key($config['database']['connections']);
|
||||||
$properties = array_merge(array(
|
}
|
||||||
'propel.database' => 'mysql',
|
|
||||||
'project.dir' => $workingDirectory,
|
|
||||||
'propel.output.dir' => $kernel->getRootDir().'/propel',
|
|
||||||
'propel.php.dir' => $kernel->getRootDir().'/..',
|
|
||||||
'propel.packageObjectModel' => true,
|
|
||||||
'propel.useDateTimeClass' => true,
|
|
||||||
'propel.dateTimeClass' => 'DateTime',
|
|
||||||
'propel.defaultTimeFormat' => '',
|
|
||||||
'propel.defaultDateFormat' => '',
|
|
||||||
'propel.addClassLevelComment' => false,
|
|
||||||
'propel.defaultTimeStampFormat' => '',
|
|
||||||
'propel.builder.pluralizer.class' => 'builder.util.StandardEnglishPluralizer',
|
|
||||||
), $properties);
|
|
||||||
|
|
||||||
// Adding user defined properties from the configuration
|
/**
|
||||||
$properties = array_merge(
|
* Reads the platform class from the configuration
|
||||||
$properties,
|
*
|
||||||
$this->getContainer()->get('propel.build_properties')->getProperties()
|
* @return string The platform class name.
|
||||||
);
|
*/
|
||||||
|
protected function getPlatform()
|
||||||
foreach ($properties as $key => $value) {
|
{
|
||||||
$args[] = "-D$key=$value";
|
$config = $this->getContainer()->getParameter('propel.configuration');
|
||||||
}
|
return $config['generator']['platformClass'];
|
||||||
|
|
||||||
// Build file
|
|
||||||
$args[] = '-f';
|
|
||||||
$args[] = realpath($this->getContainer()->getParameter('propel.path').'/generator/build.xml');
|
|
||||||
|
|
||||||
return $args;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,27 +8,26 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Command;
|
namespace Propel\Bundle\PropelBundle\Command;
|
||||||
|
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
use Symfony\Component\Console\Output\Output;
|
use Symfony\Component\Console\Output\Output;
|
||||||
use Symfony\Component\Filesystem\Filesystem;
|
|
||||||
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
||||||
use Symfony\Component\HttpKernel\KernelInterface;
|
use Symfony\Component\HttpKernel\KernelInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||||
*/
|
*/
|
||||||
class AclInitCommand extends SqlInsertCommand
|
class AclInitCommand extends AbstractCommand
|
||||||
{
|
{
|
||||||
protected function configure()
|
protected function configure()
|
||||||
{
|
{
|
||||||
$this
|
$this
|
||||||
->setDescription('Initialize "Access Control Lists" model and SQL')
|
->setDescription('Initialize "Access Control Lists" model and SQL')
|
||||||
->addOption('force', null, InputOption::VALUE_NONE, 'Set this parameter to execute this action.')
|
->addOption('force', null, InputOption::VALUE_NONE, 'Set this parameter to execute this action.')
|
||||||
->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'Set this parameter to define a connection to use')
|
->addOption('connection', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'Connection to use. Example: default, bookstore')
|
||||||
->setHelp(<<<EOT
|
->setHelp(<<<EOT
|
||||||
The <info>%command.name%</info> command connects to the database and executes all SQL statements required to setup the ACL database, it also generates the ACL model.
|
The <info>%command.name%</info> command connects to the database and executes all SQL statements required to setup the ACL database, it also generates the ACL model.
|
||||||
|
|
||||||
|
@ -45,55 +44,93 @@ EOT
|
||||||
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
{
|
{
|
||||||
if ($input->getOption('verbose')) {
|
$outputDir = realpath($this->getApplication()->getKernel()->getRootDir().'/../');
|
||||||
$this->additionalPhingArgs[] = 'verbose';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate ACL model
|
// Generate ACL model
|
||||||
if (true == $result = $this->callPhing('om')) {
|
$modelBuildCmd = new \Propel\Generator\Command\ModelBuildCommand();
|
||||||
|
$modelBuildArgs = array(
|
||||||
|
'--output-dir' => $outputDir,
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($this->runCommand($modelBuildCmd, $modelBuildArgs, $input, $output) === 0) {
|
||||||
$output->writeln(sprintf(
|
$output->writeln(sprintf(
|
||||||
'>> <info>%20s</info> Generated model classes from <comment>%s</comment>',
|
'>> <info>%20s</info> Generated model classes from <comment>%s</comment>',
|
||||||
$this->getApplication()->getKernel()->getBundle('PropelBundle')->getName(),
|
$this->getApplication()->getKernel()->getBundle('PropelBundle')->getName(),
|
||||||
'acl_schema.xml'
|
'acl_schema.xml'
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
$this->writeTaskError($output, 'om');
|
$this->writeTaskError($output, 'model:build');
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare SQL directory
|
// Prepare SQL
|
||||||
$sqlDirectory = $this->getSqlDir();
|
$sqlBuildCmd = new \Propel\Generator\Command\SqlBuildCommand();
|
||||||
$filesystem = new Filesystem();
|
$sqlBuildArgs = array(
|
||||||
$filesystem->remove($sqlDirectory);
|
'--connection' => $this->getConnections($input->getOption('connection')),
|
||||||
$filesystem->mkdir($sqlDirectory);
|
'--output-dir' => $this->getCacheDir(),
|
||||||
|
);
|
||||||
|
|
||||||
if (true == $result = $this->callPhing('build-sql', array('propel.sql.dir' => $sqlDirectory))) {
|
if ($this->runCommand($sqlBuildCmd, $sqlBuildArgs, $input, $output) === 0) {
|
||||||
$this->writeSection(
|
$this->writeSection(
|
||||||
$output,
|
$output,
|
||||||
'<comment>1</comment> <info>SQL file has been generated.</info>'
|
'<comment>1</comment> <info>SQL file has been generated.</info>'
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
$this->writeTaskError($output, 'build-sql');
|
$this->writeTaskError($output, 'sql:build');
|
||||||
|
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent::execute($input, $output);
|
|
||||||
|
if ($input->getOption('force')) {
|
||||||
|
// insert sql
|
||||||
|
$sqlInsertCmd = new \Propel\Generator\Command\SqlInsertCommand();
|
||||||
|
$sqlInsertArgs = array(
|
||||||
|
'--connection' => $this->getConnections($input->getOption('connection')),
|
||||||
|
'--sql-dir' => $this->getCacheDir(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($this->runCommand($sqlInsertCmd, $sqlInsertArgs, $input, $output) === 0) {
|
||||||
|
$this->writeSection(
|
||||||
|
$output,
|
||||||
|
'<comment>1</comment> <info>SQL file has been inserted.</info>'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->writeTaskError($output, 'sql:insert');
|
||||||
|
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @note We override this method to only return the acl-related schema
|
||||||
|
*/
|
||||||
protected function getFinalSchemas(KernelInterface $kernel, BundleInterface $bundle = null)
|
protected function getFinalSchemas(KernelInterface $kernel, BundleInterface $bundle = null)
|
||||||
{
|
{
|
||||||
$aclSchema = new \SplFileInfo($kernel->locateResource('@PropelBundle/Resources/acl_schema.xml'));
|
$aclSchema = new \SplFileInfo($kernel->locateResource('@PropelBundle/Resources/acl_schema.xml'));
|
||||||
|
|
||||||
return array((string) $aclSchema => array($kernel->getBundle('PropelBundle'), $aclSchema));
|
return array(
|
||||||
}
|
array($kernel->getBundle('PropelBundle'), $aclSchema)
|
||||||
|
|
||||||
protected function getSqlDir()
|
|
||||||
{
|
|
||||||
return sprintf('%s/cache/%s/propel/acl/sql',
|
|
||||||
$this->getApplication()->getKernel()->getRootDir(),
|
|
||||||
$this->getApplication()->getKernel()->getEnvironment()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @note We override this method to modify the cache directory
|
||||||
|
*/
|
||||||
|
protected function initialize(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
parent::initialize($input, $output);
|
||||||
|
|
||||||
|
$this->cacheDir = $this->cacheDir . '/acl';
|
||||||
|
|
||||||
|
$this->setupBuildTimeFiles();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,38 +8,35 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Command;
|
namespace Propel\Bundle\PropelBundle\Command;
|
||||||
|
|
||||||
use Propel\PropelBundle\Command\AbstractCommand;
|
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
|
||||||
use Symfony\Component\Console\Input\ArrayInput;
|
use Symfony\Component\Console\Input\ArrayInput;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
use Symfony\Component\Console\Output\Output;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BuildCommand.
|
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||||
*
|
|
||||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
|
||||||
* @author William DURAND <william.durand1@gmail.com>
|
|
||||||
*/
|
*/
|
||||||
class BuildCommand extends AbstractCommand
|
class BuildCommand extends ContainerAwareCommand
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @see Command
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
protected function configure()
|
protected function configure()
|
||||||
{
|
{
|
||||||
$this
|
$this
|
||||||
|
->setName('propel:build')
|
||||||
->setDescription('Hub for Propel build commands (Model classes, SQL)')
|
->setDescription('Hub for Propel build commands (Model classes, SQL)')
|
||||||
|
|
||||||
->setDefinition(array(
|
->setDefinition(array(
|
||||||
new InputOption('classes', '', InputOption::VALUE_NONE, 'Build only classes'),
|
new InputOption('classes', '', InputOption::VALUE_NONE, 'Build only classes'),
|
||||||
new InputOption('sql', '', InputOption::VALUE_NONE, 'Build only SQL'),
|
new InputOption('sql', '', InputOption::VALUE_NONE, 'Build only SQL'),
|
||||||
new InputOption('insert-sql', '', InputOption::VALUE_NONE, 'Build all and insert SQL'),
|
new InputOption('insert-sql', '', InputOption::VALUE_NONE, 'Build all and insert SQL'),
|
||||||
new InputOption('connection', null, InputOption::VALUE_OPTIONAL, 'Set this parameter to define a connection to use')
|
new InputOption('connection', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'Connection to use. Example: default, bookstore')
|
||||||
))
|
))
|
||||||
->setName('propel:build');
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,30 +48,33 @@ class BuildCommand extends AbstractCommand
|
||||||
{
|
{
|
||||||
if (!$input->getOption('sql')) {
|
if (!$input->getOption('sql')) {
|
||||||
$in = new ArrayInput(array(
|
$in = new ArrayInput(array(
|
||||||
'command' => 'propel:model:build',
|
'command' => 'propel:model:build',
|
||||||
'--connection' => $input->getOption('connection')
|
'--connection' => $input->getOption('connection'),
|
||||||
|
'--verbose' => $input->getOption('verbose')
|
||||||
));
|
));
|
||||||
$modelCommand = $this->getApplication()->find('propel:model:build');
|
$cmd = $this->getApplication()->find('propel:model:build');
|
||||||
$res = $modelCommand->run($in, $output);
|
$cmd->run($in, $output);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$input->getOption('classes')) {
|
if (!$input->getOption('classes')) {
|
||||||
$in = new ArrayInput(array(
|
$in = new ArrayInput(array(
|
||||||
'command' => 'propel:build:sql',
|
'command' => 'propel:build:sql',
|
||||||
'--connection' => $input->getOption('connection'),
|
'--connection' => $input->getOption('connection'),
|
||||||
|
'--verbose' => $input->getOption('verbose'),
|
||||||
));
|
));
|
||||||
$sqlCommand = $this->getApplication()->find('propel:sql:build');
|
$cmd = $this->getApplication()->find('propel:sql:build');
|
||||||
$sqlCommand->run($in, $output);
|
$cmd->run($in, $output);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($input->getOption('insert-sql')) {
|
if ($input->getOption('insert-sql')) {
|
||||||
$in = new ArrayInput(array(
|
$in = new ArrayInput(array(
|
||||||
'command' => 'propel:sql:insert',
|
'command' => 'propel:sql:insert',
|
||||||
'--connection' => $input->getOption('connection'),
|
'--connection' => $input->getOption('connection'),
|
||||||
'--force' => true,
|
'--force' => true,
|
||||||
|
'--verbose' => $input->getOption('verbose'),
|
||||||
));
|
));
|
||||||
$insertCommand = $this->getApplication()->find('propel:sql:insert');
|
$cmd = $this->getApplication()->find('propel:sql:insert');
|
||||||
$insertCommand->run($in, $output);
|
$cmd->run($in, $output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
65
Command/BundleTrait.php
Normal file
65
Command/BundleTrait.php
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
<?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\Bundle\PropelBundle\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Console\Question\Question;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Moritz Schroeder <moritz.schroeder@molabs.de>
|
||||||
|
*/
|
||||||
|
trait BundleTrait
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return ContainerInterface
|
||||||
|
*/
|
||||||
|
protected abstract function getContainer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the selected bundle.
|
||||||
|
* If no bundle argument is set, the user will get ask for it.
|
||||||
|
*
|
||||||
|
* @param InputInterface $input
|
||||||
|
* @param OutputInterface $output
|
||||||
|
*
|
||||||
|
* @return BundleInterface
|
||||||
|
*/
|
||||||
|
protected function getBundle(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$kernel = $this
|
||||||
|
->getContainer()
|
||||||
|
->get('kernel');
|
||||||
|
|
||||||
|
if ($input->hasArgument('bundle') && '@' === substr($input->getArgument('bundle'), 0, 1)) {
|
||||||
|
return $kernel->getBundle(substr($input->getArgument('bundle'), 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
$bundleNames = array_keys($kernel->getBundles());
|
||||||
|
|
||||||
|
do {
|
||||||
|
$question = '<info>Select the bundle</info>: ';
|
||||||
|
$question = new Question($question);
|
||||||
|
$question->setAutocompleterValues($bundleNames);
|
||||||
|
|
||||||
|
$bundleName = $this->getHelperSet()->get('question')->ask($input, $output, $question);
|
||||||
|
|
||||||
|
if (in_array($bundleName, $bundleNames)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$output->writeln(sprintf('<bg=red>Bundle "%s" does not exist.</bg>', $bundleName));
|
||||||
|
} while (true);
|
||||||
|
|
||||||
|
return $kernel->getBundle($bundleName);
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,9 +8,10 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Command;
|
namespace Propel\Bundle\PropelBundle\Command;
|
||||||
|
|
||||||
use Propel\PropelBundle\Command\AbstractCommand;
|
use Propel\Runtime\Connection\ConnectionManagerSingle;
|
||||||
|
use Propel\Runtime\Propel;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
@ -29,9 +30,11 @@ class DatabaseCreateCommand extends AbstractCommand
|
||||||
protected function configure()
|
protected function configure()
|
||||||
{
|
{
|
||||||
$this
|
$this
|
||||||
|
->setName('propel:database:create')
|
||||||
->setDescription('Create a given database or the default one.')
|
->setDescription('Create a given database or the default one.')
|
||||||
|
|
||||||
->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'Set this parameter to define a connection to use')
|
->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'Set this parameter to define a connection to use')
|
||||||
->setName('propel:database:create');
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,8 +44,9 @@ class DatabaseCreateCommand extends AbstractCommand
|
||||||
*/
|
*/
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
{
|
{
|
||||||
list($name, $config) = $this->getConnection($input, $output);
|
$connectionName = $input->getOption('connection') ?: $this->getDefaultConnection();
|
||||||
$dbName = $this->parseDbName($config['connection']['dsn']);
|
$config = $this->getConnectionData($connectionName);
|
||||||
|
$dbName = $this->parseDbName($config['dsn']);
|
||||||
|
|
||||||
if (null === $dbName) {
|
if (null === $dbName) {
|
||||||
return $output->writeln('<error>No database name found.</error>');
|
return $output->writeln('<error>No database name found.</error>');
|
||||||
|
@ -50,21 +54,19 @@ class DatabaseCreateCommand extends AbstractCommand
|
||||||
$query = 'CREATE DATABASE '. $dbName .';';
|
$query = 'CREATE DATABASE '. $dbName .';';
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
$manager = new ConnectionManagerSingle();
|
||||||
\Propel::setConfiguration($this->getTemporaryConfiguration($name, $config));
|
$manager->setConfiguration($this->getTemporaryConfiguration($config));
|
||||||
$connection = \Propel::getConnection($name);
|
|
||||||
|
|
||||||
$statement = $connection->prepare($query);
|
$serviceContainer = Propel::getServiceContainer();
|
||||||
$statement->execute();
|
$serviceContainer->setAdapterClass($connectionName, $config['adapter']);
|
||||||
|
$serviceContainer->setConnectionManager($connectionName, $manager);
|
||||||
|
|
||||||
$output->writeln(sprintf('<info>Database <comment>%s</comment> has been created.</info>', $dbName));
|
$connection = Propel::getConnection($connectionName);
|
||||||
} catch (\Exception $e) {
|
|
||||||
$this->writeSection($output, array(
|
$statement = $connection->prepare($query);
|
||||||
'[Propel] Exception caught',
|
$statement->execute();
|
||||||
'',
|
|
||||||
$e->getMessage()
|
$output->writeln(sprintf('<info>Database <comment>%s</comment> has been created.</info>', $dbName));
|
||||||
), 'fg=white;bg=red');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,22 +75,19 @@ class DatabaseCreateCommand extends AbstractCommand
|
||||||
*
|
*
|
||||||
* @see https://github.com/doctrine/doctrine1/blob/master/lib/Doctrine/Connection.php#L1491
|
* @see https://github.com/doctrine/doctrine1/blob/master/lib/Doctrine/Connection.php#L1491
|
||||||
*
|
*
|
||||||
* @param string $name A connection name.
|
* @param array $config A Propel connection configuration.
|
||||||
* @param array $config A Propel connection configuration.
|
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
private function getTemporaryConfiguration($name, $config)
|
private function getTemporaryConfiguration($config)
|
||||||
{
|
{
|
||||||
$dbName = $this->parseDbName($config['connection']['dsn']);
|
$dbName = $this->parseDbName($config['dsn']);
|
||||||
|
|
||||||
$config['connection']['dsn'] = preg_replace(
|
$config['dsn'] = preg_replace(
|
||||||
'#dbname='.$dbName.';#',
|
'#;?(dbname|Database)='.$dbName.'#',
|
||||||
'',
|
'',
|
||||||
$config['connection']['dsn']
|
$config['dsn']
|
||||||
);
|
);
|
||||||
|
|
||||||
return array(
|
return $config;
|
||||||
'datasources' => array($name => $config)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,13 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Command;
|
namespace Propel\Bundle\PropelBundle\Command;
|
||||||
|
|
||||||
use Propel\PropelBundle\Command\AbstractCommand;
|
use Propel\Runtime\Propel;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Propel\Runtime\Connection\ConnectionManagerSingle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DatabaseDropCommand class.
|
* DatabaseDropCommand class.
|
||||||
|
@ -24,14 +25,13 @@ use Symfony\Component\Console\Input\InputOption;
|
||||||
class DatabaseDropCommand extends AbstractCommand
|
class DatabaseDropCommand extends AbstractCommand
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @see Command
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
protected function configure()
|
protected function configure()
|
||||||
{
|
{
|
||||||
$this
|
$this
|
||||||
|
->setName('propel:database:drop')
|
||||||
->setDescription('Drop a given database or the default one.')
|
->setDescription('Drop a given database or the default one.')
|
||||||
->addOption('force', null, InputOption::VALUE_NONE, 'Set this parameter to execute this action.')
|
|
||||||
->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'Set this parameter to define a connection to use')
|
|
||||||
->setHelp(<<<EOT
|
->setHelp(<<<EOT
|
||||||
The <info>propel:database:drop</info> command will drop your database.
|
The <info>propel:database:drop</info> command will drop your database.
|
||||||
|
|
||||||
|
@ -42,51 +42,79 @@ The <info>--connection</info> parameter allows you to change the connection to u
|
||||||
The default connection is the active connection (propel.dbal.default_connection).
|
The default connection is the active connection (propel.dbal.default_connection).
|
||||||
EOT
|
EOT
|
||||||
)
|
)
|
||||||
->setName('propel:database:drop');
|
|
||||||
|
->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'Connection to use. Example: default, bookstore')
|
||||||
|
->addOption('force', null, InputOption::VALUE_NONE, 'Set this parameter to execute this action.')
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Command
|
* {@inheritdoc}
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException When the target directory does not exist
|
|
||||||
*/
|
*/
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
{
|
{
|
||||||
if ($input->getOption('force')) {
|
if (!$input->getOption('force')) {
|
||||||
if ('prod' === $this->getApplication()->getKernel()->getEnvironment()) {
|
|
||||||
$this->writeSection($output, 'WARNING: you are about to drop a database in production !', 'bg=red;fg=white');
|
|
||||||
|
|
||||||
if (false === $this->askConfirmation($output, 'Are you sure ? (y/n) ', false)) {
|
|
||||||
$output->writeln('Aborted, nice decision !');
|
|
||||||
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
list($name, $config) = $this->getConnection($input, $output);
|
|
||||||
$dbName = $this->parseDbName($config['connection']['dsn']);
|
|
||||||
|
|
||||||
if (null === $dbName) {
|
|
||||||
return $output->writeln('<error>No database name found.</error>');
|
|
||||||
} else {
|
|
||||||
$query = 'DROP DATABASE '. $dbName .';';
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$connection = \Propel::getConnection($name);
|
|
||||||
$statement = $connection->prepare($query);
|
|
||||||
$statement->execute();
|
|
||||||
|
|
||||||
$output->writeln(sprintf('<info>Database <comment>%s</comment> has been dropped.</info>', $dbName));
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$this->writeSection($output, array(
|
|
||||||
'[Propel] Exception caught',
|
|
||||||
'',
|
|
||||||
$e->getMessage()
|
|
||||||
), 'fg=white;bg=red');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$output->writeln('<error>You have to use the "--force" option to drop the database.</error>');
|
$output->writeln('<error>You have to use the "--force" option to drop the database.</error>');
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ('prod' === $this->getApplication()->getKernel()->getEnvironment()) {
|
||||||
|
$this->writeSection($output, 'WARNING: you are about to drop a database in production !', 'bg=red;fg=white');
|
||||||
|
|
||||||
|
if (false === $this->askConfirmation($input, $output, 'Are you sure ? (y/n) ', false)) {
|
||||||
|
$output->writeln('Aborted, nice decision !');
|
||||||
|
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$connectionName = $input->getOption('connection') ?: $this->getDefaultConnection();
|
||||||
|
$config = $this->getConnectionData($connectionName);
|
||||||
|
$connection = Propel::getConnection($connectionName);
|
||||||
|
$dbName = $this->parseDbName($config['dsn']);
|
||||||
|
|
||||||
|
if (null === $dbName) {
|
||||||
|
return $output->writeln('<error>No database name found.</error>');
|
||||||
|
} else {
|
||||||
|
$query = 'DROP DATABASE '. $dbName .';';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$manager = new ConnectionManagerSingle();
|
||||||
|
$manager->setConfiguration($this->getTemporaryConfiguration($config));
|
||||||
|
|
||||||
|
$serviceContainer = Propel::getServiceContainer();
|
||||||
|
$serviceContainer->setAdapterClass($connectionName, $config['adapter']);
|
||||||
|
$serviceContainer->setConnectionManager($connectionName, $manager);
|
||||||
|
|
||||||
|
$connection = Propel::getConnection($connectionName);
|
||||||
|
|
||||||
|
$statement = $connection->prepare($query);
|
||||||
|
$statement->execute();
|
||||||
|
|
||||||
|
$output->writeln(sprintf('<info>Database <comment>%s</comment> has been dropped.</info>', $dbName));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a temporary configuration to connect to the database in order
|
||||||
|
* to create a given database. This idea comes from Doctrine1.
|
||||||
|
*
|
||||||
|
* @see https://github.com/doctrine/doctrine1/blob/master/lib/Doctrine/Connection.php#L1491
|
||||||
|
*
|
||||||
|
* @param array $config A Propel connection configuration.
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getTemporaryConfiguration($config)
|
||||||
|
{
|
||||||
|
$dbName = $this->parseDbName($config['dsn']);
|
||||||
|
|
||||||
|
$config['dsn'] = preg_replace(
|
||||||
|
'#;?(dbname|Database)='.$dbName.'#',
|
||||||
|
'',
|
||||||
|
$config['dsn']
|
||||||
|
);
|
||||||
|
|
||||||
|
return $config;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
63
Command/DatabaseReverseCommand.php
Normal file
63
Command/DatabaseReverseCommand.php
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
<?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\Bundle\PropelBundle\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
|
||||||
|
use Propel\Generator\Command\DatabaseReverseCommand as BaseDatabaseReverseCommand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||||
|
*/
|
||||||
|
class DatabaseReverseCommand extends WrappedCommand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
parent::configure();
|
||||||
|
|
||||||
|
$this
|
||||||
|
->setName('propel:database:reverse')
|
||||||
|
->setDescription('Reverse-engineer a XML schema file based on given database')
|
||||||
|
|
||||||
|
->addArgument('connection', InputArgument::REQUIRED, 'Connection to use. Example: "default"')
|
||||||
|
->addOption('output-dir', null, InputOption::VALUE_REQUIRED, 'The output directory', BaseDatabaseReverseCommand::DEFAULT_OUTPUT_DIRECTORY)
|
||||||
|
->addOption('database-name', null, InputOption::VALUE_REQUIRED, 'The database name to reverse', BaseDatabaseReverseCommand::DEFAULT_DATABASE_NAME)
|
||||||
|
->addOption('schema-name', null, InputOption::VALUE_REQUIRED, 'The schema name to generate', BaseDatabaseReverseCommand::DEFAULT_SCHEMA_NAME)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function createSubCommandInstance()
|
||||||
|
{
|
||||||
|
return new BaseDatabaseReverseCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function getSubCommandArguments(InputInterface $input)
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'--output-dir' => $input->getOption('output-dir'),
|
||||||
|
'--database-name' => $input->getOption('database-name'),
|
||||||
|
'--schema-name' => $input->getOption('schema-name'),
|
||||||
|
// this one is an argument, so no leading '--'
|
||||||
|
'connection' => $this->getDsn($input->getArgument('connection')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,13 +8,12 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Command;
|
namespace Propel\Bundle\PropelBundle\Command;
|
||||||
|
|
||||||
use Propel\PropelBundle\Command\AbstractCommand;
|
|
||||||
use Propel\PropelBundle\DataFixtures\Dumper\YamlDataDumper;
|
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Filesystem\Filesystem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FixturesDumpCommand.
|
* FixturesDumpCommand.
|
||||||
|
@ -27,7 +26,7 @@ class FixturesDumpCommand extends AbstractCommand
|
||||||
* Default fixtures directory.
|
* Default fixtures directory.
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $defaultFixturesDir = 'app/propel/fixtures';
|
protected $defaultFixturesDir = 'app/propel/fixtures';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Command
|
* @see Command
|
||||||
|
@ -35,9 +34,8 @@ class FixturesDumpCommand extends AbstractCommand
|
||||||
protected function configure()
|
protected function configure()
|
||||||
{
|
{
|
||||||
$this
|
$this
|
||||||
|
->setName('propel:fixtures:dump')
|
||||||
->setDescription('Dump data from database into YAML fixtures file.')
|
->setDescription('Dump data from database into YAML fixtures file.')
|
||||||
->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'Set this parameter to define a connection to use')
|
|
||||||
->addOption('dir', null, InputOption::VALUE_OPTIONAL, 'Set this parameter to define a fixture directory')
|
|
||||||
->setHelp(<<<EOT
|
->setHelp(<<<EOT
|
||||||
The <info>propel:fixtures:dump</info> dumps data from database into YAML fixtures file.
|
The <info>propel:fixtures:dump</info> dumps data from database into YAML fixtures file.
|
||||||
|
|
||||||
|
@ -48,46 +46,35 @@ The <info>--dir</info> parameter allows you to change the output directory.
|
||||||
The default connection is the active connection (propel.dbal.default_connection).
|
The default connection is the active connection (propel.dbal.default_connection).
|
||||||
EOT
|
EOT
|
||||||
)
|
)
|
||||||
->setName('propel:fixtures:dump')
|
|
||||||
|
->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'Set this parameter to define a connection to use')
|
||||||
|
->addOption('dir', null, InputOption::VALUE_OPTIONAL, 'Set this parameter to define a fixture directory')
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Command
|
* {@inheritdoc}
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException When the target directory does not exist
|
|
||||||
*/
|
*/
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
{
|
{
|
||||||
list($name, $defaultConfig) = $this->getConnection($input, $output);
|
$fixtureDir = $input->getOption('dir') ?: $this->defaultFixturesDir;
|
||||||
$fixtureDir = $input->getOption('dir') ? $input->getOption('dir') : $this->defaultFixturesDir;
|
|
||||||
|
|
||||||
$path = realpath($this->getApplication()->getKernel()->getRootDir() . '/../') . '/' . $fixtureDir;
|
$path = realpath($this->getApplication()->getKernel()->getRootDir() . '/../') . '/' . $fixtureDir;
|
||||||
|
|
||||||
if (!file_exists($path)) {
|
if (!file_exists($path)) {
|
||||||
$output->writeln("<info>The $path folder does not exists.</info>");
|
$output->writeln("<info>The $path folder does not exists.</info>");
|
||||||
if ($this->askConfirmation($output, "<question>Do you want me to create it for you ?</question> [Yes]")) {
|
if ($this->askConfirmation($input, $output, "<question>Do you want me to create it for you ?</question> [Yes]")) {
|
||||||
$fs = new Filesystem();
|
$fs = new Filesystem();
|
||||||
$fs->mkdir($path);
|
$fs->mkdir($path);
|
||||||
|
$this->writeNewDirectory($output, $path);
|
||||||
} else {
|
} else {
|
||||||
throw new \IOException(sprintf('Unable to find the %s folder', $path));
|
throw new \IOException(sprintf('Unable to find the %s folder', $path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$filename = $path . '/fixtures_' . time() . '.yml';
|
$filename = $path . '/fixtures_' . time() . '.yml';
|
||||||
|
$dumper = $this->getContainer()->get('propel.dumper.yaml');
|
||||||
|
|
||||||
$dumper = new YamlDataDumper($this->getApplication()->getKernel()->getRootDir());
|
$dumper->dump($filename, $input->getOption('connection'));
|
||||||
|
|
||||||
try {
|
|
||||||
$dumper->dump($filename, $name);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$this->writeSection($output, array(
|
|
||||||
'[Propel] Exception',
|
|
||||||
'',
|
|
||||||
$e->getMessage()), 'fg=white;bg=red');
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->writeNewFile($output, $filename);
|
$this->writeNewFile($output, $filename);
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,9 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Command;
|
namespace Propel\Bundle\PropelBundle\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Input\ArrayInput;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
@ -18,10 +19,6 @@ use Symfony\Component\Filesystem\Filesystem;
|
||||||
use Symfony\Component\Finder\Finder;
|
use Symfony\Component\Finder\Finder;
|
||||||
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
||||||
|
|
||||||
use Propel\PropelBundle\Command\AbstractCommand;
|
|
||||||
use Propel\PropelBundle\DataFixtures\Loader\YamlDataLoader;
|
|
||||||
use Propel\PropelBundle\DataFixtures\Loader\XmlDataLoader;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FixturesLoadCommand
|
* FixturesLoadCommand
|
||||||
*
|
*
|
||||||
|
@ -53,17 +50,8 @@ class FixturesLoadCommand extends AbstractCommand
|
||||||
protected function configure()
|
protected function configure()
|
||||||
{
|
{
|
||||||
$this
|
$this
|
||||||
|
->setName('propel:fixtures:load')
|
||||||
->setDescription('Load XML, SQL and/or YAML fixtures')
|
->setDescription('Load XML, SQL and/or YAML fixtures')
|
||||||
->addArgument('bundle', InputArgument::OPTIONAL, 'The bundle to load fixtures from')
|
|
||||||
->addOption(
|
|
||||||
'dir', 'd', InputOption::VALUE_OPTIONAL,
|
|
||||||
'The directory where XML, SQL and/or YAML fixtures files are located',
|
|
||||||
$this->defaultFixturesDir
|
|
||||||
)
|
|
||||||
->addOption('xml', '', InputOption::VALUE_NONE, 'Load XML fixtures')
|
|
||||||
->addOption('sql', '', InputOption::VALUE_NONE, 'Load SQL fixtures')
|
|
||||||
->addOption('yml', '', InputOption::VALUE_NONE, 'Load YAML fixtures')
|
|
||||||
->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'Set this parameter to define a connection to use')
|
|
||||||
->setHelp(<<<EOT
|
->setHelp(<<<EOT
|
||||||
The <info>propel:fixtures:load</info> loads <info>XML</info>, <info>SQL</info> and/or <info>YAML</info> fixtures.
|
The <info>propel:fixtures:load</info> loads <info>XML</info>, <info>SQL</info> and/or <info>YAML</info> fixtures.
|
||||||
|
|
||||||
|
@ -107,14 +95,22 @@ YAML fixtures are:
|
||||||
</comment>
|
</comment>
|
||||||
EOT
|
EOT
|
||||||
)
|
)
|
||||||
->setName('propel:fixtures:load')
|
|
||||||
;
|
->addArgument('bundle', InputArgument::OPTIONAL, 'The bundle to load fixtures from')
|
||||||
|
->addOption(
|
||||||
|
'dir', 'd', InputOption::VALUE_OPTIONAL,
|
||||||
|
'The directory where XML, SQL and/or YAML fixtures files are located',
|
||||||
|
$this->defaultFixturesDir
|
||||||
|
)
|
||||||
|
->addOption('xml', '', InputOption::VALUE_NONE, 'Load XML fixtures')
|
||||||
|
->addOption('sql', '', InputOption::VALUE_NONE, 'Load SQL fixtures')
|
||||||
|
->addOption('yml', '', InputOption::VALUE_NONE, 'Load YAML fixtures')
|
||||||
|
->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'Set this parameter to define a connection to use')
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Command
|
* {@inheritdoc}
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException When the target directory does not exist
|
|
||||||
*/
|
*/
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
{
|
{
|
||||||
|
@ -126,17 +122,13 @@ EOT
|
||||||
$this->absoluteFixturesPath = realpath($this->getApplication()->getKernel()->getRootDir() . '/../' . $input->getOption('dir'));
|
$this->absoluteFixturesPath = realpath($this->getApplication()->getKernel()->getRootDir() . '/../' . $input->getOption('dir'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($input->getOption('verbose')) {
|
|
||||||
$this->additionalPhingArgs[] = 'verbose';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->absoluteFixturesPath && !file_exists($this->absoluteFixturesPath)) {
|
if (!$this->absoluteFixturesPath && !file_exists($this->absoluteFixturesPath)) {
|
||||||
return $this->writeSection($output, array(
|
return $this->writeSection($output, array(
|
||||||
'The fixtures directory "' . $this->absoluteFixturesPath . '" does not exist.'
|
'The fixtures directory "' . $this->absoluteFixturesPath . '" does not exist.'
|
||||||
), 'fg=white;bg=red');
|
), 'fg=white;bg=red');
|
||||||
}
|
}
|
||||||
|
|
||||||
$noOptions = (!$input->getOption('xml') && !$input->getOption('sql') && !$input->getOption('yml'));
|
$noOptions = !$input->getOption('xml') && !$input->getOption('sql') && !$input->getOption('yml');
|
||||||
|
|
||||||
if ($input->getOption('sql') || $noOptions) {
|
if ($input->getOption('sql') || $noOptions) {
|
||||||
if (-1 === $this->loadSqlFixtures($input, $output)) {
|
if (-1 === $this->loadSqlFixtures($input, $output)) {
|
||||||
|
@ -160,9 +152,9 @@ EOT
|
||||||
/**
|
/**
|
||||||
* Load fixtures
|
* Load fixtures
|
||||||
*
|
*
|
||||||
* @param \Symfony\Component\Console\Input\InputInterface $input
|
* @param \Symfony\Component\Console\Input\InputInterface $input
|
||||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||||
* @return void
|
* @param string $type If specified, only fixtures with the given type will be loaded (yml, xml).
|
||||||
*/
|
*/
|
||||||
protected function loadFixtures(InputInterface $input, OutputInterface $output, $type = null)
|
protected function loadFixtures(InputInterface $input, OutputInterface $output, $type = null)
|
||||||
{
|
{
|
||||||
|
@ -176,26 +168,17 @@ EOT
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
list($name, $defaultConfig) = $this->getConnection($input, $output);
|
$connectionName = $input->getOption('connection') ?: $this->getDefaultConnection();
|
||||||
|
|
||||||
if ('yml' === $type) {
|
if ('yml' === $type) {
|
||||||
$loader = new YamlDataLoader($this->getApplication()->getKernel()->getRootDir(), $this->getContainer());
|
$loader = $this->getContainer()->get('propel.loader.yaml');
|
||||||
} elseif ('xml' === $type) {
|
} elseif ('xml' === $type) {
|
||||||
$loader = new XmlDataLoader($this->getApplication()->getKernel()->getRootDir());
|
$loader = $this->getContainer()->get('propel.loader.xml');
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
$nb = $loader->load($datas, $connectionName);
|
||||||
$nb = $loader->load($datas, $name);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$this->writeSection($output, array(
|
|
||||||
'[Propel] Exception',
|
|
||||||
'',
|
|
||||||
$e->getMessage()), 'fg=white;bg=red');
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$output->writeln(sprintf('<comment>%s</comment> %s fixtures file%s loaded.', $nb, strtoupper($type), $nb > 1 ? 's' : ''));
|
$output->writeln(sprintf('<comment>%s</comment> %s fixtures file%s loaded.', $nb, strtoupper($type), $nb > 1 ? 's' : ''));
|
||||||
|
|
||||||
|
@ -205,36 +188,35 @@ EOT
|
||||||
/**
|
/**
|
||||||
* Load SQL fixtures
|
* Load SQL fixtures
|
||||||
*
|
*
|
||||||
* @param \Symfony\Component\Console\Input\InputInterface $input
|
* @param \Symfony\Component\Console\Input\InputInterface $input
|
||||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
protected function loadSqlFixtures(InputInterface $input, OutputInterface $output)
|
protected function loadSqlFixtures(InputInterface $input, OutputInterface $output)
|
||||||
{
|
{
|
||||||
$tmpdir = $this->getApplication()->getKernel()->getRootDir() . '/cache/propel';
|
$tmpdir = $this->getCacheDir();
|
||||||
$datas = $this->getFixtureFiles('sql');
|
$datas = $this->getFixtureFiles('sql');
|
||||||
|
|
||||||
$this->prepareCache($tmpdir);
|
$this->prepareCache($tmpdir);
|
||||||
|
|
||||||
list($name, $defaultConfig) = $this->getConnection($input, $output);
|
$connectionName = $input->getOption('connection') ?: $this->getContainer()->getParameter('propel.dbal.default_connection');
|
||||||
|
|
||||||
// Create a "sqldb.map" file
|
// Create a "sqldb.map" file
|
||||||
$sqldbContent = '';
|
$sqldbContent = '';
|
||||||
foreach ($datas as $data) {
|
foreach ($datas as $data) {
|
||||||
$output->writeln(sprintf('<info>Loading SQL fixtures from</info> <comment>%s</comment>.', $data));
|
$output->writeln(sprintf('<info>Loading SQL fixtures from</info> <comment>%s</comment>.', $data));
|
||||||
|
|
||||||
$sqldbContent .= $data->getFilename() . '=' . $name . PHP_EOL;
|
$sqldbContent .= $data->getFilename() . '=' . $connectionName . PHP_EOL;
|
||||||
$this->filesystem->copy($data, $tmpdir . '/fixtures/' . $data->getFilename(), true);
|
$this->filesystem->copy($data, $tmpdir . '/' . $data->getFilename(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('' === $sqldbContent) {
|
if ('' === $sqldbContent) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$sqldbFile = $tmpdir . '/fixtures/sqldb.map';
|
$sqldbFile = $tmpdir . '/sqldb.map';
|
||||||
file_put_contents($sqldbFile, $sqldbContent);
|
file_put_contents($sqldbFile, $sqldbContent);
|
||||||
|
|
||||||
if (!$this->insertSql($defaultConfig, $tmpdir . '/fixtures', $tmpdir, $output)) {
|
if (!$this->insertSql($connectionName, $input, $output)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,36 +235,36 @@ EOT
|
||||||
// Recreate a propel directory in cache
|
// Recreate a propel directory in cache
|
||||||
$this->filesystem->remove($tmpdir);
|
$this->filesystem->remove($tmpdir);
|
||||||
$this->filesystem->mkdir($tmpdir);
|
$this->filesystem->mkdir($tmpdir);
|
||||||
|
|
||||||
$fixturesdir = $tmpdir . '/fixtures/';
|
|
||||||
$this->filesystem->remove($fixturesdir);
|
|
||||||
$this->filesystem->mkdir($fixturesdir);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert SQL
|
* Insert SQL
|
||||||
*/
|
*/
|
||||||
protected function insertSql($config, $sqlDir, $schemaDir, $output)
|
protected function insertSql($connectionName, InputInterface $input, OutputInterface $output)
|
||||||
{
|
{
|
||||||
// Insert SQL
|
$parameters = array(
|
||||||
$ret = $this->callPhing('insert-sql', array(
|
'--connection' => array($connectionName),
|
||||||
'propel.database.url' => $config['connection']['dsn'],
|
'--verbose' => $input->getOption('verbose'),
|
||||||
'propel.database.database' => $config['adapter'],
|
'--sql-dir' => $this->getCacheDir(),
|
||||||
'propel.database.user' => $config['connection']['user'],
|
'--force' => 'force'
|
||||||
'propel.database.password' => $config['connection']['password'],
|
);
|
||||||
'propel.schema.dir' => $schemaDir,
|
|
||||||
'propel.sql.dir' => $sqlDir,
|
|
||||||
));
|
|
||||||
|
|
||||||
if (true === $ret) {
|
// add the command's name to the parameters
|
||||||
|
array_unshift($parameters, $this->getName());
|
||||||
|
|
||||||
|
$command = $this->getApplication()->find('propel:sql:insert');
|
||||||
|
$command->setApplication($this->getApplication());
|
||||||
|
|
||||||
|
// and run the sub-command
|
||||||
|
$ret = $command->run(new ArrayInput($parameters), $output);
|
||||||
|
|
||||||
|
if ($ret === 0) {
|
||||||
$output->writeln('All SQL statements have been inserted.');
|
$output->writeln('All SQL statements have been inserted.');
|
||||||
} else {
|
} else {
|
||||||
$this->writeTaskError($output, 'insert-sql', false);
|
$this->writeTaskError($output, 'insert-sql', false);
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return $ret === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -290,14 +272,16 @@ EOT
|
||||||
*
|
*
|
||||||
* @param string $type The extension of the files.
|
* @param string $type The extension of the files.
|
||||||
* @param string $in The directory in which we search the files. If null,
|
* @param string $in The directory in which we search the files. If null,
|
||||||
* we'll use the absoluteFixturesPath property.
|
* we'll use the absoluteFixturesPath property.
|
||||||
*
|
*
|
||||||
* @return \Iterator An iterator through the files.
|
* @return \Iterator An iterator through the files.
|
||||||
*/
|
*/
|
||||||
protected function getFixtureFiles($type = 'sql', $in = null)
|
protected function getFixtureFiles($type = 'sql', $in = null)
|
||||||
{
|
{
|
||||||
$finder = new Finder();
|
$finder = new Finder();
|
||||||
$finder->sortByName()->name('*.' . $type);
|
$finder->sort(function ($a, $b) {
|
||||||
|
return strcmp($a->getPathname(), $b->getPathname());
|
||||||
|
})->name('*.' . $type);
|
||||||
|
|
||||||
$files = $finder->in(null !== $in ? $in : $this->absoluteFixturesPath);
|
$files = $finder->in(null !== $in ? $in : $this->absoluteFixturesPath);
|
||||||
|
|
||||||
|
@ -318,10 +302,20 @@ EOT
|
||||||
/**
|
/**
|
||||||
* Returns the path the command will look into to find fixture files
|
* Returns the path the command will look into to find fixture files
|
||||||
*
|
*
|
||||||
|
* @param BundleInterface $bundle The bundle to explore.
|
||||||
|
*
|
||||||
* @return String
|
* @return String
|
||||||
*/
|
*/
|
||||||
protected function getFixturesPath(BundleInterface $bundle)
|
protected function getFixturesPath(BundleInterface $bundle)
|
||||||
{
|
{
|
||||||
return $bundle->getPath() . DIRECTORY_SEPARATOR . 'Resources' . DIRECTORY_SEPARATOR . 'fixtures';
|
return $bundle->getPath() . DIRECTORY_SEPARATOR . 'Resources' . DIRECTORY_SEPARATOR . 'fixtures';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Symfony\Component\Config\FileLocatorInterface
|
||||||
|
*/
|
||||||
|
protected function getFileLocator()
|
||||||
|
{
|
||||||
|
return $this->getContainer()->get('file_locator');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,13 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Command;
|
namespace Propel\Bundle\PropelBundle\Command;
|
||||||
|
|
||||||
|
use Propel\Bundle\PropelBundle\Form\FormBuilder;
|
||||||
|
use Propel\Generator\Config\GeneratorConfig;
|
||||||
|
use Propel\Generator\Model\Database;
|
||||||
|
use Propel\Generator\Model\Table;
|
||||||
|
use Propel\Generator\Manager\ModelManager;
|
||||||
|
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
@ -20,50 +26,73 @@ use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
||||||
/**
|
/**
|
||||||
* @author William DURAND <william.durand1@gmail.com>
|
* @author William DURAND <william.durand1@gmail.com>
|
||||||
*/
|
*/
|
||||||
class FormGenerateCommand extends GeneratorAwareCommand
|
class FormGenerateCommand extends AbstractCommand
|
||||||
{
|
{
|
||||||
const DEFAULT_FORM_TYPE_DIRECTORY = '/Form/Type';
|
const DEFAULT_FORM_TYPE_DIRECTORY = '/Form/Type';
|
||||||
|
|
||||||
|
use BundleTrait;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Command
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
protected function configure()
|
protected function configure()
|
||||||
{
|
{
|
||||||
$this
|
$this
|
||||||
|
->setName('propel:form:generate')
|
||||||
->setDescription('Generate Form types stubs based on the schema.xml')
|
->setDescription('Generate Form types stubs based on the schema.xml')
|
||||||
->addArgument('bundle', InputArgument::REQUIRED, 'The bundle to use to generate Form types')
|
|
||||||
->addArgument('models', InputArgument::IS_ARRAY, 'Model classes to generate Form Types from')
|
|
||||||
->addOption('force', 'f', InputOption::VALUE_NONE, 'Overwrite existing Form types')
|
->addOption('force', 'f', InputOption::VALUE_NONE, 'Overwrite existing Form types')
|
||||||
|
->addOption('platform', null, InputOption::VALUE_REQUIRED, 'The platform')
|
||||||
|
->addArgument('bundle', InputArgument::OPTIONAL, 'The bundle to use to generate Form types (Ex: @AcmeDemoBundle)')
|
||||||
|
->addArgument('models', InputArgument::IS_ARRAY, 'Model classes to generate Form Types from')
|
||||||
|
|
||||||
->setHelp(<<<EOT
|
->setHelp(<<<EOT
|
||||||
The <info>%command.name%</info> command allows you to quickly generate Form Type stubs for a given bundle.
|
The <info>%command.name%</info> command allows you to quickly generate Form Type stubs for a given bundle.
|
||||||
|
|
||||||
<info>php app/console %command.full_name%</info>
|
<info>php app/console %command.full_name%</info>
|
||||||
|
|
||||||
The <info>--force</info> parameter allows you to overwrite existing files.
|
The <info>--force</info> parameter allows you to overwrite existing files.
|
||||||
EOT
|
EOT
|
||||||
)
|
);
|
||||||
->setName('propel:form:generate');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Command
|
* {@inheritdoc}
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException When the target directory does not exist
|
|
||||||
*/
|
*/
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
{
|
{
|
||||||
if ($schemas = $this->getSchemasFromBundle($this->bundle)) {
|
$kernel = $this->getApplication()->getKernel();
|
||||||
foreach ($schemas as $fileName => $array) {
|
$models = $input->getArgument('models');
|
||||||
foreach ($this->getDatabasesFromSchema($array[1]) as $database) {
|
$force = $input->getOption('force');
|
||||||
$this->createFormTypeFromDatabase($this->bundle, $database, $input->getArgument('models'), $output, $input->getOption('force'));
|
|
||||||
}
|
$bundle = $this->getBundle($input, $output);
|
||||||
|
|
||||||
|
$this->setupBuildTimeFiles();
|
||||||
|
$schemas = $this->getFinalSchemas($kernel, $bundle);
|
||||||
|
if (!$schemas) {
|
||||||
|
$output->writeln(sprintf('No <comment>*schemas.xml</comment> files found in bundle <comment>%s</comment>.', $bundle->getName()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$manager = $this->getModelManager($input, $schemas);
|
||||||
|
|
||||||
|
foreach ($manager->getDataModels() as $dataModel) {
|
||||||
|
foreach ($dataModel->getDatabases() as $database) {
|
||||||
|
$this->createFormTypeFromDatabase($bundle, $database, $models, $output, $force);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
$output->writeln(sprintf('No <comment>*schemas.xml</comment> files found in bundle <comment>%s</comment>.', $this->bundle->getName()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createFormTypeFromDatabase(BundleInterface $bundle, \Database $database, $models, OutputInterface $output, $force = false)
|
/**
|
||||||
|
* Create FormTypes from a given database, bundle and models.
|
||||||
|
*
|
||||||
|
* @param BundleInterface $bundle The bundle for which the FormTypes will be generated.
|
||||||
|
* @param Database $database The database to inspect.
|
||||||
|
* @param array $models The models to build.
|
||||||
|
* @param OutputInterface $output An OutputInterface instance
|
||||||
|
* @param boolean $force Override files if present.
|
||||||
|
*/
|
||||||
|
protected function createFormTypeFromDatabase(BundleInterface $bundle, Database $database, $models, OutputInterface $output, $force = false)
|
||||||
{
|
{
|
||||||
$dir = $this->createDirectory($bundle, $output);
|
$dir = $this->createDirectory($bundle, $output);
|
||||||
|
|
||||||
|
@ -82,11 +111,19 @@ EOT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createDirectory(BundleInterface $bundle, OutputInterface $output)
|
/**
|
||||||
|
* Create the FormType directory and log the result.
|
||||||
|
*
|
||||||
|
* @param BundleInterface $bundle The bundle in which we'll create the directory.
|
||||||
|
* @param OutputInterface $output An OutputInterface instance.
|
||||||
|
*
|
||||||
|
* @return string The path to the created directory.
|
||||||
|
*/
|
||||||
|
protected function createDirectory(BundleInterface $bundle, OutputInterface $output)
|
||||||
{
|
{
|
||||||
$fs = new Filesystem();
|
$fs = new Filesystem();
|
||||||
|
|
||||||
if (!is_dir($dir = $bundle->getPath() . self::DEFAULT_FORM_TYPE_DIRECTORY)) {
|
if (!$fs->exists($dir = $bundle->getPath() . self::DEFAULT_FORM_TYPE_DIRECTORY)) {
|
||||||
$fs->mkdir($dir);
|
$fs->mkdir($dir);
|
||||||
$this->writeNewDirectory($output, $dir);
|
$this->writeNewDirectory($output, $dir);
|
||||||
}
|
}
|
||||||
|
@ -94,30 +131,71 @@ EOT
|
||||||
return $dir;
|
return $dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function writeFormType(BundleInterface $bundle, \Table $table, \SplFileInfo $file, $force, OutputInterface $output)
|
/**
|
||||||
|
* Write a FormType.
|
||||||
|
*
|
||||||
|
* @param BundleInterface $bundle The bundle in which the FormType will be created.
|
||||||
|
* @param Table $table The table for which the FormType will be created.
|
||||||
|
* @param \SplFileInfo $file File representing the FormType.
|
||||||
|
* @param boolean $force Is the write forced?
|
||||||
|
* @param OutputInterface $output An OutputInterface instance.
|
||||||
|
*/
|
||||||
|
protected function writeFormType(BundleInterface $bundle, Table $table, \SplFileInfo $file, $force, OutputInterface $output)
|
||||||
{
|
{
|
||||||
$modelName = $table->getPhpName();
|
$formBuilder = new FormBuilder();
|
||||||
$formTypeContent = file_get_contents(__DIR__ . '/../Resources/skeleton/FormType.php');
|
$formTypeContent = $formBuilder->buildFormType($bundle, $table, self::DEFAULT_FORM_TYPE_DIRECTORY);
|
||||||
|
|
||||||
$formTypeContent = str_replace('##NAMESPACE##', $bundle->getNamespace() . str_replace('/', '\\', self::DEFAULT_FORM_TYPE_DIRECTORY), $formTypeContent);
|
|
||||||
$formTypeContent = str_replace('##CLASS##', $modelName . 'Type', $formTypeContent);
|
|
||||||
$formTypeContent = str_replace('##FQCN##', sprintf('%s\%s', $table->getNamespace(), $modelName), $formTypeContent);
|
|
||||||
$formTypeContent = str_replace('##TYPE_NAME##', strtolower($modelName), $formTypeContent);
|
|
||||||
$formTypeContent = $this->addFields($table, $formTypeContent);
|
|
||||||
|
|
||||||
file_put_contents($file->getPathName(), $formTypeContent);
|
file_put_contents($file->getPathName(), $formTypeContent);
|
||||||
$this->writeNewFile($output, $this->getRelativeFileName($file) . ($force ? ' (forced)' : ''));
|
$this->writeNewFile($output, $this->getRelativeFileName($file) . ($force ? ' (forced)' : ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function addFields(\Table $table, $formTypeContent)
|
/**
|
||||||
|
* @param \SplFileInfo $file
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function getRelativeFileName(\SplFileInfo $file)
|
||||||
{
|
{
|
||||||
$buildCode = '';
|
return substr(str_replace(realpath($this->getContainer()->getParameter('kernel.root_dir') . '/../'), '', $file), 1);
|
||||||
foreach ($table->getColumns() as $column) {
|
}
|
||||||
if (!$column->isPrimaryKey()) {
|
|
||||||
$buildCode .= sprintf("\n \$builder->add('%s');", lcfirst($column->getPhpName()));
|
/**
|
||||||
}
|
* Get the GeneratorConfig instance to use.
|
||||||
|
*
|
||||||
|
* @param InputInterface $input An InputInterface instance.
|
||||||
|
*
|
||||||
|
* @return GeneratorConfig
|
||||||
|
*/
|
||||||
|
protected function getGeneratorConfig(InputInterface $input)
|
||||||
|
{
|
||||||
|
$generatorConfig = null;
|
||||||
|
|
||||||
|
if (null !== $input->getOption('platform')) {
|
||||||
|
$generatorConfig['propel']['generator']['platformClass'] = $input->getOption('platform');
|
||||||
}
|
}
|
||||||
|
|
||||||
return str_replace('##BUILD_CODE##', $buildCode, $formTypeContent);
|
return new GeneratorConfig($this->getCacheDir().'/propel.json', $generatorConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the ModelManager to use.
|
||||||
|
*
|
||||||
|
* @param InputInterface $input An InputInterface instance.
|
||||||
|
* @param array $schemas A list of schemas.
|
||||||
|
*
|
||||||
|
* @return ModelManager
|
||||||
|
*/
|
||||||
|
protected function getModelManager(InputInterface $input, array $schemas)
|
||||||
|
{
|
||||||
|
$schemaFiles = array();
|
||||||
|
foreach ($schemas as $data) {
|
||||||
|
$schemaFiles[] = $data[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
$manager = new ModelManager();
|
||||||
|
$manager->setFilesystem(new Filesystem());
|
||||||
|
$manager->setGeneratorConfig($this->getGeneratorConfig($input));
|
||||||
|
$manager->setSchemas($schemaFiles);
|
||||||
|
|
||||||
|
return $manager;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
100
Command/FormattingHelpers.php
Normal file
100
Command/FormattingHelpers.php
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
<?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\Bundle\PropelBundle\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Console\Question\Question;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||||
|
*/
|
||||||
|
trait FormattingHelpers
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Comes from the SensioGeneratorBundle.
|
||||||
|
* @see https://github.com/sensio/SensioGeneratorBundle/blob/master/Command/Helper/DialogHelper.php#L52
|
||||||
|
*
|
||||||
|
* @param OutputInterface $output The output.
|
||||||
|
* @param string $text A text message.
|
||||||
|
* @param string $style A style to apply on the section.
|
||||||
|
*/
|
||||||
|
protected function writeSection(OutputInterface $output, $text, $style = 'bg=blue;fg=white')
|
||||||
|
{
|
||||||
|
$output->writeln(array(
|
||||||
|
'',
|
||||||
|
$this->getHelperSet()->get('formatter')->formatBlock($text, $style, true),
|
||||||
|
'',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asks a confirmation to the user.
|
||||||
|
*
|
||||||
|
* The question will be asked until the user answers by nothing, yes, or no.
|
||||||
|
*
|
||||||
|
* @param InputInterface $input An Input instance
|
||||||
|
* @param OutputInterface $output An Output instance
|
||||||
|
* @param string|array $question The question to ask
|
||||||
|
* @param bool $default The default answer if the user enters nothing
|
||||||
|
*
|
||||||
|
* @return bool true if the user has confirmed, false otherwise
|
||||||
|
*/
|
||||||
|
protected function askConfirmation(InputInterface $input, OutputInterface $output, $question, $default = true)
|
||||||
|
{
|
||||||
|
$question = new Question($question);
|
||||||
|
do {
|
||||||
|
$answer = $this->getHelperSet()->get('question')->ask($input, $output, $question);
|
||||||
|
} while ($answer && !in_array(strtolower($answer[0]), array('y', 'n')));
|
||||||
|
|
||||||
|
if (false === $default) {
|
||||||
|
return $answer && 'y' == strtolower($answer[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return !$answer || 'y' == strtolower($answer[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param OutputInterface $output The output.
|
||||||
|
* @param string $filename The filename.
|
||||||
|
*/
|
||||||
|
protected function writeNewFile(OutputInterface $output, $filename)
|
||||||
|
{
|
||||||
|
$output->writeln('>> <info>File+</info> ' . $filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param OutputInterface $output The output.
|
||||||
|
* @param string $directory The directory.
|
||||||
|
*/
|
||||||
|
protected function writeNewDirectory(OutputInterface $output, $directory)
|
||||||
|
{
|
||||||
|
$output->writeln('>> <info>Dir+</info> ' . $directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders an error message if a task has failed.
|
||||||
|
*
|
||||||
|
* @param OutputInterface $output The output.
|
||||||
|
* @param string $taskName A task name.
|
||||||
|
* @param Boolean $more Whether to add a 'more details' message or not.
|
||||||
|
*/
|
||||||
|
protected function writeTaskError($output, $taskName, $more = true)
|
||||||
|
{
|
||||||
|
$moreText = $more ? ' To get more details, run the command with the "--verbose" option.' : '';
|
||||||
|
|
||||||
|
$this->writeSection($output, array(
|
||||||
|
'[Propel] Error',
|
||||||
|
'',
|
||||||
|
'An error has occured during the "' . $taskName . '" task process.' . $moreText
|
||||||
|
), 'fg=white;bg=red');
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,67 +0,0 @@
|
||||||
<?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\InputInterface;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author William Durand <william.durand1@gmail.com>
|
|
||||||
*/
|
|
||||||
abstract class GeneratorAwareCommand extends AbstractCommand
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
protected function initialize(InputInterface $input, OutputInterface $output)
|
|
||||||
{
|
|
||||||
parent::initialize($input, $output);
|
|
||||||
|
|
||||||
$this->loadPropelGenerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function loadPropelGenerator()
|
|
||||||
{
|
|
||||||
$propelPath = $this->getContainer()->getParameter('propel.path');
|
|
||||||
|
|
||||||
require_once sprintf('%s/generator/lib/builder/util/XmlToAppData.php', $propelPath);
|
|
||||||
require_once sprintf('%s/generator/lib/config/GeneratorConfig.php', $propelPath);
|
|
||||||
require_once sprintf('%s/generator/lib/config/QuickGeneratorConfig.php', $propelPath);
|
|
||||||
|
|
||||||
set_include_path(sprintf('%s/generator/lib', $propelPath) . PATH_SEPARATOR . get_include_path());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getDatabasesFromSchema(\SplFileInfo $file)
|
|
||||||
{
|
|
||||||
$transformer = new \XmlToAppData(null, null, 'UTF-8');
|
|
||||||
$config = new \QuickGeneratorConfig();
|
|
||||||
|
|
||||||
if (file_exists($propelIni = $this->getContainer()->getParameter('kernel.root_dir') . '/config/propel.ini')) {
|
|
||||||
foreach ($this->getProperties($propelIni) as $key => $value) {
|
|
||||||
if (0 === strpos($key, 'propel.')) {
|
|
||||||
$newKey = substr($key, strlen('propel.'));
|
|
||||||
|
|
||||||
$j = strpos($newKey, '.');
|
|
||||||
while (false !== $j) {
|
|
||||||
$newKey = substr($newKey, 0, $j) . ucfirst(substr($newKey, $j + 1));
|
|
||||||
$j = strpos($newKey, '.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$config->setBuildProperty($newKey, $value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$transformer->setGeneratorConfig($config);
|
|
||||||
|
|
||||||
return $transformer->parseFile($file->getPathName())->getDatabases();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,49 +8,48 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Command;
|
namespace Propel\Bundle\PropelBundle\Command;
|
||||||
|
|
||||||
use Propel\PropelBundle\Command\AbstractCommand;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
|
use Propel\Generator\Command\GraphvizGenerateCommand as BaseGraphvizGenerateCommand;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GraphvizGenerateCommand.
|
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||||
*
|
|
||||||
* @author William DURAND <william.durand1@gmail.com>
|
|
||||||
*/
|
*/
|
||||||
class GraphvizGenerateCommand extends AbstractCommand
|
class GraphvizGenerateCommand extends WrappedCommand
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @see Command
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
protected function configure()
|
protected function configure()
|
||||||
{
|
{
|
||||||
$this
|
parent::configure();
|
||||||
->setDescription('Generates Graphviz file for your project')
|
|
||||||
->setHelp(<<<EOT
|
|
||||||
The <info>propel:graphviz</info> generates Graphviz file for your project.
|
|
||||||
|
|
||||||
<info>php app/console propel:graphviz</info>
|
$this
|
||||||
EOT
|
|
||||||
)
|
|
||||||
->setName('propel:graphviz:generate')
|
->setName('propel:graphviz:generate')
|
||||||
|
->setDescription('Generate Graphviz files (.dot)')
|
||||||
|
|
||||||
|
->addOption('output-dir', null, InputOption::VALUE_REQUIRED, 'The output directory', BaseGraphvizGenerateCommand::DEFAULT_OUTPUT_DIRECTORY)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Command
|
* {@inheritdoc}
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException When the target directory does not exist
|
|
||||||
*/
|
*/
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function createSubCommandInstance()
|
||||||
{
|
{
|
||||||
$dest = $this->getApplication()->getKernel()->getRootDir() . '/propel/graph/';
|
return new BaseGraphvizGenerateCommand();
|
||||||
|
}
|
||||||
|
|
||||||
$this->callPhing('graphviz', array(
|
/**
|
||||||
'propel.graph.dir' => $dest,
|
* {@inheritdoc}
|
||||||
));
|
*/
|
||||||
|
protected function getSubCommandArguments(InputInterface $input)
|
||||||
$this->writeNewDirectory($output, $dest);
|
{
|
||||||
|
return array(
|
||||||
|
'--output-dir' => $input->getOption('output-dir'),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
69
Command/MigrationDiffCommand.php
Normal file
69
Command/MigrationDiffCommand.php
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
<?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\Bundle\PropelBundle\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
|
||||||
|
use Propel\Generator\Command\MigrationDiffCommand as BaseMigrationCommand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||||
|
*/
|
||||||
|
class MigrationDiffCommand extends WrappedCommand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
parent::configure();
|
||||||
|
|
||||||
|
$this
|
||||||
|
->setName('propel:migration:diff')
|
||||||
|
->setDescription('Generate diff classes')
|
||||||
|
|
||||||
|
->addOption('connection', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'Connection to use. Example: default, bookstore')
|
||||||
|
->addOption('output-dir', null, InputOption::VALUE_OPTIONAL, 'The output directory')
|
||||||
|
->addOption('migration-table', null, InputOption::VALUE_OPTIONAL, 'Migration table name (if none given, the configured table is used)', null)
|
||||||
|
->addOption('table-renaming', null, InputOption::VALUE_NONE, 'Detect table renaming', null)
|
||||||
|
->addOption('editor', null, InputOption::VALUE_OPTIONAL, 'The text editor to use to open diff files', null)
|
||||||
|
->addOption('skip-removed-table', null, InputOption::VALUE_NONE, 'Option to skip removed table from the migration')
|
||||||
|
->addOption('skip-tables', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'List of excluded tables', array())
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function createSubCommandInstance()
|
||||||
|
{
|
||||||
|
return new BaseMigrationCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function getSubCommandArguments(InputInterface $input)
|
||||||
|
{
|
||||||
|
$defaultOutputDir = $this->getContainer()->getParameter('propel.configuration')['paths']['migrationDir'];
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'--connection' => $this->getConnections($input->getOption('connection')),
|
||||||
|
'--migration-table' => $input->getOption('migration-table') ?: $this->getMigrationsTable(),
|
||||||
|
'--output-dir' => $input->getOption('output-dir') ?: $defaultOutputDir,
|
||||||
|
'--table-renaming' => $input->getOption('table-renaming'),
|
||||||
|
'--editor' => $input->getOption('editor'),
|
||||||
|
'--skip-removed-table' => $input->getOption('skip-removed-table'),
|
||||||
|
'--skip-tables' => $input->getOption('skip-tables'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
65
Command/MigrationDownCommand.php
Normal file
65
Command/MigrationDownCommand.php
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
<?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\Bundle\PropelBundle\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
|
||||||
|
use Propel\Generator\Command\MigrationDownCommand as BaseMigrationCommand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||||
|
*/
|
||||||
|
class MigrationDownCommand extends WrappedCommand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
parent::configure();
|
||||||
|
|
||||||
|
$this
|
||||||
|
->setName('propel:migration:down')
|
||||||
|
->setDescription('Execute migrations down')
|
||||||
|
|
||||||
|
->addOption('connection', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'Connection to use. Example: default, bookstore')
|
||||||
|
->addOption('migration-table', null, InputOption::VALUE_OPTIONAL, 'Migration table name (if none given, the configured table is used)', null)
|
||||||
|
->addOption('output-dir', null, InputOption::VALUE_OPTIONAL, 'The output directory')
|
||||||
|
->addOption('fake', null, InputOption::VALUE_NONE, 'Does not touch the actual schema, but marks previous migration as executed.')
|
||||||
|
->addOption('force', null, InputOption::VALUE_NONE, 'Continues with the migration even when errors occur.')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function createSubCommandInstance()
|
||||||
|
{
|
||||||
|
return new BaseMigrationCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function getSubCommandArguments(InputInterface $input)
|
||||||
|
{
|
||||||
|
$defaultOutputDir = $this->getContainer()->getParameter('propel.configuration')['paths']['migrationDir'];
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'--connection' => $this->getConnections($input->getOption('connection')),
|
||||||
|
'--migration-table' => $input->getOption('migration-table') ?: $this->getMigrationsTable(),
|
||||||
|
'--output-dir' => $input->getOption('output-dir') ?: $defaultOutputDir,
|
||||||
|
'--fake' => $input->getOption('fake'),
|
||||||
|
'--force' => $input->getOption('force'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,54 +0,0 @@
|
||||||
<?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 Propel\PropelBundle\Command\AbstractCommand;
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MigrationGenerateDiffCommand.
|
|
||||||
*
|
|
||||||
* @author William DURAND <william.durand1@gmail.com>
|
|
||||||
*/
|
|
||||||
class MigrationGenerateDiffCommand extends AbstractCommand
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @see Command
|
|
||||||
*/
|
|
||||||
protected function configure()
|
|
||||||
{
|
|
||||||
$this
|
|
||||||
->setDescription('Generates SQL diff between the XML schemas and the current database structure')
|
|
||||||
->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'Set this parameter to define a connection to use')
|
|
||||||
->setHelp(<<<EOT
|
|
||||||
The <info>propel:migration:generate-diff</info> command compares the current database structure and the available schemas. If there is a difference, it creates a migration file.
|
|
||||||
|
|
||||||
<info>php app/console propel:migration:generate-diff</info>
|
|
||||||
EOT
|
|
||||||
)
|
|
||||||
->setName('propel:migration:generate-diff')
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see Command
|
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException When the target directory does not exist
|
|
||||||
*/
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
|
||||||
{
|
|
||||||
$this->callPhing('diff');
|
|
||||||
|
|
||||||
$this->writeSummary($output, 'propel-sql-diff');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,62 +8,58 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Command;
|
namespace Propel\Bundle\PropelBundle\Command;
|
||||||
|
|
||||||
use Propel\PropelBundle\Command\AbstractCommand;
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
|
||||||
|
use Propel\Generator\Command\MigrationMigrateCommand as BaseMigrationCommand;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MigrationMigrateCommand.
|
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||||
*
|
|
||||||
* @author William DURAND <william.durand1@gmail.com>
|
|
||||||
*/
|
*/
|
||||||
class MigrationMigrateCommand extends AbstractCommand
|
class MigrationMigrateCommand extends WrappedCommand
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @see Command
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
protected function configure()
|
protected function configure()
|
||||||
{
|
{
|
||||||
|
parent::configure();
|
||||||
|
|
||||||
$this
|
$this
|
||||||
->setDescription('Executes the next migrations up')
|
|
||||||
->setDefinition(array(
|
|
||||||
new InputOption('--up', '', InputOption::VALUE_NONE, 'Executes the next migration up'),
|
|
||||||
new InputOption('--down', '', InputOption::VALUE_NONE, 'Executes the next migration down'),
|
|
||||||
))
|
|
||||||
->setHelp(<<<EOT
|
|
||||||
The <info>propel:migration:migrate</info> command checks the version of the database structure, looks for migrations files not yet executed (i.e. with a greater version timestamp), and executes them.
|
|
||||||
|
|
||||||
<info>php app/console propel:migration:migrate [--up] [--down]</info>
|
|
||||||
|
|
||||||
<info>php app/console propel:migration:migrate</info> : is the default command, it <comment>executes all</comment> migrations files.
|
|
||||||
|
|
||||||
<info>php app/console propel:migration:migrate --up</info> : checks the version of the database structure, looks for migrations files not yet executed (i.e. with a greater version timestamp), and <comment>executes the first one</comment> of them.
|
|
||||||
|
|
||||||
<info>php app/console propel:migration:migrate --down</info> : checks the version of the database structure, and looks for migration files already executed (i.e. with a lower version timestamp). <comment>The last executed migration found is reversed.</comment>
|
|
||||||
EOT
|
|
||||||
)
|
|
||||||
->setName('propel:migration:migrate')
|
->setName('propel:migration:migrate')
|
||||||
|
->setDescription('Execute all pending migrations')
|
||||||
|
|
||||||
|
->addOption('connection', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'Connection to use. Example: default, bookstore')
|
||||||
|
->addOption('migration-table', null, InputOption::VALUE_OPTIONAL, 'Migration table name (if none given, the configured table is used)', null)
|
||||||
|
->addOption('output-dir', null, InputOption::VALUE_OPTIONAL, 'The output directory')
|
||||||
|
->addOption('fake', null, InputOption::VALUE_NONE, 'Does not touch the actual schema, but marks all migration as executed.')
|
||||||
|
->addOption('force', null, InputOption::VALUE_NONE, 'Continues with the migration even when errors occur.')
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Command
|
* {@inheritdoc}
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException When the target directory does not exist
|
|
||||||
*/
|
*/
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function createSubCommandInstance()
|
||||||
{
|
{
|
||||||
if ($input->getOption('down')) {
|
return new BaseMigrationCommand();
|
||||||
$this->callPhing('migration-down');
|
}
|
||||||
} elseif ($input->getOption('up')) {
|
|
||||||
$this->callPhing('migration-up');
|
|
||||||
} else {
|
|
||||||
$this->callPhing('migrate');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->writeSummary($output, 'propel-migration');
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function getSubCommandArguments(InputInterface $input)
|
||||||
|
{
|
||||||
|
$defaultOutputDir = $this->getContainer()->getParameter('propel.configuration')['paths']['migrationDir'];
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'--connection' => $this->getConnections($input->getOption('connection')),
|
||||||
|
'--migration-table' => $input->getOption('migration-table') ?: $this->getMigrationsTable(),
|
||||||
|
'--output-dir' => $input->getOption('output-dir') ?: $defaultOutputDir,
|
||||||
|
'--fake' => $input->getOption('fake'),
|
||||||
|
'--force' => $input->getOption('force'),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,45 +8,54 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Command;
|
namespace Propel\Bundle\PropelBundle\Command;
|
||||||
|
|
||||||
use Propel\PropelBundle\Command\AbstractCommand;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
|
use Propel\Generator\Command\MigrationStatusCommand as BaseMigrationCommand;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MigrationStatusCommand.
|
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||||
*
|
|
||||||
* @author William DURAND <william.durand1@gmail.com>
|
|
||||||
*/
|
*/
|
||||||
class MigrationStatusCommand extends AbstractCommand
|
class MigrationStatusCommand extends WrappedCommand
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @see Command
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
protected function configure()
|
protected function configure()
|
||||||
{
|
{
|
||||||
$this
|
parent::configure();
|
||||||
->setDescription('Lists the migrations yet to be executed')
|
|
||||||
->setHelp(<<<EOT
|
|
||||||
The <info>propel:migration:status</info> command checks the version of the database structure, and looks for migration files not yet executed (i.e. with a greater version timestamp).
|
|
||||||
|
|
||||||
<info>php app/console propel:migration:status</info>
|
$this
|
||||||
EOT
|
|
||||||
)
|
|
||||||
->setName('propel:migration:status')
|
->setName('propel:migration:status')
|
||||||
|
->setDescription('Get migration status')
|
||||||
|
|
||||||
|
->addOption('connection', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'Connection to use. Example: default, bookstore')
|
||||||
|
->addOption('migration-table', null, InputOption::VALUE_OPTIONAL, 'Migration table name (if none given, the configured table is used)', null)
|
||||||
|
->addOption('output-dir', null, InputOption::VALUE_OPTIONAL, 'The output directory')
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Command
|
* {@inheritdoc}
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException When the target directory does not exist
|
|
||||||
*/
|
*/
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function createSubCommandInstance()
|
||||||
{
|
{
|
||||||
$this->callPhing('status');
|
return new BaseMigrationCommand();
|
||||||
|
}
|
||||||
|
|
||||||
$this->writeSummary($output, 'propel-migration-status');
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function getSubCommandArguments(InputInterface $input)
|
||||||
|
{
|
||||||
|
$defaultOutputDir = $this->getContainer()->getParameter('propel.configuration')['paths']['migrationDir'];
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'--connection' => $this->getConnections($input->getOption('connection')),
|
||||||
|
'--migration-table' => $input->getOption('migration-table') ?: $this->getMigrationsTable(),
|
||||||
|
'--output-dir' => $input->getOption('output-dir') ?: $defaultOutputDir,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
65
Command/MigrationUpCommand.php
Normal file
65
Command/MigrationUpCommand.php
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
<?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\Bundle\PropelBundle\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
|
||||||
|
use Propel\Generator\Command\MigrationUpCommand as BaseMigrationCommand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||||
|
*/
|
||||||
|
class MigrationUpCommand extends WrappedCommand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
parent::configure();
|
||||||
|
|
||||||
|
$this
|
||||||
|
->setName('propel:migration:up')
|
||||||
|
->setDescription('Execute (only one) next migration')
|
||||||
|
|
||||||
|
->addOption('connection', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'Connection to use. Example: default, bookstore')
|
||||||
|
->addOption('migration-table', null, InputOption::VALUE_OPTIONAL, 'Migration table name (if none given, the configured table is used)', null)
|
||||||
|
->addOption('output-dir', null, InputOption::VALUE_OPTIONAL, 'The output directory')
|
||||||
|
->addOption('fake', null, InputOption::VALUE_NONE, 'Does not touch the actual schema, but marks next migration as executed.')
|
||||||
|
->addOption('force', null, InputOption::VALUE_NONE, 'Continues with the migration even when errors occur.')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function createSubCommandInstance()
|
||||||
|
{
|
||||||
|
return new BaseMigrationCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function getSubCommandArguments(InputInterface $input)
|
||||||
|
{
|
||||||
|
$defaultOutputDir = $this->getContainer()->getParameter('propel.configuration')['paths']['migrationDir'];
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'--connection' => $this->getConnections($input->getOption('connection')),
|
||||||
|
'--migration-table' => $input->getOption('migration-table') ?: $this->getMigrationsTable(),
|
||||||
|
'--output-dir' => $input->getOption('output-dir') ?: $defaultOutputDir,
|
||||||
|
'--fake' => $input->getOption('fake'),
|
||||||
|
'--force' => $input->getOption('force'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,62 +8,52 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Command;
|
namespace Propel\Bundle\PropelBundle\Command;
|
||||||
|
|
||||||
use Propel\PropelBundle\Command\AbstractCommand;
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
|
||||||
|
use Propel\Generator\Command\ModelBuildCommand as BaseModelBuildCommand;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ModelBuildCommand.
|
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||||
*
|
|
||||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
|
||||||
* @author William DURAND <william.durand1@gmail.com>
|
|
||||||
*/
|
*/
|
||||||
class ModelBuildCommand extends AbstractCommand
|
class ModelBuildCommand extends WrappedCommand
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @see Command
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
protected function configure()
|
protected function configure()
|
||||||
{
|
{
|
||||||
$this
|
parent::configure();
|
||||||
->setDescription('Build the Propel Object Model classes based on XML schemas')
|
|
||||||
->addArgument('bundle', InputArgument::OPTIONAL, 'The bundle to generate model classes from')
|
|
||||||
->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'Set this parameter to define a connection to use')
|
|
||||||
->setHelp(<<<EOT
|
|
||||||
The <info>%command.name%</info> command builds the Propel runtime model classes (ActiveRecord, Query, Peer, and TableMap classes) based on the XML schemas defined in all Bundles.
|
|
||||||
|
|
||||||
<info>php app/console %command.full_name%</info>
|
$this
|
||||||
EOT
|
|
||||||
)
|
|
||||||
->setName('propel:model:build')
|
->setName('propel:model:build')
|
||||||
|
->setDescription('Build the model classes based on Propel XML schemas')
|
||||||
|
|
||||||
|
->addOption('connection', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'Connection to use. Example: default, bookstore')
|
||||||
|
->addArgument('bundle', InputArgument::OPTIONAL, 'The bundle to generate model classes from')
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Command
|
* {@inheritdoc}
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException When the target directory does not exist
|
|
||||||
*/
|
*/
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function createSubCommandInstance()
|
||||||
{
|
{
|
||||||
if ($input->getOption('verbose')) {
|
return new BaseModelBuildCommand();
|
||||||
$this->additionalPhingArgs[] = 'verbose';
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (true === $this->callPhing('om')) {
|
/**
|
||||||
foreach ($this->tempSchemas as $schemaFile => $schemaDetails) {
|
* {@inheritdoc}
|
||||||
$output->writeln(sprintf(
|
*/
|
||||||
'>> <info>%20s</info> Generated model classes from <comment>%s</comment>',
|
protected function getSubCommandArguments(InputInterface $input)
|
||||||
$schemaDetails['bundle'],
|
{
|
||||||
$schemaDetails['basename']
|
$outputDir = $this->getApplication()->getKernel()->getRootDir().'/../';
|
||||||
));
|
|
||||||
}
|
return array(
|
||||||
} else {
|
'--output-dir' => $outputDir,
|
||||||
$this->writeTaskError($output, 'om');
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
<?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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
|
||||||
*/
|
|
||||||
class Phing extends \Phing
|
|
||||||
{
|
|
||||||
public static function getPhingVersion()
|
|
||||||
{
|
|
||||||
return 'Phing/Symfony';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see Phing
|
|
||||||
*/
|
|
||||||
public function runBuild()
|
|
||||||
{
|
|
||||||
// workaround for included phing 2.3 which by default loads many tasks
|
|
||||||
// that are not needed and incompatible (eg phing.tasks.ext.FtpDeployTask)
|
|
||||||
// by placing current directory on the include path our defaults will be loaded
|
|
||||||
// see ticket #5054
|
|
||||||
$includePath = get_include_path();
|
|
||||||
set_include_path(dirname(__FILE__).PATH_SEPARATOR.$includePath);
|
|
||||||
parent::runBuild();
|
|
||||||
set_include_path($includePath);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,87 +0,0 @@
|
||||||
<?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 Propel\PropelBundle\Command\AbstractCommand;
|
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
use Symfony\Component\Filesystem\Filesystem;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ReverseCommand.
|
|
||||||
*
|
|
||||||
* @author William DURAND <william.durand1@gmail.com>
|
|
||||||
*/
|
|
||||||
class ReverseCommand extends AbstractCommand
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @see Command
|
|
||||||
*/
|
|
||||||
protected function configure()
|
|
||||||
{
|
|
||||||
$this
|
|
||||||
->setDescription('Generate XML schema from reverse-engineered database')
|
|
||||||
->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'Set this parameter to define a connection to use')
|
|
||||||
->setHelp(<<<EOT
|
|
||||||
The <info>propel:reverse</info> command generates an XML schema from reverse-engineered database.
|
|
||||||
<info>php app/console propel:reverse</info>
|
|
||||||
|
|
||||||
The <info>--connection</info> parameter allows you to change the connection to use.
|
|
||||||
The default connection is the active connection (propel.dbal.default_connection).
|
|
||||||
EOT
|
|
||||||
)
|
|
||||||
->setName('propel:reverse')
|
|
||||||
;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see Command
|
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException When the target directory does not exist
|
|
||||||
*/
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
|
||||||
{
|
|
||||||
if ($input->getOption('verbose')) {
|
|
||||||
$this->additionalPhingArgs[] = 'verbose';
|
|
||||||
}
|
|
||||||
|
|
||||||
list($name, $defaultConfig) = $this->getConnection($input, $output);
|
|
||||||
|
|
||||||
$ret = $this->callPhing('reverse', array(
|
|
||||||
'propel.project' => $name,
|
|
||||||
'propel.database' => $defaultConfig['adapter'],
|
|
||||||
'propel.database.url' => $defaultConfig['connection']['dsn'],
|
|
||||||
'propel.database.user' => $defaultConfig['connection']['user'],
|
|
||||||
'propel.database.password' => isset($defaultConfig['connection']['password']) ? $defaultConfig['connection']['password'] : '',
|
|
||||||
));
|
|
||||||
|
|
||||||
if (true === $ret) {
|
|
||||||
$filesystem = new Filesystem();
|
|
||||||
$generated = $this->getCacheDir().'/schema.xml';
|
|
||||||
$filename = $name . '_reversed_schema.xml';
|
|
||||||
$destFile = $this->getApplication()->getKernel()->getRootDir() . '/propel/generated-schemas/' . $filename;
|
|
||||||
|
|
||||||
if (file_exists($generated)) {
|
|
||||||
$filesystem->copy($generated, $destFile);
|
|
||||||
$output->writeln(array(
|
|
||||||
'',
|
|
||||||
sprintf('>> <info>File+</info> %s', $destFile),
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
$output->writeln(array('', 'No generated files.'));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$this->writeTaskError($output, 'reverse');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,127 +8,51 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Command;
|
namespace Propel\Bundle\PropelBundle\Command;
|
||||||
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\Output;
|
|
||||||
use Symfony\Component\Filesystem\Filesystem;
|
|
||||||
use Symfony\Component\Finder\Finder;
|
|
||||||
|
|
||||||
use Propel\PropelBundle\Command\AbstractCommand;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SqlBuildCommand.
|
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||||
*
|
|
||||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
|
||||||
* @author William DURAND <william.durand1@gmail.com>
|
|
||||||
*/
|
*/
|
||||||
class SqlBuildCommand extends AbstractCommand
|
class SqlBuildCommand extends WrappedCommand
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @see Command
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
protected function configure()
|
protected function configure()
|
||||||
{
|
{
|
||||||
$this
|
parent::configure();
|
||||||
->setDescription('Build the SQL generation code for all tables based on Propel XML schemas')
|
|
||||||
->setHelp(<<<EOT
|
|
||||||
The <info>%command.name%</info> command builds the SQL table generation code based on the XML schemas defined in all Bundles.
|
|
||||||
|
|
||||||
<info>php %command.full_name%</info>
|
$this
|
||||||
EOT
|
|
||||||
)
|
|
||||||
->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'Set this parameter to define a connection to use')
|
|
||||||
->setName('propel:sql:build')
|
->setName('propel:sql:build')
|
||||||
|
->setDescription('Build SQL files')
|
||||||
|
->addOption('sql-dir', null, InputOption::VALUE_REQUIRED, 'The SQL files directory')
|
||||||
|
->addOption('overwrite', null, InputOption::VALUE_NONE, '')
|
||||||
|
->addOption('connection', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'Connection to use. Example: default, bookstore')
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Command
|
* {@inheritdoc}
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException When the target directory does not exist
|
|
||||||
*/
|
*/
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function createSubCommandInstance()
|
||||||
{
|
{
|
||||||
if ($input->getOption('verbose')) {
|
return new \Propel\Generator\Command\SqlBuildCommand();
|
||||||
$this->additionalPhingArgs[] = 'verbose';
|
|
||||||
}
|
|
||||||
|
|
||||||
$finder = new Finder();
|
|
||||||
$filesystem = new Filesystem();
|
|
||||||
|
|
||||||
$sqlDir = $this->getApplication()->getKernel()->getRootDir(). DIRECTORY_SEPARATOR . 'propel'. DIRECTORY_SEPARATOR . 'sql';
|
|
||||||
$cacheDir = $this->getApplication()->getKernel()->getCacheDir(). DIRECTORY_SEPARATOR . 'sql';
|
|
||||||
|
|
||||||
$filesystem->remove($cacheDir);
|
|
||||||
$filesystem->mkdir($cacheDir);
|
|
||||||
|
|
||||||
if (!$filesystem->exists($sqlDir)) {
|
|
||||||
$filesystem->mkdir($sqlDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute the task
|
|
||||||
$ret = $this->callPhing('build-sql', array(
|
|
||||||
'propel.sql.dir' => $cacheDir
|
|
||||||
));
|
|
||||||
|
|
||||||
// Show the list of generated files
|
|
||||||
if (true === $ret) {
|
|
||||||
$files = $finder->name('*')->in($cacheDir);
|
|
||||||
|
|
||||||
$nbFiles = 0;
|
|
||||||
foreach ($files as $file) {
|
|
||||||
$fileExt = pathinfo($file->getFilename(), PATHINFO_EXTENSION);
|
|
||||||
$finalLocation = $sqlDir. DIRECTORY_SEPARATOR. $file->getFilename();
|
|
||||||
|
|
||||||
if ($fileExt === 'map' && $filesystem->exists($finalLocation)) {
|
|
||||||
$this->mergeMapFiles($finalLocation, (string) $file);
|
|
||||||
} else {
|
|
||||||
$filesystem->remove($finalLocation);
|
|
||||||
$filesystem->rename((string) $file, $finalLocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->writeNewFile($output, (string) $file);
|
|
||||||
|
|
||||||
if ('sql' === $fileExt) {
|
|
||||||
$nbFiles++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$output->writeln(sprintf('<comment>%d</comment> <info>SQL file%s ha%s been generated.</info>',
|
|
||||||
$nbFiles, $nbFiles > 1 ? 's' : '', $nbFiles > 1 ? 've' : 's'
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
$this->writeSection($output, array(
|
|
||||||
'[Propel] Error',
|
|
||||||
'',
|
|
||||||
'An error has occured during the "propel:sql:build" command process. To get more details, run the command with the "--verbose" option.'
|
|
||||||
), 'fg=white;bg=red');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the existing target and the generated map files, and adds to the
|
* {@inheritdoc}
|
||||||
* target the missing lines that are in the generated file.
|
|
||||||
*
|
|
||||||
* @param string $target target map filename
|
|
||||||
* @param string $generated generated map filename
|
|
||||||
*
|
|
||||||
* @return boolean result
|
|
||||||
*/
|
*/
|
||||||
protected function mergeMapFiles($target, $generated)
|
protected function getSubCommandArguments(InputInterface $input)
|
||||||
{
|
{
|
||||||
if(($targetContent = file($target)) === false)
|
$defaultSqlDir = $this->getContainer()->getParameter('propel.configuration')['paths']['sqlDir'];
|
||||||
|
|
||||||
return false;
|
return array(
|
||||||
if(($generatedContent = file($generated)) === false)
|
'--connection' => $this->getConnections($input->getOption('connection')),
|
||||||
|
'--output-dir' => $input->getOption('sql-dir') ?: $defaultSqlDir,
|
||||||
return false;
|
'--overwrite' => $input->getOption('overwrite')
|
||||||
|
);
|
||||||
$targetContent = array_merge($generatedContent, array_diff($targetContent, $generatedContent));
|
|
||||||
|
|
||||||
return file_put_contents($target, $targetContent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,121 +8,62 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Command;
|
namespace Propel\Bundle\PropelBundle\Command;
|
||||||
|
|
||||||
use Propel\PropelBundle\Command\AbstractCommand;
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SqlInsertCommand.
|
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||||
*
|
|
||||||
* @author William DURAND <william.durand1@gmail.com>
|
|
||||||
*/
|
*/
|
||||||
class SqlInsertCommand extends AbstractCommand
|
class SqlInsertCommand extends WrappedCommand
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @see Command
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
protected function configure()
|
protected function configure()
|
||||||
{
|
{
|
||||||
$this
|
$this
|
||||||
->setDescription('Insert SQL for current model')
|
|
||||||
->addOption('force', null, InputOption::VALUE_NONE, 'Set this parameter to execute this action.')
|
|
||||||
->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'Set this parameter to define a connection to use')
|
|
||||||
->setHelp(<<<EOT
|
|
||||||
The <info>%command.name%</info> command connects to the database and executes all SQL statements found in <comment>app/propel/sql/*schema.sql</comment>.
|
|
||||||
|
|
||||||
<info>php %command.full_name%</info>
|
|
||||||
|
|
||||||
The <info>--force</info> parameter has to be used to actually insert SQL.
|
|
||||||
The <info>--connection</info> parameter allows you to change the connection to use.
|
|
||||||
The default connection is the active connection (propel.dbal.default_connection).
|
|
||||||
EOT
|
|
||||||
)
|
|
||||||
->setName('propel:sql:insert')
|
->setName('propel:sql:insert')
|
||||||
|
->setDescription('Insert SQL statements')
|
||||||
|
->addOption('force', null, InputOption::VALUE_NONE, 'Set this parameter to execute this action.')
|
||||||
|
->addOption('sql-dir', null, InputOption::VALUE_REQUIRED, 'The SQL files directory')
|
||||||
|
->addOption('connection', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'Connection to use. Example: default, bookstore')
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Command
|
* {@inheritdoc}
|
||||||
*
|
*/
|
||||||
* @throws \InvalidArgumentException When the target directory does not exist
|
protected function createSubCommandInstance()
|
||||||
|
{
|
||||||
|
return new \Propel\Generator\Command\SqlInsertCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
{
|
{
|
||||||
// Bad require but needed :(
|
|
||||||
require_once $this->getContainer()->getParameter('propel.path') . '/generator/lib/util/PropelSqlManager.php';
|
|
||||||
|
|
||||||
if ($input->getOption('force')) {
|
if ($input->getOption('force')) {
|
||||||
if ($input->getOption('verbose')) {
|
parent::execute($input, $output);
|
||||||
$this->additionalPhingArgs[] = 'verbose';
|
|
||||||
}
|
|
||||||
|
|
||||||
$connections = $this->getConnections();
|
|
||||||
$sqlDir = $this->getSqlDir();
|
|
||||||
|
|
||||||
$manager = new \PropelSqlManager();
|
|
||||||
$manager->setWorkingDirectory($sqlDir);
|
|
||||||
$manager->setConnections($connections);
|
|
||||||
|
|
||||||
if ($input->getOption('connection')) {
|
|
||||||
list($name, $config) = $this->getConnection($input, $output);
|
|
||||||
$this->doSqlInsert($manager, $output, $name);
|
|
||||||
} else {
|
|
||||||
foreach ($connections as $name => $config) {
|
|
||||||
$output->writeln(sprintf('Use connection named <comment>%s</comment> in <comment>%s</comment> environment.',
|
|
||||||
$name, $this->getApplication()->getKernel()->getEnvironment()));
|
|
||||||
$this->doSqlInsert($manager, $output, $name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
$output->writeln('<error>You have to use --force to execute all SQL statements.</error>');
|
$output->writeln('<error>You have to use --force to execute all SQL statements.</error>');
|
||||||
}
|
return 1;
|
||||||
}
|
|
||||||
|
|
||||||
protected function getSqlDir()
|
|
||||||
{
|
|
||||||
return sprintf('%s/propel/sql', $this->getApplication()->getKernel()->getRootDir());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param \PropelSqlManager $manager
|
|
||||||
* @param OutputInterface $output
|
|
||||||
* @param string $connectionName
|
|
||||||
*/
|
|
||||||
protected function doSqlInsert(\PropelSqlManager $manager, OutputInterface $output, $connectionName)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$statusCode = $manager->insertSql($connectionName);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return $this->writeSection(
|
|
||||||
$output,
|
|
||||||
array('[Propel] Exception', '', $e),
|
|
||||||
'fg=white;bg=red'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (true === $statusCode) {
|
|
||||||
$output->writeln('<info>All SQL statements have been inserted.</info>');
|
|
||||||
} else {
|
|
||||||
$output->writeln('<comment>No SQL statements found.</comment>');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
protected function getConnections()
|
protected function getSubCommandArguments(InputInterface $input)
|
||||||
{
|
{
|
||||||
$propelConfiguration = $this->getContainer()->get('propel.configuration');
|
$defaultSqlDir = $this->getContainer()->getParameter('propel.configuration')['paths']['sqlDir'];
|
||||||
|
|
||||||
$connections = array();
|
return array(
|
||||||
foreach ($propelConfiguration['datasources'] as $name => $config) {
|
'--connection' => $this->getConnections($input->getOption('connection')),
|
||||||
$connections[$name] = $config['connection'];
|
'--sql-dir' => $input->getOption('sql-dir') ?: $defaultSqlDir,
|
||||||
}
|
);
|
||||||
|
|
||||||
return $connections;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,119 +8,105 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Command;
|
namespace Propel\Bundle\PropelBundle\Command;
|
||||||
|
|
||||||
use Propel\PropelBundle\Command\AbstractCommand;
|
use Propel\Runtime\Adapter\Pdo\MysqlAdapter;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Propel\Runtime\Propel;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TableDropCommand class.
|
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||||
* Useful to drop table in a database.
|
|
||||||
*
|
|
||||||
* @author Maxime AILLOUD
|
|
||||||
*/
|
*/
|
||||||
class TableDropCommand extends AbstractCommand
|
class TableDropCommand extends ContainerAwareCommand
|
||||||
{
|
{
|
||||||
|
use FormattingHelpers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Command
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
protected function configure()
|
protected function configure()
|
||||||
{
|
{
|
||||||
$this
|
$this
|
||||||
|
->setName('propel:table:drop')
|
||||||
->setDescription('Drop a given table or all tables in the database.')
|
->setDescription('Drop a given table or all tables in the database.')
|
||||||
->addArgument('table', InputArgument::IS_ARRAY, 'Set this parameter to défine which table to delete (default all the table in the database.')
|
|
||||||
->addOption('force', null, InputOption::VALUE_NONE, 'Set this parameter to execute this action.')
|
|
||||||
->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'Set this parameter to define a connection to use')
|
|
||||||
->setHelp(<<<EOT
|
|
||||||
The <info>propel:table:drop</info> command will drop one or several table.
|
|
||||||
|
|
||||||
<info>php app/console propel:table:drop</info>
|
->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'Connection to use. Example: default, bookstore')
|
||||||
|
->addOption('force', null, InputOption::VALUE_NONE, 'Set this parameter to execute this action.')
|
||||||
The <info>table</info> arguments define the list of table which has to be delete <comment>(default: all table)</comment>.
|
->addArgument('table', InputArgument::IS_ARRAY, 'Set this parameter to défine which table to delete (default all the table in the database.')
|
||||||
The <info>--force</info> parameter has to be used to actually drop the table.
|
;
|
||||||
The <info>--connection</info> parameter allows you to change the connection to use.
|
|
||||||
The default connection is the active connection (propel.dbal.default_connection).
|
|
||||||
EOT
|
|
||||||
)
|
|
||||||
->setName('propel:table:drop');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Command
|
* {@inheritdoc}
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException When the target directory does not exist
|
|
||||||
*/
|
*/
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
{
|
{
|
||||||
|
$connection = Propel::getConnection($input->getOption('connection'));
|
||||||
|
$adapter = Propel::getAdapter($connection->getName());
|
||||||
|
|
||||||
|
if (!$adapter instanceof MysqlAdapter) {
|
||||||
|
return $output->writeln('<error>This command is MySQL only.</error>');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$input->getOption('force')) {
|
||||||
|
return $output->writeln('<error>You have to use the "--force" option to drop some tables.</error>');
|
||||||
|
}
|
||||||
|
|
||||||
$tablesToDelete = $input->getArgument('table');
|
$tablesToDelete = $input->getArgument('table');
|
||||||
|
$nbTable = count($tablesToDelete);
|
||||||
|
$tablePlural = (($nbTable > 1 || $nbTable == 0) ? 's' : '' );
|
||||||
|
|
||||||
if ($input->getOption('force')) {
|
if ('prod' === $this->getApplication()->getKernel()->getEnvironment()) {
|
||||||
$nbTable = count($tablesToDelete);
|
$count = $nbTable ?: 'all';
|
||||||
$tablePlural = (($nbTable > 1 || $nbTable == 0) ? 's' : '' );
|
|
||||||
|
|
||||||
if ('prod' === $this->getApplication()->getKernel()->getEnvironment()) {
|
$this->writeSection(
|
||||||
$count = (count($input->getArgument('table')) ?: 'all');
|
$output,
|
||||||
|
'WARNING: you are about to drop ' . $count . ' table' . $tablePlural . ' in production !',
|
||||||
|
'bg=red;fg=white'
|
||||||
|
);
|
||||||
|
|
||||||
$this->writeSection(
|
if (false === $this->askConfirmation($input, $output, 'Are you sure ? (y/n) ', false)) {
|
||||||
$output,
|
$output->writeln('<info>Aborted, nice decision !</info>');
|
||||||
'WARNING: you are about to drop ' . $count . ' table' . $tablePlural . ' in production !',
|
|
||||||
'bg=red;fg=white'
|
|
||||||
);
|
|
||||||
|
|
||||||
if (false === $this->askConfirmation($output, 'Are you sure ? (y/n) ', false)) {
|
return -2;
|
||||||
$output->writeln('<info>Aborted, nice decision !</info>');
|
|
||||||
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
$showStatement = $connection->prepare('SHOW TABLES;');
|
||||||
list($name, $config) = $this->getConnection($input, $output);
|
$showStatement->execute();
|
||||||
$connection = \Propel::getConnection($name);
|
|
||||||
$adapter = \Propel::getDB($name);
|
|
||||||
|
|
||||||
$showStatement = $connection->prepare('SHOW TABLES;');
|
$allTables = $showStatement->fetchAll(\PDO::FETCH_COLUMN);
|
||||||
$showStatement->execute();
|
|
||||||
|
|
||||||
$allTables = $showStatement->fetchAll(\PDO::FETCH_COLUMN);
|
if ($nbTable) {
|
||||||
|
foreach ($tablesToDelete as $tableToDelete) {
|
||||||
if ($nbTable) {
|
if (!array_search($tableToDelete, $allTables)) {
|
||||||
foreach ($tablesToDelete as $tableToDelete) {
|
throw new \InvalidArgumentException(sprintf('Table %s doesn\'t exist in the database.', $tableToDelete));
|
||||||
if (!array_search($tableToDelete, $allTables)) {
|
|
||||||
throw new \InvalidArgumentException(sprintf('Table %s doesn\'t exist in the database.', $tableToDelete));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$tablesToDelete = $allTables;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$connection->exec('SET FOREIGN_KEY_CHECKS = 0;');
|
|
||||||
|
|
||||||
array_walk($tablesToDelete, function(&$table, $key, $dbAdapter) { $table = $dbAdapter->quoteIdentifierTable($table); }, $adapter);
|
|
||||||
|
|
||||||
$tablesToDelete = join(', ', $tablesToDelete);
|
|
||||||
|
|
||||||
if ('' !== $tablesToDelete) {
|
|
||||||
$connection->exec('DROP TABLE ' . $tablesToDelete . ' ;');
|
|
||||||
|
|
||||||
$output->writeln(sprintf('Table' . $tablePlural . ' <info><comment>%s</comment> has been dropped.</info>', $tablesToDelete));
|
|
||||||
} else {
|
|
||||||
$output->writeln('<info>No tables have been dropped</info>');
|
|
||||||
}
|
|
||||||
|
|
||||||
$connection->exec('SET FOREIGN_KEY_CHECKS = 1;');
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$this->writeSection($output, array(
|
|
||||||
'[Propel] Exception caught',
|
|
||||||
'',
|
|
||||||
$e->getMessage()
|
|
||||||
), 'fg=white;bg=red');
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$output->writeln('<error>You have to use the "--force" option to drop some tables.</error>');
|
$tablesToDelete = $allTables;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$connection->exec('SET FOREIGN_KEY_CHECKS = 0;');
|
||||||
|
|
||||||
|
array_walk($tablesToDelete, function (&$table, $key, $dbAdapter) {
|
||||||
|
$table = $dbAdapter->quoteIdentifierTable($table);
|
||||||
|
}, $adapter);
|
||||||
|
|
||||||
|
$tablesToDelete = join(', ', $tablesToDelete);
|
||||||
|
|
||||||
|
if ('' !== $tablesToDelete) {
|
||||||
|
$connection->exec('DROP TABLE ' . $tablesToDelete . ' ;');
|
||||||
|
|
||||||
|
$output->writeln(sprintf('Table' . $tablePlural . ' <info><comment>%s</comment> has been dropped.</info>', $tablesToDelete));
|
||||||
|
} else {
|
||||||
|
$output->writeln('<info>No tables have been dropped</info>');
|
||||||
|
}
|
||||||
|
|
||||||
|
$connection->exec('SET FOREIGN_KEY_CHECKS = 1;');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
58
Command/WrappedCommand.php
Normal file
58
Command/WrappedCommand.php
Normal 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\Bundle\PropelBundle\Command;
|
||||||
|
|
||||||
|
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>
|
||||||
|
*/
|
||||||
|
abstract class WrappedCommand extends AbstractCommand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Creates the instance of the Propel sub-command to execute.
|
||||||
|
*
|
||||||
|
* @return \Symfony\Component\Console\Command\Command
|
||||||
|
*/
|
||||||
|
abstract protected function createSubCommandInstance();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all the arguments and options needed by the Propel sub-command.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
abstract protected function getSubCommandArguments(InputInterface $input);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this
|
||||||
|
->addOption('platform', null, InputOption::VALUE_OPTIONAL, 'The platform')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$params = $this->getSubCommandArguments($input);
|
||||||
|
$command = $this->createSubCommandInstance();
|
||||||
|
|
||||||
|
$this->setupBuildTimeFiles();
|
||||||
|
|
||||||
|
return $this->runCommand($command, $params, $input, $output);
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,9 +8,12 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Controller;
|
namespace Propel\Bundle\PropelBundle\Controller;
|
||||||
|
|
||||||
use Symfony\Component\DependencyInjection\ContainerAware;
|
use Propel\Runtime\Propel;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,24 +21,19 @@ use Symfony\Component\HttpFoundation\Response;
|
||||||
*
|
*
|
||||||
* @author William DURAND <william.durand1@gmail.com>
|
* @author William DURAND <william.durand1@gmail.com>
|
||||||
*/
|
*/
|
||||||
class PanelController extends ContainerAware
|
class PanelController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* This method renders the global Propel configuration.
|
* This method renders the global Propel configuration.
|
||||||
*/
|
*/
|
||||||
public function configurationAction()
|
public function configurationAction()
|
||||||
{
|
{
|
||||||
$templating = $this->container->get('templating');
|
return $this->render(
|
||||||
|
'@Propel/Panel/configuration.html.twig',
|
||||||
return $templating->renderResponse(
|
|
||||||
'PropelBundle:Panel:configuration.html.twig',
|
|
||||||
array(
|
array(
|
||||||
'propel_version' => \Propel::VERSION,
|
'propel_version' => Propel::VERSION,
|
||||||
'configuration' => $this->container->get('propel.configuration')->getParameters(),
|
'configuration' => $this->getParameter('propel.configuration'),
|
||||||
'default_connection' => $this->container->getParameter('propel.dbal.default_connection'),
|
'logging' => $this->getParameter('propel.logging'),
|
||||||
'logging' => $this->container->getParameter('propel.logging'),
|
|
||||||
'path' => $this->container->getParameter('propel.path'),
|
|
||||||
'phing_path' => $this->container->getParameter('propel.phing_path'),
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -47,11 +45,11 @@ class PanelController extends ContainerAware
|
||||||
* @param string $connection The connection name
|
* @param string $connection The connection name
|
||||||
* @param integer $query
|
* @param integer $query
|
||||||
*
|
*
|
||||||
* @return Symfony\Component\HttpFoundation\Response A Response instance
|
* @return Response A Response instance
|
||||||
*/
|
*/
|
||||||
public function explainAction($token, $connection, $query)
|
public function explainAction($token, $connection, $query)
|
||||||
{
|
{
|
||||||
$profiler = $this->container->get('profiler');
|
$profiler = $this->get('profiler');
|
||||||
$profiler->disable();
|
$profiler->disable();
|
||||||
|
|
||||||
$profile = $profiler->loadProfile($token);
|
$profile = $profiler->loadProfile($token);
|
||||||
|
@ -62,20 +60,18 @@ class PanelController extends ContainerAware
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the connection
|
// Open the connection
|
||||||
$con = \Propel::getConnection($connection);
|
$con = Propel::getConnection($connection);
|
||||||
|
|
||||||
// Get the adapter
|
|
||||||
$db = \Propel::getDB($connection);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$stmt = $db->doExplainPlan($con, $queries[$query]['sql']);
|
$dataFetcher = $con->query('EXPLAIN ' . $queries[$query]['sql']);
|
||||||
$results = $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
$results = array();
|
||||||
|
while (($results[] = $dataFetcher->fetch(\PDO::FETCH_ASSOC)));
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return new Response('<div class="error">This query cannot be explained.</div>');
|
return new Response('<div class="error">This query cannot be explained.</div>');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->container->get('templating')->renderResponse(
|
return $this->render(
|
||||||
'PropelBundle:Panel:explain.html.twig',
|
'@Propel/Panel/explain.html.twig',
|
||||||
array(
|
array(
|
||||||
'data' => $results,
|
'data' => $results,
|
||||||
'query' => $query,
|
'query' => $query,
|
||||||
|
|
115
DataCollector/PropelDataCollector.php
Normal file
115
DataCollector/PropelDataCollector.php
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
<?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\Bundle\PropelBundle\DataCollector;
|
||||||
|
|
||||||
|
use Propel\Bundle\PropelBundle\Logger\PropelLogger;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The PropelDataCollector collector class collects information.
|
||||||
|
*
|
||||||
|
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||||
|
*/
|
||||||
|
class PropelDataCollector extends DataCollector
|
||||||
|
{
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
|
public function __construct(PropelLogger $logger)
|
||||||
|
{
|
||||||
|
$this->logger = $logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function collect(Request $request, Response $response, \Exception $exception = null)
|
||||||
|
{
|
||||||
|
$this->data = array(
|
||||||
|
'queries' => $this->cloneVar($this->buildQueries()),
|
||||||
|
'querycount' => $this->countQueries(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the collector name.
|
||||||
|
*
|
||||||
|
* @return string The collector name.
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'propel';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns queries.
|
||||||
|
*
|
||||||
|
* @return array Queries
|
||||||
|
*/
|
||||||
|
public function getQueries()
|
||||||
|
{
|
||||||
|
return $this->data['queries'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the query count.
|
||||||
|
*
|
||||||
|
* @return int The query count
|
||||||
|
*/
|
||||||
|
public function getQueryCount()
|
||||||
|
{
|
||||||
|
return $this->data['querycount'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the total time of queries.
|
||||||
|
*
|
||||||
|
* @return float The total time of queries
|
||||||
|
*/
|
||||||
|
public function getTime()
|
||||||
|
{
|
||||||
|
$time = 0;
|
||||||
|
foreach ($this->data['queries'] as $query) {
|
||||||
|
$time += (float) $query['time'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $time;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array of Build objects.
|
||||||
|
*
|
||||||
|
* @return array An array of Build objects
|
||||||
|
*/
|
||||||
|
private function buildQueries()
|
||||||
|
{
|
||||||
|
return $this->logger->getQueries();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count queries.
|
||||||
|
*
|
||||||
|
* @return int The number of queries.
|
||||||
|
*/
|
||||||
|
private function countQueries()
|
||||||
|
{
|
||||||
|
return count($this->logger->getQueries());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function reset()
|
||||||
|
{
|
||||||
|
// TODO: Implement reset() method.
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,9 +8,10 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\DataFixtures;
|
namespace Propel\Bundle\PropelBundle\DataFixtures;
|
||||||
|
|
||||||
use \Propel;
|
use Propel\Runtime\Map\DatabaseMap;
|
||||||
|
use Propel\Runtime\Propel;
|
||||||
use Symfony\Component\Finder\Finder;
|
use Symfony\Component\Finder\Finder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,23 +23,32 @@ abstract class AbstractDataHandler
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $rootDir;
|
protected $rootDir;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \PDO
|
* @var \PDO
|
||||||
*/
|
*/
|
||||||
protected $con;
|
protected $con;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \DatabaseMap
|
* @var DatabaseMap
|
||||||
*/
|
*/
|
||||||
protected $dbMap;
|
protected $dbMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $datasources = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor
|
* Default constructor
|
||||||
*
|
*
|
||||||
* @param string $rootDir The root directory.
|
* @param string $rootDir The root directory.
|
||||||
|
* @param array $datasources
|
||||||
*/
|
*/
|
||||||
public function __construct($rootDir)
|
public function __construct($rootDir, array $datasources)
|
||||||
{
|
{
|
||||||
$this->rootDir = $rootDir;
|
$this->rootDir = $rootDir;
|
||||||
|
$this->datasources = $datasources;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,8 +73,10 @@ abstract class AbstractDataHandler
|
||||||
$this->dbMap = Propel::getDatabaseMap($connectionName);
|
$this->dbMap = Propel::getDatabaseMap($connectionName);
|
||||||
if (0 === count($this->dbMap->getTables())) {
|
if (0 === count($this->dbMap->getTables())) {
|
||||||
$finder = new Finder();
|
$finder = new Finder();
|
||||||
$files = $finder->files()->name('*TableMap.php')
|
$files = $finder
|
||||||
->in($this->getRootDir() . '/../')
|
->files()->name('*TableMap.php')
|
||||||
|
->in($this->getModelSearchPaths($connectionName))
|
||||||
|
->notName('TableMap.php')
|
||||||
->exclude('PropelBundle')
|
->exclude('PropelBundle')
|
||||||
->exclude('Tests');
|
->exclude('Tests');
|
||||||
|
|
||||||
|
@ -80,15 +92,15 @@ abstract class AbstractDataHandler
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a table is in a database
|
* Check if a table is in a database
|
||||||
* @param string $class
|
*
|
||||||
* @param string $connectionName
|
* @param string $class
|
||||||
|
* @param string $connectionName
|
||||||
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
protected function isInDatabase($class, $connectionName)
|
protected function isInDatabase($class, $connectionName)
|
||||||
{
|
{
|
||||||
$table = new $class();
|
return constant($class.'::DATABASE_NAME') === $connectionName;
|
||||||
|
|
||||||
return constant($table->getPeerClassname().'::DATABASE_NAME') == $connectionName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -97,6 +109,8 @@ abstract class AbstractDataHandler
|
||||||
*
|
*
|
||||||
* @param string $path The relative path of the file.
|
* @param string $path The relative path of the file.
|
||||||
* @param string $shortClassName The short class name aka the filename without extension.
|
* @param string $shortClassName The short class name aka the filename without extension.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
private function guessFullClassName($path, $shortClassName)
|
private function guessFullClassName($path, $shortClassName)
|
||||||
{
|
{
|
||||||
|
@ -120,4 +134,27 @@ abstract class AbstractDataHandler
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the search path for models out of the configuration.
|
||||||
|
*
|
||||||
|
* @param string $connectionName A connection name.
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
protected function getModelSearchPaths($connectionName)
|
||||||
|
{
|
||||||
|
$searchPath = array();
|
||||||
|
|
||||||
|
if (!empty($this->datasources['database']['connections'][$connectionName]['model_paths'])) {
|
||||||
|
$modelPaths = $this->datasources['database']['connections'][$connectionName]['model_paths'];
|
||||||
|
foreach ($modelPaths as $modelPath) {
|
||||||
|
$searchPath[] = $this->getRootDir() . '/../' . $modelPath;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$searchPath[] = $this->getRootDir() . '/../';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $searchPath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,12 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\DataFixtures\Dumper;
|
namespace Propel\Bundle\PropelBundle\DataFixtures\Dumper;
|
||||||
|
|
||||||
use Propel\PropelBundle\DataFixtures\AbstractDataHandler;
|
|
||||||
use \PDO;
|
use \PDO;
|
||||||
use \Propel;
|
use Propel\Bundle\PropelBundle\DataFixtures\AbstractDataHandler;
|
||||||
use \PropelColumnTypes;
|
use Propel\Generator\Model\PropelTypes;
|
||||||
|
use Propel\Runtime\Propel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class to manage a common logic to dump data.
|
* Abstract class to manage a common logic to dump data.
|
||||||
|
@ -69,7 +69,7 @@ abstract class AbstractDataDumper extends AbstractDataHandler implements DataDum
|
||||||
|
|
||||||
$dumpData = array();
|
$dumpData = array();
|
||||||
foreach ($tables as $tableName) {
|
foreach ($tables as $tableName) {
|
||||||
$tableMap = $this->dbMap->getTable(constant(constant($tableName.'::PEER').'::TABLE_NAME'));
|
$tableMap = $this->dbMap->getTable(constant(constant($tableName.'::TABLE_MAP').'::TABLE_NAME'));
|
||||||
$hasParent = false;
|
$hasParent = false;
|
||||||
$haveParents = false;
|
$haveParents = false;
|
||||||
$fixColumn = null;
|
$fixColumn = null;
|
||||||
|
@ -107,10 +107,14 @@ abstract class AbstractDataDumper extends AbstractDataHandler implements DataDum
|
||||||
}
|
}
|
||||||
$stmt = $this
|
$stmt = $this
|
||||||
->con
|
->con
|
||||||
->query(sprintf('SELECT %s FROM %s', implode(',', $in), constant(constant($tableName.'::PEER').'::TABLE_NAME')));
|
->query(sprintf('SELECT `%s` FROM `%s`', implode('`, `', $in), constant(constant($tableName.'::TABLE_MAP').'::TABLE_NAME')));
|
||||||
|
|
||||||
$resultsSets[] = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$set = array();
|
||||||
$stmt->closeCursor();
|
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
$set[] = $row;
|
||||||
|
}
|
||||||
|
$resultsSets[] = $set;
|
||||||
|
$stmt->close();
|
||||||
unset($stmt);
|
unset($stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +152,7 @@ abstract class AbstractDataDumper extends AbstractDataHandler implements DataDum
|
||||||
$values[$col] = strlen($row[$col]) ? $relatedTable->getPhpName().'_'.$row[$col] : '';
|
$values[$col] = strlen($row[$col]) ? $relatedTable->getPhpName().'_'.$row[$col] : '';
|
||||||
}
|
}
|
||||||
} elseif (!$isPrimaryKey || ($isPrimaryKey && !$tableMap->isUseIdGenerator())) {
|
} elseif (!$isPrimaryKey || ($isPrimaryKey && !$tableMap->isUseIdGenerator())) {
|
||||||
if (!empty($row[$col]) && PropelColumnTypes::PHP_ARRAY === $column->getType()) {
|
if (!empty($row[$col]) && PropelTypes::PHP_ARRAY === $column->getType()) {
|
||||||
$serialized = substr($row[$col], 2, -2);
|
$serialized = substr($row[$col], 2, -2);
|
||||||
$row[$col] = $serialized ? explode(' | ', $serialized) : array();
|
$row[$col] = $serialized ? explode(' | ', $serialized) : array();
|
||||||
}
|
}
|
||||||
|
@ -157,7 +161,7 @@ abstract class AbstractDataDumper extends AbstractDataHandler implements DataDum
|
||||||
$values[$col] = $row[$col];
|
$values[$col] = $row[$col];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PropelColumnTypes::OBJECT === $column->getType()) {
|
if (PropelTypes::OBJECT === $column->getType()) {
|
||||||
$values[$col] = unserialize($row[$col]);
|
$values[$col] = unserialize($row[$col]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,7 +191,7 @@ abstract class AbstractDataDumper extends AbstractDataHandler implements DataDum
|
||||||
// reordering classes to take foreign keys into account
|
// reordering classes to take foreign keys into account
|
||||||
for ($i = 0, $count = count($classes); $i < $count; $i++) {
|
for ($i = 0, $count = count($classes); $i < $count; $i++) {
|
||||||
$class = $classes[$i];
|
$class = $classes[$i];
|
||||||
$tableMap = $this->dbMap->getTable(constant(constant($class.'::PEER').'::TABLE_NAME'));
|
$tableMap = $this->dbMap->getTable(constant(constant($class.'::TABLE_MAP').'::TABLE_NAME'));
|
||||||
|
|
||||||
foreach ($tableMap->getColumns() as $column) {
|
foreach ($tableMap->getColumns() as $column) {
|
||||||
if ($column->isForeignKey()) {
|
if ($column->isForeignKey()) {
|
||||||
|
@ -216,7 +220,7 @@ abstract class AbstractDataDumper extends AbstractDataHandler implements DataDum
|
||||||
protected function fixOrderingOfForeignKeyDataInSameTable($resultsSets, $tableName, $column, $in = null)
|
protected function fixOrderingOfForeignKeyDataInSameTable($resultsSets, $tableName, $column, $in = null)
|
||||||
{
|
{
|
||||||
$sql = sprintf('SELECT * FROM %s WHERE %s %s',
|
$sql = sprintf('SELECT * FROM %s WHERE %s %s',
|
||||||
constant(constant($tableName.'::PEER').'::TABLE_NAME'),
|
constant(constant($tableName.'::TABLE_MAP').'::TABLE_NAME'),
|
||||||
strtolower($column->getName()),
|
strtolower($column->getName()),
|
||||||
null === $in ? 'IS NULL' : 'IN ('.$in.')');
|
null === $in ? 'IS NULL' : 'IN ('.$in.')');
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\DataFixtures\Dumper;
|
namespace Propel\Bundle\PropelBundle\DataFixtures\Dumper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface that exposes how Propel data dumpers should work.
|
* Interface that exposes how Propel data dumpers should work.
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\DataFixtures\Dumper;
|
namespace Propel\Bundle\PropelBundle\DataFixtures\Dumper;
|
||||||
|
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
|
@ -28,8 +28,7 @@ class YamlDataDumper extends AbstractDataDumper
|
||||||
$data,
|
$data,
|
||||||
$inline = 3,
|
$inline = 3,
|
||||||
$indent = 4,
|
$indent = 4,
|
||||||
$exceptionOnInvalidType = false,
|
Yaml::DUMP_OBJECT
|
||||||
$objectSupport = true
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,15 +8,15 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\DataFixtures\Loader;
|
namespace Propel\Bundle\PropelBundle\DataFixtures\Loader;
|
||||||
|
|
||||||
use \BasePeer;
|
use Propel\Bundle\PropelBundle\DataFixtures\AbstractDataHandler;
|
||||||
use \BaseObject;
|
use Propel\Bundle\PropelBundle\Util\PropelInflector;
|
||||||
use \Propel;
|
use Propel\Generator\Model\PropelTypes;
|
||||||
use \PropelColumnTypes;
|
use Propel\Runtime\ActiveRecord\ActiveRecordInterface;
|
||||||
use \PropelException;
|
use Propel\Runtime\Map\Exception\TableNotFoundException;
|
||||||
use Propel\PropelBundle\DataFixtures\AbstractDataHandler;
|
use Propel\Runtime\Map\TableMap;
|
||||||
use Propel\PropelBundle\Util\PropelInflector;
|
use Propel\Runtime\Propel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class to manage a common logic to load datas.
|
* Abstract class to manage a common logic to load datas.
|
||||||
|
@ -105,15 +105,8 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
||||||
*/
|
*/
|
||||||
protected function deleteClassData($class)
|
protected function deleteClassData($class)
|
||||||
{
|
{
|
||||||
// Check that peer class exists before calling doDeleteAll()
|
$tableMap = $this->dbMap->getTable(constant(constant($class.'::TABLE_MAP').'::TABLE_NAME'));
|
||||||
$peerClass = constant($class.'::PEER');
|
$tableMap->doDeleteAll($this->con);
|
||||||
if (!class_exists($peerClass)) {
|
|
||||||
throw new \InvalidArgumentException(sprintf('Unknown class "%sPeer".', $class));
|
|
||||||
}
|
|
||||||
|
|
||||||
// bypass the soft_delete behavior if enabled
|
|
||||||
$deleteMethod = method_exists($peerClass, 'doForceDeleteAll') ? 'doForceDeleteAll' : 'doDeleteAll';
|
|
||||||
call_user_func(array($peerClass, $deleteMethod), $this->con);
|
|
||||||
|
|
||||||
$this->deletedClasses[] = $class;
|
$this->deletedClasses[] = $class;
|
||||||
|
|
||||||
|
@ -129,7 +122,7 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
||||||
/**
|
/**
|
||||||
* Loads the data using the generated data model.
|
* Loads the data using the generated data model.
|
||||||
*
|
*
|
||||||
* @param array $data The data to be loaded
|
* @param array|null $data The data to be loaded
|
||||||
*/
|
*/
|
||||||
protected function loadDataFromArray($data = null)
|
protected function loadDataFromArray($data = null)
|
||||||
{
|
{
|
||||||
|
@ -138,20 +131,20 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($data as $class => $datas) {
|
foreach ($data as $class => $datas) {
|
||||||
$class = trim($class);
|
|
||||||
if ('\\' == $class[0]) {
|
|
||||||
$class = substr($class, 1);
|
|
||||||
}
|
|
||||||
$tableMap = $this->dbMap->getTable(constant(constant($class.'::PEER').'::TABLE_NAME'));
|
|
||||||
$column_names = call_user_func_array(array(constant($class.'::PEER'), 'getFieldNames'), array(BasePeer::TYPE_FIELDNAME));
|
|
||||||
|
|
||||||
// iterate through datas for this class
|
// iterate through datas for this class
|
||||||
// might have been empty just for force a table to be emptied on import
|
// might have been empty just for force a table to be emptied on import
|
||||||
if (!is_array($datas)) {
|
if (!is_array($datas)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($datas as $key => $data) {
|
$class = trim($class);
|
||||||
|
if ('\\' == $class[0]) {
|
||||||
|
$class = substr($class, 1);
|
||||||
|
}
|
||||||
|
$tableMap = $this->dbMap->getTable(constant(constant($class.'::TABLE_MAP').'::TABLE_NAME'));
|
||||||
|
$column_names = $tableMap->getFieldnames(TableMap::TYPE_PHPNAME);
|
||||||
|
|
||||||
|
foreach ($datas as $key => $values) {
|
||||||
// create a new entry in the database
|
// create a new entry in the database
|
||||||
if (!class_exists($class)) {
|
if (!class_exists($class)) {
|
||||||
throw new \InvalidArgumentException(sprintf('Unknown class "%s".', $class));
|
throw new \InvalidArgumentException(sprintf('Unknown class "%s".', $class));
|
||||||
|
@ -159,28 +152,28 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
||||||
|
|
||||||
$obj = new $class();
|
$obj = new $class();
|
||||||
|
|
||||||
if (!$obj instanceof BaseObject) {
|
if (!$obj instanceof ActiveRecordInterface) {
|
||||||
throw new \RuntimeException(
|
throw new \RuntimeException(
|
||||||
sprintf('The class "%s" is not a Propel class. There is probably another class named "%s" somewhere.', $class, $class)
|
sprintf('The class "%s" is not a Propel class. There is probably another class named "%s" somewhere.', $class, $class)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_array($data)) {
|
if (!is_array($values)) {
|
||||||
throw new \InvalidArgumentException(sprintf('You must give a name for each fixture data entry (class %s).', $class));
|
throw new \InvalidArgumentException(sprintf('You must give a name for each fixture data entry (class %s).', $class));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($data as $name => $value) {
|
foreach ($values as $name => $value) {
|
||||||
if (is_array($value) && 's' === substr($name, -1)) {
|
if (is_array($value) && 's' === substr($name, -1)) {
|
||||||
try {
|
try {
|
||||||
// many to many relationship
|
// many to many relationship
|
||||||
$this->loadManyToMany($obj, substr($name, 0, -1), $value);
|
$this->loadManyToMany($obj, substr($name, 0, -1), $value);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
} catch (PropelException $e) {
|
} catch (TableNotFoundException $e) {
|
||||||
// Check whether this is actually an array stored in the object.
|
// Check whether this is actually an array stored in the object.
|
||||||
if ('Cannot fetch TableMap for undefined table: ' . substr($name, 0, -1) === $e->getMessage()) {
|
if ('Cannot fetch TableMap for undefined table: ' . substr($name, 0, -1) === $e->getMessage()) {
|
||||||
if (PropelColumnTypes::PHP_ARRAY !== $tableMap->getColumn($name)->getType()
|
if (PropelTypes::PHP_ARRAY !== $tableMap->getColumn($name)->getType()
|
||||||
&& PropelColumnTypes::OBJECT !== $tableMap->getColumn($name)->getType()) {
|
&& PropelTypes::OBJECT !== $tableMap->getColumn($name)->getType()) {
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,8 +196,8 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
||||||
* but which is not a ForeignKey (e.g. delegatable behavior on 1:1 relation).
|
* but which is not a ForeignKey (e.g. delegatable behavior on 1:1 relation).
|
||||||
*/
|
*/
|
||||||
if ($column->isPrimaryKey() && null !== $value && !$column->isForeignKey()) {
|
if ($column->isPrimaryKey() && null !== $value && !$column->isForeignKey()) {
|
||||||
if (isset($this->object_references[$class.'_'.$value])) {
|
if (isset($this->object_references[$this->cleanObjectRef($class.'_'.$value)])) {
|
||||||
$obj = $this->object_references[$class.'_'.$value];
|
$obj = $this->object_references[$this->cleanObjectRef($class.'_'.$value)];
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -212,14 +205,19 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
||||||
|
|
||||||
if ($column->isForeignKey() && null !== $value) {
|
if ($column->isForeignKey() && null !== $value) {
|
||||||
$relatedTable = $this->dbMap->getTable($column->getRelatedTableName());
|
$relatedTable = $this->dbMap->getTable($column->getRelatedTableName());
|
||||||
if (!isset($this->object_references[$relatedTable->getClassname().'_'.$value])) {
|
if (isset($this->object_references[$this->cleanObjectRef($relatedTable->getClassname().'_'.$value)])) {
|
||||||
throw new \InvalidArgumentException(
|
$value = $this
|
||||||
sprintf('The object "%s" from class "%s" is not defined in your data file.', $value, $relatedTable->getClassname())
|
->object_references[$this->cleanObjectRef($relatedTable->getClassname().'_'.$value)]
|
||||||
);
|
->getByName($column->getRelatedName(), TableMap::TYPE_COLNAME);
|
||||||
|
} else {
|
||||||
|
$relatedClass = $this->cleanObjectRef($relatedTable->getClassName());
|
||||||
|
if (isset($data[$relatedClass]) || isset($data['\\' . $relatedClass])) {
|
||||||
|
throw new \InvalidArgumentException(
|
||||||
|
sprintf('The object "%s" from class "%s" is not defined in your data file.', $value, $relatedTable->getClassname())
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$value = $this
|
|
||||||
->object_references[$relatedTable->getClassname().'_'.$value]
|
|
||||||
->getByName($column->getRelatedName(), BasePeer::TYPE_COLNAME);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,43 +240,42 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
||||||
/**
|
/**
|
||||||
* Save a reference to the specified object (and its ancestors) before loading them.
|
* Save a reference to the specified object (and its ancestors) before loading them.
|
||||||
*
|
*
|
||||||
* @param string $class Class name of passed object
|
* @param string $class Class name of passed object
|
||||||
* @param string $key Key identifying specified object
|
* @param string $key Key identifying specified object
|
||||||
* @param BaseObject $obj A Propel object
|
* @param ActiveRecordInterface $obj A Propel object
|
||||||
*/
|
*/
|
||||||
protected function saveParentReference($class, $key, &$obj)
|
protected function saveParentReference($class, $key, &$obj)
|
||||||
{
|
{
|
||||||
if (method_exists($obj, 'getPrimaryKey')) {
|
if (!method_exists($obj, 'getPrimaryKey')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$this->object_references[$class.'_'.$key] = $obj;
|
$this->object_references[$this->cleanObjectRef($class.'_'.$key)] = $obj;
|
||||||
|
|
||||||
// Get parent (schema ancestor) of parent (Propel base class) in case of inheritance
|
// Get parent (schema ancestor) of parent (Propel base class) in case of inheritance
|
||||||
if (false !== ($parentClass = get_parent_class(get_parent_class($class)))) {
|
if (false !== ($parentClass = get_parent_class(get_parent_class($class)))) {
|
||||||
|
|
||||||
$reflectionClass = new \ReflectionClass($parentClass);
|
|
||||||
if (!$reflectionClass->isAbstract()) {
|
|
||||||
$parentObj = new $parentClass;
|
|
||||||
$parentObj->fromArray($obj->toArray());
|
|
||||||
$this->saveParentReference($parentClass, $key, $parentObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
$reflectionClass = new \ReflectionClass($parentClass);
|
||||||
|
if (!$reflectionClass->isAbstract()) {
|
||||||
|
$parentObj = new $parentClass();
|
||||||
|
$parentObj->fromArray($obj->toArray());
|
||||||
|
$this->saveParentReference($parentClass, $key, $parentObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads many to many objects.
|
* Loads many to many objects.
|
||||||
*
|
*
|
||||||
* @param BaseObject $obj A Propel object
|
* @param ActiveRecordInterface $obj A Propel object
|
||||||
* @param string $middleTableName The middle table name
|
* @param string $middleTableName The middle table name
|
||||||
* @param array $values An array of values
|
* @param array $values An array of values
|
||||||
*/
|
*/
|
||||||
protected function loadManyToMany($obj, $middleTableName, $values)
|
protected function loadManyToMany($obj, $middleTableName, $values)
|
||||||
{
|
{
|
||||||
$middleTable = $this->dbMap->getTable($middleTableName);
|
$middleTable = $this->dbMap->getTable($middleTableName);
|
||||||
$middleClass = $middleTable->getClassname();
|
$middleClass = $middleTable->getClassname();
|
||||||
$tableName = constant(constant(get_class($obj).'::PEER').'::TABLE_NAME');
|
$tableName = constant(constant(get_class($obj).'::TABLE_MAP').'::TABLE_NAME');
|
||||||
|
|
||||||
foreach ($middleTable->getColumns() as $column) {
|
foreach ($middleTable->getColumns() as $column) {
|
||||||
if ($column->isForeignKey()) {
|
if ($column->isForeignKey()) {
|
||||||
|
@ -296,7 +293,7 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($values as $value) {
|
foreach ($values as $value) {
|
||||||
if (!isset($this->object_references[$relatedClass.'_'.$value])) {
|
if (!isset($this->object_references[$this->cleanObjectRef($relatedClass.'_'.$value)])) {
|
||||||
throw new \InvalidArgumentException(
|
throw new \InvalidArgumentException(
|
||||||
sprintf('The object "%s" from class "%s" is not defined in your data file.', $value, $relatedClass)
|
sprintf('The object "%s" from class "%s" is not defined in your data file.', $value, $relatedClass)
|
||||||
);
|
);
|
||||||
|
@ -304,8 +301,13 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
||||||
|
|
||||||
$middle = new $middleClass();
|
$middle = new $middleClass();
|
||||||
$middle->$setter($obj);
|
$middle->$setter($obj);
|
||||||
$middle->$relatedSetter($this->object_references[$relatedClass.'_'.$value]);
|
$middle->$relatedSetter($this->object_references[$this->cleanObjectRef($relatedClass.'_'.$value)]);
|
||||||
$middle->save($this->con);
|
$middle->save($this->con);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function cleanObjectRef($ref)
|
||||||
|
{
|
||||||
|
return $ref[0] === '\\' ? substr($ref, 1) : $ref;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\DataFixtures\Loader;
|
namespace Propel\Bundle\PropelBundle\DataFixtures\Loader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface that exposes how Propel data loaders should work.
|
* Interface that exposes how Propel data loaders should work.
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
<?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\DataFixtures\Loader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
|
||||||
*/
|
|
||||||
class DataWiper extends AbstractDataLoader
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Clears the database completely.
|
|
||||||
*
|
|
||||||
* @param array $files A set of files containing datas to load.
|
|
||||||
* @param string $connectionName The Propel connection name
|
|
||||||
*/
|
|
||||||
public function load($files = array(), $connectionName)
|
|
||||||
{
|
|
||||||
$this->deletedClasses = array();
|
|
||||||
$this->loadMapBuilders($connectionName);
|
|
||||||
|
|
||||||
$this->con = \Propel::getConnection($connectionName);
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->con->beginTransaction();
|
|
||||||
if ('mysql' === $this->con->getAttribute(\PDO::ATTR_DRIVER_NAME)) {
|
|
||||||
$this->con->exec('SET FOREIGN_KEY_CHECKS = 0;');
|
|
||||||
}
|
|
||||||
|
|
||||||
$tables = array();
|
|
||||||
foreach ($this->dbMap->getTables() as $eachTable) {
|
|
||||||
/* @var $eachTable \TableMap */
|
|
||||||
$tables[$eachTable->getClassname()] = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->deleteCurrentData($tables);
|
|
||||||
|
|
||||||
if ('mysql' === $this->con->getAttribute(\PDO::ATTR_DRIVER_NAME)) {
|
|
||||||
$this->con->exec('SET FOREIGN_KEY_CHECKS = 1;');
|
|
||||||
}
|
|
||||||
$this->con->commit();
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$this->con->rollBack();
|
|
||||||
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Not used by this data loader.
|
|
||||||
*
|
|
||||||
* @param string $file A filename.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function transformDataToArray($file)
|
|
||||||
{
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,7 +8,7 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\DataFixtures\Loader;
|
namespace Propel\Bundle\PropelBundle\DataFixtures\Loader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* XML fixtures loader.
|
* XML fixtures loader.
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\DataFixtures\Loader;
|
namespace Propel\Bundle\PropelBundle\DataFixtures\Loader;
|
||||||
|
|
||||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
use Faker\Generator;
|
||||||
use Symfony\Component\Yaml\ParseException;
|
use Symfony\Component\Yaml\ParseException;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
|
@ -22,18 +22,18 @@ use Symfony\Component\Yaml\Yaml;
|
||||||
class YamlDataLoader extends AbstractDataLoader
|
class YamlDataLoader extends AbstractDataLoader
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var \Symfony\Component\DependencyInjection\ContainerInterface
|
* @var \Faker\Generator
|
||||||
*/
|
*/
|
||||||
private $container;
|
private $faker;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function __construct($rootDir, ContainerInterface $container = null)
|
public function __construct($rootDir, array $datasources, Generator $faker = null)
|
||||||
{
|
{
|
||||||
parent::__construct($rootDir);
|
parent::__construct($rootDir, $datasources);
|
||||||
|
|
||||||
$this->container = $container;
|
$this->faker = $faker;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,22 +46,22 @@ class YamlDataLoader extends AbstractDataLoader
|
||||||
throw new ParseException(sprintf('Unable to parse "%s" as the file is not readable.', $file));
|
throw new ParseException(sprintf('Unable to parse "%s" as the file is not readable.', $file));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $this->container && $this->container->has('faker.generator')) {
|
if (null !== $this->faker) {
|
||||||
$generator = $this->container->get('faker.generator');
|
$generator = $this->faker;
|
||||||
$faker = function($type) use ($generator) {
|
$faker = function ($type) use ($generator) {
|
||||||
$args = func_get_args();
|
$args = func_get_args();
|
||||||
array_shift($args);
|
array_shift($args);
|
||||||
|
|
||||||
echo Yaml::dump(call_user_func_array(array($generator, $type), $args)) . "\n";
|
echo Yaml::dump(call_user_func_array(array($generator, $type), $args)) . "\n";
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
$faker = function($text) {
|
$faker = function ($text) {
|
||||||
echo $text . "\n";
|
echo $text . "\n";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ob_start();
|
ob_start();
|
||||||
$retval = include($file);
|
$retval = include $file;
|
||||||
$content = ob_get_clean();
|
$content = ob_get_clean();
|
||||||
|
|
||||||
// if an array is returned by the config file assume it's in plain php form else in YAML
|
// if an array is returned by the config file assume it's in plain php form else in YAML
|
||||||
|
|
|
@ -8,249 +8,238 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\DependencyInjection;
|
namespace Propel\Bundle\PropelBundle\DependencyInjection;
|
||||||
|
|
||||||
|
use Propel\Common\Config\PropelConfiguration;
|
||||||
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
||||||
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
|
||||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class contains the configuration information for the bundle
|
* This class contains the configuration information for the bundle
|
||||||
*
|
*/
|
||||||
* This information is solely responsible for how the different configuration
|
class Configuration extends PropelConfiguration
|
||||||
* sections are normalized, and merged.
|
|
||||||
*
|
|
||||||
* @author William DURAND <william.durand1@gmail.com>
|
|
||||||
*/
|
|
||||||
class Configuration implements ConfigurationInterface
|
|
||||||
{
|
{
|
||||||
private $debug;
|
private $debug;
|
||||||
|
private $defaultDir;
|
||||||
|
|
||||||
/**
|
public function __construct($debug, $kernelDir)
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param Boolean $debug Wether to use the debug mode
|
|
||||||
*/
|
|
||||||
public function __construct($debug)
|
|
||||||
{
|
{
|
||||||
$this->debug = (Boolean) $debug;
|
$this->debug = $debug;
|
||||||
|
$this->defaultDir = $kernelDir.'/propel';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function addPathsSection(ArrayNodeDefinition $node)
|
||||||
* Generates the configuration tree builder.
|
|
||||||
*
|
|
||||||
* @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
|
|
||||||
*/
|
|
||||||
public function getConfigTreeBuilder()
|
|
||||||
{
|
|
||||||
$treeBuilder = new TreeBuilder();
|
|
||||||
$rootNode = $treeBuilder->root('propel');
|
|
||||||
|
|
||||||
$this->addGeneralSection($rootNode);
|
|
||||||
$this->addDbalSection($rootNode);
|
|
||||||
|
|
||||||
return $treeBuilder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds 'general' configuration.
|
|
||||||
*
|
|
||||||
* propel:
|
|
||||||
* path: xxxxxxx
|
|
||||||
* path_phing: xxxxxxx
|
|
||||||
* logging: %kernel.debug%
|
|
||||||
* build_properties:
|
|
||||||
* xxxx.xxxx: xxxxxx
|
|
||||||
* ...
|
|
||||||
* behaviors:
|
|
||||||
* fooable: My\FooableBehavior
|
|
||||||
* barable: src.barable.BarableBehavior
|
|
||||||
*/
|
|
||||||
private function addGeneralSection(ArrayNodeDefinition $node)
|
|
||||||
{
|
{
|
||||||
$node
|
$node
|
||||||
->children()
|
->children()
|
||||||
->scalarNode('path')->end()
|
->arrayNode('paths')
|
||||||
->scalarNode('phing_path')->end()
|
->addDefaultsIfNotSet()
|
||||||
->scalarNode('logging')->defaultValue($this->debug)->end()
|
->children()
|
||||||
->arrayNode('build_properties')
|
->scalarNode('schemaDir')->defaultValue($this->defaultDir)->end()
|
||||||
->useAttributeAsKey('key')
|
->scalarNode('sqlDir')->defaultValue($this->defaultDir.'/sql')->end()
|
||||||
->prototype('scalar')->end()
|
->scalarNode('migrationDir')->defaultValue($this->defaultDir.'/migrations')->end()
|
||||||
->end()
|
->scalarNode('phpConfDir')->defaultValue($this->defaultDir.'/generated-conf')->end()
|
||||||
->arrayNode('behaviors')
|
->scalarNode('composerDir')->defaultNull()->end()
|
||||||
->useAttributeAsKey('key')
|
|
||||||
->prototype('scalar')->end()
|
|
||||||
->end()
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds 'dbal' configuration.
|
|
||||||
*
|
|
||||||
* propel:
|
|
||||||
* dbal:
|
|
||||||
* driver: mysql
|
|
||||||
* user: root
|
|
||||||
* password: null
|
|
||||||
* dsn: xxxxxxxx
|
|
||||||
* options: {}
|
|
||||||
* attributes: {}
|
|
||||||
* settings: {}
|
|
||||||
* default_connection: xxxxxx
|
|
||||||
*/
|
|
||||||
private function addDbalSection(ArrayNodeDefinition $node)
|
|
||||||
{
|
|
||||||
$node
|
|
||||||
->children()
|
|
||||||
->arrayNode('dbal')
|
|
||||||
->beforeNormalization()
|
|
||||||
->ifNull()
|
|
||||||
->then(function($v) { return array ('connections' => array('default' => array())); })
|
|
||||||
->end()
|
|
||||||
->children()
|
|
||||||
->scalarNode('default_connection')->defaultValue('default')->end()
|
|
||||||
->scalarNode('driver')
|
|
||||||
->beforeNormalization()
|
|
||||||
->always()
|
|
||||||
->then(function($v) { return str_replace('pdo_', '', $v); })
|
|
||||||
->end()
|
|
||||||
->defaultValue('mysql')
|
|
||||||
->end()
|
|
||||||
->scalarNode('user')->defaultValue('root')->end()
|
|
||||||
->scalarNode('password')->defaultValue('')->end()
|
|
||||||
->scalarNode('dsn')
|
|
||||||
->beforeNormalization()
|
|
||||||
->always()
|
|
||||||
->then(function($v) { return str_replace('pdo_', '', $v); })
|
|
||||||
->end()
|
|
||||||
->defaultValue('')
|
|
||||||
->end()
|
|
||||||
->scalarNode('classname')->defaultValue($this->debug ? 'DebugPDO' : 'PropelPDO')->end()
|
|
||||||
->end()
|
|
||||||
->fixXmlConfig('option')
|
|
||||||
->children()
|
|
||||||
->arrayNode('options')
|
|
||||||
->useAttributeAsKey('key')
|
|
||||||
->prototype('scalar')->end()
|
|
||||||
->end()
|
->end()
|
||||||
->end()
|
->end()
|
||||||
->fixXmlConfig('attribute')
|
|
||||||
->children()
|
|
||||||
->arrayNode('attributes')
|
|
||||||
->useAttributeAsKey('key')
|
|
||||||
->prototype('scalar')->end()
|
|
||||||
->end()
|
|
||||||
->end()
|
|
||||||
->fixXmlConfig('setting')
|
|
||||||
->children()
|
|
||||||
->arrayNode('settings')
|
|
||||||
->useAttributeAsKey('key')
|
|
||||||
->prototype('array')
|
|
||||||
->useAttributeAsKey('key')
|
|
||||||
->prototype('scalar')->end()
|
|
||||||
->end()
|
|
||||||
->end()
|
|
||||||
->end()
|
|
||||||
->fixXmlConfig('connection')
|
|
||||||
->append($this->getDbalConnectionsNode())
|
|
||||||
->end()
|
->end()
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function addRuntimeSection(ArrayNodeDefinition $node)
|
||||||
* Returns a tree configuration for this part of configuration:
|
|
||||||
*
|
|
||||||
* connections:
|
|
||||||
* default:
|
|
||||||
* driver: mysql
|
|
||||||
* user: root
|
|
||||||
* password: null
|
|
||||||
* dsn: xxxxxxxx
|
|
||||||
* classname: PropelPDO
|
|
||||||
* options: {}
|
|
||||||
* attributes: {}
|
|
||||||
* settings: {}
|
|
||||||
*
|
|
||||||
* @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
|
|
||||||
*/
|
|
||||||
private function getDbalConnectionsNode()
|
|
||||||
{
|
{
|
||||||
$treeBuilder = new TreeBuilder();
|
|
||||||
$node = $treeBuilder->root('connections');
|
|
||||||
|
|
||||||
$node
|
$node
|
||||||
->requiresAtLeastOneElement()
|
->children()
|
||||||
->useAttributeAsKey('name')
|
->arrayNode('runtime')
|
||||||
->prototype('array')
|
->addDefaultsIfNotSet()
|
||||||
->children()
|
->fixXmlConfig('connection')
|
||||||
->scalarNode('driver')
|
->children()
|
||||||
->beforeNormalization()
|
->scalarNode('defaultConnection')->end()
|
||||||
->always()
|
->arrayNode('connections')
|
||||||
->then(function($v) { return str_replace('pdo_', '', $v); })
|
->prototype('scalar')->end()
|
||||||
->end()
|
->end()
|
||||||
->defaultValue('mysql')
|
->booleanNode('logging')->defaultValue($this->debug)->end()
|
||||||
->end()
|
->arrayNode('log')
|
||||||
->scalarNode('user')->defaultValue('root')->end()
|
->useAttributeAsKey('name')
|
||||||
->scalarNode('password')->defaultValue('')->end()
|
->prototype('array')
|
||||||
->scalarNode('dsn')
|
->children()
|
||||||
->beforeNormalization()
|
->scalarNode('type')->end()
|
||||||
->always()
|
->scalarNode('path')->end()
|
||||||
->then(function($v) { return str_replace('pdo_', '', $v); })
|
->enumNode('level')->values(array(100, 200, 250, 300, 400, 500, 550, 600))->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
->end()
|
->end()
|
||||||
->defaultValue('')
|
->arrayNode('profiler')
|
||||||
->end()
|
|
||||||
->scalarNode('classname')->defaultValue($this->debug ? 'DebugPDO' : 'PropelPDO')->end()
|
|
||||||
->arrayNode('slaves')
|
|
||||||
->useAttributeAsKey('name')
|
|
||||||
->prototype('array')
|
|
||||||
->children()
|
->children()
|
||||||
->scalarNode('driver')
|
->scalarNode('classname')->defaultValue('\Propel\Runtime\Util\Profiler')->end()
|
||||||
->beforeNormalization()
|
->floatNode('slowTreshold')->defaultValue(0.1)->end()
|
||||||
->always()
|
->arrayNode('details')
|
||||||
->then(function($v) { return str_replace('pdo_', '', $v); })
|
->children()
|
||||||
|
->arrayNode('time')
|
||||||
|
->addDefaultsIfNotSet()
|
||||||
|
->children()
|
||||||
|
->integerNode('precision')->min(0)->defaultValue(3)->end()
|
||||||
|
->integerNode('pad')->min(0)->defaultValue(8)->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->arrayNode('memory')
|
||||||
|
->addDefaultsIfNotSet()
|
||||||
|
->children()
|
||||||
|
->integerNode('precision')->min(0)->defaultValue(3)->end()
|
||||||
|
->integerNode('pad')->min(0)->defaultValue(8)->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->arrayNode('memDelta')
|
||||||
|
->addDefaultsIfNotSet()
|
||||||
|
->children()
|
||||||
|
->integerNode('precision')->min(0)->defaultValue(3)->end()
|
||||||
|
->integerNode('pad')->min(0)->defaultValue(8)->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->arrayNode('memPeak')
|
||||||
|
->addDefaultsIfNotSet()
|
||||||
|
->children()
|
||||||
|
->integerNode('precision')->min(0)->defaultValue(3)->end()
|
||||||
|
->integerNode('pad')->min(0)->defaultValue(8)->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
->end()
|
->end()
|
||||||
->defaultValue('mysql')
|
|
||||||
->end()
|
->end()
|
||||||
->scalarNode('user')->defaultValue('root')->end()
|
->scalarNode('innerGlue')->defaultValue(':')->end()
|
||||||
->scalarNode('password')->defaultValue('')->end()
|
->scalarNode('outerGlue')->defaultValue('|')->end()
|
||||||
->scalarNode('dsn')
|
|
||||||
->beforeNormalization()
|
|
||||||
->always()
|
|
||||||
->then(function($v) { return str_replace('pdo_', '', $v); })
|
|
||||||
->end()
|
|
||||||
->defaultValue('')
|
|
||||||
->end()
|
|
||||||
->scalarNode('classname')->defaultValue($this->debug ? 'DebugPDO' : 'PropelPDO')->end()
|
|
||||||
->end()
|
->end()
|
||||||
->end()
|
->end()
|
||||||
->end()
|
->end()
|
||||||
->end()
|
->end() //runtime
|
||||||
->fixXmlConfig('option')
|
->end();
|
||||||
->children()
|
}
|
||||||
->arrayNode('options')
|
|
||||||
->useAttributeAsKey('key')
|
|
||||||
->prototype('scalar')->end()
|
|
||||||
->end()
|
|
||||||
->end()
|
|
||||||
->fixXmlConfig('attribute')
|
|
||||||
->children()
|
|
||||||
->arrayNode('attributes')
|
|
||||||
->useAttributeAsKey('key')
|
|
||||||
->prototype('scalar')->end()
|
|
||||||
->end()
|
|
||||||
->end()
|
|
||||||
->fixXmlConfig('setting')
|
|
||||||
->children()
|
|
||||||
->arrayNode('settings')
|
|
||||||
->useAttributeAsKey('key')
|
|
||||||
->prototype('array')
|
|
||||||
->useAttributeAsKey('key')
|
|
||||||
->prototype('scalar')
|
|
||||||
->end()
|
|
||||||
->end()
|
|
||||||
->end()
|
|
||||||
;
|
|
||||||
|
|
||||||
return $node;
|
protected function addDatabaseSection(ArrayNodeDefinition $node)
|
||||||
|
{
|
||||||
|
$validAdapters = array('mysql', 'pgsql', 'sqlite', 'mssql', 'sqlsrv', 'oracle');
|
||||||
|
|
||||||
|
$node
|
||||||
|
->children()
|
||||||
|
->arrayNode('database')
|
||||||
|
->isRequired()
|
||||||
|
->addDefaultsIfNotSet()
|
||||||
|
->children()
|
||||||
|
->arrayNode('connections')
|
||||||
|
->isRequired()
|
||||||
|
->validate()
|
||||||
|
->always()
|
||||||
|
->then(function($connections) {
|
||||||
|
foreach ($connections as $name => $connection) {
|
||||||
|
if (strpos($name, '.') !== false) {
|
||||||
|
throw new \InvalidArgumentException('Dots are not allowed in connection names');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $connections;
|
||||||
|
})
|
||||||
|
->end()
|
||||||
|
->requiresAtLeastOneElement()
|
||||||
|
->normalizeKeys(false)
|
||||||
|
->useAttributeAsKey('id')
|
||||||
|
->prototype('array')
|
||||||
|
->fixXmlConfig('slave')
|
||||||
|
->fixXmlConfig('model_path')
|
||||||
|
->children()
|
||||||
|
->scalarNode('classname')->defaultValue($this->debug ? '\Propel\Runtime\Connection\DebugPDO' : '\Propel\Runtime\Connection\ConnectionWrapper')->end()
|
||||||
|
->scalarNode('adapter')
|
||||||
|
->isRequired()
|
||||||
|
->cannotBeEmpty()
|
||||||
|
->beforeNormalization()
|
||||||
|
->ifString()
|
||||||
|
->then(function ($v) { return preg_replace('/^pdo_/', '', strtolower($v)); })
|
||||||
|
->end()
|
||||||
|
->validate()
|
||||||
|
->ifNotInArray($validAdapters)
|
||||||
|
->thenInvalid('The adapter %s is not supported. Please choose one of ' . implode(', ', $validAdapters))
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->scalarNode('dsn')
|
||||||
|
->isRequired()
|
||||||
|
->cannotBeEmpty()
|
||||||
|
->beforeNormalization()
|
||||||
|
->ifString()
|
||||||
|
->then(function ($v) { return preg_replace('/^pdo_/', '', $v); })
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->scalarNode('user')->isRequired()->end()
|
||||||
|
->scalarNode('password')->isRequired()->treatNullLike('')->end()
|
||||||
|
->arrayNode('options')
|
||||||
|
->addDefaultsIfNotSet()
|
||||||
|
->children()
|
||||||
|
->booleanNode('ATTR_PERSISTENT')->defaultFalse()->end()
|
||||||
|
->scalarNode('MYSQL_ATTR_SSL_CA')->end()
|
||||||
|
->scalarNode('MYSQL_ATTR_SSL_CERT')->end()
|
||||||
|
->scalarNode('MYSQL_ATTR_SSL_KEY')->end()
|
||||||
|
->scalarNode('MYSQL_ATTR_MAX_BUFFER_SIZE')->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->arrayNode('attributes')
|
||||||
|
->addDefaultsIfNotSet()
|
||||||
|
->children()
|
||||||
|
->booleanNode('ATTR_EMULATE_PREPARES')->defaultFalse()->end()
|
||||||
|
->scalarNode('SQLSRV_ATTR_ENCODING')->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->arrayNode('model_paths')
|
||||||
|
->defaultValue(['src', 'vendor'])
|
||||||
|
->prototype('scalar')->end()
|
||||||
|
->end()
|
||||||
|
->arrayNode('settings')
|
||||||
|
->fixXmlConfig('query', 'queries')
|
||||||
|
->children()
|
||||||
|
->scalarNode('charset')->defaultValue('utf8')->end()
|
||||||
|
->arrayNode('queries')
|
||||||
|
->prototype('scalar')->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->arrayNode('slaves')
|
||||||
|
->prototype('array')
|
||||||
|
->children()
|
||||||
|
->scalarNode('dsn')
|
||||||
|
->beforeNormalization()
|
||||||
|
->ifString()
|
||||||
|
->then(function ($v) { return preg_replace('/^pdo_/', '', $v); })
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->arrayNode('adapters')
|
||||||
|
->addDefaultsIfNotSet()
|
||||||
|
->children()
|
||||||
|
->arrayNode('mysql')
|
||||||
|
->addDefaultsIfNotSet()
|
||||||
|
->children()
|
||||||
|
->scalarNode('tableType')->defaultValue('InnoDB')->treatNullLike('InnoDB')->end()
|
||||||
|
->scalarNode('tableEngineKeyword')->defaultValue('ENGINE')->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->arrayNode('sqlite')
|
||||||
|
->addDefaultsIfNotSet()
|
||||||
|
->children()
|
||||||
|
->scalarNode('foreignKey')->end()
|
||||||
|
->scalarNode('tableAlteringWorkaround')->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->arrayNode('oracle')
|
||||||
|
->addDefaultsIfNotSet()
|
||||||
|
->children()
|
||||||
|
->scalarNode('autoincrementSequencePattern')->defaultValue('${table}_SEQ')->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
->end() //adapters
|
||||||
|
->end()
|
||||||
|
->end() //database
|
||||||
|
->end()
|
||||||
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,14 +8,13 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\DependencyInjection;
|
namespace Propel\Bundle\PropelBundle\DependencyInjection;
|
||||||
|
|
||||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
use Symfony\Component\DependencyInjection\Definition;
|
use Symfony\Component\DependencyInjection\Definition;
|
||||||
use Symfony\Component\Config\FileLocator;
|
use Symfony\Component\Config\FileLocator;
|
||||||
use Symfony\Component\Config\Definition\Processor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PropelExtension loads the PropelBundle configuration.
|
* PropelExtension loads the PropelBundle configuration.
|
||||||
|
@ -32,115 +31,35 @@ class PropelExtension extends Extension
|
||||||
*/
|
*/
|
||||||
public function load(array $configs, ContainerBuilder $container)
|
public function load(array $configs, ContainerBuilder $container)
|
||||||
{
|
{
|
||||||
$processor = new Processor();
|
|
||||||
$configuration = $this->getConfiguration($configs, $container);
|
$configuration = $this->getConfiguration($configs, $container);
|
||||||
$config = $processor->processConfiguration($configuration, $configs);
|
$config = $this->processConfiguration($configuration, $configs);
|
||||||
|
|
||||||
// Composer
|
if (1 === count($config['database']['connections'])) {
|
||||||
if (file_exists($propelPath = $container->getParameter('kernel.root_dir') . '/../vendor/propel/propel1')) {
|
$defaultConnection = array_keys($config['database']['connections'])[0];
|
||||||
$container->setParameter('propel.path', $propelPath);
|
if (!isset($config['runtime']['defaultConnection'])) {
|
||||||
}
|
$config['runtime']['defaultConnection'] = $defaultConnection;
|
||||||
if (file_exists($phingPath = $container->getParameter('kernel.root_dir') . '/../vendor/phing/phing/classes')) {
|
}
|
||||||
$container->setParameter('propel.phing_path', $phingPath);
|
if (!isset($config['generator']['defaultConnection'])) {
|
||||||
}
|
$config['generator']['defaultConnection'] = $defaultConnection;
|
||||||
|
|
||||||
if (!$container->hasParameter('propel.path')) {
|
|
||||||
if (!isset($config['path'])) {
|
|
||||||
throw new \InvalidArgumentException('PropelBundle expects a "path" parameter that must contain the absolute path to the Propel ORM vendor library. The "path" parameter must be defined under the "propel" root node in your configuration.');
|
|
||||||
} else {
|
|
||||||
$container->setParameter('propel.path', $config['path']);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$container->hasParameter('propel.phing_path')) {
|
$container->setParameter('propel.logging', $config['runtime']['logging']);
|
||||||
if (!isset($config['phing_path'])) {
|
$container->setParameter('propel.configuration', $config);
|
||||||
throw new \InvalidArgumentException('PropelBundle expects a "phing_path" parameter that must contain the absolute path to the Phing vendor library. The "phing_path" parameter must be defined under the "propel" root node in your configuration.');
|
|
||||||
} else {
|
|
||||||
$container->setParameter('propel.phing_path', $config['phing_path']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($config['logging']) && $config['logging']) {
|
|
||||||
$logging = $config['logging'];
|
|
||||||
} else {
|
|
||||||
$logging = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$container->setParameter('propel.logging', $logging);
|
|
||||||
|
|
||||||
// Load services
|
// Load services
|
||||||
if (!$container->hasDefinition('propel')) {
|
if (!$container->hasDefinition('propel')) {
|
||||||
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
|
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
|
||||||
$loader->load('propel.xml');
|
$loader->load('propel.xml');
|
||||||
$loader->load('converters.xml');
|
$loader->load('converters.xml');
|
||||||
|
$loader->load('security.xml');
|
||||||
|
$loader->load('console.xml');
|
||||||
}
|
}
|
||||||
|
|
||||||
// build properties
|
|
||||||
if (isset($config['build_properties']) && is_array($config['build_properties'])) {
|
|
||||||
$buildProperties = $config['build_properties'];
|
|
||||||
} else {
|
|
||||||
$buildProperties = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
// behaviors
|
|
||||||
if (isset($config['behaviors']) && is_array($config['behaviors'])) {
|
|
||||||
foreach ($config['behaviors'] as $name => $class) {
|
|
||||||
$buildProperties[sprintf('propel.behavior.%s.class', $name)] = $class;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$container->getDefinition('propel.build_properties')->setArguments(array($buildProperties));
|
|
||||||
|
|
||||||
if (!empty($config['dbal'])) {
|
|
||||||
$this->dbalLoad($config['dbal'], $container);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads the DBAL configuration.
|
|
||||||
*
|
|
||||||
* @param array $config An array of configuration settings
|
|
||||||
* @param ContainerBuilder $container A ContainerBuilder instance
|
|
||||||
*/
|
|
||||||
protected function dbalLoad(array $config, ContainerBuilder $container)
|
|
||||||
{
|
|
||||||
if (empty($config['default_connection'])) {
|
|
||||||
$keys = array_keys($config['connections']);
|
|
||||||
$config['default_connection'] = reset($keys);
|
|
||||||
}
|
|
||||||
|
|
||||||
$connectionName = $config['default_connection'];
|
|
||||||
$container->setParameter('propel.dbal.default_connection', $connectionName);
|
|
||||||
|
|
||||||
if (0 === count($config['connections'])) {
|
|
||||||
$config['connections'] = array($connectionName => $config);
|
|
||||||
}
|
|
||||||
|
|
||||||
$c = array();
|
|
||||||
foreach ($config['connections'] as $name => $conf) {
|
|
||||||
$c['datasources'][$name]['adapter'] = $conf['driver'];
|
|
||||||
if (!empty($conf['slaves'])) {
|
|
||||||
$c['datasources'][$name]['slaves']['connection'] = $conf['slaves'];
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (array('dsn', 'user', 'password', 'classname', 'options', 'attributes', 'settings') as $att) {
|
|
||||||
if (isset($conf[$att])) {
|
|
||||||
$c['datasources'][$name]['connection'][$att] = $conf[$att];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alias the default connection if not defined
|
|
||||||
if (!isset($c['datasources']['default'])) {
|
|
||||||
$c['datasources']['default'] = $c['datasources'][$connectionName];
|
|
||||||
}
|
|
||||||
|
|
||||||
$container->getDefinition('propel.configuration')->setArguments(array($c));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getConfiguration(array $config, ContainerBuilder $container)
|
public function getConfiguration(array $config, ContainerBuilder $container)
|
||||||
{
|
{
|
||||||
return new Configuration($container->getParameter('kernel.debug'));
|
return new Configuration($container->getParameter('kernel.debug'), $container->getParameter('kernel.root_dir'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
<?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\DependencyInjection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Properties.
|
|
||||||
*
|
|
||||||
* @author William Durand <william.durand1@gmail.com>
|
|
||||||
*/
|
|
||||||
class Properties
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Build properties.
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
private $properties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor.
|
|
||||||
*
|
|
||||||
* @param $properties An array of properties.
|
|
||||||
*/
|
|
||||||
public function __construct(array $properties = array())
|
|
||||||
{
|
|
||||||
$this->properties = $properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get properties.
|
|
||||||
*
|
|
||||||
* @return array An array of properties.
|
|
||||||
*/
|
|
||||||
public function getProperties()
|
|
||||||
{
|
|
||||||
return $this->properties;
|
|
||||||
}
|
|
||||||
}
|
|
51
DependencyInjection/Security/UserProvider/PropelFactory.php
Normal file
51
DependencyInjection/Security/UserProvider/PropelFactory.php
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
namespace Propel\Bundle\PropelBundle\DependencyInjection\Security\UserProvider;
|
||||||
|
|
||||||
|
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\UserProviderFactoryInterface;
|
||||||
|
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||||
|
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
/**
|
||||||
|
* PropelFactory creates services for Propel user provider.
|
||||||
|
*
|
||||||
|
* @author William Durand <william.durand1@gmail.com>
|
||||||
|
*/
|
||||||
|
class PropelFactory implements UserProviderFactoryInterface
|
||||||
|
{
|
||||||
|
private $key;
|
||||||
|
private $providerId;
|
||||||
|
public function __construct($key, $providerId)
|
||||||
|
{
|
||||||
|
$this->key = $key;
|
||||||
|
$this->providerId = $providerId;
|
||||||
|
}
|
||||||
|
public function create(ContainerBuilder $container, $id, $config)
|
||||||
|
{
|
||||||
|
$container
|
||||||
|
->setDefinition($id, new ChildDefinition($this->providerId))
|
||||||
|
->addArgument($config['class'])
|
||||||
|
->addArgument($config['property'])
|
||||||
|
;
|
||||||
|
}
|
||||||
|
public function getKey()
|
||||||
|
{
|
||||||
|
return $this->key;
|
||||||
|
}
|
||||||
|
public function addConfiguration(NodeDefinition $node)
|
||||||
|
{
|
||||||
|
$node
|
||||||
|
->children()
|
||||||
|
->scalarNode('class')->isRequired()->cannotBeEmpty()->end()
|
||||||
|
->scalarNode('property')->defaultNull()->end()
|
||||||
|
->end()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +1,26 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Form;
|
/**
|
||||||
|
* 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\Bundle\PropelBundle\Form;
|
||||||
|
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
|
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author William DURAND <william.durand1@gmail.com>
|
||||||
|
* @deprecated use AbstractType directly
|
||||||
|
*/
|
||||||
abstract class BaseAbstractType extends AbstractType
|
abstract class BaseAbstractType extends AbstractType
|
||||||
{
|
{
|
||||||
protected $options = array(
|
protected $options = array();
|
||||||
'name' => '',
|
|
||||||
);
|
|
||||||
|
|
||||||
public function __construct($mergeOptions = null)
|
public function __construct($mergeOptions = null)
|
||||||
{
|
{
|
||||||
|
@ -44,18 +55,18 @@ abstract class BaseAbstractType extends AbstractType
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function setDefaultOptions(OptionsResolverInterface $resolver)
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
{
|
{
|
||||||
$resolver->setDefaults($this->options);
|
$resolver->setDefaults($this->options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function getName()
|
public function getName()
|
||||||
{
|
{
|
||||||
return $this->getOption('name');
|
return get_class($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
213
Form/ChoiceList/PropelChoiceLoader.php
Normal file
213
Form/ChoiceList/PropelChoiceLoader.php
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
<?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\Bundle\PropelBundle\Form\ChoiceList;
|
||||||
|
|
||||||
|
use Propel\Runtime\ActiveQuery\Criteria;
|
||||||
|
use Propel\Runtime\ActiveQuery\ModelCriteria;
|
||||||
|
use Propel\Runtime\ActiveRecord\ActiveRecordInterface;
|
||||||
|
use Propel\Runtime\Map\ColumnMap;
|
||||||
|
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
|
||||||
|
use Symfony\Component\Form\ChoiceList\Factory\ChoiceListFactoryInterface;
|
||||||
|
use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author William Durand <william.durand1@gmail.com>
|
||||||
|
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||||
|
* @author Moritz Schroeder <moritz.schroeder@molabs.de>
|
||||||
|
*/
|
||||||
|
class PropelChoiceLoader implements ChoiceLoaderInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var ChoiceListFactoryInterface
|
||||||
|
*/
|
||||||
|
protected $factory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ModelCriteria
|
||||||
|
*/
|
||||||
|
protected $query;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The fields of which the identifier of the underlying class consists
|
||||||
|
*
|
||||||
|
* This property should only be accessed through identifier.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $identifier = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to use the identifier for index generation.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $identifierAsIndex = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ChoiceListInterface
|
||||||
|
*/
|
||||||
|
protected $choiceList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PropelChoiceListLoader constructor.
|
||||||
|
*
|
||||||
|
* @param ChoiceListFactoryInterface $factory
|
||||||
|
* @param string $class
|
||||||
|
*/
|
||||||
|
public function __construct(ChoiceListFactoryInterface $factory, $class, ModelCriteria $queryObject, $useAsIdentifier = null)
|
||||||
|
{
|
||||||
|
$this->factory = $factory;
|
||||||
|
$this->class = $class;
|
||||||
|
$this->query = $queryObject;
|
||||||
|
if ($useAsIdentifier) {
|
||||||
|
$this->identifier = array($this->query->getTableMap()->getColumn($useAsIdentifier));
|
||||||
|
} else {
|
||||||
|
$this->identifier = $this->query->getTableMap()->getPrimaryKeys();
|
||||||
|
}
|
||||||
|
if (1 === count($this->identifier) && $this->isScalar(current($this->identifier))) {
|
||||||
|
$this->identifierAsIndex = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function loadChoiceList($value = null)
|
||||||
|
{
|
||||||
|
if ($this->choiceList) {
|
||||||
|
return $this->choiceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
$models = iterator_to_array($this->query->find());
|
||||||
|
|
||||||
|
$this->choiceList = $this->factory->createListFromChoices($models, $value);
|
||||||
|
|
||||||
|
return $this->choiceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function loadChoicesForValues(array $values, $value = null)
|
||||||
|
{
|
||||||
|
// Performance optimization
|
||||||
|
if (empty($values)) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optimize performance in case we have a single-field identifier
|
||||||
|
if (!$this->choiceList && $this->identifierAsIndex && current($this->identifier) instanceof ColumnMap) {
|
||||||
|
$phpName = current($this->identifier)->getPhpName();
|
||||||
|
$query = clone $this->query;
|
||||||
|
$unorderedObjects = $query->filterBy($phpName, $values, Criteria::IN);
|
||||||
|
$objectsById = array();
|
||||||
|
$objects = array();
|
||||||
|
|
||||||
|
// Maintain order and indices from the given $values
|
||||||
|
foreach ($unorderedObjects as $object) {
|
||||||
|
$objectsById[(string) current($this->getIdentifierValues($object))] = $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($values as $i => $id) {
|
||||||
|
if (isset($objectsById[$id])) {
|
||||||
|
$objects[$i] = $objectsById[$id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $objects;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->loadChoiceList($value)->getChoicesForValues($values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function loadValuesForChoices(array $choices, $value = null)
|
||||||
|
{
|
||||||
|
// Performance optimization
|
||||||
|
if (empty($choices)) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->choiceList && $this->identifierAsIndex) {
|
||||||
|
$values = array();
|
||||||
|
|
||||||
|
// Maintain order and indices of the given objects
|
||||||
|
foreach ($choices as $i => $object) {
|
||||||
|
if ($object instanceof $this->class) {
|
||||||
|
// Make sure to convert to the right format
|
||||||
|
$values[$i] = (string) current($this->getIdentifierValues($object));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $values;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->loadChoiceList($value)->getValuesForChoices($choices);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this column contains scalar values (to be used as indices).
|
||||||
|
*
|
||||||
|
* @param ColumnMap $column
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function isScalar(ColumnMap $column)
|
||||||
|
{
|
||||||
|
return in_array(
|
||||||
|
$column->getPdoType(),
|
||||||
|
array(
|
||||||
|
\PDO::PARAM_BOOL,
|
||||||
|
\PDO::PARAM_INT,
|
||||||
|
\PDO::PARAM_STR,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the values of the identifier fields of a model.
|
||||||
|
*
|
||||||
|
* Propel must know about this model, that is, the model must already
|
||||||
|
* be persisted or added to the idmodel map before. Otherwise an
|
||||||
|
* exception is thrown.
|
||||||
|
*
|
||||||
|
* @param object $model The model for which to get the identifier
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getIdentifierValues($model)
|
||||||
|
{
|
||||||
|
if (!$model instanceof $this->class) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1 === count($this->identifier) && current($this->identifier) instanceof ColumnMap) {
|
||||||
|
$phpName = current($this->identifier)->getPhpName();
|
||||||
|
if (method_exists($model, 'get' . $phpName)) {
|
||||||
|
return array($model->{'get' . $phpName}());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($model instanceof ActiveRecordInterface) {
|
||||||
|
return array($model->getPrimaryKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $model->getPrimaryKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
55
Form/DataTransformer/CollectionToArrayTransformer.php
Normal file
55
Form/DataTransformer/CollectionToArrayTransformer.php
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Propel\Bundle\PropelBundle\Form\DataTransformer;
|
||||||
|
|
||||||
|
use Propel\Runtime\Collection\ObjectCollection;
|
||||||
|
use Symfony\Component\Form\DataTransformerInterface;
|
||||||
|
use Symfony\Component\Form\Exception\TransformationFailedException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CollectionToArrayTransformer class.
|
||||||
|
*
|
||||||
|
* @author William Durand <william.durand1@gmail.com>
|
||||||
|
* @author Pierre-Yves Lebecq <py.lebecq@gmail.com>
|
||||||
|
*/
|
||||||
|
class CollectionToArrayTransformer implements DataTransformerInterface
|
||||||
|
{
|
||||||
|
public function transform($collection)
|
||||||
|
{
|
||||||
|
if (null === $collection) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$collection instanceof ObjectCollection) {
|
||||||
|
throw new TransformationFailedException('Expected a \Propel\Runtime\Collection\ObjectCollection.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $collection->getData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reverseTransform($array)
|
||||||
|
{
|
||||||
|
$collection = new ObjectCollection();
|
||||||
|
|
||||||
|
if ('' === $array || null === $array) {
|
||||||
|
return $collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_array($array)) {
|
||||||
|
throw new TransformationFailedException('Expected an array.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$collection->setData($array);
|
||||||
|
|
||||||
|
return $collection;
|
||||||
|
}
|
||||||
|
}
|
101
Form/EventListener/TranslationCollectionFormListener.php
Normal file
101
Form/EventListener/TranslationCollectionFormListener.php
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Propel\Bundle\PropelBundle\Form\EventListener;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\FormEvents;
|
||||||
|
use Symfony\Component\Form\Exception\UnexpectedTypeException;
|
||||||
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||||
|
use Symfony\Component\Form\FormEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* listener class for propel_translatable_collection
|
||||||
|
*
|
||||||
|
* @author Patrick Kaufmann
|
||||||
|
*/
|
||||||
|
class TranslationCollectionFormListener implements EventSubscriberInterface
|
||||||
|
{
|
||||||
|
private $i18nClass;
|
||||||
|
private $languages;
|
||||||
|
|
||||||
|
public function __construct($languages, $i18nClass)
|
||||||
|
{
|
||||||
|
$this->i18nClass = $i18nClass;
|
||||||
|
$this->languages = $languages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getSubscribedEvents()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
FormEvents::PRE_SET_DATA => array('preSetData', 1),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function preSetData(FormEvent $event)
|
||||||
|
{
|
||||||
|
$form = $event->getForm();
|
||||||
|
$data = $event->getData();
|
||||||
|
|
||||||
|
if (null === $data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_array($data) && !($data instanceof \Traversable && $data instanceof \ArrayAccess)) {
|
||||||
|
throw new UnexpectedTypeException($data, 'array or (\Traversable and \ArrayAccess)');
|
||||||
|
}
|
||||||
|
|
||||||
|
//get the class name of the i18nClass
|
||||||
|
$temp = explode('\\', $this->i18nClass);
|
||||||
|
$dataClass = end($temp);
|
||||||
|
|
||||||
|
$rootData = $form->getRoot()->getData();
|
||||||
|
$foundData = false;
|
||||||
|
|
||||||
|
$addFunction = 'add'.$dataClass;
|
||||||
|
|
||||||
|
//add a database row for every needed language
|
||||||
|
foreach ($this->languages as $lang) {
|
||||||
|
$found = false;
|
||||||
|
|
||||||
|
foreach ($data as $i18n) {
|
||||||
|
if (!method_exists($i18n, 'getLocale')) {
|
||||||
|
throw new UnexpectedTypeException($i18n, 'Propel i18n object');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($i18n->getLocale() == $lang) {
|
||||||
|
$found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$found) {
|
||||||
|
$currentForm = $form;
|
||||||
|
while (!$foundData) {
|
||||||
|
if (method_exists($rootData, $addFunction)) {
|
||||||
|
$foundData = true;
|
||||||
|
break;
|
||||||
|
} elseif (null != ($currentForm = $currentForm->getParent())) {
|
||||||
|
$rootData = $currentForm->getData();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$foundData) {
|
||||||
|
throw new UnexpectedTypeException($rootData, 'Propel i18n object');
|
||||||
|
}
|
||||||
|
|
||||||
|
$newTranslation = new $this->i18nClass();
|
||||||
|
$newTranslation->setLocale($lang);
|
||||||
|
|
||||||
|
$rootData->$addFunction($newTranslation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
82
Form/EventListener/TranslationFormListener.php
Normal file
82
Form/EventListener/TranslationFormListener.php
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Propel\Bundle\PropelBundle\Form\EventListener;
|
||||||
|
|
||||||
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
|
use Symfony\Component\Form\FormEvent;
|
||||||
|
use Symfony\Component\Form\FormEvents;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event Listener class for propel_translation
|
||||||
|
*
|
||||||
|
* @author Patrick Kaufmann
|
||||||
|
*/
|
||||||
|
class TranslationFormListener implements EventSubscriberInterface
|
||||||
|
{
|
||||||
|
private $columns;
|
||||||
|
private $dataClass;
|
||||||
|
|
||||||
|
public function __construct($columns, $dataClass)
|
||||||
|
{
|
||||||
|
$this->columns = $columns;
|
||||||
|
$this->dataClass = $dataClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getSubscribedEvents()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
FormEvents::PRE_SET_DATA => array('preSetData', 1),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function preSetData(FormEvent $event)
|
||||||
|
{
|
||||||
|
$form = $event->getForm();
|
||||||
|
$data = $event->getData();
|
||||||
|
|
||||||
|
if (!$data instanceof $this->dataClass) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//loop over all columns and add the input
|
||||||
|
foreach ($this->columns as $column => $options) {
|
||||||
|
if (is_string($options)) {
|
||||||
|
$column = $options;
|
||||||
|
$options = array();
|
||||||
|
}
|
||||||
|
if (null === $options) {
|
||||||
|
$options = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$type = TextType::class;
|
||||||
|
if (array_key_exists('type', $options)) {
|
||||||
|
$type = $options['type'];
|
||||||
|
}
|
||||||
|
$label = $column;
|
||||||
|
if (array_key_exists('label', $options)) {
|
||||||
|
$label = $options['label'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$customOptions = array();
|
||||||
|
if (array_key_exists('options', $options)) {
|
||||||
|
$customOptions = $options['options'];
|
||||||
|
}
|
||||||
|
$options = array(
|
||||||
|
'label' => $label.' '.strtoupper($data->getLocale())
|
||||||
|
);
|
||||||
|
|
||||||
|
$options = array_merge($options, $customOptions);
|
||||||
|
|
||||||
|
$form->add($column, $type, $options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
72
Form/FormBuilder.php
Normal file
72
Form/FormBuilder.php
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?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\Bundle\PropelBundle\Form;
|
||||||
|
|
||||||
|
use Propel\Generator\Model\ForeignKey;
|
||||||
|
use Propel\Generator\Model\Table;
|
||||||
|
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Moritz Schroeder <moritz.schroeder@molabs.de>
|
||||||
|
*/
|
||||||
|
class FormBuilder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Build a form based on the given table.
|
||||||
|
*
|
||||||
|
* @param BundleInterface $bundle
|
||||||
|
* @param Table $table
|
||||||
|
* @param string $formTypeNamespace
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function buildFormType(BundleInterface $bundle, Table $table, $formTypeNamespace)
|
||||||
|
{
|
||||||
|
$modelName = $table->getPhpName();
|
||||||
|
$formTypeContent = file_get_contents(__DIR__ . '/../Resources/skeleton/FormType.php');
|
||||||
|
|
||||||
|
$formTypeContent = str_replace('##NAMESPACE##', $bundle->getNamespace() . str_replace('/', '\\', $formTypeNamespace), $formTypeContent);
|
||||||
|
$formTypeContent = str_replace('##CLASS##', $modelName . 'Type', $formTypeContent);
|
||||||
|
$formTypeContent = str_replace('##FQCN##', sprintf('%s\%s', $table->getNamespace(), $modelName), $formTypeContent);
|
||||||
|
$formTypeContent = str_replace('##TYPE_NAME##', strtolower($modelName), $formTypeContent);
|
||||||
|
$formTypeContent = str_replace('##BUILD_CODE##', $this->buildFormFields($table), $formTypeContent);
|
||||||
|
|
||||||
|
return $formTypeContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the fields in the FormType.
|
||||||
|
*
|
||||||
|
* @param Table $table Table from which the fields will be extracted.
|
||||||
|
*
|
||||||
|
* @return string The FormType code.
|
||||||
|
*/
|
||||||
|
protected function buildFormFields(Table $table)
|
||||||
|
{
|
||||||
|
$buildCode = '';
|
||||||
|
foreach ($table->getColumns() as $column) {
|
||||||
|
if ($column->isPrimaryKey()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$name = $column->getPhpName();
|
||||||
|
|
||||||
|
// Use foreignKey table name, so the TypeGuesser gets it right
|
||||||
|
if ($column->isForeignKey()) {
|
||||||
|
/** @var ForeignKey $foreignKey */
|
||||||
|
$foreignKey = current($column->getForeignKeys());
|
||||||
|
$name = $foreignKey->getForeignTable()->getPhpName();
|
||||||
|
}
|
||||||
|
$buildCode .= sprintf("\n \$builder->add('%s');", lcfirst($name));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $buildCode;
|
||||||
|
}
|
||||||
|
}
|
64
Form/PropelExtension.php
Normal file
64
Form/PropelExtension.php
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Propel\Bundle\PropelBundle\Form;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractExtension;
|
||||||
|
use Symfony\Component\Form\ChoiceList\Factory\ChoiceListFactoryInterface;
|
||||||
|
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory;
|
||||||
|
use Symfony\Component\Form\ChoiceList\Factory\PropertyAccessDecorator;
|
||||||
|
use Symfony\Component\PropertyAccess\PropertyAccess;
|
||||||
|
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the Propel form extension, which loads the Propel functionality.
|
||||||
|
*
|
||||||
|
* @author Joseph Rouff <rouffj@gmail.com>
|
||||||
|
*/
|
||||||
|
class PropelExtension extends AbstractExtension
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var PropertyAccessorInterface
|
||||||
|
*/
|
||||||
|
protected $propertyAccessor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ChoiceListFactoryInterface
|
||||||
|
*/
|
||||||
|
protected $choiceListFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PropelExtension constructor.
|
||||||
|
*
|
||||||
|
* @param PropertyAccessorInterface|null $propertyAccessor
|
||||||
|
* @param ChoiceListFactoryInterface|null $choiceListFactory
|
||||||
|
*/
|
||||||
|
public function __construct(PropertyAccessorInterface $propertyAccessor = null, ChoiceListFactoryInterface $choiceListFactory = null)
|
||||||
|
{
|
||||||
|
$this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor();
|
||||||
|
$this->choiceListFactory = $choiceListFactory ?: new PropertyAccessDecorator(new DefaultChoiceListFactory(), $this->propertyAccessor);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadTypes()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
new Type\ModelType($this->propertyAccessor, $this->choiceListFactory),
|
||||||
|
new Type\TranslationCollectionType(),
|
||||||
|
new Type\TranslationType()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadTypeGuesser()
|
||||||
|
{
|
||||||
|
return new TypeGuesser();
|
||||||
|
}
|
||||||
|
}
|
263
Form/Type/ModelType.php
Normal file
263
Form/Type/ModelType.php
Normal file
|
@ -0,0 +1,263 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Propel\Bundle\PropelBundle\Form\Type;
|
||||||
|
|
||||||
|
use Propel\Bundle\PropelBundle\Form\ChoiceList\PropelChoiceLoader;
|
||||||
|
use Propel\Bundle\PropelBundle\Form\DataTransformer\CollectionToArrayTransformer;
|
||||||
|
use Propel\Runtime\ActiveQuery\ModelCriteria;
|
||||||
|
use Propel\Runtime\Map\ColumnMap;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\ChoiceList\Factory\ChoiceListFactoryInterface;
|
||||||
|
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory;
|
||||||
|
use Symfony\Component\Form\ChoiceList\Factory\PropertyAccessDecorator;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\Options;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
|
||||||
|
use Symfony\Component\OptionsResolver\Exception\MissingOptionsException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ModelType class.
|
||||||
|
*
|
||||||
|
* @author William Durand <william.durand1@gmail.com>
|
||||||
|
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||||
|
*
|
||||||
|
* Example using the preferred_choices option.
|
||||||
|
*
|
||||||
|
* <code>
|
||||||
|
* public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
* {
|
||||||
|
* $builder
|
||||||
|
* ->add('product', 'model', array(
|
||||||
|
* 'class' => 'Model\Product',
|
||||||
|
* 'query' => ProductQuery::create()
|
||||||
|
* ->filterIsActive(true)
|
||||||
|
* ->useI18nQuery($options['locale'])
|
||||||
|
* ->orderByName()
|
||||||
|
* ->endUse()
|
||||||
|
* ,
|
||||||
|
* 'preferred_choices' => ProductQuery::create()
|
||||||
|
* ->filterByIsTopProduct(true)
|
||||||
|
* ,
|
||||||
|
* ))
|
||||||
|
* ;
|
||||||
|
* }
|
||||||
|
* </code>
|
||||||
|
*/
|
||||||
|
class ModelType extends AbstractType
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var ChoiceListFactoryInterface
|
||||||
|
*/
|
||||||
|
private $choiceListFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ModelType constructor.
|
||||||
|
*
|
||||||
|
* @param PropertyAccessorInterface|null $propertyAccessor
|
||||||
|
* @param ChoiceListFactoryInterface|null $choiceListFactory
|
||||||
|
*/
|
||||||
|
public function __construct(PropertyAccessorInterface $propertyAccessor = null, ChoiceListFactoryInterface $choiceListFactory = null)
|
||||||
|
{
|
||||||
|
$this->choiceListFactory = $choiceListFactory ?: new PropertyAccessDecorator(
|
||||||
|
new DefaultChoiceListFactory(),
|
||||||
|
$propertyAccessor
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the label for a choice.
|
||||||
|
*
|
||||||
|
* For backwards compatibility, objects are cast to strings by default.
|
||||||
|
*
|
||||||
|
* @param object $choice The object.
|
||||||
|
*
|
||||||
|
* @return string The string representation of the object.
|
||||||
|
*
|
||||||
|
* @internal This method is public to be usable as callback. It should not
|
||||||
|
* be used in user code.
|
||||||
|
*/
|
||||||
|
public static function createChoiceLabel($choice)
|
||||||
|
{
|
||||||
|
return (string) $choice;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the field name for a choice.
|
||||||
|
*
|
||||||
|
* This method is used to generate field names if the underlying object has
|
||||||
|
* a single-column integer ID. In that case, the value of the field is
|
||||||
|
* the ID of the object. That ID is also used as field name.
|
||||||
|
*
|
||||||
|
* @param object $choice The object.
|
||||||
|
* @param int|string $key The choice key.
|
||||||
|
* @param string $value The choice value. Corresponds to the object's
|
||||||
|
* ID here.
|
||||||
|
*
|
||||||
|
* @return string The field name.
|
||||||
|
*
|
||||||
|
* @internal This method is public to be usable as callback. It should not
|
||||||
|
* be used in user code.
|
||||||
|
*/
|
||||||
|
public static function createChoiceName($choice, $key, $value)
|
||||||
|
{
|
||||||
|
return str_replace('-', '_', (string) $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
if ($options['multiple']) {
|
||||||
|
$builder
|
||||||
|
->addViewTransformer(new CollectionToArrayTransformer(), true)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$choiceLoader = function (Options $options) {
|
||||||
|
// Unless the choices are given explicitly, load them on demand
|
||||||
|
if (null === $options['choices']) {
|
||||||
|
|
||||||
|
$propelChoiceLoader = new PropelChoiceLoader(
|
||||||
|
$this->choiceListFactory,
|
||||||
|
$options['class'],
|
||||||
|
$options['query'],
|
||||||
|
$options['index_property']
|
||||||
|
);
|
||||||
|
|
||||||
|
return $propelChoiceLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
$choiceName = function (Options $options) {
|
||||||
|
|
||||||
|
/** @var ModelCriteria $query */
|
||||||
|
$query = $options['query'];
|
||||||
|
if ($options['index_property']) {
|
||||||
|
$identifier = array($query->getTableMap()->getColumn($options['index_property']));
|
||||||
|
} else {
|
||||||
|
$identifier = $query->getTableMap()->getPrimaryKeys();
|
||||||
|
}
|
||||||
|
/** @var ColumnMap $firstIdentifier */
|
||||||
|
$firstIdentifier = current($identifier);
|
||||||
|
if (count($identifier) === 1 && $firstIdentifier->getPdoType() === \PDO::PARAM_INT) {
|
||||||
|
return array(__CLASS__, 'createChoiceName');
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
$choiceValue = function (Options $options) {
|
||||||
|
|
||||||
|
/** @var ModelCriteria $query */
|
||||||
|
$query = $options['query'];
|
||||||
|
if ($options['index_property']) {
|
||||||
|
$identifier = array($query->getTableMap()->getColumn($options['index_property']));
|
||||||
|
} else {
|
||||||
|
$identifier = $query->getTableMap()->getPrimaryKeys();
|
||||||
|
}
|
||||||
|
/** @var ColumnMap $firstIdentifier */
|
||||||
|
$firstIdentifier = current($identifier);
|
||||||
|
if (count($identifier) === 1 && in_array($firstIdentifier->getPdoType(), [\PDO::PARAM_BOOL, \PDO::PARAM_INT, \PDO::PARAM_STR])) {
|
||||||
|
return function($object) use ($firstIdentifier) {
|
||||||
|
if ($object) {
|
||||||
|
return call_user_func([$object, 'get' . ucfirst($firstIdentifier->getPhpName())]);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
$queryNormalizer = function (Options $options, $query) {
|
||||||
|
if ($query === null) {
|
||||||
|
$queryClass = $options['class'] . 'Query';
|
||||||
|
if (!class_exists($queryClass)) {
|
||||||
|
if (empty($options['class'])) {
|
||||||
|
throw new MissingOptionsException('The "class" parameter is empty, you should provide the model class');
|
||||||
|
}
|
||||||
|
throw new InvalidOptionsException(
|
||||||
|
sprintf(
|
||||||
|
'The query class "%s" is not found, you should provide the FQCN of the model class',
|
||||||
|
$queryClass
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$query = new $queryClass();
|
||||||
|
}
|
||||||
|
return $query;
|
||||||
|
};
|
||||||
|
|
||||||
|
$choiceLabelNormalizer = function (Options $options, $choiceLabel) {
|
||||||
|
if ($choiceLabel === null) {
|
||||||
|
if ($options['property'] == null) {
|
||||||
|
$choiceLabel = array(__CLASS__, 'createChoiceLabel');
|
||||||
|
} else {
|
||||||
|
$valueProperty = $options['property'];
|
||||||
|
/** @var ModelCriteria $query */
|
||||||
|
$query = $options['query'];
|
||||||
|
|
||||||
|
$choiceLabel = function($choice) use ($valueProperty) {
|
||||||
|
$getter = 'get'.ucfirst($valueProperty);
|
||||||
|
if (!method_exists($choice, $getter)) {
|
||||||
|
$getter = 'get' . ucfirst($query->getTableMap()->getColumn($valueProperty)->getPhpName());
|
||||||
|
}
|
||||||
|
|
||||||
|
return call_user_func([$choice, $getter]);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $choiceLabel;
|
||||||
|
};
|
||||||
|
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'query' => null,
|
||||||
|
'index_property' => null,
|
||||||
|
'property' => null,
|
||||||
|
'choices' => null,
|
||||||
|
'choice_loader' => $choiceLoader,
|
||||||
|
'choice_label' => null,
|
||||||
|
'choice_name' => $choiceName,
|
||||||
|
'choice_value' => $choiceValue,
|
||||||
|
'choice_translation_domain' => false,
|
||||||
|
'by_reference' => false,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$resolver->setRequired(array('class'));
|
||||||
|
$resolver->setNormalizer('query', $queryNormalizer);
|
||||||
|
$resolver->setNormalizer('choice_label', $choiceLabelNormalizer);
|
||||||
|
$resolver->setAllowedTypes('query', ['null', 'Propel\Runtime\ActiveQuery\ModelCriteria']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getBlockPrefix()
|
||||||
|
{
|
||||||
|
return 'model';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getParent()
|
||||||
|
{
|
||||||
|
return 'Symfony\Component\Form\Extension\Core\Type\ChoiceType';
|
||||||
|
}
|
||||||
|
}
|
84
Form/Type/TranslationCollectionType.php
Normal file
84
Form/Type/TranslationCollectionType.php
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Propel\Bundle\PropelBundle\Form\Type;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
|
||||||
|
use Symfony\Component\OptionsResolver\Exception\MissingOptionsException;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Propel\Bundle\PropelBundle\Form\EventListener\TranslationCollectionFormListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* form type for i18n-columns in propel
|
||||||
|
*
|
||||||
|
* @author Patrick Kaufmann
|
||||||
|
*/
|
||||||
|
class TranslationCollectionType extends AbstractType
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
if (!isset($options['entry_options']['data_class']) || null === $options['entry_options']['data_class']) {
|
||||||
|
throw new MissingOptionsException('data_class must be set');
|
||||||
|
}
|
||||||
|
if (!isset($options['entry_options']['columns']) || null === $options['entry_options']['columns']) {
|
||||||
|
throw new MissingOptionsException('columns must be set');
|
||||||
|
}
|
||||||
|
|
||||||
|
$listener = new TranslationCollectionFormListener($options['languages'], $options['entry_options']['data_class']);
|
||||||
|
$builder->addEventSubscriber($listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver->setRequired(array(
|
||||||
|
'languages'
|
||||||
|
));
|
||||||
|
|
||||||
|
$resolver->setDefaults(array(
|
||||||
|
'entry_type' => TranslationType::class,
|
||||||
|
'allow_add' => false,
|
||||||
|
'allow_delete' => false,
|
||||||
|
'entry_options' => array(
|
||||||
|
'data_class' => null,
|
||||||
|
'columns' => null
|
||||||
|
)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getParent()
|
||||||
|
{
|
||||||
|
return CollectionType::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getBlockPrefix()
|
||||||
|
{
|
||||||
|
return 'propel_translation_collection';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->getBlockPrefix();
|
||||||
|
}
|
||||||
|
}
|
60
Form/Type/TranslationType.php
Normal file
60
Form/Type/TranslationType.php
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Propel\Bundle\PropelBundle\Form\Type;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Propel\Bundle\PropelBundle\Form\EventListener\TranslationFormListener;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translation type class
|
||||||
|
*
|
||||||
|
* @author Patrick Kaufmann
|
||||||
|
*/
|
||||||
|
class TranslationType extends AbstractType
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
$builder->addEventSubscriber(
|
||||||
|
new TranslationFormListener($options['columns'], $options['data_class'])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver->setRequired(array(
|
||||||
|
'data_class',
|
||||||
|
'columns'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getBlockPrefix()
|
||||||
|
{
|
||||||
|
return 'propel_translation';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->getBlockPrefix();
|
||||||
|
}
|
||||||
|
}
|
209
Form/TypeGuesser.php
Normal file
209
Form/TypeGuesser.php
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Propel\Bundle\PropelBundle\Form;
|
||||||
|
|
||||||
|
use Propel\Bundle\PropelBundle\Form\Type\ModelType;
|
||||||
|
use Propel\Runtime\Map\ColumnMap;
|
||||||
|
use Propel\Runtime\Map\RelationMap;
|
||||||
|
use Propel\Generator\Model\PropelTypes;
|
||||||
|
use Propel\Runtime\Map\TableMap;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\NumberType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TimeType;
|
||||||
|
use Symfony\Component\Form\FormTypeGuesserInterface;
|
||||||
|
use Symfony\Component\Form\Guess\Guess;
|
||||||
|
use Symfony\Component\Form\Guess\TypeGuess;
|
||||||
|
use Symfony\Component\Form\Guess\ValueGuess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Propel Type guesser.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class TypeGuesser implements FormTypeGuesserInterface
|
||||||
|
{
|
||||||
|
private $cache = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function guessType($class, $property)
|
||||||
|
{
|
||||||
|
if (!$table = $this->getTable($class)) {
|
||||||
|
return new TypeGuess(TextType::class, array(), Guess::LOW_CONFIDENCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($table->getRelations() as $relation) {
|
||||||
|
if ($relation->getType() === RelationMap::MANY_TO_ONE) {
|
||||||
|
if (strtolower($property) === strtolower($relation->getName())) {
|
||||||
|
return new TypeGuess(ModelType::class, array(
|
||||||
|
'class' => $relation->getForeignTable()->getClassName(),
|
||||||
|
'multiple' => false,
|
||||||
|
), Guess::HIGH_CONFIDENCE);
|
||||||
|
}
|
||||||
|
} elseif ($relation->getType() === RelationMap::ONE_TO_MANY) {
|
||||||
|
if (strtolower($property) === strtolower($relation->getPluralName())) {
|
||||||
|
return new TypeGuess(ModelType::class, array(
|
||||||
|
'class' => $relation->getForeignTable()->getClassName(),
|
||||||
|
'multiple' => true,
|
||||||
|
), Guess::HIGH_CONFIDENCE);
|
||||||
|
}
|
||||||
|
} elseif ($relation->getType() === RelationMap::MANY_TO_MANY) {
|
||||||
|
if (strtolower($property) == strtolower($relation->getPluralName())) {
|
||||||
|
return new TypeGuess(ModelType::class, array(
|
||||||
|
'class' => $relation->getLocalTable()->getClassName(),
|
||||||
|
'multiple' => true,
|
||||||
|
), Guess::HIGH_CONFIDENCE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$column = $this->getColumn($class, $property)) {
|
||||||
|
return new TypeGuess(TextType::class, array(), Guess::LOW_CONFIDENCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($column->getType()) {
|
||||||
|
case PropelTypes::BOOLEAN:
|
||||||
|
case PropelTypes::BOOLEAN_EMU:
|
||||||
|
return new TypeGuess(CheckboxType::class, array(), Guess::HIGH_CONFIDENCE);
|
||||||
|
case PropelTypes::TIMESTAMP:
|
||||||
|
case PropelTypes::BU_TIMESTAMP:
|
||||||
|
return new TypeGuess(DateTimeType::class, array(), Guess::HIGH_CONFIDENCE);
|
||||||
|
case PropelTypes::DATE:
|
||||||
|
case PropelTypes::BU_DATE:
|
||||||
|
return new TypeGuess(DateType::class, array(), Guess::HIGH_CONFIDENCE);
|
||||||
|
case PropelTypes::TIME:
|
||||||
|
return new TypeGuess(TimeType::class, array(), Guess::HIGH_CONFIDENCE);
|
||||||
|
case PropelTypes::FLOAT:
|
||||||
|
case PropelTypes::REAL:
|
||||||
|
case PropelTypes::DOUBLE:
|
||||||
|
case PropelTypes::DECIMAL:
|
||||||
|
return new TypeGuess(NumberType::class, array(), Guess::MEDIUM_CONFIDENCE);
|
||||||
|
case PropelTypes::TINYINT:
|
||||||
|
case PropelTypes::SMALLINT:
|
||||||
|
case PropelTypes::INTEGER:
|
||||||
|
case PropelTypes::BIGINT:
|
||||||
|
case PropelTypes::NUMERIC:
|
||||||
|
return new TypeGuess(IntegerType::class, array(), Guess::MEDIUM_CONFIDENCE);
|
||||||
|
case PropelTypes::ENUM:
|
||||||
|
case PropelTypes::CHAR:
|
||||||
|
if ($column->getValueSet()) {
|
||||||
|
//check if this is mysql enum
|
||||||
|
$choices = $column->getValueSet();
|
||||||
|
$labels = array_map('ucfirst', $choices);
|
||||||
|
|
||||||
|
return new TypeGuess(ChoiceType::class, array('choices' => array_combine($choices, $labels)), Guess::MEDIUM_CONFIDENCE);
|
||||||
|
}
|
||||||
|
case PropelTypes::VARCHAR:
|
||||||
|
return new TypeGuess(TextType::class, array(), Guess::MEDIUM_CONFIDENCE);
|
||||||
|
case PropelTypes::LONGVARCHAR:
|
||||||
|
case PropelTypes::BLOB:
|
||||||
|
case PropelTypes::CLOB:
|
||||||
|
case PropelTypes::CLOB_EMU:
|
||||||
|
return new TypeGuess(TextareaType::class, array(), Guess::MEDIUM_CONFIDENCE);
|
||||||
|
default:
|
||||||
|
return new TypeGuess(TextType::class, array(), Guess::LOW_CONFIDENCE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function guessRequired($class, $property)
|
||||||
|
{
|
||||||
|
if ($column = $this->getColumn($class, $property)) {
|
||||||
|
return new ValueGuess($column->isNotNull(), Guess::HIGH_CONFIDENCE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function guessMaxLength($class, $property)
|
||||||
|
{
|
||||||
|
if ($column = $this->getColumn($class, $property)) {
|
||||||
|
if ($column->isText()) {
|
||||||
|
return new ValueGuess($column->getSize(), Guess::HIGH_CONFIDENCE);
|
||||||
|
}
|
||||||
|
switch ($column->getType()) {
|
||||||
|
case PropelTypes::FLOAT:
|
||||||
|
case PropelTypes::REAL:
|
||||||
|
case PropelTypes::DOUBLE:
|
||||||
|
case PropelTypes::DECIMAL:
|
||||||
|
return new ValueGuess(null, Guess::MEDIUM_CONFIDENCE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function guessPattern($class, $property)
|
||||||
|
{
|
||||||
|
if ($column = $this->getColumn($class, $property)) {
|
||||||
|
switch ($column->getType()) {
|
||||||
|
case PropelTypes::FLOAT:
|
||||||
|
case PropelTypes::REAL:
|
||||||
|
case PropelTypes::DOUBLE:
|
||||||
|
case PropelTypes::DECIMAL:
|
||||||
|
return new ValueGuess(null, Guess::MEDIUM_CONFIDENCE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $class
|
||||||
|
*
|
||||||
|
* @return TableMap|null
|
||||||
|
*/
|
||||||
|
protected function getTable($class)
|
||||||
|
{
|
||||||
|
if (isset($this->cache[$class])) {
|
||||||
|
return $this->cache[$class];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (class_exists($queryClass = $class.'Query')) {
|
||||||
|
$query = new $queryClass();
|
||||||
|
|
||||||
|
return $this->cache[$class] = $query->getTableMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $class
|
||||||
|
* @param string $property
|
||||||
|
*
|
||||||
|
* @return ColumnMap|null
|
||||||
|
*/
|
||||||
|
protected function getColumn($class, $property)
|
||||||
|
{
|
||||||
|
if (isset($this->cache[$class.'::'.$property])) {
|
||||||
|
return $this->cache[$class.'::'.$property];
|
||||||
|
}
|
||||||
|
|
||||||
|
$table = $this->getTable($class);
|
||||||
|
|
||||||
|
if ($table && $table->hasColumn($property)) {
|
||||||
|
return $this->cache[$class.'::'.$property] = $table->getColumn($property);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
105
Logger/PropelLogger.php
Normal file
105
Logger/PropelLogger.php
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
<?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\Bundle\PropelBundle\Logger;
|
||||||
|
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Psr\Log\LoggerTrait;
|
||||||
|
use Symfony\Component\Stopwatch\Stopwatch;
|
||||||
|
use Symfony\Component\VarDumper\Caster\TraceStub;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||||
|
*/
|
||||||
|
class PropelLogger implements LoggerInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var LoggerInterface
|
||||||
|
*/
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $queries = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Stopwatch
|
||||||
|
*/
|
||||||
|
protected $stopwatch;
|
||||||
|
|
||||||
|
use LoggerTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param LoggerInterface $logger A LoggerInterface instance
|
||||||
|
* @param Stopwatch $stopwatch A Stopwatch instance
|
||||||
|
*/
|
||||||
|
public function __construct(LoggerInterface $logger = null, Stopwatch $stopwatch = null)
|
||||||
|
{
|
||||||
|
$this->logger = $logger;
|
||||||
|
$this->stopwatch = $stopwatch;
|
||||||
|
$this->isPrepared = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs with an arbitrary level.
|
||||||
|
*
|
||||||
|
* @param mixed $level
|
||||||
|
* @param string $message
|
||||||
|
* @param array $context
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
public function log($level, $message, array $context = array())
|
||||||
|
{
|
||||||
|
if (null === $this->logger) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$add = true;
|
||||||
|
$trace = debug_backtrace();
|
||||||
|
|
||||||
|
if (null !== $this->stopwatch) {
|
||||||
|
$method = $trace[3]['function'];
|
||||||
|
|
||||||
|
$watch = 'Propel Query '.(count($this->queries)+1);
|
||||||
|
if ('prepare' === $method) {
|
||||||
|
$this->isPrepared = true;
|
||||||
|
$this->stopwatch->start($watch, 'propel');
|
||||||
|
|
||||||
|
$add = false;
|
||||||
|
} elseif ($this->isPrepared) {
|
||||||
|
$this->isPrepared = false;
|
||||||
|
$event = $this->stopwatch->stop($watch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// $trace[2] has no 'object' key if an exception is thrown while executing a query
|
||||||
|
if ($add && isset($event) && isset($trace[2]['object'])) {
|
||||||
|
$connection = $trace[2]['object'];
|
||||||
|
|
||||||
|
$this->queries[] = array(
|
||||||
|
'sql' => $message,
|
||||||
|
'connection' => $connection->getName(),
|
||||||
|
'time' => $event->getDuration() / 1000,
|
||||||
|
'memory' => $event->getMemory(),
|
||||||
|
'trace' => new TraceStub($trace),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logger->log($level, $message, $context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueries()
|
||||||
|
{
|
||||||
|
return $this->queries;
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,9 +8,10 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Model\Acl;
|
namespace Propel\Bundle\PropelBundle\Model\Acl;
|
||||||
|
|
||||||
use Propel\PropelBundle\Model\Acl\om\BaseAclClass;
|
use Propel\Bundle\PropelBundle\Model\Acl\Base\AclClass as BaseAclClass;
|
||||||
|
use Propel\Runtime\Connection\ConnectionInterface;
|
||||||
|
|
||||||
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
|
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
|
||||||
|
|
||||||
|
@ -22,11 +23,11 @@ class AclClass extends BaseAclClass
|
||||||
* If none can be found, a new one will be saved.
|
* If none can be found, a new one will be saved.
|
||||||
*
|
*
|
||||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||||
* @param \PropelPDO $con
|
* @param ConnectionInterface $con
|
||||||
*
|
*
|
||||||
* @return \Propel\PropelBundle\Model\Acl\AclClass
|
* @return \Propel\Bundle\PropelBundle\Model\Acl\AclClass
|
||||||
*/
|
*/
|
||||||
public static function fromAclObjectIdentity(ObjectIdentityInterface $objectIdentity, \PropelPDO $con = null)
|
public static function fromAclObjectIdentity(ObjectIdentityInterface $objectIdentity, ConnectionInterface $con = null)
|
||||||
{
|
{
|
||||||
$obj = AclClassQuery::create()
|
$obj = AclClassQuery::create()
|
||||||
->filterByType($objectIdentity->getType())
|
->filterByType($objectIdentity->getType())
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
<?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\Model\Acl;
|
|
||||||
|
|
||||||
use Propel\PropelBundle\Model\Acl\om\BaseAclClassPeer;
|
|
||||||
|
|
||||||
class AclClassPeer extends BaseAclClassPeer
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -8,9 +8,9 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Model\Acl;
|
namespace Propel\Bundle\PropelBundle\Model\Acl;
|
||||||
|
|
||||||
use Propel\PropelBundle\Model\Acl\om\BaseAclClassQuery;
|
use Propel\Bundle\PropelBundle\Model\Acl\Base\AclClassQuery as BaseAclClassQuery;
|
||||||
|
|
||||||
class AclClassQuery extends BaseAclClassQuery
|
class AclClassQuery extends BaseAclClassQuery
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,12 +8,12 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Model\Acl;
|
namespace Propel\Bundle\PropelBundle\Model\Acl;
|
||||||
|
|
||||||
use Propel\PropelBundle\Model\Acl\om\BaseEntry;
|
use Propel\Bundle\PropelBundle\Model\Acl\Base\Entry as BaseEntry;
|
||||||
|
|
||||||
use Propel\PropelBundle\Security\Acl\Domain\Entry as AclEntry;
|
use Propel\Bundle\PropelBundle\Security\Acl\Domain\Entry as AclEntry;
|
||||||
use Propel\PropelBundle\Security\Acl\Domain\FieldEntry as AclFieldEntry;
|
use Propel\Bundle\PropelBundle\Security\Acl\Domain\FieldEntry as AclFieldEntry;
|
||||||
|
|
||||||
use Symfony\Component\Security\Acl\Model\AclInterface;
|
use Symfony\Component\Security\Acl\Model\AclInterface;
|
||||||
use Symfony\Component\Security\Acl\Model\EntryInterface;
|
use Symfony\Component\Security\Acl\Model\EntryInterface;
|
||||||
|
@ -29,7 +29,7 @@ class Entry extends BaseEntry
|
||||||
*
|
*
|
||||||
* @param \Symfony\Component\Security\Acl\Model\EntryInterface $aclEntry
|
* @param \Symfony\Component\Security\Acl\Model\EntryInterface $aclEntry
|
||||||
*
|
*
|
||||||
* @return \Propel\PropelBundle\Model\Acl\Entry
|
* @return \Propel\Bundle\PropelBundle\Model\Acl\Entry
|
||||||
*/
|
*/
|
||||||
public static function fromAclEntry(EntryInterface $aclEntry)
|
public static function fromAclEntry(EntryInterface $aclEntry)
|
||||||
{
|
{
|
||||||
|
@ -64,7 +64,7 @@ class Entry extends BaseEntry
|
||||||
/**
|
/**
|
||||||
* Transform a given model entry into an ACL related Entry (ACE).
|
* Transform a given model entry into an ACL related Entry (ACE).
|
||||||
*
|
*
|
||||||
* @param \Propel\PropelBundle\Model\Acl\Entry $modelEntry
|
* @param \Propel\Bundle\PropelBundle\Model\Acl\Entry $modelEntry
|
||||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $acl
|
* @param \Symfony\Component\Security\Acl\Model\AclInterface $acl
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\Security\Acl\Model\EntryInterface
|
* @return \Symfony\Component\Security\Acl\Model\EntryInterface
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
<?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\Model\Acl;
|
|
||||||
|
|
||||||
use Propel\PropelBundle\Model\Acl\om\BaseEntryPeer;
|
|
||||||
|
|
||||||
class EntryPeer extends BaseEntryPeer
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -8,10 +8,14 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Model\Acl;
|
namespace Propel\Bundle\PropelBundle\Model\Acl;
|
||||||
|
|
||||||
use Propel\PropelBundle\Model\Acl\om\BaseEntryQuery;
|
use Propel\Bundle\PropelBundle\Model\Acl\Base\EntryQuery as BaseEntryQuery;
|
||||||
use Propel\PropelBundle\Model\Acl\EntryPeer;
|
use Propel\Bundle\PropelBundle\Model\Acl\Map\EntryTableMap;
|
||||||
|
use Propel\Bundle\PropelBundle\Model\Acl\Map\ObjectIdentityTableMap;
|
||||||
|
|
||||||
|
use Propel\Runtime\ActiveQuery\Criteria;
|
||||||
|
use Propel\Runtime\Connection\ConnectionInterface;
|
||||||
|
|
||||||
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
|
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
|
||||||
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
|
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
|
||||||
|
@ -25,11 +29,11 @@ class EntryQuery extends BaseEntryQuery
|
||||||
*
|
*
|
||||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity An ACL related ObjectIdentity.
|
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity An ACL related ObjectIdentity.
|
||||||
* @param array $securityIdentities A list of SecurityIdentity to filter by.
|
* @param array $securityIdentities A list of SecurityIdentity to filter by.
|
||||||
* @param \PropelPDO $con
|
* @param \ConnectionInterface $con
|
||||||
*
|
*
|
||||||
* @return \PropelObjectCollection
|
* @return \PropelObjectCollection
|
||||||
*/
|
*/
|
||||||
public function findByAclIdentity(ObjectIdentityInterface $objectIdentity, array $securityIdentities = array(), \PropelPDO $con = null)
|
public function findByAclIdentity(ObjectIdentityInterface $objectIdentity, array $securityIdentities = array(), ConnectionInterface $con = null)
|
||||||
{
|
{
|
||||||
$securityIds = array();
|
$securityIds = array();
|
||||||
foreach ($securityIdentities as $eachIdentity) {
|
foreach ($securityIdentities as $eachIdentity) {
|
||||||
|
@ -49,12 +53,12 @@ class EntryQuery extends BaseEntryQuery
|
||||||
}
|
}
|
||||||
|
|
||||||
$this
|
$this
|
||||||
->useAclClassQuery(null, \Criteria::INNER_JOIN)
|
->useAclClassQuery(null, Criteria::INNER_JOIN)
|
||||||
->filterByType((string) $objectIdentity->getType())
|
->filterByType((string) $objectIdentity->getType())
|
||||||
->endUse()
|
->endUse()
|
||||||
->leftJoinObjectIdentity()
|
->leftJoinObjectIdentity()
|
||||||
->add(ObjectIdentityPeer::OBJECT_IDENTIFIER, (string) $objectIdentity->getIdentifier(), \Criteria::EQUAL)
|
->add(ObjectIdentityTableMap::COL_OBJECT_IDENTIFIER, (string) $objectIdentity->getIdentifier(), Criteria::EQUAL)
|
||||||
->addOr(EntryPeer::OBJECT_IDENTITY_ID, null, \Criteria::ISNULL)
|
->addOr(EntryTableMap::COL_OBJECT_IDENTITY_ID, null, Criteria::ISNULL)
|
||||||
;
|
;
|
||||||
|
|
||||||
if (!empty($securityIdentities)) {
|
if (!empty($securityIdentities)) {
|
||||||
|
|
|
@ -8,13 +8,17 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Model\Acl;
|
namespace Propel\Bundle\PropelBundle\Model\Acl;
|
||||||
|
|
||||||
use Propel\PropelBundle\Model\Acl\om\BaseObjectIdentity;
|
use Propel\Bundle\PropelBundle\Model\Acl\Base\ObjectIdentity as BaseObjectIdentity;
|
||||||
|
use Propel\Bundle\PropelBundle\Model\Acl\Map\ObjectIdentityTableMap;
|
||||||
|
|
||||||
|
use Propel\Runtime\ActiveQuery\Criteria;
|
||||||
|
use Propel\Runtime\Connection\ConnectionInterface;
|
||||||
|
|
||||||
class ObjectIdentity extends BaseObjectIdentity
|
class ObjectIdentity extends BaseObjectIdentity
|
||||||
{
|
{
|
||||||
public function preInsert(\PropelPDO $con = null)
|
public function preInsert(ConnectionInterface $con = null)
|
||||||
{
|
{
|
||||||
// Compatibility with default implementation.
|
// Compatibility with default implementation.
|
||||||
$ancestor = new ObjectIdentityAncestor();
|
$ancestor = new ObjectIdentityAncestor();
|
||||||
|
@ -30,16 +34,16 @@ class ObjectIdentity extends BaseObjectIdentity
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function preUpdate(\PropelPDO $con = null)
|
public function preUpdate(ConnectionInterface $con = null)
|
||||||
{
|
{
|
||||||
if ($this->isColumnModified(ObjectIdentityPeer::PARENT_OBJECT_IDENTITY_ID)) {
|
if ($this->isColumnModified(ObjectIdentityTableMap::COL_PARENT_OBJECT_IDENTITY_ID)) {
|
||||||
$this->updateAncestorsTree($con);
|
$this->updateAncestorsTree($con);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function preDelete(\PropelPDO $con = null)
|
public function preDelete(ConnectionInterface $con = null)
|
||||||
{
|
{
|
||||||
// Only retrieve direct children, it's faster and grand children will be retrieved recursively.
|
// Only retrieve direct children, it's faster and grand children will be retrieved recursively.
|
||||||
$children = ObjectIdentityQuery::create()->findChildren($this, $con);
|
$children = ObjectIdentityQuery::create()->findChildren($this, $con);
|
||||||
|
@ -51,7 +55,7 @@ class ObjectIdentity extends BaseObjectIdentity
|
||||||
|
|
||||||
// Manually delete those for DBAdapter not capable of cascading the DELETE.
|
// Manually delete those for DBAdapter not capable of cascading the DELETE.
|
||||||
ObjectIdentityAncestorQuery::create()
|
ObjectIdentityAncestorQuery::create()
|
||||||
->filterByObjectIdentityId($objIds, \Criteria::IN)
|
->filterByObjectIdentityId($objIds, Criteria::IN)
|
||||||
->delete($con)
|
->delete($con)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -61,11 +65,11 @@ class ObjectIdentity extends BaseObjectIdentity
|
||||||
/**
|
/**
|
||||||
* Update all ancestor entries to reflect changes on this instance.
|
* Update all ancestor entries to reflect changes on this instance.
|
||||||
*
|
*
|
||||||
* @param \PropelPDO $con
|
* @param ConnectionInterface $con
|
||||||
*
|
*
|
||||||
* @return \Propel\PropelBundle\Model\Acl\ObjectIdentity $this
|
* @return \Propel\Bundle\PropelBundle\Model\Acl\ObjectIdentity $this
|
||||||
*/
|
*/
|
||||||
protected function updateAncestorsTree(\PropelPDO $con = null)
|
protected function updateAncestorsTree(ConnectionInterface $con = null)
|
||||||
{
|
{
|
||||||
$con->beginTransaction();
|
$con->beginTransaction();
|
||||||
|
|
||||||
|
@ -82,13 +86,13 @@ class ObjectIdentity extends BaseObjectIdentity
|
||||||
*/
|
*/
|
||||||
$query = ObjectIdentityAncestorQuery::create()
|
$query = ObjectIdentityAncestorQuery::create()
|
||||||
->filterByObjectIdentityId($eachChild->getId())
|
->filterByObjectIdentityId($eachChild->getId())
|
||||||
->filterByObjectIdentityRelatedByAncestorId($oldAncestors, \Criteria::IN)
|
->filterByObjectIdentityRelatedByAncestorId($oldAncestors, Criteria::IN)
|
||||||
;
|
;
|
||||||
|
|
||||||
if ($eachChild->getId() !== $this->getId()) {
|
if ($eachChild->getId() !== $this->getId()) {
|
||||||
$query->filterByAncestorId(array($eachChild->getId(), $this->getId()), \Criteria::NOT_IN);
|
$query->filterByAncestorId(array($eachChild->getId(), $this->getId()), Criteria::NOT_IN);
|
||||||
} else {
|
} else {
|
||||||
$query->filterByAncestorId($this->getId(), \Criteria::NOT_EQUAL);
|
$query->filterByAncestorId($this->getId(), Criteria::NOT_EQUAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
$query->delete($con);
|
$query->delete($con);
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Model\Acl;
|
namespace Propel\Bundle\PropelBundle\Model\Acl;
|
||||||
|
|
||||||
use Propel\PropelBundle\Model\Acl\om\BaseObjectIdentityAncestor;
|
use Propel\Bundle\PropelBundle\Model\Acl\Base\ObjectIdentityAncestor as BaseObjectIdentityAncestor;
|
||||||
|
|
||||||
class ObjectIdentityAncestor extends BaseObjectIdentityAncestor
|
class ObjectIdentityAncestor extends BaseObjectIdentityAncestor
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
<?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\Model\Acl;
|
|
||||||
|
|
||||||
use Propel\PropelBundle\Model\Acl\om\BaseObjectIdentityAncestorPeer;
|
|
||||||
|
|
||||||
class ObjectIdentityAncestorPeer extends BaseObjectIdentityAncestorPeer
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -8,9 +8,9 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Model\Acl;
|
namespace Propel\Bundle\PropelBundle\Model\Acl;
|
||||||
|
|
||||||
use Propel\PropelBundle\Model\Acl\om\BaseObjectIdentityAncestorQuery;
|
use Propel\Bundle\PropelBundle\Model\Acl\Base\ObjectIdentityAncestorQuery as BaseObjectIdentityAncestorQuery;
|
||||||
|
|
||||||
class ObjectIdentityAncestorQuery extends BaseObjectIdentityAncestorQuery
|
class ObjectIdentityAncestorQuery extends BaseObjectIdentityAncestorQuery
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
<?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\Model\Acl;
|
|
||||||
|
|
||||||
use Propel\PropelBundle\Model\Acl\om\BaseObjectIdentityPeer;
|
|
||||||
|
|
||||||
class ObjectIdentityPeer extends BaseObjectIdentityPeer
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -8,10 +8,12 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Model\Acl;
|
namespace Propel\Bundle\PropelBundle\Model\Acl;
|
||||||
|
|
||||||
use Propel\PropelBundle\Model\Acl\ObjectIdentity;
|
use Propel\Bundle\PropelBundle\Model\Acl\Base\ObjectIdentityQuery as BaseObjectIdentityQuery;
|
||||||
use Propel\PropelBundle\Model\Acl\om\BaseObjectIdentityQuery;
|
|
||||||
|
use Propel\Runtime\ActiveQuery\Criteria;
|
||||||
|
use Propel\Runtime\Connection\ConnectionInterface;
|
||||||
|
|
||||||
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
|
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
|
||||||
|
|
||||||
|
@ -21,11 +23,11 @@ class ObjectIdentityQuery extends BaseObjectIdentityQuery
|
||||||
* Filter by an ObjectIdentity object belonging to the given ACL related ObjectIdentity.
|
* Filter by an ObjectIdentity object belonging to the given ACL related ObjectIdentity.
|
||||||
*
|
*
|
||||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||||
* @param \PropelPDO $con
|
* @param ConnectionInterface $con
|
||||||
*
|
*
|
||||||
* @return \Propel\PropelBundle\Model\Acl\ObjectIdentityQuery $this
|
* @return \Propel\Bundle\PropelBundle\Model\Acl\ObjectIdentityQuery $this
|
||||||
*/
|
*/
|
||||||
public function filterByAclObjectIdentity(ObjectIdentityInterface $objectIdentity, \PropelPDO $con = null)
|
public function filterByAclObjectIdentity(ObjectIdentityInterface $objectIdentity, ConnectionInterface $con = null)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Not using a JOIN here, because the filter may be applied on 'findOneOrCreate',
|
* Not using a JOIN here, because the filter may be applied on 'findOneOrCreate',
|
||||||
|
@ -44,11 +46,11 @@ class ObjectIdentityQuery extends BaseObjectIdentityQuery
|
||||||
* Return an ObjectIdentity object belonging to the given ACL related ObjectIdentity.
|
* Return an ObjectIdentity object belonging to the given ACL related ObjectIdentity.
|
||||||
*
|
*
|
||||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||||
* @param \PropelPDO $con
|
* @param ConnectionInterface $con
|
||||||
*
|
*
|
||||||
* @return \Propel\PropelBundle\Model\Acl\ObjectIdentity
|
* @return \Propel\Bundle\PropelBundle\Model\Acl\ObjectIdentity
|
||||||
*/
|
*/
|
||||||
public function findOneByAclObjectIdentity(ObjectIdentityInterface $objectIdentity, \PropelPDO $con = null)
|
public function findOneByAclObjectIdentity(ObjectIdentityInterface $objectIdentity, ConnectionInterface $con = null)
|
||||||
{
|
{
|
||||||
return $this
|
return $this
|
||||||
->filterByAclObjectIdentity($objectIdentity, $con)
|
->filterByAclObjectIdentity($objectIdentity, $con)
|
||||||
|
@ -59,12 +61,12 @@ class ObjectIdentityQuery extends BaseObjectIdentityQuery
|
||||||
/**
|
/**
|
||||||
* Return all children of the given object identity.
|
* Return all children of the given object identity.
|
||||||
*
|
*
|
||||||
* @param \Propel\PropelBundle\Model\Acl\ObjectIdentity $objectIdentity
|
* @param \Propel\Bundle\PropelBundle\Model\Acl\ObjectIdentity $objectIdentity
|
||||||
* @param \PropelPDO $con
|
* @param ConnectionInterface $con
|
||||||
*
|
*
|
||||||
* @return \PropelObjectCollection
|
* @return \PropelObjectCollection
|
||||||
*/
|
*/
|
||||||
public function findChildren(ObjectIdentity $objectIdentity, \PropelPDO $con = null)
|
public function findChildren(ObjectIdentity $objectIdentity, ConnectionInterface $con = null)
|
||||||
{
|
{
|
||||||
return $this
|
return $this
|
||||||
->filterByObjectIdentityRelatedByParentObjectIdentityId($objectIdentity)
|
->filterByObjectIdentityRelatedByParentObjectIdentityId($objectIdentity)
|
||||||
|
@ -75,17 +77,17 @@ class ObjectIdentityQuery extends BaseObjectIdentityQuery
|
||||||
/**
|
/**
|
||||||
* Return all children and grand-children of the given object identity.
|
* Return all children and grand-children of the given object identity.
|
||||||
*
|
*
|
||||||
* @param \Propel\PropelBundle\Model\Acl\ObjectIdentity $objectIdentity
|
* @param \Propel\Bundle\PropelBundle\Model\Acl\ObjectIdentity $objectIdentity
|
||||||
* @param \PropelPDO $con
|
* @param ConnectionInterface $con
|
||||||
*
|
*
|
||||||
* @return \PropelObjectCollection
|
* @return \PropelObjectCollection
|
||||||
*/
|
*/
|
||||||
public function findGrandChildren(ObjectIdentity $objectIdentity, \PropelPDO $con = null)
|
public function findGrandChildren(ObjectIdentity $objectIdentity, ConnectionInterface $con = null)
|
||||||
{
|
{
|
||||||
return $this
|
return $this
|
||||||
->useObjectIdentityAncestorRelatedByObjectIdentityIdQuery()
|
->useObjectIdentityAncestorRelatedByObjectIdentityIdQuery()
|
||||||
->filterByObjectIdentityRelatedByAncestorId($objectIdentity)
|
->filterByObjectIdentityRelatedByAncestorId($objectIdentity)
|
||||||
->filterByObjectIdentityRelatedByObjectIdentityId($objectIdentity, \Criteria::NOT_EQUAL)
|
->filterByObjectIdentityRelatedByObjectIdentityId($objectIdentity, Criteria::NOT_EQUAL)
|
||||||
->endUse()
|
->endUse()
|
||||||
->find($con)
|
->find($con)
|
||||||
;
|
;
|
||||||
|
@ -94,17 +96,17 @@ class ObjectIdentityQuery extends BaseObjectIdentityQuery
|
||||||
/**
|
/**
|
||||||
* Return all ancestors of the given object identity.
|
* Return all ancestors of the given object identity.
|
||||||
*
|
*
|
||||||
* @param ObjectIdentity $objectIdentity
|
* @param ObjectIdentity $objectIdentity
|
||||||
* @param \PropelPDO $con
|
* @param ConnectionInterface $con
|
||||||
*
|
*
|
||||||
* @return \PropelObjectCollection
|
* @return \PropelObjectCollection
|
||||||
*/
|
*/
|
||||||
public function findAncestors(ObjectIdentity $objectIdentity, \PropelPDO $con = null)
|
public function findAncestors(ObjectIdentity $objectIdentity, ConnectionInterface $con = null)
|
||||||
{
|
{
|
||||||
return $this
|
return $this
|
||||||
->useObjectIdentityAncestorRelatedByAncestorIdQuery()
|
->useObjectIdentityAncestorRelatedByAncestorIdQuery()
|
||||||
->filterByObjectIdentityRelatedByObjectIdentityId($objectIdentity)
|
->filterByObjectIdentityRelatedByObjectIdentityId($objectIdentity)
|
||||||
->filterByObjectIdentityRelatedByAncestorId($objectIdentity, \Criteria::NOT_EQUAL)
|
->filterByObjectIdentityRelatedByAncestorId($objectIdentity, Criteria::NOT_EQUAL)
|
||||||
->endUse()
|
->endUse()
|
||||||
->find($con)
|
->find($con)
|
||||||
;
|
;
|
||||||
|
|
|
@ -8,9 +8,11 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Model\Acl;
|
namespace Propel\Bundle\PropelBundle\Model\Acl;
|
||||||
|
|
||||||
use Propel\PropelBundle\Model\Acl\om\BaseSecurityIdentity;
|
use Propel\Bundle\PropelBundle\Model\Acl\Base\SecurityIdentity as BaseSecurityIdentity;
|
||||||
|
|
||||||
|
use Propel\Runtime\Connection\ConnectionInterface;
|
||||||
|
|
||||||
use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity;
|
use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity;
|
||||||
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
|
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
|
||||||
|
@ -21,7 +23,7 @@ class SecurityIdentity extends BaseSecurityIdentity
|
||||||
/**
|
/**
|
||||||
* Transform a given mode security identity into an ACL related SecurityIdentity.
|
* Transform a given mode security identity into an ACL related SecurityIdentity.
|
||||||
*
|
*
|
||||||
* @param \Propel\PropelBundle\Model\Acl\SecurityIdentity $securityIdentity
|
* @param \Propel\Bundle\PropelBundle\Model\Acl\SecurityIdentity $securityIdentity
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\Security\Acl\Model\SecurityIdentityInterface
|
* @return \Symfony\Component\Security\Acl\Model\SecurityIdentityInterface
|
||||||
*/
|
*/
|
||||||
|
@ -54,11 +56,11 @@ class SecurityIdentity extends BaseSecurityIdentity
|
||||||
* @throws \InvalidArgumentException
|
* @throws \InvalidArgumentException
|
||||||
*
|
*
|
||||||
* @param \Symfony\Component\Security\Acl\Model\SecurityIdentityInterface $aclIdentity
|
* @param \Symfony\Component\Security\Acl\Model\SecurityIdentityInterface $aclIdentity
|
||||||
* @param \PropelPDO $con
|
* @param ConnectionInterface $con
|
||||||
*
|
*
|
||||||
* @return \Propel\PropelBundle\Model\Acl\SecurityIdentity
|
* @return \Propel\Bundle\PropelBundle\Model\Acl\SecurityIdentity
|
||||||
*/
|
*/
|
||||||
public static function fromAclIdentity(SecurityIdentityInterface $aclIdentity, \PropelPDO $con = null)
|
public static function fromAclIdentity(SecurityIdentityInterface $aclIdentity, ConnectionInterface $con = null)
|
||||||
{
|
{
|
||||||
if ($aclIdentity instanceof UserSecurityIdentity) {
|
if ($aclIdentity instanceof UserSecurityIdentity) {
|
||||||
$identifier = $aclIdentity->getClass().'-'.$aclIdentity->getUsername();
|
$identifier = $aclIdentity->getClass().'-'.$aclIdentity->getUsername();
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
<?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\Model\Acl;
|
|
||||||
|
|
||||||
use Propel\PropelBundle\Model\Acl\om\BaseSecurityIdentityPeer;
|
|
||||||
|
|
||||||
class SecurityIdentityPeer extends BaseSecurityIdentityPeer
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -8,9 +8,9 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Model\Acl;
|
namespace Propel\Bundle\PropelBundle\Model\Acl;
|
||||||
|
|
||||||
use Propel\PropelBundle\Model\Acl\om\BaseSecurityIdentityQuery;
|
use Propel\Bundle\PropelBundle\Model\Acl\Base\SecurityIdentityQuery as BaseSecurityIdentityQuery;
|
||||||
|
|
||||||
class SecurityIdentityQuery extends BaseSecurityIdentityQuery
|
class SecurityIdentityQuery extends BaseSecurityIdentityQuery
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,9 +8,13 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle;
|
namespace Propel\Bundle\PropelBundle;
|
||||||
|
|
||||||
|
use Propel\Bundle\PropelBundle\DependencyInjection\Security\UserProvider\PropelFactory;
|
||||||
|
use Propel\Runtime\Propel;
|
||||||
|
use Propel\Runtime\Connection\ConnectionManagerSingle;
|
||||||
|
use Propel\Runtime\Connection\ConnectionManagerMasterSlave;
|
||||||
|
|
||||||
use Symfony\Bridge\Propel1\DependencyInjection\Security\UserProvider\PropelFactory;
|
|
||||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
|
||||||
|
@ -26,44 +30,18 @@ class PropelBundle extends Bundle
|
||||||
*/
|
*/
|
||||||
public function boot()
|
public function boot()
|
||||||
{
|
{
|
||||||
require_once $this->container->getParameter('propel.path').'/runtime/lib/Propel.php';
|
try {
|
||||||
|
$this->configureConnections();
|
||||||
if (0 === strncasecmp(PHP_SAPI, 'cli', 3)) {
|
|
||||||
set_include_path($this->container->getParameter('kernel.root_dir').'/..'.PATH_SEPARATOR.
|
|
||||||
$this->container->getParameter('propel.phing_path').PATH_SEPARATOR.
|
|
||||||
$this->container->getParameter('propel.phing_path').'/classes'.PATH_SEPARATOR.
|
|
||||||
get_include_path());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!\Propel::isInit()) {
|
|
||||||
\Propel::setConfiguration($this->container->get('propel.configuration'));
|
|
||||||
|
|
||||||
if ($this->container->getParameter('propel.logging')) {
|
if ($this->container->getParameter('propel.logging')) {
|
||||||
$config = $this
|
$this->configureLogging();
|
||||||
->container
|
|
||||||
->get('propel.configuration')
|
|
||||||
;
|
|
||||||
$config->setParameter('debugpdo.logging.methods', array(
|
|
||||||
'PropelPDO::exec',
|
|
||||||
'PropelPDO::query',
|
|
||||||
'PropelPDO::prepare',
|
|
||||||
'DebugPDOStatement::execute',
|
|
||||||
), false);
|
|
||||||
$config->setParameter('debugpdo.logging.details', array(
|
|
||||||
'time' => array('enabled' => true),
|
|
||||||
'mem' => array('enabled' => true),
|
|
||||||
'connection' => array('enabled' => true),
|
|
||||||
));
|
|
||||||
|
|
||||||
\Propel::setLogger($this->container->get('propel.logger'));
|
|
||||||
}
|
}
|
||||||
|
} catch( \Exception $e ) {
|
||||||
\Propel::initialize();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function build(ContainerBuilder $container)
|
public function build(ContainerBuilder $container)
|
||||||
{
|
{
|
||||||
|
@ -73,4 +51,55 @@ class PropelBundle extends Bundle
|
||||||
$container->getExtension('security')->addUserProviderFactory(new PropelFactory('propel', 'propel.security.user.provider'));
|
$container->getExtension('security')->addUserProviderFactory(new PropelFactory('propel', 'propel.security.user.provider'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function configureConnections()
|
||||||
|
{
|
||||||
|
$config = $this->container->getParameter('propel.configuration');
|
||||||
|
$defaultConnection = !empty($config['runtime']['defaultConnection']) ? $config['runtime']['defaultConnection'] : key($config['database']['connections']);
|
||||||
|
|
||||||
|
$serviceContainer = Propel::getServiceContainer();
|
||||||
|
$serviceContainer->setDefaultDatasource($defaultConnection);
|
||||||
|
|
||||||
|
foreach ($config['database']['connections'] as $name => $config) {
|
||||||
|
if (!empty($config['slaves'])) {
|
||||||
|
$manager = new ConnectionManagerMasterSlave();
|
||||||
|
|
||||||
|
// configure the master (write) connection
|
||||||
|
$manager->setWriteConfiguration($config);
|
||||||
|
|
||||||
|
// configure the slave (read) connections
|
||||||
|
$slaveConnections = [];
|
||||||
|
foreach ($config['slaves'] as $slave) {
|
||||||
|
$slaveConnections[] = array_merge($config, [
|
||||||
|
'dsn' => $slave['dsn'],
|
||||||
|
'slaves' => null
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$manager->setReadConfiguration($slaveConnections);
|
||||||
|
} else {
|
||||||
|
$manager = new ConnectionManagerSingle();
|
||||||
|
$manager->setConfiguration($config);
|
||||||
|
}
|
||||||
|
|
||||||
|
$serviceContainer->setAdapterClass($name, $config['adapter']);
|
||||||
|
$serviceContainer->setConnectionManager($name, $manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
$serviceContainer->initDatabaseMaps([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configureLogging()
|
||||||
|
{
|
||||||
|
$serviceContainer = Propel::getServiceContainer();
|
||||||
|
$serviceContainer->setLogger('defaultLogger', $this->container->get('propel.logger'));
|
||||||
|
|
||||||
|
foreach ($serviceContainer->getConnectionManagers() as $manager) {
|
||||||
|
$connection = $manager->getReadConnection($serviceContainer->getAdapter($manager->getName()));
|
||||||
|
$connection->setLogMethods(array_merge($connection->getLogMethods(), array('prepare')));
|
||||||
|
|
||||||
|
$connection = $manager->getWriteConnection();
|
||||||
|
$connection->setLogMethods(array_merge($connection->getLogMethods(), array('prepare')));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
PropelBundle
|
PropelBundle
|
||||||
============
|
============
|
||||||
|
|
||||||
[![Build Status](https://secure.travis-ci.org/propelorm/PropelBundle.png)](http://travis-ci.org/propelorm/PropelBundle)
|
[![Build Status](https://travis-ci.org/propelorm/PropelBundle.svg?branch=4.0)](https://travis-ci.org/propelorm/PropelBundle)
|
||||||
|
|
||||||
This is the official implementation of [Propel](http://www.propelorm.org/) in Symfony2.
|
This is the official implementation of [Propel](http://www.propelorm.org/) in Symfony.
|
||||||
|
|
||||||
## Branching model
|
## Branching model
|
||||||
|
|
||||||
|
@ -12,17 +12,9 @@ As `Propel2` will be released in the near future, we are migrating the branching
|
||||||
* The `1.0` branch contains Propel *1.6* integration for Symfony *2.0* (*currently 2.0 branch*).
|
* The `1.0` branch contains Propel *1.6* integration for Symfony *2.0* (*currently 2.0 branch*).
|
||||||
* The `1.1` branch contains Propel *1.6* integration for Symfony *2.1* (*currently 2.1 branch*).
|
* The `1.1` branch contains Propel *1.6* integration for Symfony *2.1* (*currently 2.1 branch*).
|
||||||
* The `1.2` branch contains Propel *1.6* integration for Symfony *2.2* (*currently master branch*).
|
* The `1.2` branch contains Propel *1.6* integration for Symfony *2.2* (*currently master branch*).
|
||||||
* The `2.0` branch will contain `Propel2` integration for Symfony *2.1*.
|
* The `2.0` branch contains `Propel2` integration for Symfony *2.5-2.8*.
|
||||||
We are still considering to integrate `Propel2` with Symfony *2.0*.
|
* The `3.0` branch contains `Propel2` integration for Symfony *2.8-3.x*.
|
||||||
In case, we will do so, there will be a `2.1` and `2.0` branch integrating the respective Symfony version!
|
* The `4.0` branch contains `Propel2` integration for Symfony *3.4-4.x*.
|
||||||
|
|
||||||
**The 1.x branches are already available and you are encouraged to migrate your dependencies according to the listings!**
|
|
||||||
|
|
||||||
* If you depend on Symfony `master` branch, switch to the `1.2` branch.
|
|
||||||
* If you depend on Symfony `2.1` branch, switch to the `1.1` branch.
|
|
||||||
* If you depend on Symfony `2.0` branch, switch to the `1.0` branch.
|
|
||||||
|
|
||||||
**Note:** the `master`, and `2.0` branches won't be updated anymore, and will trigger a `E_USER_DEPRECATED` error to notice people.
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
@ -30,20 +22,16 @@ As `Propel2` will be released in the near future, we are migrating the branching
|
||||||
* Insertion of SQL statements;
|
* Insertion of SQL statements;
|
||||||
* Runtime autoloading of Propel and generated classes;
|
* Runtime autoloading of Propel and generated classes;
|
||||||
* Propel runtime initialization through the XML configuration;
|
* Propel runtime initialization through the XML configuration;
|
||||||
* Migrations [Propel 1.6](http://www.propelorm.org/documentation/10-migrations.html);
|
* [Propel Migrations](http://propelorm.org/documentation/09-migrations.html);
|
||||||
* Reverse engineering from [existing database](http://www.propelorm.org/wiki/Documentation/1.6/Existing-Database);
|
* Reverse engineering from [existing database](http://propelorm.org/documentation/cookbook/working-with-existing-databases.html);
|
||||||
* Integration to the Symfony2 Profiler;
|
* Integration to the Symfony Profiler;
|
||||||
* Load SQL, YAML and XML fixtures;
|
* Load SQL, YAML and XML fixtures;
|
||||||
* Create/Drop databases;
|
* Create/Drop databases;
|
||||||
* Integration with the Form component;
|
* Integration with the Form component;
|
||||||
* Integration with the Security component;
|
* Integration with the Security component;
|
||||||
* Propel ParamConverter can be used with Sensio Framework Extra Bundle.
|
* Propel ParamConverter can be used with Sensio Framework Extra Bundle.
|
||||||
|
|
||||||
For documentation, see:
|
[Read the documentation](http://propelorm.org/documentation/)
|
||||||
|
|
||||||
Resources/doc/
|
|
||||||
|
|
||||||
[Read the documentation](https://github.com/propelorm/PropelBundle/blob/1.1/Resources/doc/index.markdown)
|
|
||||||
|
|
||||||
For license, see:
|
For license, see:
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Request\ParamConverter;
|
namespace Propel\Bundle\PropelBundle\Request\ParamConverter;
|
||||||
|
|
||||||
use Propel\PropelBundle\Util\PropelInflector;
|
use Propel\Bundle\PropelBundle\Util\PropelInflector;
|
||||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface;
|
use Propel\Runtime\ActiveQuery\Criteria;
|
||||||
|
use Propel\Runtime\ActiveQuery\ModelCriteria;
|
||||||
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||||
use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterInterface;
|
use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterInterface;
|
||||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
@ -46,14 +48,20 @@ class PropelParamConverter implements ParamConverterInterface
|
||||||
*/
|
*/
|
||||||
protected $withs;
|
protected $withs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* name of method use to call a query method
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $queryMethod;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
protected $hasWith = false;
|
protected $hasWith = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param ConfigurationInterface $configuration
|
* @param ParamConverter $configuration
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*
|
*
|
||||||
|
@ -61,24 +69,35 @@ class PropelParamConverter implements ParamConverterInterface
|
||||||
* @throws NotFoundHttpException
|
* @throws NotFoundHttpException
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function apply(Request $request, ConfigurationInterface $configuration)
|
public function apply(Request $request, ParamConverter $configuration)
|
||||||
{
|
{
|
||||||
$classQuery = $configuration->getClass() . 'Query';
|
$class = $configuration->getClass();
|
||||||
$classPeer = $configuration->getClass() . 'Peer';
|
$classQuery = $class . 'Query';
|
||||||
|
$classTableMap = $class::TABLE_MAP;
|
||||||
|
$this->filters = array();
|
||||||
|
$this->exclude = array();
|
||||||
|
|
||||||
if (!class_exists($classQuery)) {
|
if (!class_exists($classQuery)) {
|
||||||
throw new \Exception(sprintf('The %s Query class does not exist', $classQuery));
|
throw new \Exception(sprintf('The %s Query class does not exist', $classQuery));
|
||||||
}
|
}
|
||||||
|
|
||||||
$tableMap = $classPeer::getTableMap();
|
$tableMap = new $classTableMap();
|
||||||
$pkColumns = $tableMap->getPrimaryKeyColumns();
|
$pkColumns = $tableMap->getPrimaryKeys();
|
||||||
|
|
||||||
if (count($pkColumns) == 1) {
|
if (count($pkColumns) === 1) {
|
||||||
$this->pk = strtolower($pkColumns[0]->getName());
|
$pk = array_pop($pkColumns);
|
||||||
|
$this->pk = strtolower($pk->getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
$options = $configuration->getOptions();
|
$options = $configuration->getOptions();
|
||||||
|
|
||||||
|
// Check request attributes for converter options, if there are non provided.
|
||||||
|
if (empty($options) && $request->attributes->has('propel_converter') && $configuration instanceof ParamConverter) {
|
||||||
|
$converterOption = $request->attributes->get('propel_converter');
|
||||||
|
if (!empty($converterOption[$configuration->getName()])) {
|
||||||
|
$options = $converterOption[$configuration->getName()];
|
||||||
|
}
|
||||||
|
}
|
||||||
if (isset($options['mapping'])) {
|
if (isset($options['mapping'])) {
|
||||||
// We use the mapping for calling findPk or filterBy
|
// We use the mapping for calling findPk or filterBy
|
||||||
foreach ($options['mapping'] as $routeParam => $column) {
|
foreach ($options['mapping'] as $routeParam => $column) {
|
||||||
|
@ -91,21 +110,34 @@ class PropelParamConverter implements ParamConverterInterface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->exclude = isset($options['exclude'])? $options['exclude'] : array();
|
$this->exclude = isset($options['exclude']) ? $options['exclude'] : array();
|
||||||
$this->filters = $request->attributes->all();
|
$this->filters = $request->attributes->all();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->withs = isset($options['with'])? is_array($options['with'])? $options['with'] : array($options['with']) : array();
|
if (array_key_exists($configuration->getName(), $this->filters)) {
|
||||||
|
unset($this->filters[$configuration->getName()]);
|
||||||
|
}
|
||||||
|
|
||||||
// find by Pk
|
$this->withs = isset($options['with']) ? is_array($options['with']) ? $options['with'] : array($options['with']) : array();
|
||||||
if (false === $object = $this->findPk($classQuery, $request)) {
|
|
||||||
// find by criteria
|
$this->queryMethod = $queryMethod = isset($options['query_method']) ? $options['query_method'] : null;
|
||||||
if (false === $object = $this->findOneBy($classQuery, $request)) {
|
|
||||||
if ($configuration->isOptional()) {
|
if (null !== $this->queryMethod && method_exists($classQuery, $this->queryMethod)) {
|
||||||
//we find nothing but the object is optional
|
// find by custom method
|
||||||
$object = null;
|
$query = $this->getQuery($classQuery);
|
||||||
} else {
|
// execute a custom query
|
||||||
throw new \LogicException('Unable to guess how to get a Propel object from the request information.');
|
$object = $query->$queryMethod($request->attributes);
|
||||||
|
} else {
|
||||||
|
// find by Pk
|
||||||
|
if (false === $object = $this->findPk($classQuery, $request)) {
|
||||||
|
// find by criteria
|
||||||
|
if (false === $object = $this->findOneBy($classQuery, $request)) {
|
||||||
|
if ($configuration->isOptional()) {
|
||||||
|
//we find nothing but the object is optional
|
||||||
|
$object = null;
|
||||||
|
} else {
|
||||||
|
throw new \LogicException('Unable to guess how to get a Propel object from the request information.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,21 +152,23 @@ class PropelParamConverter implements ParamConverterInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ConfigurationInterface $configuration
|
* @param ParamConverter $configuration
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function supports(ConfigurationInterface $configuration)
|
public function supports(ParamConverter $configuration)
|
||||||
{
|
{
|
||||||
if (null === ($classname = $configuration->getClass())) {
|
if (null === ($classname = $configuration->getClass())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!class_exists($classname)) {
|
if (!class_exists($classname)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Propel Class?
|
// Propel Class?
|
||||||
$class = new \ReflectionClass($configuration->getClass());
|
$class = new \ReflectionClass($configuration->getClass());
|
||||||
if ($class->isSubclassOf('BaseObject')) {
|
if ($class->implementsInterface('\Propel\Runtime\ActiveRecord\ActiveRecordInterface')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +215,7 @@ class PropelParamConverter implements ParamConverterInterface
|
||||||
try {
|
try {
|
||||||
$query->{'filterBy' . PropelInflector::camelize($column)}($value);
|
$query->{'filterBy' . PropelInflector::camelize($column)}($value);
|
||||||
$hasCriteria = true;
|
$hasCriteria = true;
|
||||||
} catch (\PropelException $e) { }
|
} catch (\Exception $e) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,7 +235,7 @@ class PropelParamConverter implements ParamConverterInterface
|
||||||
*
|
*
|
||||||
* @param string $classQuery
|
* @param string $classQuery
|
||||||
*
|
*
|
||||||
* @return \ModelCriteria
|
* @return ModelCriteria
|
||||||
*
|
*
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
|
@ -241,11 +275,11 @@ class PropelParamConverter implements ParamConverterInterface
|
||||||
{
|
{
|
||||||
switch (trim(str_replace(array('_', 'JOIN'), '', strtoupper($with[1])))) {
|
switch (trim(str_replace(array('_', 'JOIN'), '', strtoupper($with[1])))) {
|
||||||
case 'LEFT':
|
case 'LEFT':
|
||||||
return \Criteria::LEFT_JOIN;
|
return Criteria::LEFT_JOIN;
|
||||||
case 'RIGHT':
|
case 'RIGHT':
|
||||||
return \Criteria::RIGHT_JOIN;
|
return Criteria::RIGHT_JOIN;
|
||||||
case 'INNER':
|
case 'INNER':
|
||||||
return \Criteria::INNER_JOIN;
|
return Criteria::INNER_JOIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new \Exception(sprintf('ParamConverter : "with" parameter "%s" is invalid,
|
throw new \Exception(sprintf('ParamConverter : "with" parameter "%s" is invalid,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<database name="default" namespace="Propel\PropelBundle\Model\Acl" defaultIdMethod="native" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://xsd.propelorm.org/1.6/database.xsd">
|
<database name="default" namespace="Propel\Bundle\PropelBundle\Model\Acl" defaultIdMethod="native" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://xsd.propelorm.org/1.6/database.xsd">
|
||||||
<table name="acl_classes" phpName="AclClass">
|
<table name="acl_classes" phpName="AclClass">
|
||||||
<column name="id" type="integer" autoIncrement="true" primaryKey="true" />
|
<column name="id" type="integer" autoIncrement="true" primaryKey="true" />
|
||||||
<column name="class_type" type="varchar" size="200" required="true" phpName="Type" />
|
<column name="class_type" type="varchar" size="200" required="true" phpName="Type" />
|
||||||
|
@ -48,10 +48,10 @@
|
||||||
<column name="object_identity_id" type="integer" primaryKey="true" />
|
<column name="object_identity_id" type="integer" primaryKey="true" />
|
||||||
<column name="ancestor_id" type="integer" primaryKey="true" />
|
<column name="ancestor_id" type="integer" primaryKey="true" />
|
||||||
|
|
||||||
<foreign-key foreignTable="acl_object_identities" onDelete="CASCADE" onUpdate="CASCADE">
|
<foreign-key name="acl_object_identity_id" foreignTable="acl_object_identities" onDelete="CASCADE" onUpdate="CASCADE">
|
||||||
<reference local="object_identity_id" foreign="id" />
|
<reference local="object_identity_id" foreign="id" />
|
||||||
</foreign-key>
|
</foreign-key>
|
||||||
<foreign-key foreignTable="acl_object_identities" onDelete="CASCADE" onUpdate="CASCADE">
|
<foreign-key name="acl_object_ancestor_id" foreignTable="acl_object_identities" onDelete="CASCADE" onUpdate="CASCADE">
|
||||||
<reference local="ancestor_id" foreign="id" />
|
<reference local="ancestor_id" foreign="id" />
|
||||||
</foreign-key>
|
</foreign-key>
|
||||||
</table>
|
</table>
|
||||||
|
|
78
Resources/config/console.xml
Normal file
78
Resources/config/console.xml
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
<?xml version="1.0" ?>
|
||||||
|
|
||||||
|
<container xmlns="http://symfony.com/schema/dic/services"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||||
|
<services>
|
||||||
|
<service id="propel_bundle_propel.command.acl_init_command" class="Propel\Bundle\PropelBundle\Command\AclInitCommand">
|
||||||
|
<tag name="console.command" command="propel:acl:init" />
|
||||||
|
</service>
|
||||||
|
<service id="propel_bundle_propel.command.build_command" class="Propel\Bundle\PropelBundle\Command\BuildCommand">
|
||||||
|
<tag name="console.command" command="propel:build" />
|
||||||
|
</service>
|
||||||
|
<service id="propel_bundle_propel.command.database_create_command" class="Propel\Bundle\PropelBundle\Command\DatabaseCreateCommand">
|
||||||
|
<tag name="console.command" command="propel:database:create" />
|
||||||
|
</service>
|
||||||
|
<service class="Propel\Bundle\PropelBundle\Command\DatabaseDropCommand"
|
||||||
|
id="propel_bundle_propel.command.database_drop_command">
|
||||||
|
<tag name="console.command" command="propel:database:drop"/>
|
||||||
|
</service>
|
||||||
|
<service class="Propel\Bundle\PropelBundle\Command\DatabaseReverseCommand"
|
||||||
|
id="propel_bundle_propel.command.database_reverse_command">
|
||||||
|
<tag name="console.command" command="propel:database:reverse"/>
|
||||||
|
</service>
|
||||||
|
<service class="Propel\Bundle\PropelBundle\Command\FixturesDumpCommand"
|
||||||
|
id="propel_bundle_propel.command.fixtures_dump_command">
|
||||||
|
<tag name="console.command" command="propel:fixtures:dump"/>
|
||||||
|
</service>
|
||||||
|
<service class="Propel\Bundle\PropelBundle\Command\FixturesLoadCommand"
|
||||||
|
id="propel_bundle_propel.command.fixtures_load_command">
|
||||||
|
<tag name="console.command" command="propel:fixtures:load"/>
|
||||||
|
</service>
|
||||||
|
<service class="Propel\Bundle\PropelBundle\Command\FormGenerateCommand"
|
||||||
|
id="propel_bundle_propel.command.form_generate_command">
|
||||||
|
<tag name="console.command" command="propel:form:generate"/>
|
||||||
|
</service>
|
||||||
|
<service class="Propel\Bundle\PropelBundle\Command\GraphvizGenerateCommand"
|
||||||
|
id="propel_bundle_propel.command.graphviz_generate_command">
|
||||||
|
<tag name="console.command" command="propel:graphviz:generate"/>
|
||||||
|
</service>
|
||||||
|
<service class="Propel\Bundle\PropelBundle\Command\MigrationDiffCommand"
|
||||||
|
id="propel_bundle_propel.command.migration_diff_command">
|
||||||
|
<tag name="console.command" command="propel:migration:diff"/>
|
||||||
|
</service>
|
||||||
|
<service class="Propel\Bundle\PropelBundle\Command\MigrationDownCommand"
|
||||||
|
id="propel_bundle_propel.command.migration_down_command">
|
||||||
|
<tag name="console.command" command="propel:migration:down"/>
|
||||||
|
</service>
|
||||||
|
<service class="Propel\Bundle\PropelBundle\Command\MigrationMigrateCommand"
|
||||||
|
id="propel_bundle_propel.command.migration_migrate_command">
|
||||||
|
<tag name="console.command" command="propel:migration:migrate"/>
|
||||||
|
</service>
|
||||||
|
<service class="Propel\Bundle\PropelBundle\Command\MigrationStatusCommand"
|
||||||
|
id="propel_bundle_propel.command.migration_status_command">
|
||||||
|
<tag name="console.command" command="propel:migration:status"/>
|
||||||
|
</service>
|
||||||
|
<service class="Propel\Bundle\PropelBundle\Command\MigrationUpCommand"
|
||||||
|
id="propel_bundle_propel.command.migration_up_command">
|
||||||
|
<tag name="console.command" command="propel:migration:up"/>
|
||||||
|
</service>
|
||||||
|
<service class="Propel\Bundle\PropelBundle\Command\ModelBuildCommand"
|
||||||
|
id="propel_bundle_propel.command.model_build_command">
|
||||||
|
<tag name="console.command" command="propel:model:build"/>
|
||||||
|
</service>
|
||||||
|
<service class="Propel\Bundle\PropelBundle\Command\SqlBuildCommand"
|
||||||
|
id="propel_bundle_propel.command.sql_build_command">
|
||||||
|
<tag name="console.command" command="propel:sql:build"/>
|
||||||
|
</service>
|
||||||
|
<service class="Propel\Bundle\PropelBundle\Command\SqlInsertCommand"
|
||||||
|
id="propel_bundle_propel.command.sql_insert_command">
|
||||||
|
<tag name="console.command" command="propel:sql:insert"/>
|
||||||
|
</service>
|
||||||
|
<service class="Propel\Bundle\PropelBundle\Command\TableDropCommand"
|
||||||
|
id="propel_bundle_propel.command.table_drop_command">
|
||||||
|
<tag name="console.command" command="propel:table:drop"/>
|
||||||
|
</service>
|
||||||
|
</services>
|
||||||
|
|
||||||
|
</container>
|
|
@ -5,12 +5,12 @@
|
||||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||||
|
|
||||||
<parameters>
|
<parameters>
|
||||||
<parameter key="propel.converter.propel.class">Propel\PropelBundle\Request\ParamConverter\PropelParamConverter</parameter>
|
<parameter key="propel.converter.propel.class">Propel\Bundle\PropelBundle\Request\ParamConverter\PropelParamConverter</parameter>
|
||||||
</parameters>
|
</parameters>
|
||||||
|
|
||||||
<services>
|
<services>
|
||||||
<service id="propel.converter.propel.orm" class="%propel.converter.propel.class%">
|
<service id="propel.converter.propel.orm" class="%propel.converter.propel.class%">
|
||||||
<tag name="request.param_converter" priority="10" />
|
<tag name="request.param_converter" converter="propel" priority="1" />
|
||||||
</service>
|
</service>
|
||||||
</services>
|
</services>
|
||||||
</container>
|
</container>
|
||||||
|
|
|
@ -6,36 +6,33 @@
|
||||||
|
|
||||||
<parameters>
|
<parameters>
|
||||||
<parameter key="propel.dbal.default_connection">default</parameter>
|
<parameter key="propel.dbal.default_connection">default</parameter>
|
||||||
<parameter key="propel.configuration.class">PropelConfiguration</parameter>
|
|
||||||
<parameter key="propel.logger.class">Symfony\Bridge\Propel1\Logger\PropelLogger</parameter>
|
<parameter key="propel.schema_locator.class">Propel\Bundle\PropelBundle\Service\SchemaLocator</parameter>
|
||||||
<parameter key="propel.data_collector.class">Symfony\Bridge\Propel1\DataCollector\PropelDataCollector</parameter>
|
<parameter key="propel.data_collector.class">Propel\Bundle\PropelBundle\DataCollector\PropelDataCollector</parameter>
|
||||||
<parameter key="propel.build_properties.class">Propel\PropelBundle\DependencyInjection\Properties</parameter>
|
<parameter key="propel.logger.class">Propel\Bundle\PropelBundle\Logger\PropelLogger</parameter>
|
||||||
<parameter key="propel.form.type.model.class">Symfony\Bridge\Propel1\Form\Type\ModelType</parameter>
|
<parameter key="propel.twig.extension.syntax.class">Propel\Bundle\PropelBundle\Twig\Extension\SyntaxExtension</parameter>
|
||||||
<parameter key="propel.twig.extension.syntax.class">Propel\PropelBundle\Twig\Extension\SyntaxExtension</parameter>
|
<parameter key="form.type_guesser.propel.class">Propel\Bundle\PropelBundle\Form\TypeGuesser</parameter>
|
||||||
<parameter key="form.type_guesser.propel.class">Symfony\Bridge\Propel1\Form\PropelTypeGuesser</parameter>
|
<parameter key="propel.form.type.model.class">Propel\Bundle\PropelBundle\Form\Type\ModelType</parameter>
|
||||||
<parameter key="propel.security.acl.provider.model.class">Propel\PropelBundle\Security\Acl\AuditableAclProvider</parameter>
|
<parameter key="propel.dumper.yaml.class">Propel\Bundle\PropelBundle\DataFixtures\Dumper\YamlDataDumper</parameter>
|
||||||
<parameter key="propel.security.user.provider.class">Symfony\Bridge\Propel1\Security\User\PropelUserProvider</parameter>
|
<parameter key="propel.loader.yaml.class">Propel\Bundle\PropelBundle\DataFixtures\Loader\YamlDataLoader</parameter>
|
||||||
|
<parameter key="propel.loader.xml.class">Propel\Bundle\PropelBundle\DataFixtures\Loader\XmlDataLoader</parameter>
|
||||||
</parameters>
|
</parameters>
|
||||||
|
|
||||||
<services>
|
<services>
|
||||||
<service id="propel.configuration" class="%propel.configuration.class%" />
|
<service id="propel.schema_locator" class="%propel.schema_locator.class%" public="true">
|
||||||
|
<argument type="service" id="file_locator" />
|
||||||
|
<argument>%propel.configuration%</argument>
|
||||||
|
</service>
|
||||||
|
|
||||||
<service id="propel.build_properties" class="%propel.build_properties.class%" />
|
<service id="propel.logger" class="%propel.logger.class%" public="true">
|
||||||
|
|
||||||
<service id="propel.logger" class="%propel.logger.class%">
|
|
||||||
<tag name="monolog.logger" channel="propel" />
|
<tag name="monolog.logger" channel="propel" />
|
||||||
<argument type="service" id="logger" on-invalid="null" />
|
<argument type="service" id="logger" on-invalid="null" />
|
||||||
<argument type="service" id="debug.stopwatch" on-invalid="null" />
|
<argument type="service" id="debug.stopwatch" on-invalid="null" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service id="propel.data_collector" class="%propel.data_collector.class%" public="false">
|
<service id="propel.data_collector" class="%propel.data_collector.class%" public="false">
|
||||||
<tag name="data_collector" template="PropelBundle:Collector:propel" id="propel" />
|
|
||||||
<argument type="service" id="propel.logger" />
|
<argument type="service" id="propel.logger" />
|
||||||
<argument type="service" id="propel.configuration" />
|
<tag name="data_collector" template="@Propel/Collector/propel" id="propel" />
|
||||||
</service>
|
|
||||||
|
|
||||||
<service id="propel.form.type.model" class="%propel.form.type.model.class%">
|
|
||||||
<tag name="form.type" alias="model" />
|
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service id="propel.twig.extension.syntax" class="%propel.twig.extension.syntax.class%">
|
<service id="propel.twig.extension.syntax" class="%propel.twig.extension.syntax.class%">
|
||||||
|
@ -46,13 +43,26 @@
|
||||||
<tag name="form.type_guesser" />
|
<tag name="form.type_guesser" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service id="propel.security.acl.provider" class="%propel.security.acl.provider.model.class%" public="false">
|
<service id="propel.form.type.model" class="%propel.form.type.model.class%">
|
||||||
<argument type="service" id="security.acl.permission_granting_strategy" />
|
<tag name="form.type" alias="model" />
|
||||||
<argument type="service" id="propel.security.acl.connection" on-invalid="null" />
|
|
||||||
<argument type="service" id="security.acl.cache" on-invalid="null" />
|
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service id="propel.security.user.provider" class="%propel.security.user.provider.class%" abstract="true" public="false">
|
<service id="propel.dumper.yaml" class="%propel.dumper.yaml.class%">
|
||||||
|
<argument>%kernel.root_dir%</argument>
|
||||||
|
<argument>%propel.configuration%</argument>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
<service id="propel.loader.yaml" class="%propel.loader.yaml.class%">
|
||||||
|
<argument>%kernel.root_dir%</argument>
|
||||||
|
<argument>%propel.configuration%</argument>
|
||||||
|
<argument type="service" id="faker.generator" on-invalid="null" />
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<service id="propel.loader.xml" class="%propel.loader.xml.class%">
|
||||||
|
<argument>%kernel.root_dir%</argument>
|
||||||
|
<argument>%propel.configuration%</argument>
|
||||||
|
</service>
|
||||||
|
|
||||||
|
|
||||||
</services>
|
</services>
|
||||||
</container>
|
</container>
|
||||||
|
|
21
Resources/config/security.xml
Normal file
21
Resources/config/security.xml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" ?>
|
||||||
|
|
||||||
|
<container xmlns="http://symfony.com/schema/dic/services"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||||
|
|
||||||
|
<parameters>
|
||||||
|
<parameter key="propel.security.acl.provider.model.class">Propel\Bundle\PropelBundle\Security\Acl\AuditableAclProvider</parameter>
|
||||||
|
<parameter key="propel.security.user.provider.class">Propel\Bundle\PropelBundle\Security\User\PropelUserProvider</parameter>
|
||||||
|
</parameters>
|
||||||
|
|
||||||
|
<services>
|
||||||
|
<service id="propel.security.acl.provider" class="%propel.security.acl.provider.model.class%" public="false">
|
||||||
|
<argument type="service" id="security.acl.permission_granting_strategy" />
|
||||||
|
<argument type="service" id="propel.security.acl.connection" on-invalid="null" />
|
||||||
|
<argument type="service" id="security.acl.cache" on-invalid="null" />
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<service id="propel.security.user.provider" class="%propel.security.user.provider.class%" abstract="true" public="false" />
|
||||||
|
</services>
|
||||||
|
</container>
|
|
@ -1,39 +0,0 @@
|
||||||
ACL Implementation
|
|
||||||
==================
|
|
||||||
|
|
||||||
The `PropelBundle` provides a model-based implementation of the Security components' interfaces.
|
|
||||||
To make us of this `AuditableAclProvider` you only need to change your security configuration.
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
security:
|
|
||||||
acl:
|
|
||||||
provider: propel.security.acl.provider
|
|
||||||
```
|
|
||||||
|
|
||||||
This will switch the provider to be the `AuditableAclProvider` of the `PropelBundle`.
|
|
||||||
|
|
||||||
The auditing of this provider is set to a sensible default. It will audit all ACL failures but no success by default.
|
|
||||||
If you also want to audit successful authorizations, you need to update the auditing of the given ACL accordingly.
|
|
||||||
|
|
||||||
After adding the provider, you only need to run the `propel:acl:init` command in order to get the model generated.
|
|
||||||
If you already got an ACL database, the schema of the `PropelBundle` is compatible with the default schema of Symfony2.
|
|
||||||
|
|
||||||
#### Separate database connection for ACL ####
|
|
||||||
|
|
||||||
In case you want to use a different database for your ACL than your business model, you only need to configure this service.
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
services:
|
|
||||||
propel.security.acl.connection:
|
|
||||||
class: PropelPDO
|
|
||||||
factory_class: Propel
|
|
||||||
factory_method: getConnection
|
|
||||||
arguments:
|
|
||||||
- "acl"
|
|
||||||
```
|
|
||||||
|
|
||||||
The `PropelBundle` looks for this service, and if given uses the provided connection for all ACL related operations.
|
|
||||||
The given argument (`acl` in the example) is the name of the connection to use, as defined in your runtime configuration.
|
|
||||||
|
|
||||||
|
|
||||||
[Back to index](index.markdown)
|
|
|
@ -1,97 +0,0 @@
|
||||||
The Commands
|
|
||||||
============
|
|
||||||
|
|
||||||
The PropelBundle provides a lot of commands to manage migrations, database/table manipulations,
|
|
||||||
and so on.
|
|
||||||
|
|
||||||
|
|
||||||
## Database Manipulations ##
|
|
||||||
|
|
||||||
You can create a **database**:
|
|
||||||
|
|
||||||
> php app/console propel:database:create [--connection[=""]]
|
|
||||||
|
|
||||||
As usual, `--connection` allows to specify a connection.
|
|
||||||
|
|
||||||
|
|
||||||
You can drop a **database**:
|
|
||||||
|
|
||||||
> php app/console propel:database:drop [--connection[=""]] [--force]
|
|
||||||
|
|
||||||
As usual, `--connection` allows to specify a connection.
|
|
||||||
|
|
||||||
Note that the `--force` option is needed to actually execute the SQL statements.
|
|
||||||
|
|
||||||
|
|
||||||
## Form Types ##
|
|
||||||
|
|
||||||
You can generate stub classes based on your `schema.xml` in a given bundle:
|
|
||||||
|
|
||||||
> php app/console propel:form:generate [-f|--force] bundle [models1] ... [modelsN]
|
|
||||||
|
|
||||||
It will write Form Type classes in `src/YourVendor/YourBundle/Form/Type`.
|
|
||||||
|
|
||||||
You can choose which Form Type to build by specifing Model names:
|
|
||||||
|
|
||||||
> php app/console propel:form:generate @AcmeDemoBundle Book Author
|
|
||||||
|
|
||||||
|
|
||||||
## Graphviz ##
|
|
||||||
|
|
||||||
You can generate **Graphviz** file for your project by using the following command line:
|
|
||||||
|
|
||||||
> php app/console propel:graphviz:generate
|
|
||||||
|
|
||||||
It will write files in `app/propel/graph/`.
|
|
||||||
|
|
||||||
|
|
||||||
## Migrations ##
|
|
||||||
|
|
||||||
Generates SQL diff between the XML schemas and the current database structure:
|
|
||||||
|
|
||||||
> php app/console propel:migration:generate-diff [--connection[=""]]
|
|
||||||
|
|
||||||
As usual, `--connection` allows to specify a connection.
|
|
||||||
|
|
||||||
Executes the migrations:
|
|
||||||
|
|
||||||
> php app/console propel:migration:migrate
|
|
||||||
|
|
||||||
Executes the next migration up:
|
|
||||||
|
|
||||||
> php app/console propel:migration:migrate --up
|
|
||||||
|
|
||||||
Executes the previous migration down:
|
|
||||||
|
|
||||||
> php app/console propel:migration:migrate --down
|
|
||||||
|
|
||||||
Lists the migrations yet to be executed:
|
|
||||||
|
|
||||||
> php app/console propel:migration:status
|
|
||||||
|
|
||||||
|
|
||||||
## Table Manipulations ##
|
|
||||||
|
|
||||||
You can drop one or several **tables**:
|
|
||||||
|
|
||||||
> php app/console propel:table:drop [--force] [--connection[="..."]] [table1] ... [tableN]
|
|
||||||
|
|
||||||
As usual, `--connection` allows to specify a connection.
|
|
||||||
|
|
||||||
The table arguments define which table will be delete, by default all table.
|
|
||||||
|
|
||||||
Note that the `--force` option is needed to actually execute the deletion.
|
|
||||||
|
|
||||||
|
|
||||||
## Working with existing databases ##
|
|
||||||
|
|
||||||
Run the following command to generate an XML schema from your `default` database:
|
|
||||||
|
|
||||||
> php app/console propel:reverse
|
|
||||||
|
|
||||||
You can define which connection to use:
|
|
||||||
|
|
||||||
> php app/console propel:reverse --connection=default
|
|
||||||
|
|
||||||
|
|
||||||
[Back to index](index.markdown)
|
|
|
@ -1,129 +0,0 @@
|
||||||
Configuration
|
|
||||||
=============
|
|
||||||
|
|
||||||
In order to use Propel, you have to configure few parameters in your `app/config/config.yml` file.
|
|
||||||
|
|
||||||
If you are **not** using Composer, add this configuration:
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
# in app/config/config.yml
|
|
||||||
propel:
|
|
||||||
path: "%kernel.root_dir%/../vendor/propel"
|
|
||||||
phing_path: "%kernel.root_dir%/../vendor/phing"
|
|
||||||
```
|
|
||||||
|
|
||||||
Now, you can configure your application.
|
|
||||||
|
|
||||||
|
|
||||||
## Basic Configuration ##
|
|
||||||
|
|
||||||
If you have just one database connection, your configuration will look like as following:
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
# app/config/config*.yml
|
|
||||||
propel:
|
|
||||||
dbal:
|
|
||||||
driver: mysql
|
|
||||||
user: root
|
|
||||||
password: null
|
|
||||||
dsn: mysql:host=localhost;dbname=test;charset=UTF8
|
|
||||||
options: {}
|
|
||||||
attributes: {}
|
|
||||||
```
|
|
||||||
|
|
||||||
The recommended way to fill in these information is to use parameters:
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
# app/config/config*.yml
|
|
||||||
propel:
|
|
||||||
dbal:
|
|
||||||
driver: %database_driver%
|
|
||||||
user: %database_user%
|
|
||||||
password: %database_password%
|
|
||||||
dsn: %database_driver%:host=%database_host%;dbname=%database_name%;charset=UTF8
|
|
||||||
options: {}
|
|
||||||
attributes: {}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Configure Multiple Connection ##
|
|
||||||
|
|
||||||
If you have more than one connection, or want to use a named connection, the configuration
|
|
||||||
will look like:
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
# app/config/config*.yml
|
|
||||||
propel:
|
|
||||||
dbal:
|
|
||||||
default_connection: conn1
|
|
||||||
connections:
|
|
||||||
conn1:
|
|
||||||
driver: mysql
|
|
||||||
user: root
|
|
||||||
password: null
|
|
||||||
dsn: mysql:host=localhost;dbname=db1
|
|
||||||
conn2:
|
|
||||||
driver: mysql
|
|
||||||
user: root
|
|
||||||
password: null
|
|
||||||
dsn: mysql:host=localhost;dbname=db2
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Configure Master/Slaves ##
|
|
||||||
|
|
||||||
You can also configure Master/Slaves:
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
# app/config/config*.yml
|
|
||||||
propel:
|
|
||||||
dbal:
|
|
||||||
default_connection: default
|
|
||||||
connections:
|
|
||||||
default:
|
|
||||||
driver: mysql
|
|
||||||
user: root
|
|
||||||
password: null
|
|
||||||
dsn: mysql:host=localhost;dbname=master
|
|
||||||
slaves:
|
|
||||||
slave_1:
|
|
||||||
user: root
|
|
||||||
password: null
|
|
||||||
dsn: mysql:host=localhost;dbname=slave_1
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Attributes, Options, Settings ##
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
# app/config/config*.yml
|
|
||||||
propel:
|
|
||||||
dbal:
|
|
||||||
default_connection: default
|
|
||||||
connections:
|
|
||||||
default:
|
|
||||||
# ...
|
|
||||||
options:
|
|
||||||
ATTR_PERSISTENT: false
|
|
||||||
attributes:
|
|
||||||
ATTR_EMULATE_PREPARES: true
|
|
||||||
settings:
|
|
||||||
charset: { value: UTF8 }
|
|
||||||
queries: { query: 'INSERT INTO BAR ('hey', 'there')' }
|
|
||||||
```
|
|
||||||
|
|
||||||
`options`, `attributes` and `settings` are parts of the runtime configuration. See [Runtime Configuration File](http://www.propelorm.org/reference/runtime-configuration.html) documentation for more explanation.
|
|
||||||
|
|
||||||
|
|
||||||
## Logging ##
|
|
||||||
|
|
||||||
You can disable the logging by changing the `logging` parameter value:
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
# in app/config/config.yml
|
|
||||||
propel:
|
|
||||||
logging: %kernel.debug%
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
[Back to index](index.markdown) | [Configure Propel](propel_configuration.markdown)
|
|
|
@ -1,104 +0,0 @@
|
||||||
The Fixtures
|
|
||||||
============
|
|
||||||
|
|
||||||
Fixtures are data you usually write to populate your database during the development, or static content
|
|
||||||
like menus, labels, ... you need by default in your database in production.
|
|
||||||
|
|
||||||
## Loading Fixtures ##
|
|
||||||
|
|
||||||
The following command is designed to load fixtures:
|
|
||||||
|
|
||||||
> php app/console propel:fixtures:load [-d|--dir[="..."]] [--xml] [--sql] [--yml] [--connection[="..."]] [bundle]
|
|
||||||
|
|
||||||
As you can see, there are many options to allow you to easily load fixtures.
|
|
||||||
|
|
||||||
As usual, `--connection` allows to specify a connection. The `--dir` option allows to specify a directory
|
|
||||||
containing the fixtures (default is: `app/propel/fixtures/`).
|
|
||||||
Note that the `--dir` expects a relative path from the root dir (which is `app/`).
|
|
||||||
|
|
||||||
The `--xml` parameter allows you to load only XML fixtures.
|
|
||||||
The `--sql` parameter allows you to load only SQL fixtures.
|
|
||||||
The `--yml` parameter allows you to load only YAML fixtures.
|
|
||||||
|
|
||||||
You can mix `--xml`, `--yml` and `--sql` parameters to load XML, YAML and SQL fixtures at the same time.
|
|
||||||
If none of this parameter are set all files YAML, XML and SQL in the directory will be load.
|
|
||||||
|
|
||||||
You can pass a bundle name to load fixtures from it. A bundle's name starts with `@` like `@AcmeDemoBundle`.
|
|
||||||
|
|
||||||
> php app/console propel:fixtures:load @AcmeDemoBundle
|
|
||||||
|
|
||||||
|
|
||||||
### XML Fixtures ###
|
|
||||||
|
|
||||||
A valid _XML fixtures file_ is:
|
|
||||||
|
|
||||||
``` xml
|
|
||||||
<Fixtures>
|
|
||||||
<Object Namespace="Awesome">
|
|
||||||
<o1 Title="My title" MyFoo="bar" />
|
|
||||||
</Object>
|
|
||||||
<Related Namespace="Awesome">
|
|
||||||
<r1 ObjectId="o1" Description="Hello world !" />
|
|
||||||
</Related>
|
|
||||||
</Fixtures>
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### YAML Fixtures ###
|
|
||||||
|
|
||||||
A valid _YAML fixtures file_ is:
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
Awesome\Object:
|
|
||||||
o1:
|
|
||||||
Title: My title
|
|
||||||
MyFoo: bar
|
|
||||||
|
|
||||||
Awesome\Related:
|
|
||||||
r1:
|
|
||||||
ObjectId: o1
|
|
||||||
Description: Hello world !
|
|
||||||
|
|
||||||
Awesome\Tag:
|
|
||||||
t1:
|
|
||||||
name: Foo
|
|
||||||
t2:
|
|
||||||
name: Baz
|
|
||||||
|
|
||||||
Awesome\Post:
|
|
||||||
p1:
|
|
||||||
title: A Post with tags (N-N relation)
|
|
||||||
tags: [ t1, t2 ]
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
#### Using Faker in YAML Fixtures ####
|
|
||||||
|
|
||||||
If you use [Faker](https://github.com/fzaninotto/Faker) with its [Symfony2 integration](https://github.com/willdurand/BazingaFakerBundle),
|
|
||||||
then the PropelBundle offers a facility to use the Faker generator in your YAML files:
|
|
||||||
|
|
||||||
``` yml
|
|
||||||
Acme\DemoBundle\Model\Book:
|
|
||||||
Book1:
|
|
||||||
name: "Awesome Feature"
|
|
||||||
description: <?php $faker('text', 500); ?>
|
|
||||||
```
|
|
||||||
|
|
||||||
The aim of this feature is to be able to mix real, and fake data in the same file. Fake data are interesting to quickly
|
|
||||||
add data tou your application, but most of the time you need to rely on real data. To integrate Faker in the YAML files
|
|
||||||
allows to write strong fixtures efficiently.
|
|
||||||
|
|
||||||
|
|
||||||
## Dumping data ##
|
|
||||||
|
|
||||||
You can dump data from your database into YAML fixtures file by using this command:
|
|
||||||
|
|
||||||
> php app/console propel:fixtures:dump [--connection[="..."]]
|
|
||||||
|
|
||||||
Dumped files will be written in the fixtures directory: `app/propel/fixtures/` with the following name:
|
|
||||||
`fixtures_99999.yml` where `99999` is a timestamp.
|
|
||||||
|
|
||||||
Once done, you will be able to load these files by using the `propel:fixtures:load` command.
|
|
||||||
|
|
||||||
|
|
||||||
[Back to index](index.markdown)
|
|
|
@ -1,128 +0,0 @@
|
||||||
PropelBundle
|
|
||||||
============
|
|
||||||
|
|
||||||
This is the official implementation of [Propel](http://www.propelorm.org/) in Symfony2.
|
|
||||||
|
|
||||||
|
|
||||||
## Installation ##
|
|
||||||
|
|
||||||
The recommended way to install this bundle is to rely on [Composer](http://getcomposer.org):
|
|
||||||
|
|
||||||
``` javascript
|
|
||||||
{
|
|
||||||
"require": {
|
|
||||||
// ...
|
|
||||||
"propel/propel-bundle": "1.1.*"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Otherwise you can use Git, SVN, Git submodules, or the Symfony vendor management (deps file):
|
|
||||||
|
|
||||||
* Clone this bundle in the `vendor/bundles/Propel` directory:
|
|
||||||
|
|
||||||
> git submodule add https://github.com/propelorm/PropelBundle.git vendor/bundles/Propel/PropelBundle
|
|
||||||
|
|
||||||
* Checkout Propel and Phing in the `vendor` directory:
|
|
||||||
|
|
||||||
> svn checkout http://svn.github.com/propelorm/Propel.git vendor/propel
|
|
||||||
|
|
||||||
> svn checkout http://svn.phing.info/tags/2.4.6/ vendor/phing
|
|
||||||
|
|
||||||
* Instead of using svn, you can clone the unofficial Git repositories:
|
|
||||||
|
|
||||||
> git submodule add https://github.com/phingofficial/phing.git vendor/phing
|
|
||||||
|
|
||||||
> git submodule add https://github.com/propelorm/Propel.git vendor/propel
|
|
||||||
|
|
||||||
* Instead of doing this manually, you can use the Symfony vendor management via the deps file:
|
|
||||||
|
|
||||||
See http://www.propelorm.org/cookbook/symfony2/working-with-symfony2.html#via_symfony2_vendor_management
|
|
||||||
|
|
||||||
If you are using a Symfony2 2.x.x version (actually, a version which is not 2.1 or above), be sure to deps.lock the PropelBundle to a commit on the 2.0 branch,
|
|
||||||
which does not use the Bridge
|
|
||||||
|
|
||||||
|
|
||||||
The second step is to register this bundle in the `AppKernel` class:
|
|
||||||
|
|
||||||
``` php
|
|
||||||
public function registerBundles()
|
|
||||||
{
|
|
||||||
$bundles = array(
|
|
||||||
// ...
|
|
||||||
new Propel\PropelBundle\PropelBundle(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Don't forget to register the PropelBundle namespace in `app/autoload.php` if you are not using Composer:
|
|
||||||
|
|
||||||
``` php
|
|
||||||
$loader->registerNamespaces(array(
|
|
||||||
// ...
|
|
||||||
'Propel' => __DIR__.'/../vendor/bundles',
|
|
||||||
));
|
|
||||||
$loader->registerPrefixes(array(
|
|
||||||
// ...
|
|
||||||
'Phing' => __DIR__.'/../vendor/phing/classes/phing',
|
|
||||||
));
|
|
||||||
```
|
|
||||||
|
|
||||||
You are almost ready, the next steps are:
|
|
||||||
|
|
||||||
* to [configure the bundle](configuration.markdown);
|
|
||||||
* to [configure Propel](propel_configuration.markdown);
|
|
||||||
* to [write an XML schema](schema.markdown).
|
|
||||||
|
|
||||||
Now, you can build your model classes, and SQL by running the following command:
|
|
||||||
|
|
||||||
> php app/console propel:build [--classes] [--sql] [--insert-sql] [--connection[=""]]
|
|
||||||
|
|
||||||
To insert SQL statements, use the `propel:sql:insert` command:
|
|
||||||
|
|
||||||
> php app/console propel:sql:insert [--force] [--connection[=""]]
|
|
||||||
|
|
||||||
Note that the `--force` option is needed to actually execute the SQL statements.
|
|
||||||
|
|
||||||
Congratulation! You're done, just use the Model classes as any other class in Symfony2:
|
|
||||||
|
|
||||||
``` php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
class HelloController extends Controller
|
|
||||||
{
|
|
||||||
public function indexAction($name)
|
|
||||||
{
|
|
||||||
$author = new \Acme\DemoBundle\Model\Author();
|
|
||||||
$author->setFirstName($name);
|
|
||||||
$author->save();
|
|
||||||
|
|
||||||
return $this->render('AcmeDemoBundle:Hello:index.html.twig', array(
|
|
||||||
'name' => $name, 'author' => $author)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Now you can read more about:
|
|
||||||
|
|
||||||
* [The ACL Implementation](acl.markdown);
|
|
||||||
* [The Commands](commands.markdown);
|
|
||||||
* [The Fixtures](fixtures.markdown);
|
|
||||||
* [The PropelParamConverter](param_converter.markdown);
|
|
||||||
* [The UniqueObjectValidator](unique_object_validator.markdown).
|
|
||||||
|
|
||||||
|
|
||||||
## Bundle Inheritance ##
|
|
||||||
|
|
||||||
The `PropelBundle` makes use of the bundle inheritance. Currently only schema inheritance is provided.
|
|
||||||
|
|
||||||
### Schema Inheritance ###
|
|
||||||
|
|
||||||
You can override the defined schema of a bundle from within its child bundle.
|
|
||||||
To make use of the inheritance you only need to drop a schema file in the `Resources/config` folder of the child bundle.
|
|
||||||
|
|
||||||
Each file can be overridden without interfering with other schema files.
|
|
||||||
If you want to remove parts of a schema, you only need to add an empty schema file.
|
|
|
@ -1,118 +0,0 @@
|
||||||
The PropelParamConverter
|
|
||||||
========================
|
|
||||||
|
|
||||||
You can use the `PropelParamConverter` with the [SensioFrameworkExtraBundle](http://github.com/sensio/SensioFrameworkExtraBundle).
|
|
||||||
You just need to put the right _Annotation_ on top of your controller:
|
|
||||||
|
|
||||||
``` php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ParamConverter("post", class="BlogBundle\Model\Post")
|
|
||||||
*/
|
|
||||||
public function myAction(Post $post)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Your request needs to have an `id` parameter or any field as parameter (slug, title, ...).
|
|
||||||
|
|
||||||
The _Annotation_ is optional if your parameter is typed you could only have this:
|
|
||||||
|
|
||||||
``` php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
public function myAction(Post $post)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**New** with last version of `SensioFrameworkExtraBundle`,
|
|
||||||
you can ommit the `class` parameter if your controller parameter is typed,
|
|
||||||
this is usefull when you need to set extra `options`.
|
|
||||||
|
|
||||||
``` php
|
|
||||||
<?php
|
|
||||||
use BlogBundle\Model\Post;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ParamConverter("post")
|
|
||||||
*/
|
|
||||||
public function myAction(Post $post)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Exclude some parameters ####
|
|
||||||
|
|
||||||
You can exclude some attributes from being used by the converter:
|
|
||||||
|
|
||||||
If you have a route like `/my-route/{slug}/{name}/edit/{id}`
|
|
||||||
you can exclude `name` and `slug` by setting the option "exclude":
|
|
||||||
|
|
||||||
``` php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ParamConverter("post", class="BlogBundle\Model\Post", options={"exclude"={"name", "slug"}})
|
|
||||||
*/
|
|
||||||
public function myAction(Post $post)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Custom mapping ####
|
|
||||||
|
|
||||||
You can map route parameters directly to model column to be use for filtering.
|
|
||||||
|
|
||||||
If you have a route like `/my-route/{postUniqueName}/{AuthorId}`
|
|
||||||
Mapping option overwrite any other automatic mapping.
|
|
||||||
|
|
||||||
``` php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ParamConverter("post", class="BlogBundle\Model\Post", options={"mapping"={"postUniqueName":"name"}})
|
|
||||||
* @ParamConverter("author", class="BlogBundle\Model\Author", options={"mapping"={"AuthorId":"id"}})
|
|
||||||
*/
|
|
||||||
public function myAction(Post $post, $author)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Hydrate related object ####
|
|
||||||
|
|
||||||
You could hydrate related object with the "with" option:
|
|
||||||
|
|
||||||
``` php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ParamConverter("post", class="BlogBundle\Model\Post", options={"with"={"Comments"}})
|
|
||||||
*/
|
|
||||||
public function myAction(Post $post)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You can set multiple with ```"with"={"Comments", "Author", "RelatedPosts"}```.
|
|
||||||
|
|
||||||
The default join is an "inner join" but you can configure it to be a left join, right join or inner join :
|
|
||||||
|
|
||||||
``` php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ParamConverter("post", class="BlogBundle\Model\Post", options={"with"={ {"Comments", "left join" } }})
|
|
||||||
*/
|
|
||||||
public function myAction(Post $post)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
```
|
|
||||||
Accepted parmeters for join :
|
|
||||||
|
|
||||||
* left, LEFT, left join, LEFT JOIN, left_join, LEFT_JOIN
|
|
||||||
* right, RIGHT, right join, RIGHT JOIN, right_join, RIGHT_JOIN
|
|
||||||
* inner, INNER, inner join, INNER JOIN, inner_join, INNER_JOIN
|
|
||||||
|
|
||||||
[Back to index](index.markdown)
|
|
|
@ -1,69 +0,0 @@
|
||||||
Propel Configuration
|
|
||||||
====================
|
|
||||||
|
|
||||||
You can add a `app/config/propel.ini` file in your project to specify some
|
|
||||||
configuration parameters. See the [Build properties Reference](
|
|
||||||
http://www.propelorm.org/reference/buildtime-configuration.html) to get more
|
|
||||||
information. However, **the recommended way** to configure Propel is to rely
|
|
||||||
on **build properties**, see the section below.
|
|
||||||
|
|
||||||
By default the PropelBundle is configured with the default parameters:
|
|
||||||
|
|
||||||
``` ini
|
|
||||||
# Enable full use of the DateTime class.
|
|
||||||
# Setting this to true means that getter methods for date/time/timestamp
|
|
||||||
# columns will return a DateTime object when the default format is empty.
|
|
||||||
propel.useDateTimeClass = true
|
|
||||||
|
|
||||||
# Specify a custom DateTime subclass that you wish to have Propel use
|
|
||||||
# for temporal values.
|
|
||||||
propel.dateTimeClass = DateTime
|
|
||||||
|
|
||||||
# These are the default formats that will be used when fetching values from
|
|
||||||
# temporal columns in Propel. You can always specify these when calling the
|
|
||||||
# methods directly, but for methods like getByName() it is nice to change
|
|
||||||
# the defaults.
|
|
||||||
# To have these methods return DateTime objects instead, you should set these
|
|
||||||
# to empty values
|
|
||||||
propel.defaultTimeStampFormat =
|
|
||||||
propel.defaultTimeFormat =
|
|
||||||
propel.defaultDateFormat =
|
|
||||||
|
|
||||||
# A better Pluralizer
|
|
||||||
propel.builder.pluralizer.class = builder.util.StandardEnglishPluralizer
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Build properties ##
|
|
||||||
|
|
||||||
You can define _build properties_ by creating a `propel.ini` file in `app/config` like below, but you can also follow
|
|
||||||
the Symfony2 convention by adding build properties in `app/config/config.yml`:
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
# app/config/config.yml
|
|
||||||
propel:
|
|
||||||
build_properties:
|
|
||||||
xxxxx.xxxx.xxxxx: XXXX
|
|
||||||
xxxxx.xxxx.xxxxx: XXXX
|
|
||||||
// ...
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Behaviors ##
|
|
||||||
|
|
||||||
You can register Propel behaviors using the following syntax:
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
# app/config/config.yml
|
|
||||||
propel:
|
|
||||||
behaviors:
|
|
||||||
behavior_name: My\Bundle\Behavior\BehaviorClassName
|
|
||||||
```
|
|
||||||
|
|
||||||
If you rely on third party behaviors, most of them are autoloaded so you don't
|
|
||||||
need to register them. But, for your own behaviors, you can either configure the
|
|
||||||
autoloader to autoload them, or register them in this section (this is the
|
|
||||||
recommended way when you namespace your behaviors).
|
|
||||||
|
|
||||||
|
|
||||||
[Configure the bundle](configuration.markdown) | [Back to index](index.markdown) | [Write an XML Schema](schema.markdown)
|
|
|
@ -1,30 +0,0 @@
|
||||||
XML Schema
|
|
||||||
==========
|
|
||||||
|
|
||||||
Place the following schema in `src/Acme/DemoBundle/Resources/config/schema.xml`:
|
|
||||||
|
|
||||||
``` xml
|
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<database name="default" namespace="Acme\DemoBundle\Model" defaultIdMethod="native">
|
|
||||||
|
|
||||||
<table name="book">
|
|
||||||
<column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" />
|
|
||||||
<column name="title" type="varchar" primaryString="1" size="100" />
|
|
||||||
<column name="ISBN" type="varchar" size="20" />
|
|
||||||
<column name="author_id" type="integer" />
|
|
||||||
<foreign-key foreignTable="author">
|
|
||||||
<reference local="author_id" foreign="id" />
|
|
||||||
</foreign-key>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<table name="author">
|
|
||||||
<column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" />
|
|
||||||
<column name="first_name" type="varchar" size="100" />
|
|
||||||
<column name="last_name" type="varchar" size="100" />
|
|
||||||
</table>
|
|
||||||
|
|
||||||
</database>
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
[Configure Propel](propel_configuration.markdown) | [Back to index](index.markdown)
|
|
|
@ -1,124 +0,0 @@
|
||||||
The UniqueObjectValidator
|
|
||||||
=========================
|
|
||||||
|
|
||||||
In a form, if you want to validate the uniqueness of a field in a table you have to use the `UniqueObjectValidator`.
|
|
||||||
|
|
||||||
You may use as many validators of this type as you want.
|
|
||||||
|
|
||||||
The validator has 1 required parameter:
|
|
||||||
|
|
||||||
* `fields` : a field or an array of fields to test for uniqueness
|
|
||||||
|
|
||||||
and 3 optionals parameters:
|
|
||||||
|
|
||||||
* `message` : the error message with two variable `{{ object_class }}` and `{{ fields }}`
|
|
||||||
* `messageFieldSeparator` : the field separator ` and `
|
|
||||||
* `errorPath` : the relative path where the error will be attached, if none is set the error is global.
|
|
||||||
|
|
||||||
|
|
||||||
YAML
|
|
||||||
----
|
|
||||||
|
|
||||||
You can specify this using the `validation.yml` file, like this:
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
Acme\DemoBundle\Model\User:
|
|
||||||
constraints:
|
|
||||||
- Propel\PropelBundle\Validator\Constraints\UniqueObject:
|
|
||||||
fields: username
|
|
||||||
```
|
|
||||||
|
|
||||||
If you want to validate the uniqueness of more than just one field:
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
Acme\DemoBundle\Model\User:
|
|
||||||
constraints:
|
|
||||||
- Propel\PropelBundle\Validator\Constraints\UniqueObject:
|
|
||||||
fields: [username, login]
|
|
||||||
```
|
|
||||||
|
|
||||||
Full configuration :
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
Acme\DemoBundle\Model\User:
|
|
||||||
constraints:
|
|
||||||
- Propel\PropelBundle\Validator\Constraints\UniqueObject:
|
|
||||||
fields: [username, login]
|
|
||||||
message: We already have a user with {{ fields }}
|
|
||||||
messageFieldSeparator: " and "
|
|
||||||
errorPath: username
|
|
||||||
```
|
|
||||||
|
|
||||||
PHP
|
|
||||||
---
|
|
||||||
|
|
||||||
You can also specify this using php. Fields can be specified as a string if there is only one field
|
|
||||||
|
|
||||||
``` php
|
|
||||||
use Propel\PropelBundle\Validator\Constraint\UniqueObject;
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the Validation Constraints
|
|
||||||
*
|
|
||||||
* @param ClassMetadata $metadata
|
|
||||||
*/
|
|
||||||
public static function loadValidatorMetadata(ClassMetadata $metadata)
|
|
||||||
{
|
|
||||||
$metadata->addConstraint(
|
|
||||||
new UniqueObject(
|
|
||||||
array(
|
|
||||||
'fields' => 'username',
|
|
||||||
'message' => 'We already have a user with {{ fields }}',
|
|
||||||
'messageFieldSeparator' => ' and '
|
|
||||||
'errorPath' => 'username',
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
If there is more than one field you must use an array
|
|
||||||
|
|
||||||
``` php
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
$metadata->addConstraint(
|
|
||||||
new UniqueObject(
|
|
||||||
array(
|
|
||||||
'fields' => array('username', 'login'),
|
|
||||||
'message' => 'We already have a user with {{ fields }}',
|
|
||||||
'messageFieldSeparator' => ' and ',
|
|
||||||
'errorPath' => 'username'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
XML
|
|
||||||
---
|
|
||||||
|
|
||||||
You can also specify this using xml
|
|
||||||
|
|
||||||
```xml
|
|
||||||
|
|
||||||
<class name="Acme\DemoBundle\Model\User">
|
|
||||||
|
|
||||||
<constraint name="Propel\PropelBundle\Validator\Constraints\UniqueObject">
|
|
||||||
<option name="fields">username</option>
|
|
||||||
<option name="message">We already have a user with {{ fields }}</option>
|
|
||||||
<option name="messageFieldSeparator"> and </option>
|
|
||||||
<option name="errorPath">username</option>
|
|
||||||
</constraint>
|
|
||||||
|
|
||||||
</class>
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
[Back to index](index.markdown)
|
|
Binary file not shown.
Before Width: | Height: | Size: 2.4 KiB |
|
@ -2,20 +2,27 @@
|
||||||
|
|
||||||
namespace ##NAMESPACE##;
|
namespace ##NAMESPACE##;
|
||||||
|
|
||||||
use Propel\PropelBundle\Form\BaseAbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
class ##CLASS## extends BaseAbstractType
|
class ##CLASS## extends AbstractType
|
||||||
{
|
{
|
||||||
protected $options = array(
|
|
||||||
'data_class' => '##FQCN##',
|
|
||||||
'name' => '##TYPE_NAME##',
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
{##BUILD_CODE##
|
{##BUILD_CODE##
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'data_class' => '##FQCN##',
|
||||||
|
'name' => '##TYPE_NAME##',
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,33 +1,39 @@
|
||||||
{% extends 'WebProfilerBundle:Profiler:layout.html.twig' %}
|
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
|
||||||
|
|
||||||
{% block toolbar %}
|
{% block toolbar %}
|
||||||
{# the web debug toolbar content #}
|
{# the web debug toolbar content #}
|
||||||
{% set icon %}
|
{% if collector.querycount %}
|
||||||
<img alt="Propel" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAcCAYAAAB2+A+pAAACzmlDQ1BJQ0MgUHJvZmlsZQAAeNqNk8trFFkUh7/q3KCQIAy0r14Ml1lIkCSUDzQiPtJJbKKxbcpEkyBIp/p2d5mb6ppb1XEUEcnGpc4we/GxcOEf4MKFK90oEXwhiHsVRRTcqLSL6nRX8HlWX/3Oub9zzi0udNrFINApCXN+ZJxcVk5OTcsVz0ixni4ydBXdMBgsFMYAikGg+SY+PsECeNj3/fxPo6sUunNgrYTU+5IKXej4DNQqk1PTIDSQPhkFEYhzQNrE+v9Aeibm60DajDtDIG4Bq9zARCDuAQNutViCTgH0VhI1Mwme03W3Oc8fQLfyJw4DGyB1VoUjTbYWSsXhA0A/WK9KangE6AXretnbNwr0AM/LZt9EzNZGLxodjzl1xNf5sSav82fyh5qeIoiyzpJ/OH94ZEk/UdxfADJgObO1Aw6wBlJ7T1fHj8Zs6dPVoXyTH5m6MwH8BalrgS6MxbOl7jCFRuHho/CROOTI0keAoUYZDw+NRw6Fj8LgETL73UpNIcGSHC/xeYnB42/qKCQOR8jmWehtOUj7qf3Gfmxftq/Zry9m6j3tzII57rmLF95RQGFavs1sc6bY36XGIBpNBcVca6cwMWliurJ/MdN2chcvvFPn8x8TW6pEpz5mUITMYvCYR6EJUQwmuv3o9hT67plb69q9Houbxx523z2z7K5q32ylWlst/27XJc8r8afYJEbFgNiBFHvEXrFbDIsBsVOMtU5M4ONxEoUhpIjG5xRy2f9bqiV+awCkc8pXxnOlk8vKgqmVPa0ST/QX6d+MyalpGdN0HW6EsHZrW/vgYAHWmsW2Fh2EXW+h40Fb68nA6ktwc5tbN/NNa8u6D5H6JwIYqgWnjFepRnKzbW+Xg0GglRz13f5eWdRaGq9SjUJpVKjMvCr1E5a3bI5durPQ+aLR+LABVvwHX/5tND5daTS+XIWO53BbfwXAvP1FP6ZP5AAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAG9gAABvYBDBXjEwAAAAd0SU1FB9sEBhQVGSw3+igAAAWFSURBVEjH3VdfTFtVGP+d09v2jna0pYzC7EbpmsBguAw6+kCydJJh4nhYiMaYKInbNMvigpo49+CDL0bji89LlhgWH8TFaII004VIMmDAKGF/Ojr5t1YYpfS2pZTb295/vgACg4Hb9MHzdr/zfd/v/r7zO+d8B/i/jWQyueXcvXv3/h3QyclJspm9p6eHjIyMUABgXgTQ4OAg6urqcPv2bQ3HcXA6nTIAjI+PV8disUZVVc+m0+mKxcXFrMlkegfANfK8oAMDA/B4POtsIyMjJwVBOJtKpV4VBGGXoigghMBoNM6Wl5cfstvt8WdmnEgkcOXKlXWgfr//eCKR+DwSiRzL5XKQZRmEEAUAZVkWJSUlZ+12e3x4eFjzTMAPHjzQtLS0KB0dHery2p3I5XJfRSKRGlmWIUkSCCGglEKn01FKqWgymV6vrKz0VVZWoqamRib/RKVms3nj2r6RSqXO53I5bzabBQBoNBqwLAtK6RTDMCMGgyFotVp/dDqd/uWqoLa2dntxhcNhDAwMrAO9f//+W3Nzc5disdjLoigCACwWCzQaTS+ltJ1SOujxeMYppdyaLUSMRqNaVlYGAHgqY1VVQcjfLkNDQ69KknQ1nU4XZbNZ6PX6P81m87DJZPoulUpdr62tTa/4jo2NFTAMc0Kv15v37t17eWOuLRlnMplVxzt37rwmiuK5paWlGlEUg2az+arNZvt+3759/g0/ag0EAqclSWpJJBKHeJ6HVqudEUWxkxAyvdZ3O8a6aDTanEwma+bn5wMOh6Pfbrc/3Og3OzvriUajrTzP10uStD+Xy0FVVeh0Olgslm+qq6s/7u3t1dTX18s7BaahUMjicDi4zeYnJibqFhYWPuV5vlmWZSiKAkVRBAAswzDIz8/3HTly5CQAxGIxFBYWbl9qnudX9uAToKOjow1LS0vnHz9+3CxJElRVhaqqAACWZVlKKQwGw0B1dfV5AAgEAutAt2UcDAZRUVGx+j09PX18Zmbmg1wu1yyK4qoGWJYFwzAhrVY7RCm9vnv37kmHw9FLCMkCgCAIYFl2XW5mi0Mera2tq6Acx3nC4fDXU1NTxwBAlmWwLBs3GAwhlmU7M5nM5cOHD0cIIdLaPGNjY9Tlcilr1bwl40gkQoqLi9XlwKp4PP4RIeTM8vr5jUbjWH5+/g+lpaW/EkL4NXEv+f3+g4uLi2U2my3t9Xp/IoQIW1VzHeO5uTlis9lUjuOq4vH4Z6IoHmMYZpQQ8mFxcfHdkpKSHkKIuDbm1q1b9clk8mJPT0+NLMv2bDaLTCbzB4BfAOwM2Gazqel0Ok8QhFcopdd4nv/E7XZPbwwSRdHQ19f3Nsdx56ampg7KsqxfEVleXl5mz5497xNCFp+mnydKHYvFSGFhobrFeW3p7+9/M51OX8pkMqUralYURQFA9Xo9bDbb6YaGhm/dbjd8Ph+Kioq2B15YWIDJZNpsP7M+n+8Cz/NnBEEolyQJlFKoqgpK6Yqqx3Q63RdNTU1tO7l0nmDc1dVFGhoa1GVAY1dX13vz8/MXRFEsWwFavoGiOp2uW6/XX1dVtdflcnFOp5MDgM7OTmi1WjQ2Nm4NHAgEUFVVheHhYRIOh8mpU6cUALh582ZrNBr9kuf5XQzDgBAyYzQapzUazc9VVVUD+/fv/32zhN3d3fB6vdsz5jgOVqt11XDjxo13U6nURUpphSRJI3l5eX0ajab76NGjd61W68PNkrS3t8PtduPAgQM7bibI0NAQ3G43gsFgUywWuygIgqooym9arbbD6/VOEkJWr7qysjLS1tZG7Xa74nQ61efuEkOhUOHExMSJ/v5+22bz0Wj0xffAoVBoU3tBQcFTm/LnHQQAHj16BEVRiKIoqsvl+k9eGn8BMMeiAFTierUAAAAASUVORK5CYII=" />
|
{% set icon %}
|
||||||
<span class="sf-toolbar-status">{{ collector.querycount }}</span>
|
<img alt="Propel" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAcCAYAAAB2+A+pAAACzmlDQ1BJQ0MgUHJvZmlsZQAAeNqNk8trFFkUh7/q3KCQIAy0r14Ml1lIkCSUDzQiPtJJbKKxbcpEkyBIp/p2d5mb6ppb1XEUEcnGpc4we/GxcOEf4MKFK90oEXwhiHsVRRTcqLSL6nRX8HlWX/3Oub9zzi0udNrFINApCXN+ZJxcVk5OTcsVz0ixni4ydBXdMBgsFMYAikGg+SY+PsECeNj3/fxPo6sUunNgrYTU+5IKXej4DNQqk1PTIDSQPhkFEYhzQNrE+v9Aeibm60DajDtDIG4Bq9zARCDuAQNutViCTgH0VhI1Mwme03W3Oc8fQLfyJw4DGyB1VoUjTbYWSsXhA0A/WK9KangE6AXretnbNwr0AM/LZt9EzNZGLxodjzl1xNf5sSav82fyh5qeIoiyzpJ/OH94ZEk/UdxfADJgObO1Aw6wBlJ7T1fHj8Zs6dPVoXyTH5m6MwH8BalrgS6MxbOl7jCFRuHho/CROOTI0keAoUYZDw+NRw6Fj8LgETL73UpNIcGSHC/xeYnB42/qKCQOR8jmWehtOUj7qf3Gfmxftq/Zry9m6j3tzII57rmLF95RQGFavs1sc6bY36XGIBpNBcVca6cwMWliurJ/MdN2chcvvFPn8x8TW6pEpz5mUITMYvCYR6EJUQwmuv3o9hT67plb69q9Houbxx523z2z7K5q32ylWlst/27XJc8r8afYJEbFgNiBFHvEXrFbDIsBsVOMtU5M4ONxEoUhpIjG5xRy2f9bqiV+awCkc8pXxnOlk8vKgqmVPa0ST/QX6d+MyalpGdN0HW6EsHZrW/vgYAHWmsW2Fh2EXW+h40Fb68nA6ktwc5tbN/NNa8u6D5H6JwIYqgWnjFepRnKzbW+Xg0GglRz13f5eWdRaGq9SjUJpVKjMvCr1E5a3bI5durPQ+aLR+LABVvwHX/5tND5daTS+XIWO53BbfwXAvP1FP6ZP5AAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAG9gAABvYBDBXjEwAAAAd0SU1FB9sEBhQVGSw3+igAAAWFSURBVEjH3VdfTFtVGP+d09v2jna0pYzC7EbpmsBguAw6+kCydJJh4nhYiMaYKInbNMvigpo49+CDL0bji89LlhgWH8TFaII004VIMmDAKGF/Ojr5t1YYpfS2pZTb295/vgACg4Hb9MHzdr/zfd/v/r7zO+d8B/i/jWQyueXcvXv3/h3QyclJspm9p6eHjIyMUABgXgTQ4OAg6urqcPv2bQ3HcXA6nTIAjI+PV8disUZVVc+m0+mKxcXFrMlkegfANfK8oAMDA/B4POtsIyMjJwVBOJtKpV4VBGGXoigghMBoNM6Wl5cfstvt8WdmnEgkcOXKlXWgfr//eCKR+DwSiRzL5XKQZRmEEAUAZVkWJSUlZ+12e3x4eFjzTMAPHjzQtLS0KB0dHery2p3I5XJfRSKRGlmWIUkSCCGglEKn01FKqWgymV6vrKz0VVZWoqamRib/RKVms3nj2r6RSqXO53I5bzabBQBoNBqwLAtK6RTDMCMGgyFotVp/dDqd/uWqoLa2dntxhcNhDAwMrAO9f//+W3Nzc5disdjLoigCACwWCzQaTS+ltJ1SOujxeMYppdyaLUSMRqNaVlYGAHgqY1VVQcjfLkNDQ69KknQ1nU4XZbNZ6PX6P81m87DJZPoulUpdr62tTa/4jo2NFTAMc0Kv15v37t17eWOuLRlnMplVxzt37rwmiuK5paWlGlEUg2az+arNZvt+3759/g0/ag0EAqclSWpJJBKHeJ6HVqudEUWxkxAyvdZ3O8a6aDTanEwma+bn5wMOh6Pfbrc/3Og3OzvriUajrTzP10uStD+Xy0FVVeh0Olgslm+qq6s/7u3t1dTX18s7BaahUMjicDi4zeYnJibqFhYWPuV5vlmWZSiKAkVRBAAswzDIz8/3HTly5CQAxGIxFBYWbl9qnudX9uAToKOjow1LS0vnHz9+3CxJElRVhaqqAACWZVlKKQwGw0B1dfV5AAgEAutAt2UcDAZRUVGx+j09PX18Zmbmg1wu1yyK4qoGWJYFwzAhrVY7RCm9vnv37kmHw9FLCMkCgCAIYFl2XW5mi0Mera2tq6Acx3nC4fDXU1NTxwBAlmWwLBs3GAwhlmU7M5nM5cOHD0cIIdLaPGNjY9Tlcilr1bwl40gkQoqLi9XlwKp4PP4RIeTM8vr5jUbjWH5+/g+lpaW/EkL4NXEv+f3+g4uLi2U2my3t9Xp/IoQIW1VzHeO5uTlis9lUjuOq4vH4Z6IoHmMYZpQQ8mFxcfHdkpKSHkKIuDbm1q1b9clk8mJPT0+NLMv2bDaLTCbzB4BfAOwM2Gazqel0Ok8QhFcopdd4nv/E7XZPbwwSRdHQ19f3Nsdx56ampg7KsqxfEVleXl5mz5497xNCFp+mnydKHYvFSGFhobrFeW3p7+9/M51OX8pkMqUralYURQFA9Xo9bDbb6YaGhm/dbjd8Ph+Kioq2B15YWIDJZNpsP7M+n+8Cz/NnBEEolyQJlFKoqgpK6Yqqx3Q63RdNTU1tO7l0nmDc1dVFGhoa1GVAY1dX13vz8/MXRFEsWwFavoGiOp2uW6/XX1dVtdflcnFOp5MDgM7OTmi1WjQ2Nm4NHAgEUFVVheHhYRIOh8mpU6cUALh582ZrNBr9kuf5XQzDgBAyYzQapzUazc9VVVUD+/fv/32zhN3d3fB6vdsz5jgOVqt11XDjxo13U6nURUpphSRJI3l5eX0ajab76NGjd61W68PNkrS3t8PtduPAgQM7bibI0NAQ3G43gsFgUywWuygIgqooym9arbbD6/VOEkJWr7qysjLS1tZG7Xa74nQ61efuEkOhUOHExMSJ/v5+22bz0Wj0xffAoVBoU3tBQcFTm/LnHQQAHj16BEVRiKIoqsvl+k9eGn8BMMeiAFTierUAAAAASUVORK5CYII=" />
|
||||||
{% endset %}
|
<span class="sf-toolbar-value">{{ collector.querycount }}</span>
|
||||||
{% set text %}
|
<span class="sf-toolbar-info-piece-additional-detail">
|
||||||
<div class="sf-toolbar-info-piece">
|
<span class="sf-toolbar-label">in</span>
|
||||||
<b>DB Queries</b>
|
<span class="sf-toolbar-value">{{ '%0.2f'|format(collector.time * 1000) }}</span>
|
||||||
<span>{{ collector.querycount }}</span>
|
<span class="sf-toolbar-label">ms</span>
|
||||||
</div>
|
</span>
|
||||||
<div class="sf-toolbar-info-piece">
|
{% endset %}
|
||||||
<b>Query time</b>
|
{% set text %}
|
||||||
<span>{{ '%0.2f'|format(collector.time * 1000) }} ms</span>
|
<div class="sf-toolbar-info-piece">
|
||||||
</div>
|
<b>DB Queries</b>
|
||||||
{% endset %}
|
<span class="sf-toolbar-status {{ collector.querycount > 50 ? 'sf-toolbar-status-yellow' : '' }}">{{ collector.querycount }}</span>
|
||||||
{% include 'WebProfilerBundle:Profiler:toolbar_item.html.twig' with { 'link': profiler_url } %}
|
</div>
|
||||||
|
<div class="sf-toolbar-info-piece">
|
||||||
|
<b>Query time</b>
|
||||||
|
<span>{{ '%0.2f'|format(collector.time * 1000) }} ms</span>
|
||||||
|
</div>
|
||||||
|
{% endset %}
|
||||||
|
|
||||||
|
{% set status = collector.querycount > 50 ? 'yellow' : '' %}
|
||||||
|
|
||||||
|
{% include '@WebProfiler/Profiler/toolbar_item.html.twig' with { 'link': profiler_url, status: status } %}
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block menu %}
|
{% block menu %}
|
||||||
{# the menu content #}
|
{# the menu content #}
|
||||||
<span class="label">
|
<span class="label {{ not collector.querycount ? 'disabled' }}">
|
||||||
<span class="icon"><img src="{{ asset('bundles/propel/images/profiler/propel.png') }}" alt="" /></span>
|
<span class="icon"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAcCAYAAAB2+A+pAAACzmlDQ1BJQ0MgUHJvZmlsZQAAeNqNk8trFFkUh7/q3KCQIAy0r14Ml1lIkCSUDzQiPtJJbKKxbcpEkyBIp/p2d5mb6ppb1XEUEcnGpc4we/GxcOEf4MKFK90oEXwhiHsVRRTcqLSL6nRX8HlWX/3Oub9zzi0udNrFINApCXN+ZJxcVk5OTcsVz0ixni4ydBXdMBgsFMYAikGg+SY+PsECeNj3/fxPo6sUunNgrYTU+5IKXej4DNQqk1PTIDSQPhkFEYhzQNrE+v9Aeibm60DajDtDIG4Bq9zARCDuAQNutViCTgH0VhI1Mwme03W3Oc8fQLfyJw4DGyB1VoUjTbYWSsXhA0A/WK9KangE6AXretnbNwr0AM/LZt9EzNZGLxodjzl1xNf5sSav82fyh5qeIoiyzpJ/OH94ZEk/UdxfADJgObO1Aw6wBlJ7T1fHj8Zs6dPVoXyTH5m6MwH8BalrgS6MxbOl7jCFRuHho/CROOTI0keAoUYZDw+NRw6Fj8LgETL73UpNIcGSHC/xeYnB42/qKCQOR8jmWehtOUj7qf3Gfmxftq/Zry9m6j3tzII57rmLF95RQGFavs1sc6bY36XGIBpNBcVca6cwMWliurJ/MdN2chcvvFPn8x8TW6pEpz5mUITMYvCYR6EJUQwmuv3o9hT67plb69q9Houbxx523z2z7K5q32ylWlst/27XJc8r8afYJEbFgNiBFHvEXrFbDIsBsVOMtU5M4ONxEoUhpIjG5xRy2f9bqiV+awCkc8pXxnOlk8vKgqmVPa0ST/QX6d+MyalpGdN0HW6EsHZrW/vgYAHWmsW2Fh2EXW+h40Fb68nA6ktwc5tbN/NNa8u6D5H6JwIYqgWnjFepRnKzbW+Xg0GglRz13f5eWdRaGq9SjUJpVKjMvCr1E5a3bI5durPQ+aLR+LABVvwHX/5tND5daTS+XIWO53BbfwXAvP1FP6ZP5AAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAG9gAABvYBDBXjEwAAAAd0SU1FB9sEBhQVGSw3+igAAAWFSURBVEjH3VdfTFtVGP+d09v2jna0pYzC7EbpmsBguAw6+kCydJJh4nhYiMaYKInbNMvigpo49+CDL0bji89LlhgWH8TFaII004VIMmDAKGF/Ojr5t1YYpfS2pZTb295/vgACg4Hb9MHzdr/zfd/v/r7zO+d8B/i/jWQyueXcvXv3/h3QyclJspm9p6eHjIyMUABgXgTQ4OAg6urqcPv2bQ3HcXA6nTIAjI+PV8disUZVVc+m0+mKxcXFrMlkegfANfK8oAMDA/B4POtsIyMjJwVBOJtKpV4VBGGXoigghMBoNM6Wl5cfstvt8WdmnEgkcOXKlXWgfr//eCKR+DwSiRzL5XKQZRmEEAUAZVkWJSUlZ+12e3x4eFjzTMAPHjzQtLS0KB0dHery2p3I5XJfRSKRGlmWIUkSCCGglEKn01FKqWgymV6vrKz0VVZWoqamRib/RKVms3nj2r6RSqXO53I5bzabBQBoNBqwLAtK6RTDMCMGgyFotVp/dDqd/uWqoLa2dntxhcNhDAwMrAO9f//+W3Nzc5disdjLoigCACwWCzQaTS+ltJ1SOujxeMYppdyaLUSMRqNaVlYGAHgqY1VVQcjfLkNDQ69KknQ1nU4XZbNZ6PX6P81m87DJZPoulUpdr62tTa/4jo2NFTAMc0Kv15v37t17eWOuLRlnMplVxzt37rwmiuK5paWlGlEUg2az+arNZvt+3759/g0/ag0EAqclSWpJJBKHeJ6HVqudEUWxkxAyvdZ3O8a6aDTanEwma+bn5wMOh6Pfbrc/3Og3OzvriUajrTzP10uStD+Xy0FVVeh0Olgslm+qq6s/7u3t1dTX18s7BaahUMjicDi4zeYnJibqFhYWPuV5vlmWZSiKAkVRBAAswzDIz8/3HTly5CQAxGIxFBYWbl9qnudX9uAToKOjow1LS0vnHz9+3CxJElRVhaqqAACWZVlKKQwGw0B1dfV5AAgEAutAt2UcDAZRUVGx+j09PX18Zmbmg1wu1yyK4qoGWJYFwzAhrVY7RCm9vnv37kmHw9FLCMkCgCAIYFl2XW5mi0Mera2tq6Acx3nC4fDXU1NTxwBAlmWwLBs3GAwhlmU7M5nM5cOHD0cIIdLaPGNjY9Tlcilr1bwl40gkQoqLi9XlwKp4PP4RIeTM8vr5jUbjWH5+/g+lpaW/EkL4NXEv+f3+g4uLi2U2my3t9Xp/IoQIW1VzHeO5uTlis9lUjuOq4vH4Z6IoHmMYZpQQ8mFxcfHdkpKSHkKIuDbm1q1b9clk8mJPT0+NLMv2bDaLTCbzB4BfAOwM2Gazqel0Ok8QhFcopdd4nv/E7XZPbwwSRdHQ19f3Nsdx56ampg7KsqxfEVleXl5mz5497xNCFp+mnydKHYvFSGFhobrFeW3p7+9/M51OX8pkMqUralYURQFA9Xo9bDbb6YaGhm/dbjd8Ph+Kioq2B15YWIDJZNpsP7M+n+8Cz/NnBEEolyQJlFKoqgpK6Yqqx3Q63RdNTU1tO7l0nmDc1dVFGhoa1GVAY1dX13vz8/MXRFEsWwFavoGiOp2uW6/XX1dVtdflcnFOp5MDgM7OTmi1WjQ2Nm4NHAgEUFVVheHhYRIOh8mpU6cUALh582ZrNBr9kuf5XQzDgBAyYzQapzUazc9VVVUD+/fv/32zhN3d3fB6vdsz5jgOVqt11XDjxo13U6nURUpphSRJI3l5eX0ajab76NGjd61W68PNkrS3t8PtduPAgQM7bibI0NAQ3G43gsFgUywWuygIgqooym9arbbD6/VOEkJWr7qysjLS1tZG7Xa74nQ61efuEkOhUOHExMSJ/v5+22bz0Wj0xffAoVBoU3tBQcFTm/LnHQQAHj16BEVRiKIoqsvl+k9eGn8BMMeiAFTierUAAAAASUVORK5CYII=" alt="" /></span>
|
||||||
<strong>Propel</strong>
|
<strong>Propel</strong>
|
||||||
<span class="count">
|
|
||||||
<span>{{ collector.querycount }}</span>
|
|
||||||
<span>{{ '%0.0f'|format(collector.time * 1000) }} ms</span>
|
|
||||||
</span>
|
|
||||||
</span>
|
</span>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
@ -42,7 +48,7 @@
|
||||||
color: #464646;
|
color: #464646;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
.SQLInfo, .SQLComment {
|
.SQLComment {
|
||||||
color: gray;
|
color: gray;
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
|
@ -60,52 +66,80 @@
|
||||||
padding: 8px 35px 8px 14px;
|
padding: 8px 35px 8px 14px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
#content .SQLExplain h2 {
|
|
||||||
font-size: 17px;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<h2>Queries</h2>
|
<h2>Query Metrics</h2>
|
||||||
<table summary="Show logged queries">
|
|
||||||
<thead>
|
{% if not collector.querycount %}
|
||||||
<tr>
|
<div class="empty">
|
||||||
<th>SQL queries</th>
|
<p>No database queries were performed.</p>
|
||||||
</tr>
|
</div>
|
||||||
</thead>
|
{% else %}
|
||||||
<tbody>
|
<div class="metrics">
|
||||||
{% if not collector.querycount %}
|
<div class="metric">
|
||||||
<tr><td>No queries.</td></tr>
|
<span class="value">{{ collector.querycount }}</span>
|
||||||
{% else %}
|
<span class="label">Database Queries</span>
|
||||||
{% for i, query in collector.queries %}
|
</div>
|
||||||
<tr>
|
|
||||||
<td>
|
<div class="metric">
|
||||||
<a name="propel-query-{{ i }}" ></a>
|
<span class="value">{{ '%0.2f'|format(collector.time * 1000) }} <span class="unit">ms</span></span>
|
||||||
<code>{{ query.sql|format_sql }}</code>
|
<span class="label">Query time</span>
|
||||||
{% if app.request.query.has('query') and app.request.query.get('query') == i %}
|
</div>
|
||||||
<div class="SQLExplain">
|
</div>
|
||||||
{% render controller('PropelBundle:Panel:explain', {
|
|
||||||
'token': token,
|
<h2>Queries</h2>
|
||||||
'panel': 'propel',
|
<table summary="Show logged queries">
|
||||||
'query': app.request.query.get('query'),
|
<thead>
|
||||||
'connection': app.request.query.get('connection')
|
<tr>
|
||||||
}) %}
|
<th nowrap>#</th>
|
||||||
|
<th nowrap>Time</th>
|
||||||
|
<th nowrap>Memory</th>
|
||||||
|
<th style="width: 100%;">Query</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="queries">
|
||||||
|
{% for i, query in collector.queries %}
|
||||||
|
<tr>
|
||||||
|
<td class="font-normal text-small" nowrap>{{ loop.index }}</td>
|
||||||
|
<td class="font-normal text-small" nowrap>{{ '%0.2f'|format(query.time * 1000) }} ms</td>
|
||||||
|
<td class="font-normal text-small" nowrap>{{ query.memory|format_memory }}</td>
|
||||||
|
<td>
|
||||||
|
<a name="propel-query-{{ i }}" ></a>
|
||||||
|
<code>{{ query.sql|format_sql|raw }}</code>
|
||||||
|
<div class="metadata font-normal text-muted">
|
||||||
|
<span class="text-small">
|
||||||
|
Connection: {{ query.connection }}
|
||||||
|
</span>
|
||||||
|
-
|
||||||
|
<a class="btn btn-link text-small sf-toggle" data-toggle-selector="#propel-stack-trace-{{ i }}" data-toggle-alt-content="Hide trace">Show trace</a>
|
||||||
|
-
|
||||||
|
{% if app.request.query.get('query', -1) == i %}
|
||||||
|
<a class="btn btn-link text-small" href="{{ path('_profiler', {'panel': 'propel', 'token': token, 'connection': query.connection}) }}}#propel-query-{{ i }}">Hide query explanation</a>
|
||||||
|
{% else %}
|
||||||
|
<a class="btn btn-link text-small" href="{{ path('_profiler', {'panel': 'propel', 'token': token, 'connection': query.connection, 'query': i}) }}#propel-query-{{ i }}">Explain query</a>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
<div class="SQLInfo">
|
|
||||||
Time: {{ query.time }} - Memory: {{ query.memory }} - Connection: {{ query.connection }}
|
|
||||||
|
|
||||||
{% if app.request.query.get('query', -1) != i %}
|
{% if app.request.query.has('query') and app.request.query.get('query') == i %}
|
||||||
- <a href="{{ path('_profiler', {'panel': 'propel', 'token': token, 'connection': query.connection, 'query': i}) }}#propel-query-{{ i }}">Explain the query</a>
|
<div class="SQLExplain">
|
||||||
|
{{ render(controller('PropelBundle:Panel:explain', {
|
||||||
|
'token': token,
|
||||||
|
'panel': 'propel',
|
||||||
|
'query': app.request.query.get('query'),
|
||||||
|
'connection': app.request.query.get('connection')
|
||||||
|
})) }}
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
{% render controller('PropelBundle:Panel:configuration') %}
|
<div id="propel-stack-trace-{{ i }}" class="sf-toggle-content sf-toggle-hidden">
|
||||||
|
{{ profiler_dump(query.trace, maxDepth=1) }}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{{ render(controller('PropelBundle:Panel:configuration')) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -10,19 +10,11 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Default connection</th>
|
<th>Default connection</th>
|
||||||
<td>{{ default_connection }}</td>
|
<td>{{ configuration.runtime.defaultConnection }}</td>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Logging</th>
|
<th>Logging</th>
|
||||||
<td>{{ logging ? 'enabled' : 'disabled' }}</td>
|
<td>{{ logging ? 'enabled' : 'disabled' }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<th>Propel path</th>
|
|
||||||
<td>{{ path }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Phing path</th>
|
|
||||||
<td>{{ phing_path }}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
@ -36,7 +28,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for name, config in configuration.datasources %}
|
{% for name, config in configuration.database.connections %}
|
||||||
<tr>
|
<tr>
|
||||||
<th rowspan="5" style="vertical-align: top;">
|
<th rowspan="5" style="vertical-align: top;">
|
||||||
{{ name }}
|
{{ name }}
|
||||||
|
@ -46,17 +38,17 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>DSN</th>
|
<th>DSN</th>
|
||||||
<td>{{ config.connection.dsn }}</td>
|
<td>{{ config.dsn }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Class</th>
|
<th>Class</th>
|
||||||
<td>{{ config.connection.classname }}</td>
|
<td>{{ config.classname }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Options</th>
|
<th>Options</th>
|
||||||
<td>
|
<td>
|
||||||
<ul>
|
<ul>
|
||||||
{% for key, value in config.connection.options %}
|
{% for key, value in config.options %}
|
||||||
<li>{{ key }} : {{ value }}</li>
|
<li>{{ key }} : {{ value }}</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -66,7 +58,7 @@
|
||||||
<th>Attributes</th>
|
<th>Attributes</th>
|
||||||
<td>
|
<td>
|
||||||
<ul>
|
<ul>
|
||||||
{% for key, value in config.connection.attributes %}
|
{% for key, value in config.attributes %}
|
||||||
<li>{{ key }} : {{ value }}</li>
|
<li>{{ key }} : {{ value }}</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
<h2>Explanation</h2>
|
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
{% for label in data[0]|keys %}
|
{% for label in data[0]|keys %}
|
||||||
|
|
|
@ -8,13 +8,16 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Security\Acl;
|
namespace Propel\Bundle\PropelBundle\Security\Acl;
|
||||||
|
|
||||||
use Propel\PropelBundle\Model\Acl\EntryQuery;
|
use Propel\Runtime\Collection\ObjectCollection;
|
||||||
use Propel\PropelBundle\Model\Acl\ObjectIdentityQuery;
|
use Propel\Runtime\Connection\ConnectionInterface;
|
||||||
use Propel\PropelBundle\Model\Acl\SecurityIdentity;
|
|
||||||
|
|
||||||
use Propel\PropelBundle\Security\Acl\Domain\Acl;
|
use Propel\Bundle\PropelBundle\Model\Acl\EntryQuery;
|
||||||
|
use Propel\Bundle\PropelBundle\Model\Acl\ObjectIdentityQuery;
|
||||||
|
use Propel\Bundle\PropelBundle\Model\Acl\SecurityIdentity;
|
||||||
|
|
||||||
|
use Propel\Bundle\PropelBundle\Security\Acl\Domain\Acl;
|
||||||
|
|
||||||
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
|
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
|
||||||
|
|
||||||
|
@ -41,10 +44,10 @@ class AclProvider implements AclProviderInterface
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param \Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface $permissionGrantingStrategy
|
* @param \Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface $permissionGrantingStrategy
|
||||||
* @param \PropelPDO $con
|
* @param ConnectionInterface $con
|
||||||
* @param \Symfony\Component\Security\Acl\Model\AclCacheInterface $cache
|
* @param \Symfony\Component\Security\Acl\Model\AclCacheInterface $cache
|
||||||
*/
|
*/
|
||||||
public function __construct(PermissionGrantingStrategyInterface $permissionGrantingStrategy, \PropelPDO $connection = null, AclCacheInterface $cache = null)
|
public function __construct(PermissionGrantingStrategyInterface $permissionGrantingStrategy, ConnectionInterface $connection = null, AclCacheInterface $cache = null)
|
||||||
{
|
{
|
||||||
$this->permissionGrantingStrategy = $permissionGrantingStrategy;
|
$this->permissionGrantingStrategy = $permissionGrantingStrategy;
|
||||||
$this->connection = $connection;
|
$this->connection = $connection;
|
||||||
|
@ -163,15 +166,15 @@ class AclProvider implements AclProviderInterface
|
||||||
/**
|
/**
|
||||||
* Create an ACL.
|
* Create an ACL.
|
||||||
*
|
*
|
||||||
* @param \PropelObjectCollection $collection
|
* @param ObjectCollection $collection
|
||||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||||
* @param array $loadedSecurityIdentities
|
* @param array $loadedSecurityIdentities
|
||||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $parentAcl
|
* @param \Symfony\Component\Security\Acl\Model\AclInterface $parentAcl
|
||||||
* @param bool $inherited
|
* @param bool $inherited
|
||||||
*
|
*
|
||||||
* @return \Propel\PropelBundle\Security\Acl\Domain\Acl
|
* @return \Propel\Bundle\PropelBundle\Security\Acl\Domain\Acl
|
||||||
*/
|
*/
|
||||||
protected function getAcl(\PropelObjectCollection $collection, ObjectIdentityInterface $objectIdentity, array $loadedSecurityIdentities = array(), AclInterface $parentAcl = null, $inherited = true)
|
protected function getAcl(ObjectCollection $collection, ObjectIdentityInterface $objectIdentity, array $loadedSecurityIdentities = array(), AclInterface $parentAcl = null, $inherited = true)
|
||||||
{
|
{
|
||||||
return new Acl($collection, $objectIdentity, $this->permissionGrantingStrategy, $loadedSecurityIdentities, $parentAcl, $inherited);
|
return new Acl($collection, $objectIdentity, $this->permissionGrantingStrategy, $loadedSecurityIdentities, $parentAcl, $inherited);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,10 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Security\Acl;
|
namespace Propel\Bundle\PropelBundle\Security\Acl;
|
||||||
|
|
||||||
use Propel\PropelBundle\Security\Acl\Domain\AuditableAcl;
|
use Propel\Runtime\Collection\ObjectCollection;
|
||||||
|
use Propel\Bundle\PropelBundle\Security\Acl\Domain\AuditableAcl;
|
||||||
|
|
||||||
use Symfony\Component\Security\Acl\Model\AclInterface;
|
use Symfony\Component\Security\Acl\Model\AclInterface;
|
||||||
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
|
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
|
||||||
|
@ -23,15 +24,15 @@ class AuditableAclProvider extends MutableAclProvider
|
||||||
/**
|
/**
|
||||||
* Get an ACL for this provider.
|
* Get an ACL for this provider.
|
||||||
*
|
*
|
||||||
* @param \PropelObjectCollection $collection
|
* @param Propel\Runtime\Collection\ObjectCollection $collection
|
||||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||||
* @param array $loadedSecurityIdentities
|
* @param array $loadedSecurityIdentities
|
||||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $parentAcl
|
* @param \Symfony\Component\Security\Acl\Model\AclInterface $parentAcl
|
||||||
* @param bool $inherited
|
* @param bool $inherited
|
||||||
*
|
*
|
||||||
* @return \Propel\PropelBundle\Security\Acl\Domain\AuditableAcl
|
* @return \Propel\Bundle\PropelBundle\Security\Acl\Domain\AuditableAcl
|
||||||
*/
|
*/
|
||||||
protected function getAcl(\PropelObjectCollection $collection, ObjectIdentityInterface $objectIdentity, array $loadedSecurityIdentities = array(), AclInterface $parentAcl = null, $inherited = true)
|
protected function getAcl(ObjectCollection $collection, ObjectIdentityInterface $objectIdentity, array $loadedSecurityIdentities = array(), AclInterface $parentAcl = null, $inherited = true)
|
||||||
{
|
{
|
||||||
return new AuditableAcl($collection, $objectIdentity, $this->permissionGrantingStrategy, $loadedSecurityIdentities, $parentAcl, $inherited, $this->connection);
|
return new AuditableAcl($collection, $objectIdentity, $this->permissionGrantingStrategy, $loadedSecurityIdentities, $parentAcl, $inherited, $this->connection);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,9 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Security\Acl\Domain;
|
namespace Propel\Bundle\PropelBundle\Security\Acl\Domain;
|
||||||
|
|
||||||
|
use Propel\Runtime\Collection\ObjectCollection;
|
||||||
|
|
||||||
use Symfony\Component\Security\Acl\Exception\Exception as AclException;
|
use Symfony\Component\Security\Acl\Exception\Exception as AclException;
|
||||||
|
|
||||||
|
@ -18,13 +20,13 @@ use Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface;
|
||||||
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
|
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An ACL implementation that is immutable based on data from a PropelObjectCollection of Propel\PropelBundle\Model\Acl\Entry.
|
* An ACL implementation that is immutable based on data from a ObjectCollection of Propel\Bundle\PropelBundle\Model\Acl\Entry.
|
||||||
*
|
*
|
||||||
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||||
*/
|
*/
|
||||||
class Acl implements AclInterface
|
class Acl implements AclInterface
|
||||||
{
|
{
|
||||||
protected $model = 'Propel\PropelBundle\Model\Acl\Entry';
|
protected $model = '\Propel\Bundle\PropelBundle\Model\Acl\Entry';
|
||||||
|
|
||||||
protected $classAces = array();
|
protected $classAces = array();
|
||||||
protected $classFieldAces = array();
|
protected $classFieldAces = array();
|
||||||
|
@ -48,17 +50,17 @@ class Acl implements AclInterface
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param \PropelObjectCollection $entries
|
* @param ObjectCollection $entries
|
||||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||||
* @param \Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface $permissionGrantingStrategy
|
* @param \Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface $permissionGrantingStrategy
|
||||||
* @param array $loadedSecurityIdentities
|
* @param array $loadedSecurityIdentities
|
||||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $parentAcl
|
* @param \Symfony\Component\Security\Acl\Model\AclInterface $parentAcl
|
||||||
* @param bool $inherited
|
* @param bool $inherited
|
||||||
*/
|
*/
|
||||||
public function __construct(\PropelObjectCollection $entries, ObjectIdentityInterface $objectIdentity, PermissionGrantingStrategyInterface $permissionGrantingStrategy, array $loadedSecurityIdentities = array(), AclInterface $parentAcl = null, $inherited = true)
|
public function __construct(ObjectCollection $entries, ObjectIdentityInterface $objectIdentity, PermissionGrantingStrategyInterface $permissionGrantingStrategy, array $loadedSecurityIdentities = array(), AclInterface $parentAcl = null, $inherited = true)
|
||||||
{
|
{
|
||||||
if ($entries->getModel() !== $this->model) {
|
if ($entries->getFullyQualifiedModel() !== $this->model) {
|
||||||
throw new AclException(sprintf('The given collection does not contain models of class "%s" but of class "%s".', $this->model, $entries->getModel()));
|
throw new AclException(sprintf('The given collection does not contain models of class "%s" but of class "%s".', $this->model, $entries->getFullyQualifiedModel()));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($entries as $eachEntry) {
|
foreach ($entries as $eachEntry) {
|
||||||
|
@ -301,7 +303,7 @@ class Acl implements AclInterface
|
||||||
*
|
*
|
||||||
* @param string $field
|
* @param string $field
|
||||||
*
|
*
|
||||||
* @return \Propel\PropelBundle\Security\Acl\Domain\Acl $this
|
* @return \Propel\Bundle\PropelBundle\Security\Acl\Domain\Acl $this
|
||||||
*/
|
*/
|
||||||
protected function updateFields($field)
|
protected function updateFields($field)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Security\Acl\Domain;
|
namespace Propel\Bundle\PropelBundle\Security\Acl\Domain;
|
||||||
|
|
||||||
use Propel\PropelBundle\Model\Acl\Entry as ModelEntry;
|
use Propel\Bundle\PropelBundle\Model\Acl\Entry as ModelEntry;
|
||||||
|
|
||||||
use Symfony\Component\Security\Acl\Model\AuditableAclInterface;
|
use Symfony\Component\Security\Acl\Model\AuditableAclInterface;
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ class AuditableAcl extends MutableAcl implements AuditableAclInterface
|
||||||
* @param bool $auditSuccess
|
* @param bool $auditSuccess
|
||||||
* @param bool $auditFailure
|
* @param bool $auditFailure
|
||||||
*
|
*
|
||||||
* @return \Propel\PropelBundle\Security\Acl\Domain\AuditableAcl $this
|
* @return \Propel\Bundle\PropelBundle\Security\Acl\Domain\AuditableAcl $this
|
||||||
*/
|
*/
|
||||||
protected function updateAuditing(array &$list, $index, $auditSuccess, $auditFailure)
|
protected function updateAuditing(array &$list, $index, $auditSuccess, $auditFailure)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,17 +8,17 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Security\Acl\Domain;
|
namespace Propel\Bundle\PropelBundle\Security\Acl\Domain;
|
||||||
|
|
||||||
use Propel\PropelBundle\Model\Acl\Entry as ModelEntry;
|
use Propel\Bundle\PropelBundle\Model\Acl\Entry as ModelEntry;
|
||||||
use Propel\PropelBundle\Model\Acl\SecurityIdentity;
|
use Propel\Bundle\PropelBundle\Model\Acl\SecurityIdentity;
|
||||||
|
|
||||||
use Symfony\Component\Security\Acl\Model\AclInterface;
|
use Symfony\Component\Security\Acl\Model\AclInterface;
|
||||||
use Symfony\Component\Security\Acl\Model\AuditableEntryInterface;
|
use Symfony\Component\Security\Acl\Model\AuditableEntryInterface;
|
||||||
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
|
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An ACE implementation retrieving data from a given Propel\PropelBundle\Model\Acl\Entry.
|
* An ACE implementation retrieving data from a given Propel\Bundle\PropelBundle\Model\Acl\Entry.
|
||||||
*
|
*
|
||||||
* The entry is only used to grab a "snapshot" of its data as an EntryInterface is immutable!
|
* The entry is only used to grab a "snapshot" of its data as an EntryInterface is immutable!
|
||||||
*
|
*
|
||||||
|
@ -41,7 +41,7 @@ class Entry implements AuditableEntryInterface
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param \Propel\PropelBundle\Model\Acl\Entry $entry
|
* @param \Propel\Bundle\PropelBundle\Model\Acl\Entry $entry
|
||||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $acl
|
* @param \Symfony\Component\Security\Acl\Model\AclInterface $acl
|
||||||
*/
|
*/
|
||||||
public function __construct(ModelEntry $entry, AclInterface $acl)
|
public function __construct(ModelEntry $entry, AclInterface $acl)
|
||||||
|
|
|
@ -8,15 +8,15 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Security\Acl\Domain;
|
namespace Propel\Bundle\PropelBundle\Security\Acl\Domain;
|
||||||
|
|
||||||
use Propel\PropelBundle\Model\Acl\Entry as ModelEntry;
|
use Propel\Bundle\PropelBundle\Model\Acl\Entry as ModelEntry;
|
||||||
|
|
||||||
use Symfony\Component\Security\Acl\Model\AclInterface;
|
use Symfony\Component\Security\Acl\Model\AclInterface;
|
||||||
use Symfony\Component\Security\Acl\Model\FieldEntryInterface;
|
use Symfony\Component\Security\Acl\Model\FieldEntryInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An ACE implementation retrieving data from a given \Propel\PropelBundle\Model\Acl\Entry.
|
* An ACE implementation retrieving data from a given \Propel\Bundle\PropelBundle\Model\Acl\Entry.
|
||||||
*
|
*
|
||||||
* The entry is only used to grab a "snapshot" of its data as an \Symfony\Component\Security\Acl\Model\EntryInterface is immutable!
|
* The entry is only used to grab a "snapshot" of its data as an \Symfony\Component\Security\Acl\Model\EntryInterface is immutable!
|
||||||
*
|
*
|
||||||
|
@ -31,7 +31,7 @@ class FieldEntry extends Entry implements FieldEntryInterface
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param \Propel\PropelBundle\Model\Acl\Entry $entry
|
* @param \Propel\Bundle\PropelBundle\Model\Acl\Entry $entry
|
||||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $acl
|
* @param \Symfony\Component\Security\Acl\Model\AclInterface $acl
|
||||||
*/
|
*/
|
||||||
public function __construct(ModelEntry $entry, AclInterface $acl)
|
public function __construct(ModelEntry $entry, AclInterface $acl)
|
||||||
|
|
|
@ -8,12 +8,15 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Security\Acl\Domain;
|
namespace Propel\Bundle\PropelBundle\Security\Acl\Domain;
|
||||||
|
|
||||||
use Propel\PropelBundle\Model\Acl\Entry as ModelEntry;
|
use Propel\Runtime\Collection\ObjectCollection;
|
||||||
use Propel\PropelBundle\Model\Acl\SecurityIdentity;
|
use Propel\Runtime\Connection\ConnectionInterface;
|
||||||
use Propel\PropelBundle\Model\Acl\ObjectIdentity;
|
|
||||||
use Propel\PropelBundle\Model\Acl\ObjectIdentityQuery;
|
use Propel\Bundle\PropelBundle\Model\Acl\Entry as ModelEntry;
|
||||||
|
use Propel\Bundle\PropelBundle\Model\Acl\SecurityIdentity;
|
||||||
|
use Propel\Bundle\PropelBundle\Model\Acl\ObjectIdentity;
|
||||||
|
use Propel\Bundle\PropelBundle\Model\Acl\ObjectIdentityQuery;
|
||||||
|
|
||||||
use Symfony\Component\Security\Acl\Domain\PermissionGrantingStrategy;
|
use Symfony\Component\Security\Acl\Domain\PermissionGrantingStrategy;
|
||||||
|
|
||||||
|
@ -40,29 +43,29 @@ class MutableAcl extends Acl implements MutableAclInterface
|
||||||
/**
|
/**
|
||||||
* A reference to the ObjectIdentity this ACL is mapped to.
|
* A reference to the ObjectIdentity this ACL is mapped to.
|
||||||
*
|
*
|
||||||
* @var \Propel\PropelBundle\Model\Acl\ObjectIdentity
|
* @var \Propel\Bundle\PropelBundle\Model\Acl\ObjectIdentity
|
||||||
*/
|
*/
|
||||||
protected $modelObjectIdentity;
|
protected $modelObjectIdentity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A connection to be used for all changes on the ACL.
|
* A connection to be used for all changes on the ACL.
|
||||||
*
|
*
|
||||||
* @var \PropelPDO
|
* @var ConnectionInterface
|
||||||
*/
|
*/
|
||||||
protected $con;
|
protected $con;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param \PropelObjectCollection $entries
|
* @param ObjectCollection $entries
|
||||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||||
* @param \Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface $permissionGrantingStrategy
|
* @param \Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface $permissionGrantingStrategy
|
||||||
* @param array $loadedSecurityIdentities
|
* @param array $loadedSecurityIdentities
|
||||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $parentAcl
|
* @param \Symfony\Component\Security\Acl\Model\AclInterface $parentAcl
|
||||||
* @param bool $inherited
|
* @param bool $inherited
|
||||||
* @param \PropelPDO $con
|
* @param ConnectionInterface $con
|
||||||
*/
|
*/
|
||||||
public function __construct(\PropelObjectCollection $entries, ObjectIdentityInterface $objectIdentity, PermissionGrantingStrategyInterface $permissionGrantingStrategy, array $loadedSecurityIdentities = array(), AclInterface $parentAcl = null, $inherited = true, \PropelPDO $con = null)
|
public function __construct(ObjectCollection $entries, ObjectIdentityInterface $objectIdentity, PermissionGrantingStrategyInterface $permissionGrantingStrategy, array $loadedSecurityIdentities = array(), AclInterface $parentAcl = null, $inherited = true, ConnectionInterface $con = null)
|
||||||
{
|
{
|
||||||
parent::__construct($entries, $objectIdentity, $permissionGrantingStrategy, $loadedSecurityIdentities, $parentAcl, $inherited);
|
parent::__construct($entries, $objectIdentity, $permissionGrantingStrategy, $loadedSecurityIdentities, $parentAcl, $inherited);
|
||||||
|
|
||||||
|
@ -335,11 +338,11 @@ class MutableAcl extends Acl implements MutableAclInterface
|
||||||
/**
|
/**
|
||||||
* Insert a given entry into the list on the given index by shifting all others.
|
* Insert a given entry into the list on the given index by shifting all others.
|
||||||
*
|
*
|
||||||
* @param array $list
|
* @param array $list
|
||||||
* @param int $index
|
* @param int $index
|
||||||
* @param \Propel\PropelBundle\Model\Acl\Entry\Entry $entry
|
* @param \Propel\Bundle\PropelBundle\Model\Acl\Entry\Entry $entry
|
||||||
*
|
*
|
||||||
* @return \Propel\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
* @return \Propel\Bundle\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
||||||
*/
|
*/
|
||||||
protected function insertToList(array &$list, $index, Entry $entry)
|
protected function insertToList(array &$list, $index, Entry $entry)
|
||||||
{
|
{
|
||||||
|
@ -367,7 +370,7 @@ class MutableAcl extends Acl implements MutableAclInterface
|
||||||
* @param string $strategy
|
* @param string $strategy
|
||||||
* @param string $field
|
* @param string $field
|
||||||
*
|
*
|
||||||
* @return \Propel\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
* @return \Propel\Bundle\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
||||||
*/
|
*/
|
||||||
protected function updateAce(array &$list, $index, $mask, $strategy = null)
|
protected function updateAce(array &$list, $index, $mask, $strategy = null)
|
||||||
{
|
{
|
||||||
|
@ -394,7 +397,7 @@ class MutableAcl extends Acl implements MutableAclInterface
|
||||||
* @param array $list
|
* @param array $list
|
||||||
* @param $index
|
* @param $index
|
||||||
*
|
*
|
||||||
* @return \Propel\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
* @return \Propel\Bundle\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
||||||
*/
|
*/
|
||||||
protected function deleteIndex(array &$list, $index)
|
protected function deleteIndex(array &$list, $index)
|
||||||
{
|
{
|
||||||
|
@ -413,7 +416,7 @@ class MutableAcl extends Acl implements MutableAclInterface
|
||||||
* @param array $list
|
* @param array $list
|
||||||
* @param int $index
|
* @param int $index
|
||||||
*
|
*
|
||||||
* @return \Propel\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
* @return \Propel\Bundle\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
||||||
*/
|
*/
|
||||||
protected function isWithinBounds(array &$list, $index)
|
protected function isWithinBounds(array &$list, $index)
|
||||||
{
|
{
|
||||||
|
@ -433,7 +436,7 @@ class MutableAcl extends Acl implements MutableAclInterface
|
||||||
* @param array $list
|
* @param array $list
|
||||||
* @param $index
|
* @param $index
|
||||||
*
|
*
|
||||||
* @return \Propel\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
* @return \Propel\Bundle\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
||||||
*/
|
*/
|
||||||
protected function validateIndex(array &$list, $index)
|
protected function validateIndex(array &$list, $index)
|
||||||
{
|
{
|
||||||
|
@ -452,7 +455,7 @@ class MutableAcl extends Acl implements MutableAclInterface
|
||||||
* @param array $list
|
* @param array $list
|
||||||
* @param string $field
|
* @param string $field
|
||||||
*
|
*
|
||||||
* @return \Propel\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
* @return \Propel\Bundle\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
||||||
*/
|
*/
|
||||||
protected function validateField(array &$list, $field)
|
protected function validateField(array &$list, $field)
|
||||||
{
|
{
|
||||||
|
@ -469,7 +472,7 @@ class MutableAcl extends Acl implements MutableAclInterface
|
||||||
* @param array $list
|
* @param array $list
|
||||||
* @param int $index The right boundary to which the list is valid.
|
* @param int $index The right boundary to which the list is valid.
|
||||||
*
|
*
|
||||||
* @return \Propel\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
* @return \Propel\Bundle\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
||||||
*/
|
*/
|
||||||
protected function reorderList(array &$list, $index)
|
protected function reorderList(array &$list, $index)
|
||||||
{
|
{
|
||||||
|
@ -491,7 +494,7 @@ class MutableAcl extends Acl implements MutableAclInterface
|
||||||
* @param bool $granting
|
* @param bool $granting
|
||||||
* @param string $field
|
* @param string $field
|
||||||
*
|
*
|
||||||
* @return \Propel\PropelBundle\Security\Acl\Domain\Entry|\Propel\PropelBundle\Security\Acl\Domain\FieldEntry
|
* @return \Propel\Bundle\PropelBundle\Security\Acl\Domain\Entry|\Propel\Bundle\PropelBundle\Security\Acl\Domain\FieldEntry
|
||||||
*/
|
*/
|
||||||
protected function createAce($mask, $index, SecurityIdentityInterface $securityIdentity, $strategy = null, $granting = true, $field = null)
|
protected function createAce($mask, $index, SecurityIdentityInterface $securityIdentity, $strategy = null, $granting = true, $field = null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,18 +8,24 @@
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Propel\PropelBundle\Security\Acl;
|
namespace Propel\Bundle\PropelBundle\Security\Acl;
|
||||||
|
|
||||||
use Propel\PropelBundle\Model\Acl\Entry as ModelEntry;
|
use Propel\Runtime\ActiveQuery\Criteria;
|
||||||
use Propel\PropelBundle\Model\Acl\EntryPeer;
|
use Propel\Runtime\Collection\ObjectCollection;
|
||||||
use Propel\PropelBundle\Model\Acl\EntryQuery;
|
use Propel\Runtime\Connection\ConnectionInterface;
|
||||||
use Propel\PropelBundle\Model\Acl\SecurityIdentity;
|
use Propel\Runtime\Propel;
|
||||||
use Propel\PropelBundle\Model\Acl\ObjectIdentity;
|
use Propel\Runtime\ServiceContainer\ServiceContainerInterface;
|
||||||
use Propel\PropelBundle\Model\Acl\ObjectIdentityQuery;
|
|
||||||
|
|
||||||
use Propel\PropelBundle\Security\Acl\Domain\Acl;
|
use Propel\Bundle\PropelBundle\Model\Acl\Entry as ModelEntry;
|
||||||
use Propel\PropelBundle\Security\Acl\Domain\MutableAcl;
|
use Propel\Bundle\PropelBundle\Model\Acl\Map\EntryTableMap;
|
||||||
use Propel\PropelBundle\Security\Acl\Domain\Entry;
|
use Propel\Bundle\PropelBundle\Model\Acl\EntryQuery;
|
||||||
|
use Propel\Bundle\PropelBundle\Model\Acl\SecurityIdentity;
|
||||||
|
use Propel\Bundle\PropelBundle\Model\Acl\ObjectIdentity;
|
||||||
|
use Propel\Bundle\PropelBundle\Model\Acl\ObjectIdentityQuery;
|
||||||
|
|
||||||
|
use Propel\Bundle\PropelBundle\Security\Acl\Domain\Acl;
|
||||||
|
use Propel\Bundle\PropelBundle\Security\Acl\Domain\MutableAcl;
|
||||||
|
use Propel\Bundle\PropelBundle\Security\Acl\Domain\Entry;
|
||||||
|
|
||||||
use Symfony\Component\Security\Acl\Exception\AclAlreadyExistsException;
|
use Symfony\Component\Security\Acl\Exception\AclAlreadyExistsException;
|
||||||
use Symfony\Component\Security\Acl\Exception\Exception as AclException;
|
use Symfony\Component\Security\Acl\Exception\Exception as AclException;
|
||||||
|
@ -45,14 +51,14 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param \Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface $permissionGrantingStrategy
|
* @param \Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface $permissionGrantingStrategy
|
||||||
* @param \PropelPDO $connection
|
* @param ConnectionInterface $connection
|
||||||
* @param \Symfony\Component\Security\Acl\Model\AclCacheInterface $cache
|
* @param \Symfony\Component\Security\Acl\Model\AclCacheInterface $cache
|
||||||
*/
|
*/
|
||||||
public function __construct(PermissionGrantingStrategyInterface $permissionGrantingStrategy, \PropelPDO $connection = null, AclCacheInterface $cache = null)
|
public function __construct(PermissionGrantingStrategyInterface $permissionGrantingStrategy, ConnectionInterface $connection = null, AclCacheInterface $cache = null)
|
||||||
{
|
{
|
||||||
// @codeCoverageIgnoreStart
|
// @codeCoverageIgnoreStart
|
||||||
if (null === $connection) {
|
if (null === $connection) {
|
||||||
$connection = \Propel::getConnection(EntryPeer::DATABASE_NAME, \Propel::CONNECTION_WRITE);
|
$connection = Propel::getConnection(EntryTableMap::DATABASE_NAME, ServiceContainerInterface::CONNECTION_WRITE);
|
||||||
}
|
}
|
||||||
// @codeCoverageIgnoreEnd
|
// @codeCoverageIgnoreEnd
|
||||||
|
|
||||||
|
@ -66,7 +72,7 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
|
||||||
*
|
*
|
||||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||||
*
|
*
|
||||||
* @return \Propel\PropelBundle\Security\Acl\Domain\MutableAcl
|
* @return \Propel\Bundle\PropelBundle\Security\Acl\Domain\MutableAcl
|
||||||
*/
|
*/
|
||||||
public function createAcl(ObjectIdentityInterface $objectIdentity)
|
public function createAcl(ObjectIdentityInterface $objectIdentity)
|
||||||
{
|
{
|
||||||
|
@ -163,7 +169,7 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
|
||||||
public function updateAcl(MutableAclInterface $acl)
|
public function updateAcl(MutableAclInterface $acl)
|
||||||
{
|
{
|
||||||
if (!$acl instanceof MutableAcl) {
|
if (!$acl instanceof MutableAcl) {
|
||||||
throw new \InvalidArgumentException('The given ACL is not tracked by this provider. Please provide \Propel\PropelBundle\Security\Acl\Domain\MutableAcl only.');
|
throw new \InvalidArgumentException('The given ACL is not tracked by this provider. Please provide \Propel\Bundle\PropelBundle\Security\Acl\Domain\MutableAcl only.');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -184,7 +190,7 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($modelEntries as &$eachEntry) {
|
foreach ($modelEntries as $eachEntry) {
|
||||||
if (!in_array($eachEntry->getId(), $keepEntries)) {
|
if (!in_array($eachEntry->getId(), $keepEntries)) {
|
||||||
$eachEntry->delete($this->connection);
|
$eachEntry->delete($this->connection);
|
||||||
}
|
}
|
||||||
|
@ -223,9 +229,9 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
|
||||||
/**
|
/**
|
||||||
* Persist the given ACEs.
|
* Persist the given ACEs.
|
||||||
*
|
*
|
||||||
* @param array $accessControlEntries
|
* @param array $accessControlEntries
|
||||||
* @param \Propel\PropelBundle\Model\Acl\ObjectIdentity $objectIdentity
|
* @param \Propel\Bundle\PropelBundle\Model\Acl\ObjectIdentity $objectIdentity
|
||||||
* @param bool $object
|
* @param bool $object
|
||||||
*
|
*
|
||||||
* @return array The IDs of the persisted ACEs.
|
* @return array The IDs of the persisted ACEs.
|
||||||
*/
|
*/
|
||||||
|
@ -280,7 +286,7 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
|
||||||
*
|
*
|
||||||
* @param \Symfony\Component\Security\Acl\Model\EntryInterface $ace
|
* @param \Symfony\Component\Security\Acl\Model\EntryInterface $ace
|
||||||
*
|
*
|
||||||
* @return \Propel\PropelBundle\Model\Acl\Entry|null
|
* @return \Propel\Bundle\PropelBundle\Model\Acl\Entry|null
|
||||||
*/
|
*/
|
||||||
protected function getPersistedAce(EntryInterface $ace, ObjectIdentity $objectIdentity, $object = false)
|
protected function getPersistedAce(EntryInterface $ace, ObjectIdentity $objectIdentity, $object = false)
|
||||||
{
|
{
|
||||||
|
@ -304,13 +310,13 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
|
||||||
if (true === $object) {
|
if (true === $object) {
|
||||||
$ukQuery->filterByObjectIdentity($objectIdentity);
|
$ukQuery->filterByObjectIdentity($objectIdentity);
|
||||||
} else {
|
} else {
|
||||||
$ukQuery->filterByObjectIdentityId(null, \Criteria::ISNULL);
|
$ukQuery->filterByObjectIdentityId(null, Criteria::ISNULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($ace instanceof FieldEntryInterface) {
|
if ($ace instanceof FieldEntryInterface) {
|
||||||
$ukQuery->filterByFieldName($ace->getField());
|
$ukQuery->filterByFieldName($ace->getField());
|
||||||
} else {
|
} else {
|
||||||
$ukQuery->filterByFieldName(null, \Criteria::ISNULL);
|
$ukQuery->filterByFieldName(null, Criteria::ISNULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $ukQuery->findOne($this->connection);
|
return $ukQuery->findOne($this->connection);
|
||||||
|
@ -319,15 +325,15 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
|
||||||
/**
|
/**
|
||||||
* Get an ACL for this provider.
|
* Get an ACL for this provider.
|
||||||
*
|
*
|
||||||
* @param \PropelObjectCollection $collection
|
* @param ObjectCollection $collection
|
||||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||||
* @param array $loadedSecurityIdentities
|
* @param array $loadedSecurityIdentities
|
||||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $parentAcl
|
* @param \Symfony\Component\Security\Acl\Model\AclInterface $parentAcl
|
||||||
* @param bool $inherited
|
* @param bool $inherited
|
||||||
*
|
*
|
||||||
* @return \Propel\PropelBundle\Security\Acl\Domain\MutableAcl
|
* @return \Propel\Bundle\PropelBundle\Security\Acl\Domain\MutableAcl
|
||||||
*/
|
*/
|
||||||
protected function getAcl(\PropelObjectCollection $collection, ObjectIdentityInterface $objectIdentity, array $loadedSecurityIdentities = array(), AclInterface $parentAcl = null, $inherited = true)
|
protected function getAcl(ObjectCollection $collection, ObjectIdentityInterface $objectIdentity, array $loadedSecurityIdentities = array(), AclInterface $parentAcl = null, $inherited = true)
|
||||||
{
|
{
|
||||||
return new MutableAcl($collection, $objectIdentity, $this->permissionGrantingStrategy, $loadedSecurityIdentities, $parentAcl, $inherited, $this->connection);
|
return new MutableAcl($collection, $objectIdentity, $this->permissionGrantingStrategy, $loadedSecurityIdentities, $parentAcl, $inherited, $this->connection);
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue