Compare commits
No commits in common. "1.2.13" and "4.0" have entirely different histories.
14
.gitignore
vendored
14
.gitignore
vendored
|
@ -1,5 +1,9 @@
|
|||
Model/*/map
|
||||
Model/*/om
|
||||
vendor
|
||||
composer.lock
|
||||
composer.phar
|
||||
# Propel2 generated base classes, those are environment dependent
|
||||
/Model/Base
|
||||
/Model/Map
|
||||
/Model/**/Base
|
||||
/Model/**/Map
|
||||
|
||||
# Composer
|
||||
/vendor
|
||||
/composer.lock
|
||||
|
|
37
.travis.yml
37
.travis.yml
|
@ -1,22 +1,33 @@
|
|||
sudo: false
|
||||
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 7.0
|
||||
- 7.1
|
||||
- 7.2
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache/files
|
||||
|
||||
env:
|
||||
- SYMFONY_VERSION=2.2.*
|
||||
- SYMFONY_VERSION=2.3.*
|
||||
- SYMFONY_VERSION=dev-master
|
||||
- SYMFONY_VERSION="^3.0"
|
||||
- SYMFONY_VERSION="^4.0"
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- php: 5.5
|
||||
fast_finish: true
|
||||
|
||||
before_script:
|
||||
- curl -s http://getcomposer.org/installer | php
|
||||
- php composer.phar require symfony/symfony:${SYMFONY_VERSION} --no-update
|
||||
- php composer.phar --dev install
|
||||
exclude:
|
||||
- php: 7.0
|
||||
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,101 +8,55 @@
|
|||
* @license MIT License
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\Command;
|
||||
namespace Propel\Bundle\PropelBundle\Command;
|
||||
|
||||
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\Output\OutputInterface;
|
||||
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\BundleInterface;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
/**
|
||||
* Wrapper for Propel commands.
|
||||
*
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author William DURAND <william.durand1@gmail.com>
|
||||
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||
*/
|
||||
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
|
||||
*/
|
||||
protected $cacheDir = null;
|
||||
|
||||
/**
|
||||
* The Phing output.
|
||||
* @string
|
||||
*/
|
||||
protected $buffer = null;
|
||||
|
||||
/**
|
||||
* @var Symfony\Component\HttpKernel\Bundle\BundleInterface
|
||||
* @var \Symfony\Component\HttpKernel\Bundle\BundleInterface
|
||||
*/
|
||||
protected $bundle = null;
|
||||
|
||||
/**
|
||||
* @var Boolean
|
||||
*/
|
||||
private $alreadyWroteConnection = false;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var InputInterface
|
||||
*/
|
||||
protected $input;
|
||||
|
||||
/**
|
||||
* Return the package prefix for a given bundle.
|
||||
*
|
||||
* @param Bundle $bundle
|
||||
* @param string $baseDirectory The base directory to exclude from prefix.
|
||||
*
|
||||
* @return string
|
||||
* @var OutputInterface
|
||||
*/
|
||||
protected function getPackagePrefix(Bundle $bundle, $baseDirectory = '')
|
||||
{
|
||||
$parts = explode(DIRECTORY_SEPARATOR, realpath($bundle->getPath()));
|
||||
$length = count(explode('\\', $bundle->getNamespace())) * (-1);
|
||||
protected $output;
|
||||
|
||||
$prefix = implode(DIRECTORY_SEPARATOR, array_slice($parts, 0, $length));
|
||||
$prefix = ltrim(str_replace($baseDirectory, '', $prefix), DIRECTORY_SEPARATOR);
|
||||
|
||||
if (!empty($prefix)) {
|
||||
$prefix = str_replace(DIRECTORY_SEPARATOR, '.', $prefix).'.';
|
||||
}
|
||||
|
||||
return $prefix;
|
||||
}
|
||||
use FormattingHelpers;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
parent::initialize($input, $output);
|
||||
|
||||
if ($input->getOption('verbose')) {
|
||||
$this->additionalPhingArgs[] = 'verbose';
|
||||
}
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
|
||||
$this->input = $input;
|
||||
|
||||
$this->checkConfiguration();
|
||||
$this->output = $output;
|
||||
$this->cacheDir = $kernel->getCacheDir().'/propel';
|
||||
|
||||
if ($input->hasArgument('bundle') && '@' === substr($input->getArgument('bundle'), 0, 1)) {
|
||||
$this->bundle = $this
|
||||
|
@ -113,112 +67,42 @@ abstract class AbstractCommand extends ContainerAwareCommand
|
|||
}
|
||||
|
||||
/**
|
||||
* Call a Phing task.
|
||||
*
|
||||
* @param string $taskName A Propel task name.
|
||||
* @param array $properties An array of properties to pass to Phing.
|
||||
* Create all the files needed by Propel's commands.
|
||||
*/
|
||||
protected function callPhing($taskName, $properties = array())
|
||||
protected function setupBuildTimeFiles()
|
||||
{
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
|
||||
if (isset($properties['propel.schema.dir'])) {
|
||||
$this->cacheDir = $properties['propel.schema.dir'];
|
||||
} else {
|
||||
$this->cacheDir = $kernel->getCacheDir().'/propel';
|
||||
|
||||
$filesystem = new Filesystem();
|
||||
$filesystem->remove($this->cacheDir);
|
||||
$filesystem->mkdir($this->cacheDir);
|
||||
}
|
||||
$fs = new Filesystem();
|
||||
$fs->mkdir($this->cacheDir);
|
||||
|
||||
// collect all schemas
|
||||
$this->copySchemas($kernel, $this->cacheDir);
|
||||
|
||||
// build.properties
|
||||
$this->createBuildPropertiesFile($kernel, $this->cacheDir.'/build.properties');
|
||||
|
||||
// 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;
|
||||
// propel.json
|
||||
$this->createPropelConfigurationFile($this->cacheDir.'/propel.json');
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
$filesystem = new Filesystem();
|
||||
|
||||
if (!is_dir($cacheDir)) {
|
||||
$filesystem->mkdir($cacheDir);
|
||||
}
|
||||
|
||||
$base = ltrim(realpath($kernel->getRootDir().'/..'), DIRECTORY_SEPARATOR);
|
||||
|
||||
$finalSchemas = $this->getFinalSchemas($kernel, $this->bundle);
|
||||
foreach ($finalSchemas as $schema) {
|
||||
/** @var null|Bundle $bundle */
|
||||
list($bundle, $finalSchema) = $schema;
|
||||
$packagePrefix = $this->getPackagePrefix($bundle, $base);
|
||||
|
||||
$tempSchema = $bundle->getName().'-'.$finalSchema->getBaseName();
|
||||
$this->tempSchemas[$tempSchema] = array(
|
||||
'bundle' => $bundle->getName(),
|
||||
'basename' => $finalSchema->getBaseName(),
|
||||
'path' => $finalSchema->getPathname(),
|
||||
);
|
||||
if ($bundle) {
|
||||
$file = $cacheDir.DIRECTORY_SEPARATOR.'bundle-'.$bundle->getName().'-'.$finalSchema->getBaseName();
|
||||
} else {
|
||||
$file = $cacheDir.DIRECTORY_SEPARATOR.'app-'.$finalSchema->getBaseName();
|
||||
}
|
||||
|
||||
$file = $cacheDir.DIRECTORY_SEPARATOR.$tempSchema;
|
||||
$filesystem->copy((string) $finalSchema, $file, true);
|
||||
|
||||
// the package needs to be set absolute
|
||||
|
@ -231,27 +115,47 @@ abstract class AbstractCommand extends ContainerAwareCommand
|
|||
// This is used to override the package resulting from namespace conversion.
|
||||
$database['package'] = $database['package'];
|
||||
} elseif (isset($database['namespace'])) {
|
||||
$database['package'] = $packagePrefix . str_replace('\\', '.', $database['namespace']);
|
||||
if ($bundle) {
|
||||
$database['package'] = $this->getPackageFromBundle($bundle, (string)$database['namespace']);
|
||||
} else {
|
||||
$database['package'] = $this->getPackageFromApp((string)$database['namespace']);
|
||||
}
|
||||
} else {
|
||||
throw new \RuntimeException(
|
||||
sprintf('%s : Please define a `package` attribute or a `namespace` attribute for schema `%s`',
|
||||
$bundle->getName(), $finalSchema->getBaseName())
|
||||
sprintf(
|
||||
'%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')
|
||||
&& $database['name'] != $this->input->getOption('connection')) {
|
||||
//we skip this schema because the connection name doesn't match the input value
|
||||
unset($this->tempSchemas[$tempSchema]);
|
||||
$filesystem->remove($file);
|
||||
continue;
|
||||
if ($this->input->hasOption('connection')) {
|
||||
$connections = $this->input->getOption('connection') ?: array($this->getDefaultConnection());
|
||||
|
||||
if (!in_array((string) $database['name'], $connections)) {
|
||||
// we skip this schema because the connection name doesn't
|
||||
// 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) {
|
||||
if (isset($table['package'])) {
|
||||
$table['package'] = $table['package'];
|
||||
} 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 {
|
||||
$table['package'] = $database['package'];
|
||||
}
|
||||
|
@ -264,167 +168,204 @@ abstract class AbstractCommand extends ContainerAwareCommand
|
|||
/**
|
||||
* 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)
|
||||
{
|
||||
if (null !== $bundle) {
|
||||
return $this->getSchemasFromBundle($bundle);
|
||||
return $this->getSchemaLocator()->locateFromBundle($bundle);
|
||||
}
|
||||
|
||||
$finalSchemas = array();
|
||||
foreach ($kernel->getBundles() as $bundle) {
|
||||
$finalSchemas = array_merge($finalSchemas, $this->getSchemasFromBundle($bundle));
|
||||
}
|
||||
|
||||
return $finalSchemas;
|
||||
return $this->getSchemaLocator()->locateFromBundlesAndConfiguration($kernel->getBundles());
|
||||
}
|
||||
|
||||
/**
|
||||
* @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')) {
|
||||
$finder = new Finder();
|
||||
$schemas = $finder->files()->name('*schema.xml')->followLinks()->in($dir);
|
||||
// merge the default parameters
|
||||
$extraParameters = [
|
||||
'--verbose' => $input->getOption('verbose')
|
||||
];
|
||||
|
||||
if (iterator_count($schemas)) {
|
||||
foreach ($schemas as $schema) {
|
||||
$logicalName = $this->transformToLogicalName($schema, $bundle);
|
||||
$finalSchema = new \SplFileInfo($this->getFileLocator()->locate($logicalName));
|
||||
if ($command->getDefinition()->hasOption('schema-dir')) {
|
||||
$extraParameters['--schema-dir'] = $this->cacheDir;
|
||||
}
|
||||
|
||||
$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());
|
||||
|
||||
/**
|
||||
* @param \SplFileInfo $file
|
||||
* @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);
|
||||
}
|
||||
// and run the sub-command
|
||||
return $command->run(new ArrayInput($parameters), $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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')) {
|
||||
throw new \InvalidArgumentException('Could not find Propel configuration.');
|
||||
}
|
||||
//needed because because Propel2's configuration tree is a bit different
|
||||
//propel.runtime.logging is PropelBundle feature only.
|
||||
unset($propelConfig['runtime']['logging']);
|
||||
|
||||
$xml = strtr(<<<EOT
|
||||
<?xml version="1.0"?>
|
||||
<config>
|
||||
<propel>
|
||||
<datasources default="%default_connection%">
|
||||
$config = array(
|
||||
'propel' => $propelConfig
|
||||
);
|
||||
|
||||
EOT
|
||||
, 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);
|
||||
file_put_contents($file, json_encode($config, JSON_PRETTY_PRINT));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @return array An array of properties as key/value pairs.
|
||||
* @param array $connections The names.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getProperties($file)
|
||||
protected function getConnections(array $connections)
|
||||
{
|
||||
$properties = array();
|
||||
|
||||
if (false === $lines = @file($file)) {
|
||||
throw new \Exception(sprintf('Unable to parse contents of "%s".', $file));
|
||||
$dsnList = array();
|
||||
foreach ($connections as $connection) {
|
||||
$dsnList[] = sprintf('%s=%s', $connection, $this->getDsn($connection));
|
||||
}
|
||||
|
||||
foreach ($lines as $line) {
|
||||
$line = trim($line);
|
||||
return $dsnList;
|
||||
}
|
||||
|
||||
if ('' == $line || in_array($line[0], array('#', ';'))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$pos = strpos($line, '=');
|
||||
$property = trim(substr($line, 0, $pos));
|
||||
$value = trim(substr($line, $pos + 1));
|
||||
|
||||
if ("true" === $value) {
|
||||
$value = true;
|
||||
} elseif ("false" === $value) {
|
||||
$value = false;
|
||||
}
|
||||
|
||||
$properties[$property] = $value;
|
||||
/**
|
||||
* Get the data (host, user, ...) for a given connection.
|
||||
*
|
||||
* @param string $name The connection name.
|
||||
*
|
||||
* @return array The connection data.
|
||||
*/
|
||||
protected function getConnectionData($name)
|
||||
{
|
||||
$knownConnections = $this->getContainer()->getParameter('propel.configuration');
|
||||
if (!isset($knownConnections['database']['connections'][$name])) {
|
||||
throw new \InvalidArgumentException(sprintf('Unknown connection "%s"', $name));
|
||||
}
|
||||
|
||||
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 string The current Propel cache directory.
|
||||
*/
|
||||
protected function getCacheDir()
|
||||
|
@ -433,47 +374,29 @@ EOT;
|
|||
}
|
||||
|
||||
/**
|
||||
* @return \Symfony\Component\Config\FileLocatorInterface
|
||||
*/
|
||||
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.
|
||||
* Returns a relative path from $path to $current.
|
||||
*
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @throw \InvalidArgumentException If the connection does not exist.
|
||||
* @return array
|
||||
* @param string $from
|
||||
* @param string $to relative to this
|
||||
*
|
||||
* @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');
|
||||
$name = $input->getOption('connection') ?: $this->getContainer()->getParameter('propel.dbal.default_connection');
|
||||
$from = '/' . trim($from, '/');
|
||||
$to = '/' . trim($to, '/');
|
||||
|
||||
if (isset($propelConfiguration['datasources'][$name])) {
|
||||
$defaultConfig = $propelConfiguration['datasources'][$name];
|
||||
} else {
|
||||
throw new \InvalidArgumentException(sprintf('Connection named %s doesn\'t exist', $name));
|
||||
if (0 === $pos = strpos($from, $to)) {
|
||||
return substr($from, strlen($to) + ('/' === $to ? 0 : 1));
|
||||
}
|
||||
|
||||
if (false === $this->alreadyWroteConnection) {
|
||||
$output->writeln(sprintf('Use connection named <comment>%s</comment> in <comment>%s</comment> environment.',
|
||||
$name, $this->getApplication()->getKernel()->getEnvironment())
|
||||
);
|
||||
$this->alreadyWroteConnection = true;
|
||||
$result = '';
|
||||
while ($to && false === strpos($from, $to)) {
|
||||
$result .= '../';
|
||||
$to = substr($to, 0, strrpos($to, '/'));
|
||||
}
|
||||
|
||||
// prevent errors
|
||||
if (!isset($defaultConfig['connection']['password'])) {
|
||||
$defaultConfig['connection']['password'] = null;
|
||||
}
|
||||
|
||||
return array($name, $defaultConfig);
|
||||
return !$to /*we reached root*/ ? $result . substr($from, 1) : $result. substr($from, strlen($to) + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -484,10 +407,10 @@ EOT;
|
|||
*/
|
||||
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])) {
|
||||
return $matches[1];
|
||||
if (isset($matches[2])) {
|
||||
return $matches[2];
|
||||
}
|
||||
|
||||
// e.g. SQLite
|
||||
|
@ -495,158 +418,37 @@ EOT;
|
|||
}
|
||||
|
||||
/**
|
||||
* Check the PropelConfiguration object.
|
||||
*/
|
||||
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.
|
||||
* Returns the name of the migrations table.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
protected function transformToLogicalName(\SplFileInfo $schema, BundleInterface $bundle)
|
||||
protected function getMigrationsTable()
|
||||
{
|
||||
$schemaPath = str_replace(
|
||||
$bundle->getPath(). DIRECTORY_SEPARATOR . 'Resources' . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR,
|
||||
'',
|
||||
$schema->getRealPath()
|
||||
);
|
||||
$config = $this->getContainer()->getParameter('propel.configuration');
|
||||
|
||||
return sprintf('@%s/Resources/config/%s', $bundle->getName(), $schemaPath);
|
||||
return $config['migrations']['tableName'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles arguments/properties for the Phing process.
|
||||
* @return array
|
||||
* Returns the name of the default connection.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getPhingArguments(KernelInterface $kernel, $workingDirectory, $properties)
|
||||
protected function getDefaultConnection()
|
||||
{
|
||||
$args = array();
|
||||
$config = $this->getContainer()->getParameter('propel.configuration');
|
||||
|
||||
// Default properties
|
||||
$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);
|
||||
return !empty($config['generator']['defaultConnection']) ? $config['generator']['defaultConnection'] : key($config['database']['connections']);
|
||||
}
|
||||
|
||||
// Adding user defined properties from the configuration
|
||||
$properties = array_merge(
|
||||
$properties,
|
||||
$this->getContainer()->get('propel.build_properties')->getProperties()
|
||||
);
|
||||
|
||||
foreach ($properties as $key => $value) {
|
||||
$args[] = "-D$key=$value";
|
||||
}
|
||||
|
||||
// Build file
|
||||
$args[] = '-f';
|
||||
$args[] = realpath($this->getContainer()->getParameter('propel.path').'/generator/build.xml');
|
||||
|
||||
return $args;
|
||||
/**
|
||||
* Reads the platform class from the configuration
|
||||
*
|
||||
* @return string The platform class name.
|
||||
*/
|
||||
protected function getPlatform()
|
||||
{
|
||||
$config = $this->getContainer()->getParameter('propel.configuration');
|
||||
return $config['generator']['platformClass'];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,27 +8,26 @@
|
|||
* @license MIT License
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\Command;
|
||||
namespace Propel\Bundle\PropelBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Output\Output;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
/**
|
||||
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||
*/
|
||||
class AclInitCommand extends SqlInsertCommand
|
||||
class AclInitCommand extends AbstractCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDescription('Initialize "Access Control Lists" model and SQL')
|
||||
->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
|
||||
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,51 +44,93 @@ EOT
|
|||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$outputDir = realpath($this->getApplication()->getKernel()->getRootDir().'/../');
|
||||
|
||||
// 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(
|
||||
'>> <info>%20s</info> Generated model classes from <comment>%s</comment>',
|
||||
$this->getApplication()->getKernel()->getBundle('PropelBundle')->getName(),
|
||||
'acl_schema.xml'
|
||||
));
|
||||
} else {
|
||||
$this->writeTaskError($output, 'om');
|
||||
$this->writeTaskError($output, 'model:build');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Prepare SQL directory
|
||||
$sqlDirectory = $this->getSqlDir();
|
||||
$filesystem = new Filesystem();
|
||||
$filesystem->remove($sqlDirectory);
|
||||
$filesystem->mkdir($sqlDirectory);
|
||||
// Prepare SQL
|
||||
$sqlBuildCmd = new \Propel\Generator\Command\SqlBuildCommand();
|
||||
$sqlBuildArgs = array(
|
||||
'--connection' => $this->getConnections($input->getOption('connection')),
|
||||
'--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(
|
||||
$output,
|
||||
'<comment>1</comment> <info>SQL file has been generated.</info>'
|
||||
);
|
||||
} else {
|
||||
$this->writeTaskError($output, 'build-sql');
|
||||
$this->writeTaskError($output, 'sql:build');
|
||||
|
||||
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)
|
||||
{
|
||||
$aclSchema = new \SplFileInfo($kernel->locateResource('@PropelBundle/Resources/acl_schema.xml'));
|
||||
|
||||
return array((string) $aclSchema => array($kernel->getBundle('PropelBundle'), $aclSchema));
|
||||
}
|
||||
|
||||
protected function getSqlDir()
|
||||
{
|
||||
return sprintf('%s/cache/%s/propel/acl/sql',
|
||||
$this->getApplication()->getKernel()->getRootDir(),
|
||||
$this->getApplication()->getKernel()->getEnvironment()
|
||||
return array(
|
||||
array($kernel->getBundle('PropelBundle'), $aclSchema)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\Command;
|
||||
|
||||
use Propel\PropelBundle\Command\AbstractCommand;
|
||||
namespace Propel\Bundle\PropelBundle\Command;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Output\Output;
|
||||
|
||||
/**
|
||||
* BuildCommand.
|
||||
*
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author William DURAND <william.durand1@gmail.com>
|
||||
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||
*/
|
||||
class BuildCommand extends AbstractCommand
|
||||
class BuildCommand extends ContainerAwareCommand
|
||||
{
|
||||
/**
|
||||
* @see Command
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('propel:build')
|
||||
->setDescription('Hub for Propel build commands (Model classes, SQL)')
|
||||
|
||||
->setDefinition(array(
|
||||
new InputOption('classes', '', InputOption::VALUE_NONE, 'Build only classes'),
|
||||
new InputOption('sql', '', InputOption::VALUE_NONE, 'Build only 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,33 +48,33 @@ class BuildCommand extends AbstractCommand
|
|||
{
|
||||
if (!$input->getOption('sql')) {
|
||||
$in = new ArrayInput(array(
|
||||
'command' => 'propel:model:build',
|
||||
'--connection' => $input->getOption('connection'),
|
||||
'--verbose' => $input->getOption('verbose'),
|
||||
'command' => 'propel:model:build',
|
||||
'--connection' => $input->getOption('connection'),
|
||||
'--verbose' => $input->getOption('verbose')
|
||||
));
|
||||
$modelCommand = $this->getApplication()->find('propel:model:build');
|
||||
$res = $modelCommand->run($in, $output);
|
||||
$cmd = $this->getApplication()->find('propel:model:build');
|
||||
$cmd->run($in, $output);
|
||||
}
|
||||
|
||||
if (!$input->getOption('classes')) {
|
||||
$in = new ArrayInput(array(
|
||||
'command' => 'propel:build:sql',
|
||||
'--connection' => $input->getOption('connection'),
|
||||
'--verbose' => $input->getOption('verbose'),
|
||||
'command' => 'propel:build:sql',
|
||||
'--connection' => $input->getOption('connection'),
|
||||
'--verbose' => $input->getOption('verbose'),
|
||||
));
|
||||
$sqlCommand = $this->getApplication()->find('propel:sql:build');
|
||||
$sqlCommand->run($in, $output);
|
||||
$cmd = $this->getApplication()->find('propel:sql:build');
|
||||
$cmd->run($in, $output);
|
||||
}
|
||||
|
||||
if ($input->getOption('insert-sql')) {
|
||||
$in = new ArrayInput(array(
|
||||
'command' => 'propel:sql:insert',
|
||||
'--connection' => $input->getOption('connection'),
|
||||
'--verbose' => $input->getOption('verbose'),
|
||||
'--force' => true,
|
||||
'command' => 'propel:sql:insert',
|
||||
'--connection' => $input->getOption('connection'),
|
||||
'--force' => true,
|
||||
'--verbose' => $input->getOption('verbose'),
|
||||
));
|
||||
$insertCommand = $this->getApplication()->find('propel:sql:insert');
|
||||
$insertCommand->run($in, $output);
|
||||
$cmd = $this->getApplication()->find('propel:sql:insert');
|
||||
$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
|
||||
*/
|
||||
|
||||
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\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
@ -29,9 +30,11 @@ class DatabaseCreateCommand extends AbstractCommand
|
|||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('propel:database:create')
|
||||
->setDescription('Create a given database or the default one.')
|
||||
|
||||
->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)
|
||||
{
|
||||
list($name, $config) = $this->getConnection($input, $output);
|
||||
$dbName = $this->parseDbName($config['connection']['dsn']);
|
||||
$connectionName = $input->getOption('connection') ?: $this->getDefaultConnection();
|
||||
$config = $this->getConnectionData($connectionName);
|
||||
$dbName = $this->parseDbName($config['dsn']);
|
||||
|
||||
if (null === $dbName) {
|
||||
return $output->writeln('<error>No database name found.</error>');
|
||||
|
@ -50,21 +54,19 @@ class DatabaseCreateCommand extends AbstractCommand
|
|||
$query = 'CREATE DATABASE '. $dbName .';';
|
||||
}
|
||||
|
||||
try {
|
||||
\Propel::setConfiguration($this->getTemporaryConfiguration($name, $config));
|
||||
$connection = \Propel::getConnection($name);
|
||||
$manager = new ConnectionManagerSingle();
|
||||
$manager->setConfiguration($this->getTemporaryConfiguration($config));
|
||||
|
||||
$statement = $connection->prepare($query);
|
||||
$statement->execute();
|
||||
$serviceContainer = Propel::getServiceContainer();
|
||||
$serviceContainer->setAdapterClass($connectionName, $config['adapter']);
|
||||
$serviceContainer->setConnectionManager($connectionName, $manager);
|
||||
|
||||
$output->writeln(sprintf('<info>Database <comment>%s</comment> has been created.</info>', $dbName));
|
||||
} catch (\Exception $e) {
|
||||
$this->writeSection($output, array(
|
||||
'[Propel] Exception caught',
|
||||
'',
|
||||
$e->getMessage()
|
||||
), 'fg=white;bg=red');
|
||||
}
|
||||
$connection = Propel::getConnection($connectionName);
|
||||
|
||||
$statement = $connection->prepare($query);
|
||||
$statement->execute();
|
||||
|
||||
$output->writeln(sprintf('<info>Database <comment>%s</comment> has been created.</info>', $dbName));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,22 +75,19 @@ class DatabaseCreateCommand extends AbstractCommand
|
|||
*
|
||||
* @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
|
||||
*/
|
||||
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(
|
||||
'#dbname='.$dbName.';#',
|
||||
$config['dsn'] = preg_replace(
|
||||
'#;?(dbname|Database)='.$dbName.'#',
|
||||
'',
|
||||
$config['connection']['dsn']
|
||||
$config['dsn']
|
||||
);
|
||||
|
||||
return array(
|
||||
'datasources' => array($name => $config)
|
||||
);
|
||||
return $config;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,12 +8,13 @@
|
|||
* @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\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Propel\Runtime\Connection\ConnectionManagerSingle;
|
||||
|
||||
/**
|
||||
* DatabaseDropCommand class.
|
||||
|
@ -24,14 +25,13 @@ use Symfony\Component\Console\Input\InputOption;
|
|||
class DatabaseDropCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* @see Command
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('propel:database:drop')
|
||||
->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
|
||||
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).
|
||||
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
|
||||
*
|
||||
* @throws \InvalidArgumentException When the target directory does not exist
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
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 {
|
||||
if (!$input->getOption('force')) {
|
||||
$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,10 +8,8 @@
|
|||
* @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\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
@ -28,7 +26,7 @@ class FixturesDumpCommand extends AbstractCommand
|
|||
* Default fixtures directory.
|
||||
* @var string
|
||||
*/
|
||||
private $defaultFixturesDir = 'app/propel/fixtures';
|
||||
protected $defaultFixturesDir = 'app/propel/fixtures';
|
||||
|
||||
/**
|
||||
* @see Command
|
||||
|
@ -36,9 +34,8 @@ class FixturesDumpCommand extends AbstractCommand
|
|||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('propel:fixtures:dump')
|
||||
->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
|
||||
The <info>propel:fixtures:dump</info> dumps data from database into YAML fixtures file.
|
||||
|
||||
|
@ -49,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).
|
||||
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
|
||||
*
|
||||
* @throws \InvalidArgumentException When the target directory does not exist
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
list($name, $defaultConfig) = $this->getConnection($input, $output);
|
||||
$fixtureDir = $input->getOption('dir') ? $input->getOption('dir') : $this->defaultFixturesDir;
|
||||
|
||||
$fixtureDir = $input->getOption('dir') ?: $this->defaultFixturesDir;
|
||||
$path = realpath($this->getApplication()->getKernel()->getRootDir() . '/../') . '/' . $fixtureDir;
|
||||
|
||||
if (!file_exists($path)) {
|
||||
$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->mkdir($path);
|
||||
$this->writeNewDirectory($output, $path);
|
||||
} else {
|
||||
throw new \IOException(sprintf('Unable to find the %s folder', $path));
|
||||
}
|
||||
}
|
||||
|
||||
$filename = $path . '/fixtures_' . time() . '.yml';
|
||||
$dumper = $this->getContainer()->get('propel.dumper.yaml');
|
||||
|
||||
$dumper = new YamlDataDumper($this->getApplication()->getKernel()->getRootDir());
|
||||
|
||||
try {
|
||||
$dumper->dump($filename, $name);
|
||||
} catch (\Exception $e) {
|
||||
$this->writeSection($output, array(
|
||||
'[Propel] Exception',
|
||||
'',
|
||||
$e->getMessage()), 'fg=white;bg=red');
|
||||
|
||||
return false;
|
||||
}
|
||||
$dumper->dump($filename, $input->getOption('connection'));
|
||||
|
||||
$this->writeNewFile($output, $filename);
|
||||
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
* @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\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
@ -18,10 +19,6 @@ use Symfony\Component\Filesystem\Filesystem;
|
|||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
||||
|
||||
use Propel\PropelBundle\Command\AbstractCommand;
|
||||
use Propel\PropelBundle\DataFixtures\Loader\YamlDataLoader;
|
||||
use Propel\PropelBundle\DataFixtures\Loader\XmlDataLoader;
|
||||
|
||||
/**
|
||||
* FixturesLoadCommand
|
||||
*
|
||||
|
@ -53,17 +50,8 @@ class FixturesLoadCommand extends AbstractCommand
|
|||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('propel:fixtures:load')
|
||||
->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
|
||||
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>
|
||||
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
|
||||
*
|
||||
* @throws \InvalidArgumentException When the target directory does not exist
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
|
@ -132,7 +128,7 @@ EOT
|
|||
), '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 (-1 === $this->loadSqlFixtures($input, $output)) {
|
||||
|
@ -156,9 +152,9 @@ EOT
|
|||
/**
|
||||
* Load fixtures
|
||||
*
|
||||
* @param \Symfony\Component\Console\Input\InputInterface $input
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
* @return void
|
||||
* @param \Symfony\Component\Console\Input\InputInterface $input
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
* @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)
|
||||
{
|
||||
|
@ -172,26 +168,17 @@ EOT
|
|||
return -1;
|
||||
}
|
||||
|
||||
list($name, $defaultConfig) = $this->getConnection($input, $output);
|
||||
$connectionName = $input->getOption('connection') ?: $this->getDefaultConnection();
|
||||
|
||||
if ('yml' === $type) {
|
||||
$loader = new YamlDataLoader($this->getApplication()->getKernel()->getRootDir(), $this->getContainer());
|
||||
$loader = $this->getContainer()->get('propel.loader.yaml');
|
||||
} elseif ('xml' === $type) {
|
||||
$loader = new XmlDataLoader($this->getApplication()->getKernel()->getRootDir());
|
||||
$loader = $this->getContainer()->get('propel.loader.xml');
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$nb = $loader->load($datas, $name);
|
||||
} catch (\Exception $e) {
|
||||
$this->writeSection($output, array(
|
||||
'[Propel] Exception',
|
||||
'',
|
||||
$e->getMessage()), 'fg=white;bg=red');
|
||||
|
||||
return false;
|
||||
}
|
||||
$nb = $loader->load($datas, $connectionName);
|
||||
|
||||
$output->writeln(sprintf('<comment>%s</comment> %s fixtures file%s loaded.', $nb, strtoupper($type), $nb > 1 ? 's' : ''));
|
||||
|
||||
|
@ -201,36 +188,35 @@ EOT
|
|||
/**
|
||||
* Load SQL fixtures
|
||||
*
|
||||
* @param \Symfony\Component\Console\Input\InputInterface $input
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
* @return void
|
||||
* @param \Symfony\Component\Console\Input\InputInterface $input
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
*/
|
||||
protected function loadSqlFixtures(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$tmpdir = $this->getApplication()->getKernel()->getRootDir() . '/cache/propel';
|
||||
$tmpdir = $this->getCacheDir();
|
||||
$datas = $this->getFixtureFiles('sql');
|
||||
|
||||
$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
|
||||
$sqldbContent = '';
|
||||
foreach ($datas as $data) {
|
||||
$output->writeln(sprintf('<info>Loading SQL fixtures from</info> <comment>%s</comment>.', $data));
|
||||
|
||||
$sqldbContent .= $data->getFilename() . '=' . $name . PHP_EOL;
|
||||
$this->filesystem->copy($data, $tmpdir . '/fixtures/' . $data->getFilename(), true);
|
||||
$sqldbContent .= $data->getFilename() . '=' . $connectionName . PHP_EOL;
|
||||
$this->filesystem->copy($data, $tmpdir . '/' . $data->getFilename(), true);
|
||||
}
|
||||
|
||||
if ('' === $sqldbContent) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
$sqldbFile = $tmpdir . '/fixtures/sqldb.map';
|
||||
$sqldbFile = $tmpdir . '/sqldb.map';
|
||||
file_put_contents($sqldbFile, $sqldbContent);
|
||||
|
||||
if (!$this->insertSql($defaultConfig, $tmpdir . '/fixtures', $tmpdir, $output)) {
|
||||
if (!$this->insertSql($connectionName, $input, $output)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -249,36 +235,36 @@ EOT
|
|||
// Recreate a propel directory in cache
|
||||
$this->filesystem->remove($tmpdir);
|
||||
$this->filesystem->mkdir($tmpdir);
|
||||
|
||||
$fixturesdir = $tmpdir . '/fixtures/';
|
||||
$this->filesystem->remove($fixturesdir);
|
||||
$this->filesystem->mkdir($fixturesdir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert SQL
|
||||
*/
|
||||
protected function insertSql($config, $sqlDir, $schemaDir, $output)
|
||||
protected function insertSql($connectionName, InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
// Insert SQL
|
||||
$ret = $this->callPhing('insert-sql', array(
|
||||
'propel.database.url' => $config['connection']['dsn'],
|
||||
'propel.database.database' => $config['adapter'],
|
||||
'propel.database.user' => $config['connection']['user'],
|
||||
'propel.database.password' => $config['connection']['password'],
|
||||
'propel.schema.dir' => $schemaDir,
|
||||
'propel.sql.dir' => $sqlDir,
|
||||
));
|
||||
$parameters = array(
|
||||
'--connection' => array($connectionName),
|
||||
'--verbose' => $input->getOption('verbose'),
|
||||
'--sql-dir' => $this->getCacheDir(),
|
||||
'--force' => 'force'
|
||||
);
|
||||
|
||||
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.');
|
||||
} else {
|
||||
$this->writeTaskError($output, 'insert-sql', false);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return $ret === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -286,14 +272,16 @@ EOT
|
|||
*
|
||||
* @param string $type The extension of the files.
|
||||
* @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.
|
||||
*/
|
||||
protected function getFixtureFiles($type = 'sql', $in = null)
|
||||
{
|
||||
$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);
|
||||
|
||||
|
@ -314,10 +302,20 @@ EOT
|
|||
/**
|
||||
* Returns the path the command will look into to find fixture files
|
||||
*
|
||||
* @param BundleInterface $bundle The bundle to explore.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
protected function getFixturesPath(BundleInterface $bundle)
|
||||
{
|
||||
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
|
||||
*/
|
||||
|
||||
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\InputInterface;
|
||||
|
@ -20,50 +26,73 @@ use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
|||
/**
|
||||
* @author William DURAND <william.durand1@gmail.com>
|
||||
*/
|
||||
class FormGenerateCommand extends GeneratorAwareCommand
|
||||
class FormGenerateCommand extends AbstractCommand
|
||||
{
|
||||
const DEFAULT_FORM_TYPE_DIRECTORY = '/Form/Type';
|
||||
|
||||
use BundleTrait;
|
||||
|
||||
/**
|
||||
* @see Command
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('propel:form:generate')
|
||||
->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('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
|
||||
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.
|
||||
EOT
|
||||
)
|
||||
->setName('propel:form:generate');
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Command
|
||||
*
|
||||
* @throws \InvalidArgumentException When the target directory does not exist
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if ($schemas = $this->getSchemasFromBundle($this->bundle)) {
|
||||
foreach ($schemas as $fileName => $array) {
|
||||
foreach ($this->getDatabasesFromSchema($array[1]) as $database) {
|
||||
$this->createFormTypeFromDatabase($this->bundle, $database, $input->getArgument('models'), $output, $input->getOption('force'));
|
||||
}
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
$models = $input->getArgument('models');
|
||||
$force = $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);
|
||||
|
||||
|
@ -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();
|
||||
|
||||
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);
|
||||
$this->writeNewDirectory($output, $dir);
|
||||
}
|
||||
|
@ -94,30 +131,71 @@ EOT
|
|||
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();
|
||||
$formTypeContent = file_get_contents(__DIR__ . '/../Resources/skeleton/FormType.php');
|
||||
|
||||
$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);
|
||||
$formBuilder = new FormBuilder();
|
||||
$formTypeContent = $formBuilder->buildFormType($bundle, $table, self::DEFAULT_FORM_TYPE_DIRECTORY);
|
||||
|
||||
file_put_contents($file->getPathName(), $formTypeContent);
|
||||
$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 = '';
|
||||
foreach ($table->getColumns() as $column) {
|
||||
if (!$column->isPrimaryKey()) {
|
||||
$buildCode .= sprintf("\n \$builder->add('%s');", lcfirst($column->getPhpName()));
|
||||
}
|
||||
return substr(str_replace(realpath($this->getContainer()->getParameter('kernel.root_dir') . '/../'), '', $file), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
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\Output\OutputInterface;
|
||||
|
||||
use Propel\Generator\Command\GraphvizGenerateCommand as BaseGraphvizGenerateCommand;
|
||||
|
||||
/**
|
||||
* GraphvizGenerateCommand.
|
||||
*
|
||||
* @author William DURAND <william.durand1@gmail.com>
|
||||
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||
*/
|
||||
class GraphvizGenerateCommand extends AbstractCommand
|
||||
class GraphvizGenerateCommand extends WrappedCommand
|
||||
{
|
||||
/**
|
||||
* @see Command
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDescription('Generates Graphviz file for your project')
|
||||
->setHelp(<<<EOT
|
||||
The <info>propel:graphviz</info> generates Graphviz file for your project.
|
||||
parent::configure();
|
||||
|
||||
<info>php app/console propel:graphviz</info>
|
||||
EOT
|
||||
)
|
||||
$this
|
||||
->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
|
||||
*
|
||||
* @throws \InvalidArgumentException When the target directory does not exist
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
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,
|
||||
));
|
||||
|
||||
$this->writeNewDirectory($output, $dest);
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getSubCommandArguments(InputInterface $input)
|
||||
{
|
||||
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,62 +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)
|
||||
{
|
||||
if (true === $this->callPhing('diff')) {
|
||||
$this->writeSummary($output, 'propel-sql-diff');
|
||||
} elseif ( strpos( $this->buffer, 'Uncommitted migrations have been found' ) ) {
|
||||
$this->writeSection($output, array(
|
||||
'[Propel] Error',
|
||||
'',
|
||||
'Uncommitted migrations have been found. You should either execute or delete them before rerunning the propel:migration:generate-diff command.'
|
||||
), 'fg=white;bg=red');
|
||||
} else {
|
||||
$this->writeTaskError($output, 'propel-sql-diff');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,62 +8,58 @@
|
|||
* @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\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
use Propel\Generator\Command\MigrationMigrateCommand as BaseMigrationCommand;
|
||||
|
||||
/**
|
||||
* MigrationMigrateCommand.
|
||||
*
|
||||
* @author William DURAND <william.durand1@gmail.com>
|
||||
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||
*/
|
||||
class MigrationMigrateCommand extends AbstractCommand
|
||||
class MigrationMigrateCommand extends WrappedCommand
|
||||
{
|
||||
/**
|
||||
* @see Command
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$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')
|
||||
->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
|
||||
*
|
||||
* @throws \InvalidArgumentException When the target directory does not exist
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function createSubCommandInstance()
|
||||
{
|
||||
if ($input->getOption('down')) {
|
||||
$this->callPhing('migration-down');
|
||||
} elseif ($input->getOption('up')) {
|
||||
$this->callPhing('migration-up');
|
||||
} else {
|
||||
$this->callPhing('migrate');
|
||||
}
|
||||
return new BaseMigrationCommand();
|
||||
}
|
||||
|
||||
$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
|
||||
*/
|
||||
|
||||
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\Output\OutputInterface;
|
||||
|
||||
use Propel\Generator\Command\MigrationStatusCommand as BaseMigrationCommand;
|
||||
|
||||
/**
|
||||
* MigrationStatusCommand.
|
||||
*
|
||||
* @author William DURAND <william.durand1@gmail.com>
|
||||
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||
*/
|
||||
class MigrationStatusCommand extends AbstractCommand
|
||||
class MigrationStatusCommand extends WrappedCommand
|
||||
{
|
||||
/**
|
||||
* @see Command
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->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).
|
||||
parent::configure();
|
||||
|
||||
<info>php app/console propel:migration:status</info>
|
||||
EOT
|
||||
)
|
||||
$this
|
||||
->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
|
||||
*
|
||||
* @throws \InvalidArgumentException When the target directory does not exist
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
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,58 +8,52 @@
|
|||
* @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\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
use Propel\Generator\Command\ModelBuildCommand as BaseModelBuildCommand;
|
||||
|
||||
/**
|
||||
* ModelBuildCommand.
|
||||
*
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author William DURAND <william.durand1@gmail.com>
|
||||
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||
*/
|
||||
class ModelBuildCommand extends AbstractCommand
|
||||
class ModelBuildCommand extends WrappedCommand
|
||||
{
|
||||
/**
|
||||
* @see Command
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->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.
|
||||
parent::configure();
|
||||
|
||||
<info>php app/console %command.full_name%</info>
|
||||
EOT
|
||||
)
|
||||
$this
|
||||
->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
|
||||
*
|
||||
* @throws \InvalidArgumentException When the target directory does not exist
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function createSubCommandInstance()
|
||||
{
|
||||
if (true === $this->callPhing('om')) {
|
||||
foreach ($this->tempSchemas as $schemaFile => $schemaDetails) {
|
||||
$output->writeln(sprintf(
|
||||
'>> <info>%20s</info> Generated model classes from <comment>%s</comment>',
|
||||
$schemaDetails['bundle'],
|
||||
$schemaDetails['basename']
|
||||
));
|
||||
}
|
||||
} else {
|
||||
$this->writeTaskError($output, 'om');
|
||||
}
|
||||
return new BaseModelBuildCommand();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getSubCommandArguments(InputInterface $input)
|
||||
{
|
||||
$outputDir = $this->getApplication()->getKernel()->getRootDir().'/../';
|
||||
|
||||
return array(
|
||||
'--output-dir' => $outputDir,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,83 +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)
|
||||
{
|
||||
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,123 +8,51 @@
|
|||
* @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\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Output\Output;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
use Propel\PropelBundle\Command\AbstractCommand;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
* SqlBuildCommand.
|
||||
*
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
* @author William DURAND <william.durand1@gmail.com>
|
||||
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||
*/
|
||||
class SqlBuildCommand extends AbstractCommand
|
||||
class SqlBuildCommand extends WrappedCommand
|
||||
{
|
||||
/**
|
||||
* @see Command
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->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.
|
||||
parent::configure();
|
||||
|
||||
<info>php %command.full_name%</info>
|
||||
EOT
|
||||
)
|
||||
->addOption('connection', null, InputOption::VALUE_OPTIONAL, 'Set this parameter to define a connection to use')
|
||||
$this
|
||||
->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
|
||||
*
|
||||
* @throws \InvalidArgumentException When the target directory does not exist
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function createSubCommandInstance()
|
||||
{
|
||||
$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');
|
||||
}
|
||||
return new \Propel\Generator\Command\SqlBuildCommand();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the existing target and the generated map files, and adds to the
|
||||
* 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
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
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;
|
||||
if(($generatedContent = file($generated)) === false)
|
||||
|
||||
return false;
|
||||
|
||||
$targetContent = array_merge($generatedContent, array_diff($targetContent, $generatedContent));
|
||||
|
||||
return file_put_contents($target, $targetContent);
|
||||
return array(
|
||||
'--connection' => $this->getConnections($input->getOption('connection')),
|
||||
'--output-dir' => $input->getOption('sql-dir') ?: $defaultSqlDir,
|
||||
'--overwrite' => $input->getOption('overwrite')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,117 +8,62 @@
|
|||
* @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\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* SqlInsertCommand.
|
||||
*
|
||||
* @author William DURAND <william.durand1@gmail.com>
|
||||
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||
*/
|
||||
class SqlInsertCommand extends AbstractCommand
|
||||
class SqlInsertCommand extends WrappedCommand
|
||||
{
|
||||
/**
|
||||
* @see Command
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$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')
|
||||
->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
|
||||
*
|
||||
* @throws \InvalidArgumentException When the target directory does not exist
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createSubCommandInstance()
|
||||
{
|
||||
return new \Propel\Generator\Command\SqlInsertCommand();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
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')) {
|
||||
$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);
|
||||
}
|
||||
}
|
||||
parent::execute($input, $output);
|
||||
} else {
|
||||
$output->writeln('<error>You have to use --force to execute all SQL statements.</error>');
|
||||
}
|
||||
}
|
||||
|
||||
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 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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();
|
||||
foreach ($propelConfiguration['datasources'] as $name => $config) {
|
||||
$connections[$name] = $config['connection'];
|
||||
}
|
||||
|
||||
return $connections;
|
||||
return array(
|
||||
'--connection' => $this->getConnections($input->getOption('connection')),
|
||||
'--sql-dir' => $input->getOption('sql-dir') ?: $defaultSqlDir,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,119 +8,105 @@
|
|||
* @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\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Propel\Runtime\Adapter\Pdo\MysqlAdapter;
|
||||
use Propel\Runtime\Propel;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
|
||||
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.
|
||||
* Useful to drop table in a database.
|
||||
*
|
||||
* @author Maxime AILLOUD
|
||||
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||
*/
|
||||
class TableDropCommand extends AbstractCommand
|
||||
class TableDropCommand extends ContainerAwareCommand
|
||||
{
|
||||
use FormattingHelpers;
|
||||
|
||||
/**
|
||||
* @see Command
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('propel:table:drop')
|
||||
->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>
|
||||
|
||||
The <info>table</info> arguments define the list of table which has to be delete <comment>(default: all table)</comment>.
|
||||
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');
|
||||
->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.')
|
||||
->addArgument('table', InputArgument::IS_ARRAY, 'Set this parameter to défine which table to delete (default all the table in the database.')
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Command
|
||||
*
|
||||
* @throws \InvalidArgumentException When the target directory does not exist
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
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');
|
||||
$nbTable = count($tablesToDelete);
|
||||
$tablePlural = (($nbTable > 1 || $nbTable == 0) ? 's' : '' );
|
||||
|
||||
if ($input->getOption('force')) {
|
||||
$nbTable = count($tablesToDelete);
|
||||
$tablePlural = (($nbTable > 1 || $nbTable == 0) ? 's' : '' );
|
||||
if ('prod' === $this->getApplication()->getKernel()->getEnvironment()) {
|
||||
$count = $nbTable ?: 'all';
|
||||
|
||||
if ('prod' === $this->getApplication()->getKernel()->getEnvironment()) {
|
||||
$count = (count($input->getArgument('table')) ?: 'all');
|
||||
$this->writeSection(
|
||||
$output,
|
||||
'WARNING: you are about to drop ' . $count . ' table' . $tablePlural . ' in production !',
|
||||
'bg=red;fg=white'
|
||||
);
|
||||
|
||||
$this->writeSection(
|
||||
$output,
|
||||
'WARNING: you are about to drop ' . $count . ' table' . $tablePlural . ' in production !',
|
||||
'bg=red;fg=white'
|
||||
);
|
||||
if (false === $this->askConfirmation($input, $output, 'Are you sure ? (y/n) ', false)) {
|
||||
$output->writeln('<info>Aborted, nice decision !</info>');
|
||||
|
||||
if (false === $this->askConfirmation($output, 'Are you sure ? (y/n) ', false)) {
|
||||
$output->writeln('<info>Aborted, nice decision !</info>');
|
||||
|
||||
return -2;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
list($name, $config) = $this->getConnection($input, $output);
|
||||
$connection = \Propel::getConnection($name);
|
||||
$adapter = \Propel::getDB($name);
|
||||
$showStatement = $connection->prepare('SHOW TABLES;');
|
||||
$showStatement->execute();
|
||||
|
||||
$showStatement = $connection->prepare('SHOW TABLES;');
|
||||
$showStatement->execute();
|
||||
$allTables = $showStatement->fetchAll(\PDO::FETCH_COLUMN);
|
||||
|
||||
$allTables = $showStatement->fetchAll(\PDO::FETCH_COLUMN);
|
||||
|
||||
if ($nbTable) {
|
||||
foreach ($tablesToDelete as $tableToDelete) {
|
||||
if (!array_search($tableToDelete, $allTables)) {
|
||||
throw new \InvalidArgumentException(sprintf('Table %s doesn\'t exist in the database.', $tableToDelete));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$tablesToDelete = $allTables;
|
||||
if ($nbTable) {
|
||||
foreach ($tablesToDelete as $tableToDelete) {
|
||||
if (!array_search($tableToDelete, $allTables)) {
|
||||
throw new \InvalidArgumentException(sprintf('Table %s doesn\'t exist in the database.', $tableToDelete));
|
||||
}
|
||||
|
||||
$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 {
|
||||
$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
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
|
@ -18,24 +21,19 @@ use Symfony\Component\HttpFoundation\Response;
|
|||
*
|
||||
* @author William DURAND <william.durand1@gmail.com>
|
||||
*/
|
||||
class PanelController extends ContainerAware
|
||||
class PanelController extends Controller
|
||||
{
|
||||
/**
|
||||
* This method renders the global Propel configuration.
|
||||
*/
|
||||
public function configurationAction()
|
||||
{
|
||||
$templating = $this->container->get('templating');
|
||||
|
||||
return $templating->renderResponse(
|
||||
'PropelBundle:Panel:configuration.html.twig',
|
||||
return $this->render(
|
||||
'@Propel/Panel/configuration.html.twig',
|
||||
array(
|
||||
'propel_version' => \Propel::VERSION,
|
||||
'configuration' => $this->container->get('propel.configuration')->getParameters(),
|
||||
'default_connection' => $this->container->getParameter('propel.dbal.default_connection'),
|
||||
'logging' => $this->container->getParameter('propel.logging'),
|
||||
'path' => $this->container->getParameter('propel.path'),
|
||||
'phing_path' => $this->container->getParameter('propel.phing_path'),
|
||||
'propel_version' => Propel::VERSION,
|
||||
'configuration' => $this->getParameter('propel.configuration'),
|
||||
'logging' => $this->getParameter('propel.logging'),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -47,11 +45,11 @@ class PanelController extends ContainerAware
|
|||
* @param string $connection The connection name
|
||||
* @param integer $query
|
||||
*
|
||||
* @return Symfony\Component\HttpFoundation\Response A Response instance
|
||||
* @return Response A Response instance
|
||||
*/
|
||||
public function explainAction($token, $connection, $query)
|
||||
{
|
||||
$profiler = $this->container->get('profiler');
|
||||
$profiler = $this->get('profiler');
|
||||
$profiler->disable();
|
||||
|
||||
$profile = $profiler->loadProfile($token);
|
||||
|
@ -62,20 +60,18 @@ class PanelController extends ContainerAware
|
|||
}
|
||||
|
||||
// Open the connection
|
||||
$con = \Propel::getConnection($connection);
|
||||
|
||||
// Get the adapter
|
||||
$db = \Propel::getDB($connection);
|
||||
$con = Propel::getConnection($connection);
|
||||
|
||||
try {
|
||||
$stmt = $db->doExplainPlan($con, $queries[$query]['sql']);
|
||||
$results = $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||
$dataFetcher = $con->query('EXPLAIN ' . $queries[$query]['sql']);
|
||||
$results = array();
|
||||
while (($results[] = $dataFetcher->fetch(\PDO::FETCH_ASSOC)));
|
||||
} catch (\Exception $e) {
|
||||
return new Response('<div class="error">This query cannot be explained.</div>');
|
||||
}
|
||||
|
||||
return $this->container->get('templating')->renderResponse(
|
||||
'PropelBundle:Panel:explain.html.twig',
|
||||
return $this->render(
|
||||
'@Propel/Panel/explain.html.twig',
|
||||
array(
|
||||
'data' => $results,
|
||||
'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
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
|
@ -22,23 +23,32 @@ abstract class AbstractDataHandler
|
|||
* @var string
|
||||
*/
|
||||
protected $rootDir;
|
||||
|
||||
/**
|
||||
* @var \PDO
|
||||
*/
|
||||
protected $con;
|
||||
|
||||
/**
|
||||
* @var \DatabaseMap
|
||||
* @var DatabaseMap
|
||||
*/
|
||||
protected $dbMap;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $datasources = array();
|
||||
|
||||
/**
|
||||
* 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->datasources = $datasources;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -63,8 +73,10 @@ abstract class AbstractDataHandler
|
|||
$this->dbMap = Propel::getDatabaseMap($connectionName);
|
||||
if (0 === count($this->dbMap->getTables())) {
|
||||
$finder = new Finder();
|
||||
$files = $finder->files()->name('*TableMap.php')
|
||||
$files = $finder
|
||||
->files()->name('*TableMap.php')
|
||||
->in($this->getModelSearchPaths($connectionName))
|
||||
->notName('TableMap.php')
|
||||
->exclude('PropelBundle')
|
||||
->exclude('Tests');
|
||||
|
||||
|
@ -80,15 +92,15 @@ abstract class AbstractDataHandler
|
|||
|
||||
/**
|
||||
* Check if a table is in a database
|
||||
* @param string $class
|
||||
* @param string $connectionName
|
||||
*
|
||||
* @param string $class
|
||||
* @param string $connectionName
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
protected function isInDatabase($class, $connectionName)
|
||||
{
|
||||
$table = new $class();
|
||||
|
||||
return constant($table->getPeerClassname().'::DATABASE_NAME') == $connectionName;
|
||||
return constant($class.'::DATABASE_NAME') === $connectionName;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,6 +109,8 @@ abstract class AbstractDataHandler
|
|||
*
|
||||
* @param string $path The relative path of the file.
|
||||
* @param string $shortClassName The short class name aka the filename without extension.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
private function guessFullClassName($path, $shortClassName)
|
||||
{
|
||||
|
@ -128,12 +142,12 @@ abstract class AbstractDataHandler
|
|||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function getModelSearchPaths($connectionName) {
|
||||
$configuration = Propel::getConfiguration();
|
||||
protected function getModelSearchPaths($connectionName)
|
||||
{
|
||||
$searchPath = array();
|
||||
|
||||
if (!empty($configuration['datasources'][$connectionName]['connection']['model_paths'])) {
|
||||
$modelPaths = $configuration['datasources'][$connectionName]['connection']['model_paths'];
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -8,12 +8,12 @@
|
|||
* @license MIT License
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\DataFixtures\Dumper;
|
||||
namespace Propel\Bundle\PropelBundle\DataFixtures\Dumper;
|
||||
|
||||
use Propel\PropelBundle\DataFixtures\AbstractDataHandler;
|
||||
use \PDO;
|
||||
use \Propel;
|
||||
use \PropelColumnTypes;
|
||||
use Propel\Bundle\PropelBundle\DataFixtures\AbstractDataHandler;
|
||||
use Propel\Generator\Model\PropelTypes;
|
||||
use Propel\Runtime\Propel;
|
||||
|
||||
/**
|
||||
* Abstract class to manage a common logic to dump data.
|
||||
|
@ -69,7 +69,7 @@ abstract class AbstractDataDumper extends AbstractDataHandler implements DataDum
|
|||
|
||||
$dumpData = array();
|
||||
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;
|
||||
$haveParents = false;
|
||||
$fixColumn = null;
|
||||
|
@ -107,10 +107,14 @@ abstract class AbstractDataDumper extends AbstractDataHandler implements DataDum
|
|||
}
|
||||
$stmt = $this
|
||||
->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);
|
||||
$stmt->closeCursor();
|
||||
$set = array();
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$set[] = $row;
|
||||
}
|
||||
$resultsSets[] = $set;
|
||||
$stmt->close();
|
||||
unset($stmt);
|
||||
}
|
||||
|
||||
|
@ -148,7 +152,7 @@ abstract class AbstractDataDumper extends AbstractDataHandler implements DataDum
|
|||
$values[$col] = strlen($row[$col]) ? $relatedTable->getPhpName().'_'.$row[$col] : '';
|
||||
}
|
||||
} 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);
|
||||
$row[$col] = $serialized ? explode(' | ', $serialized) : array();
|
||||
}
|
||||
|
@ -157,7 +161,7 @@ abstract class AbstractDataDumper extends AbstractDataHandler implements DataDum
|
|||
$values[$col] = $row[$col];
|
||||
}
|
||||
|
||||
if (PropelColumnTypes::OBJECT === $column->getType()) {
|
||||
if (PropelTypes::OBJECT === $column->getType()) {
|
||||
$values[$col] = unserialize($row[$col]);
|
||||
}
|
||||
}
|
||||
|
@ -187,7 +191,7 @@ abstract class AbstractDataDumper extends AbstractDataHandler implements DataDum
|
|||
// reordering classes to take foreign keys into account
|
||||
for ($i = 0, $count = count($classes); $i < $count; $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) {
|
||||
if ($column->isForeignKey()) {
|
||||
|
@ -216,7 +220,7 @@ abstract class AbstractDataDumper extends AbstractDataHandler implements DataDum
|
|||
protected function fixOrderingOfForeignKeyDataInSameTable($resultsSets, $tableName, $column, $in = null)
|
||||
{
|
||||
$sql = sprintf('SELECT * FROM %s WHERE %s %s',
|
||||
constant(constant($tableName.'::PEER').'::TABLE_NAME'),
|
||||
constant(constant($tableName.'::TABLE_MAP').'::TABLE_NAME'),
|
||||
strtolower($column->getName()),
|
||||
null === $in ? 'IS NULL' : 'IN ('.$in.')');
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* @license MIT License
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\DataFixtures\Dumper;
|
||||
namespace Propel\Bundle\PropelBundle\DataFixtures\Dumper;
|
||||
|
||||
/**
|
||||
* Interface that exposes how Propel data dumpers should work.
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* @license MIT License
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\DataFixtures\Dumper;
|
||||
namespace Propel\Bundle\PropelBundle\DataFixtures\Dumper;
|
||||
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
|
@ -28,8 +28,7 @@ class YamlDataDumper extends AbstractDataDumper
|
|||
$data,
|
||||
$inline = 3,
|
||||
$indent = 4,
|
||||
$exceptionOnInvalidType = false,
|
||||
$objectSupport = true
|
||||
Yaml::DUMP_OBJECT
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,15 +8,15 @@
|
|||
* @license MIT License
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\DataFixtures\Loader;
|
||||
namespace Propel\Bundle\PropelBundle\DataFixtures\Loader;
|
||||
|
||||
use \BasePeer;
|
||||
use \BaseObject;
|
||||
use \Propel;
|
||||
use \PropelColumnTypes;
|
||||
use \PropelException;
|
||||
use Propel\PropelBundle\DataFixtures\AbstractDataHandler;
|
||||
use Propel\PropelBundle\Util\PropelInflector;
|
||||
use Propel\Bundle\PropelBundle\DataFixtures\AbstractDataHandler;
|
||||
use Propel\Bundle\PropelBundle\Util\PropelInflector;
|
||||
use Propel\Generator\Model\PropelTypes;
|
||||
use Propel\Runtime\ActiveRecord\ActiveRecordInterface;
|
||||
use Propel\Runtime\Map\Exception\TableNotFoundException;
|
||||
use Propel\Runtime\Map\TableMap;
|
||||
use Propel\Runtime\Propel;
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
// Check that peer class exists before calling doDeleteAll()
|
||||
$peerClass = constant($class.'::PEER');
|
||||
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);
|
||||
$tableMap = $this->dbMap->getTable(constant(constant($class.'::TABLE_MAP').'::TABLE_NAME'));
|
||||
$tableMap->doDeleteAll($this->con);
|
||||
|
||||
$this->deletedClasses[] = $class;
|
||||
|
||||
|
@ -129,7 +122,7 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
|||
/**
|
||||
* 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)
|
||||
{
|
||||
|
@ -138,20 +131,20 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
|||
}
|
||||
|
||||
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
|
||||
// might have been empty just for force a table to be emptied on import
|
||||
if (!is_array($datas)) {
|
||||
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
|
||||
if (!class_exists($class)) {
|
||||
throw new \InvalidArgumentException(sprintf('Unknown class "%s".', $class));
|
||||
|
@ -159,28 +152,28 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
|||
|
||||
$obj = new $class();
|
||||
|
||||
if (!$obj instanceof BaseObject) {
|
||||
if (!$obj instanceof ActiveRecordInterface) {
|
||||
throw new \RuntimeException(
|
||||
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));
|
||||
}
|
||||
|
||||
foreach ($data as $name => $value) {
|
||||
foreach ($values as $name => $value) {
|
||||
if (is_array($value) && 's' === substr($name, -1)) {
|
||||
try {
|
||||
// many to many relationship
|
||||
$this->loadManyToMany($obj, substr($name, 0, -1), $value);
|
||||
|
||||
continue;
|
||||
} catch (PropelException $e) {
|
||||
} catch (TableNotFoundException $e) {
|
||||
// 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 (PropelColumnTypes::PHP_ARRAY !== $tableMap->getColumn($name)->getType()
|
||||
&& PropelColumnTypes::OBJECT !== $tableMap->getColumn($name)->getType()) {
|
||||
if (PropelTypes::PHP_ARRAY !== $tableMap->getColumn($name)->getType()
|
||||
&& PropelTypes::OBJECT !== $tableMap->getColumn($name)->getType()) {
|
||||
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).
|
||||
*/
|
||||
if ($column->isPrimaryKey() && null !== $value && !$column->isForeignKey()) {
|
||||
if (isset($this->object_references[$class.'_'.$value])) {
|
||||
$obj = $this->object_references[$class.'_'.$value];
|
||||
if (isset($this->object_references[$this->cleanObjectRef($class.'_'.$value)])) {
|
||||
$obj = $this->object_references[$this->cleanObjectRef($class.'_'.$value)];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
@ -212,14 +205,19 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
|||
|
||||
if ($column->isForeignKey() && null !== $value) {
|
||||
$relatedTable = $this->dbMap->getTable($column->getRelatedTableName());
|
||||
if (!isset($this->object_references[$relatedTable->getClassname().'_'.$value])) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf('The object "%s" from class "%s" is not defined in your data file.', $value, $relatedTable->getClassname())
|
||||
);
|
||||
if (isset($this->object_references[$this->cleanObjectRef($relatedTable->getClassname().'_'.$value)])) {
|
||||
$value = $this
|
||||
->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.
|
||||
*
|
||||
* @param string $class Class name of passed object
|
||||
* @param string $key Key identifying specified object
|
||||
* @param BaseObject $obj A Propel object
|
||||
* @param string $class Class name of passed object
|
||||
* @param string $key Key identifying specified object
|
||||
* @param ActiveRecordInterface $obj A Propel object
|
||||
*/
|
||||
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
|
||||
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);
|
||||
}
|
||||
// Get parent (schema ancestor) of parent (Propel base class) in case of inheritance
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads many to many objects.
|
||||
*
|
||||
* @param BaseObject $obj A Propel object
|
||||
* @param string $middleTableName The middle table name
|
||||
* @param array $values An array of values
|
||||
* @param ActiveRecordInterface $obj A Propel object
|
||||
* @param string $middleTableName The middle table name
|
||||
* @param array $values An array of values
|
||||
*/
|
||||
protected function loadManyToMany($obj, $middleTableName, $values)
|
||||
{
|
||||
$middleTable = $this->dbMap->getTable($middleTableName);
|
||||
$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) {
|
||||
if ($column->isForeignKey()) {
|
||||
|
@ -296,7 +293,7 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
|||
}
|
||||
|
||||
foreach ($values as $value) {
|
||||
if (!isset($this->object_references[$relatedClass.'_'.$value])) {
|
||||
if (!isset($this->object_references[$this->cleanObjectRef($relatedClass.'_'.$value)])) {
|
||||
throw new \InvalidArgumentException(
|
||||
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->$setter($obj);
|
||||
$middle->$relatedSetter($this->object_references[$relatedClass.'_'.$value]);
|
||||
$middle->$relatedSetter($this->object_references[$this->cleanObjectRef($relatedClass.'_'.$value)]);
|
||||
$middle->save($this->con);
|
||||
}
|
||||
}
|
||||
|
||||
protected function cleanObjectRef($ref)
|
||||
{
|
||||
return $ref[0] === '\\' ? substr($ref, 1) : $ref;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* @license MIT License
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\DataFixtures\Loader;
|
||||
namespace Propel\Bundle\PropelBundle\DataFixtures\Loader;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\DataFixtures\Loader;
|
||||
namespace Propel\Bundle\PropelBundle\DataFixtures\Loader;
|
||||
|
||||
/**
|
||||
* XML fixtures loader.
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
* @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\Yaml;
|
||||
|
||||
|
@ -22,18 +22,18 @@ use Symfony\Component\Yaml\Yaml;
|
|||
class YamlDataLoader extends AbstractDataLoader
|
||||
{
|
||||
/**
|
||||
* @var \Symfony\Component\DependencyInjection\ContainerInterface
|
||||
* @var \Faker\Generator
|
||||
*/
|
||||
private $container;
|
||||
private $faker;
|
||||
|
||||
/**
|
||||
* {@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));
|
||||
}
|
||||
|
||||
if (null !== $this->container && $this->container->has('faker.generator')) {
|
||||
$generator = $this->container->get('faker.generator');
|
||||
$faker = function($type) use ($generator) {
|
||||
if (null !== $this->faker) {
|
||||
$generator = $this->faker;
|
||||
$faker = function ($type) use ($generator) {
|
||||
$args = func_get_args();
|
||||
array_shift($args);
|
||||
|
||||
echo Yaml::dump(call_user_func_array(array($generator, $type), $args)) . "\n";
|
||||
};
|
||||
} else {
|
||||
$faker = function($text) {
|
||||
$faker = function ($text) {
|
||||
echo $text . "\n";
|
||||
};
|
||||
}
|
||||
|
||||
ob_start();
|
||||
$retval = include($file);
|
||||
$retval = include $file;
|
||||
$content = ob_get_clean();
|
||||
|
||||
// if an array is returned by the config file assume it's in plain php form else in YAML
|
||||
|
|
|
@ -8,256 +8,238 @@
|
|||
* @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\TreeBuilder;
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
|
||||
/**
|
||||
* This class contains the configuration information for the bundle
|
||||
*
|
||||
* This information is solely responsible for how the different configuration
|
||||
* sections are normalized, and merged.
|
||||
*
|
||||
* @author William DURAND <william.durand1@gmail.com>
|
||||
*/
|
||||
class Configuration implements ConfigurationInterface
|
||||
* This class contains the configuration information for the bundle
|
||||
*/
|
||||
class Configuration extends PropelConfiguration
|
||||
{
|
||||
private $debug;
|
||||
private $defaultDir;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Boolean $debug Wether to use the debug mode
|
||||
*/
|
||||
public function __construct($debug)
|
||||
public function __construct($debug, $kernelDir)
|
||||
{
|
||||
$this->debug = (Boolean) $debug;
|
||||
$this->debug = $debug;
|
||||
$this->defaultDir = $kernelDir.'/propel';
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
protected function addPathsSection(ArrayNodeDefinition $node)
|
||||
{
|
||||
$node
|
||||
->children()
|
||||
->scalarNode('path')->end()
|
||||
->scalarNode('phing_path')->end()
|
||||
->scalarNode('logging')->defaultValue($this->debug)->end()
|
||||
->arrayNode('build_properties')
|
||||
->useAttributeAsKey('key')
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->arrayNode('behaviors')
|
||||
->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()
|
||||
->arrayNode('paths')
|
||||
->addDefaultsIfNotSet()
|
||||
->children()
|
||||
->scalarNode('schemaDir')->defaultValue($this->defaultDir)->end()
|
||||
->scalarNode('sqlDir')->defaultValue($this->defaultDir.'/sql')->end()
|
||||
->scalarNode('migrationDir')->defaultValue($this->defaultDir.'/migrations')->end()
|
||||
->scalarNode('phpConfDir')->defaultValue($this->defaultDir.'/generated-conf')->end()
|
||||
->scalarNode('composerDir')->defaultNull()->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()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
protected function addRuntimeSection(ArrayNodeDefinition $node)
|
||||
{
|
||||
$treeBuilder = new TreeBuilder();
|
||||
$node = $treeBuilder->root('connections');
|
||||
|
||||
$node
|
||||
->requiresAtLeastOneElement()
|
||||
->useAttributeAsKey('name')
|
||||
->prototype('array')
|
||||
->children()
|
||||
->scalarNode('driver')
|
||||
->beforeNormalization()
|
||||
->always()
|
||||
->then(function($v) { return str_replace('pdo_', '', $v); })
|
||||
->children()
|
||||
->arrayNode('runtime')
|
||||
->addDefaultsIfNotSet()
|
||||
->fixXmlConfig('connection')
|
||||
->children()
|
||||
->scalarNode('defaultConnection')->end()
|
||||
->arrayNode('connections')
|
||||
->prototype('scalar')->end()
|
||||
->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); })
|
||||
->booleanNode('logging')->defaultValue($this->debug)->end()
|
||||
->arrayNode('log')
|
||||
->useAttributeAsKey('name')
|
||||
->prototype('array')
|
||||
->children()
|
||||
->scalarNode('type')->end()
|
||||
->scalarNode('path')->end()
|
||||
->enumNode('level')->values(array(100, 200, 250, 300, 400, 500, 550, 600))->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->defaultValue('')
|
||||
->end()
|
||||
->scalarNode('classname')->defaultValue($this->debug ? 'DebugPDO' : 'PropelPDO')->end()
|
||||
->arrayNode('slaves')
|
||||
->useAttributeAsKey('name')
|
||||
->prototype('array')
|
||||
->arrayNode('profiler')
|
||||
->children()
|
||||
->scalarNode('driver')
|
||||
->beforeNormalization()
|
||||
->always()
|
||||
->then(function($v) { return str_replace('pdo_', '', $v); })
|
||||
->scalarNode('classname')->defaultValue('\Propel\Runtime\Util\Profiler')->end()
|
||||
->floatNode('slowTreshold')->defaultValue(0.1)->end()
|
||||
->arrayNode('details')
|
||||
->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()
|
||||
->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()
|
||||
->scalarNode('innerGlue')->defaultValue(':')->end()
|
||||
->scalarNode('outerGlue')->defaultValue('|')->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->fixXmlConfig('option')
|
||||
->children()
|
||||
->arrayNode('options')
|
||||
->useAttributeAsKey('key')
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->end()
|
||||
->fixXmlConfig('model_path')
|
||||
->children()
|
||||
->arrayNode('model_paths')
|
||||
->defaultValue(array('src/', 'vendor/'))
|
||||
->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()
|
||||
;
|
||||
->end() //runtime
|
||||
->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
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\DependencyInjection;
|
||||
namespace Propel\Bundle\PropelBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\Config\Definition\Processor;
|
||||
|
||||
/**
|
||||
* PropelExtension loads the PropelBundle configuration.
|
||||
|
@ -32,115 +31,35 @@ class PropelExtension extends Extension
|
|||
*/
|
||||
public function load(array $configs, ContainerBuilder $container)
|
||||
{
|
||||
$processor = new Processor();
|
||||
$configuration = $this->getConfiguration($configs, $container);
|
||||
$config = $processor->processConfiguration($configuration, $configs);
|
||||
$config = $this->processConfiguration($configuration, $configs);
|
||||
|
||||
// Composer
|
||||
if (file_exists($propelPath = $container->getParameter('kernel.root_dir') . '/../vendor/propel/propel1')) {
|
||||
$container->setParameter('propel.path', $propelPath);
|
||||
}
|
||||
if (file_exists($phingPath = $container->getParameter('kernel.root_dir') . '/../vendor/phing/phing/classes')) {
|
||||
$container->setParameter('propel.phing_path', $phingPath);
|
||||
}
|
||||
|
||||
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 (1 === count($config['database']['connections'])) {
|
||||
$defaultConnection = array_keys($config['database']['connections'])[0];
|
||||
if (!isset($config['runtime']['defaultConnection'])) {
|
||||
$config['runtime']['defaultConnection'] = $defaultConnection;
|
||||
}
|
||||
if (!isset($config['generator']['defaultConnection'])) {
|
||||
$config['generator']['defaultConnection'] = $defaultConnection;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$container->hasParameter('propel.phing_path')) {
|
||||
if (!isset($config['phing_path'])) {
|
||||
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);
|
||||
|
||||
$container->setParameter('propel.logging', $config['runtime']['logging']);
|
||||
$container->setParameter('propel.configuration', $config);
|
||||
|
||||
// Load services
|
||||
if (!$container->hasDefinition('propel')) {
|
||||
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
|
||||
$loader->load('propel.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', 'model_paths') 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)
|
||||
{
|
||||
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
|
||||
|
||||
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\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
|
||||
|
||||
/**
|
||||
* @author William DURAND <william.durand1@gmail.com>
|
||||
* @deprecated use AbstractType directly
|
||||
*/
|
||||
abstract class BaseAbstractType extends AbstractType
|
||||
{
|
||||
protected $options = array(
|
||||
'name' => '',
|
||||
);
|
||||
protected $options = array();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
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
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
|
@ -22,11 +23,11 @@ class AclClass extends BaseAclClass
|
|||
* If none can be found, a new one will be saved.
|
||||
*
|
||||
* @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()
|
||||
->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
|
||||
*/
|
||||
|
||||
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
|
||||
{
|
||||
|
|
|
@ -8,12 +8,12 @@
|
|||
* @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\PropelBundle\Security\Acl\Domain\FieldEntry as AclFieldEntry;
|
||||
use Propel\Bundle\PropelBundle\Security\Acl\Domain\Entry as AclEntry;
|
||||
use Propel\Bundle\PropelBundle\Security\Acl\Domain\FieldEntry as AclFieldEntry;
|
||||
|
||||
use Symfony\Component\Security\Acl\Model\AclInterface;
|
||||
use Symfony\Component\Security\Acl\Model\EntryInterface;
|
||||
|
@ -29,7 +29,7 @@ class Entry extends BaseEntry
|
|||
*
|
||||
* @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)
|
||||
{
|
||||
|
@ -64,7 +64,7 @@ class Entry extends BaseEntry
|
|||
/**
|
||||
* 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
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\Model\Acl;
|
||||
namespace Propel\Bundle\PropelBundle\Model\Acl;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\om\BaseEntryQuery;
|
||||
use Propel\PropelBundle\Model\Acl\EntryPeer;
|
||||
use Propel\Bundle\PropelBundle\Model\Acl\Base\EntryQuery as BaseEntryQuery;
|
||||
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\SecurityIdentityInterface;
|
||||
|
@ -25,11 +29,11 @@ class EntryQuery extends BaseEntryQuery
|
|||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity An ACL related ObjectIdentity.
|
||||
* @param array $securityIdentities A list of SecurityIdentity to filter by.
|
||||
* @param \PropelPDO $con
|
||||
* @param \ConnectionInterface $con
|
||||
*
|
||||
* @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();
|
||||
foreach ($securityIdentities as $eachIdentity) {
|
||||
|
@ -49,12 +53,12 @@ class EntryQuery extends BaseEntryQuery
|
|||
}
|
||||
|
||||
$this
|
||||
->useAclClassQuery(null, \Criteria::INNER_JOIN)
|
||||
->useAclClassQuery(null, Criteria::INNER_JOIN)
|
||||
->filterByType((string) $objectIdentity->getType())
|
||||
->endUse()
|
||||
->leftJoinObjectIdentity()
|
||||
->add(ObjectIdentityPeer::OBJECT_IDENTIFIER, (string) $objectIdentity->getIdentifier(), \Criteria::EQUAL)
|
||||
->addOr(EntryPeer::OBJECT_IDENTITY_ID, null, \Criteria::ISNULL)
|
||||
->add(ObjectIdentityTableMap::COL_OBJECT_IDENTIFIER, (string) $objectIdentity->getIdentifier(), Criteria::EQUAL)
|
||||
->addOr(EntryTableMap::COL_OBJECT_IDENTITY_ID, null, Criteria::ISNULL)
|
||||
;
|
||||
|
||||
if (!empty($securityIdentities)) {
|
||||
|
|
|
@ -8,13 +8,17 @@
|
|||
* @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
|
||||
{
|
||||
public function preInsert(\PropelPDO $con = null)
|
||||
public function preInsert(ConnectionInterface $con = null)
|
||||
{
|
||||
// Compatibility with default implementation.
|
||||
$ancestor = new ObjectIdentityAncestor();
|
||||
|
@ -30,16 +34,16 @@ class ObjectIdentity extends BaseObjectIdentity
|
|||
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);
|
||||
}
|
||||
|
||||
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.
|
||||
$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.
|
||||
ObjectIdentityAncestorQuery::create()
|
||||
->filterByObjectIdentityId($objIds, \Criteria::IN)
|
||||
->filterByObjectIdentityId($objIds, Criteria::IN)
|
||||
->delete($con)
|
||||
;
|
||||
|
||||
|
@ -61,11 +65,11 @@ class ObjectIdentity extends BaseObjectIdentity
|
|||
/**
|
||||
* 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();
|
||||
|
||||
|
@ -82,13 +86,13 @@ class ObjectIdentity extends BaseObjectIdentity
|
|||
*/
|
||||
$query = ObjectIdentityAncestorQuery::create()
|
||||
->filterByObjectIdentityId($eachChild->getId())
|
||||
->filterByObjectIdentityRelatedByAncestorId($oldAncestors, \Criteria::IN)
|
||||
->filterByObjectIdentityRelatedByAncestorId($oldAncestors, Criteria::IN)
|
||||
;
|
||||
|
||||
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 {
|
||||
$query->filterByAncestorId($this->getId(), \Criteria::NOT_EQUAL);
|
||||
$query->filterByAncestorId($this->getId(), Criteria::NOT_EQUAL);
|
||||
}
|
||||
|
||||
$query->delete($con);
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
* @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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
||||
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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\Model\Acl;
|
||||
namespace Propel\Bundle\PropelBundle\Model\Acl;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\ObjectIdentity;
|
||||
use Propel\PropelBundle\Model\Acl\om\BaseObjectIdentityQuery;
|
||||
use Propel\Bundle\PropelBundle\Model\Acl\Base\ObjectIdentityQuery as BaseObjectIdentityQuery;
|
||||
|
||||
use Propel\Runtime\ActiveQuery\Criteria;
|
||||
use Propel\Runtime\Connection\ConnectionInterface;
|
||||
|
||||
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.
|
||||
*
|
||||
* @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',
|
||||
|
@ -44,11 +46,11 @@ class ObjectIdentityQuery extends BaseObjectIdentityQuery
|
|||
* Return an ObjectIdentity object belonging to the given ACL related 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
|
||||
->filterByAclObjectIdentity($objectIdentity, $con)
|
||||
|
@ -59,12 +61,12 @@ class ObjectIdentityQuery extends BaseObjectIdentityQuery
|
|||
/**
|
||||
* Return all children of the given object identity.
|
||||
*
|
||||
* @param \Propel\PropelBundle\Model\Acl\ObjectIdentity $objectIdentity
|
||||
* @param \PropelPDO $con
|
||||
* @param \Propel\Bundle\PropelBundle\Model\Acl\ObjectIdentity $objectIdentity
|
||||
* @param ConnectionInterface $con
|
||||
*
|
||||
* @return \PropelObjectCollection
|
||||
*/
|
||||
public function findChildren(ObjectIdentity $objectIdentity, \PropelPDO $con = null)
|
||||
public function findChildren(ObjectIdentity $objectIdentity, ConnectionInterface $con = null)
|
||||
{
|
||||
return $this
|
||||
->filterByObjectIdentityRelatedByParentObjectIdentityId($objectIdentity)
|
||||
|
@ -75,17 +77,17 @@ class ObjectIdentityQuery extends BaseObjectIdentityQuery
|
|||
/**
|
||||
* Return all children and grand-children of the given object identity.
|
||||
*
|
||||
* @param \Propel\PropelBundle\Model\Acl\ObjectIdentity $objectIdentity
|
||||
* @param \PropelPDO $con
|
||||
* @param \Propel\Bundle\PropelBundle\Model\Acl\ObjectIdentity $objectIdentity
|
||||
* @param ConnectionInterface $con
|
||||
*
|
||||
* @return \PropelObjectCollection
|
||||
*/
|
||||
public function findGrandChildren(ObjectIdentity $objectIdentity, \PropelPDO $con = null)
|
||||
public function findGrandChildren(ObjectIdentity $objectIdentity, ConnectionInterface $con = null)
|
||||
{
|
||||
return $this
|
||||
->useObjectIdentityAncestorRelatedByObjectIdentityIdQuery()
|
||||
->filterByObjectIdentityRelatedByAncestorId($objectIdentity)
|
||||
->filterByObjectIdentityRelatedByObjectIdentityId($objectIdentity, \Criteria::NOT_EQUAL)
|
||||
->filterByObjectIdentityRelatedByObjectIdentityId($objectIdentity, Criteria::NOT_EQUAL)
|
||||
->endUse()
|
||||
->find($con)
|
||||
;
|
||||
|
@ -94,17 +96,17 @@ class ObjectIdentityQuery extends BaseObjectIdentityQuery
|
|||
/**
|
||||
* Return all ancestors of the given object identity.
|
||||
*
|
||||
* @param ObjectIdentity $objectIdentity
|
||||
* @param \PropelPDO $con
|
||||
* @param ObjectIdentity $objectIdentity
|
||||
* @param ConnectionInterface $con
|
||||
*
|
||||
* @return \PropelObjectCollection
|
||||
*/
|
||||
public function findAncestors(ObjectIdentity $objectIdentity, \PropelPDO $con = null)
|
||||
public function findAncestors(ObjectIdentity $objectIdentity, ConnectionInterface $con = null)
|
||||
{
|
||||
return $this
|
||||
->useObjectIdentityAncestorRelatedByAncestorIdQuery()
|
||||
->filterByObjectIdentityRelatedByObjectIdentityId($objectIdentity)
|
||||
->filterByObjectIdentityRelatedByAncestorId($objectIdentity, \Criteria::NOT_EQUAL)
|
||||
->filterByObjectIdentityRelatedByAncestorId($objectIdentity, Criteria::NOT_EQUAL)
|
||||
->endUse()
|
||||
->find($con)
|
||||
;
|
||||
|
|
|
@ -8,9 +8,11 @@
|
|||
* @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\UserSecurityIdentity;
|
||||
|
@ -21,7 +23,7 @@ class SecurityIdentity extends BaseSecurityIdentity
|
|||
/**
|
||||
* 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
|
||||
*/
|
||||
|
@ -54,11 +56,11 @@ class SecurityIdentity extends BaseSecurityIdentity
|
|||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @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) {
|
||||
$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
|
||||
*/
|
||||
|
||||
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
|
||||
{
|
||||
|
|
|
@ -8,9 +8,13 @@
|
|||
* @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\DependencyInjection\ContainerBuilder;
|
||||
|
||||
|
@ -26,44 +30,18 @@ class PropelBundle extends Bundle
|
|||
*/
|
||||
public function boot()
|
||||
{
|
||||
require_once $this->container->getParameter('propel.path').'/runtime/lib/Propel.php';
|
||||
|
||||
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'));
|
||||
try {
|
||||
$this->configureConnections();
|
||||
|
||||
if ($this->container->getParameter('propel.logging')) {
|
||||
$config = $this
|
||||
->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'));
|
||||
$this->configureLogging();
|
||||
}
|
||||
|
||||
\Propel::initialize();
|
||||
} catch( \Exception $e ) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build(ContainerBuilder $container)
|
||||
{
|
||||
|
@ -73,4 +51,55 @@ class PropelBundle extends Bundle
|
|||
$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
|
||||
============
|
||||
|
||||
[![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
|
||||
|
||||
|
@ -11,18 +11,10 @@ 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.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.1* (*currently 2.2, 2.3 and 2.4 branch*).
|
||||
* The `2.0` branch will contain `Propel2` integration for Symfony *2.1*.
|
||||
We are still considering to integrate `Propel2` with Symfony *2.0*.
|
||||
In case, we will do so, there will be a `2.1` and `2.0` branch integrating the respective Symfony version!
|
||||
|
||||
**The 1.x branches are already available and you are encouraged to migrate your dependencies according to the listings!**
|
||||
|
||||
* If you depend on Symfony `2.2`, `2.3` or `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.
|
||||
* The `1.2` branch contains Propel *1.6* integration for Symfony *2.2* (*currently master branch*).
|
||||
* The `2.0` branch contains `Propel2` integration for Symfony *2.5-2.8*.
|
||||
* The `3.0` branch contains `Propel2` integration for Symfony *2.8-3.x*.
|
||||
* The `4.0` branch contains `Propel2` integration for Symfony *3.4-4.x*.
|
||||
|
||||
## Features
|
||||
|
||||
|
@ -30,20 +22,16 @@ As `Propel2` will be released in the near future, we are migrating the branching
|
|||
* Insertion of SQL statements;
|
||||
* Runtime autoloading of Propel and generated classes;
|
||||
* Propel runtime initialization through the XML configuration;
|
||||
* Migrations [Propel 1.6](http://www.propelorm.org/documentation/10-migrations.html);
|
||||
* Reverse engineering from [existing database](http://www.propelorm.org/wiki/Documentation/1.6/Existing-Database);
|
||||
* Integration to the Symfony2 Profiler;
|
||||
* [Propel Migrations](http://propelorm.org/documentation/09-migrations.html);
|
||||
* Reverse engineering from [existing database](http://propelorm.org/documentation/cookbook/working-with-existing-databases.html);
|
||||
* Integration to the Symfony Profiler;
|
||||
* Load SQL, YAML and XML fixtures;
|
||||
* Create/Drop databases;
|
||||
* Integration with the Form component;
|
||||
* Integration with the Security component;
|
||||
* Propel ParamConverter can be used with Sensio Framework Extra Bundle.
|
||||
|
||||
For documentation, see:
|
||||
|
||||
Resources/doc/
|
||||
|
||||
[Read the documentation](https://github.com/propelorm/PropelBundle/blob/1.1/Resources/doc/index.markdown)
|
||||
[Read the documentation](http://propelorm.org/documentation/)
|
||||
|
||||
For license, see:
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace Propel\PropelBundle\Request\ParamConverter;
|
||||
namespace Propel\Bundle\PropelBundle\Request\ParamConverter;
|
||||
|
||||
use Propel\PropelBundle\Util\PropelInflector;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface;
|
||||
use Propel\Bundle\PropelBundle\Util\PropelInflector;
|
||||
use Propel\Runtime\ActiveQuery\Criteria;
|
||||
use Propel\Runtime\ActiveQuery\ModelCriteria;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\RouterInterface;
|
||||
|
||||
/**
|
||||
* PropelParamConverter
|
||||
|
@ -48,24 +48,20 @@ class PropelParamConverter implements ParamConverterInterface
|
|||
*/
|
||||
protected $withs;
|
||||
|
||||
/**
|
||||
* name of method use to call a query method
|
||||
* @var string
|
||||
*/
|
||||
protected $queryMethod;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $hasWith = false;
|
||||
|
||||
/**
|
||||
* @var RouterInterface
|
||||
*/
|
||||
protected $router;
|
||||
|
||||
public function setRouter(RouterInterface $router = null)
|
||||
{
|
||||
$this->router = $router;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param ConfigurationInterface $configuration
|
||||
* @param Request $request
|
||||
* @param ParamConverter $configuration
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
|
@ -73,10 +69,11 @@ class PropelParamConverter implements ParamConverterInterface
|
|||
* @throws NotFoundHttpException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function apply(Request $request, ConfigurationInterface $configuration)
|
||||
public function apply(Request $request, ParamConverter $configuration)
|
||||
{
|
||||
$classQuery = $configuration->getClass() . 'Query';
|
||||
$classPeer = $configuration->getClass() . 'Peer';
|
||||
$class = $configuration->getClass();
|
||||
$classQuery = $class . 'Query';
|
||||
$classTableMap = $class::TABLE_MAP;
|
||||
$this->filters = array();
|
||||
$this->exclude = array();
|
||||
|
||||
|
@ -84,23 +81,23 @@ class PropelParamConverter implements ParamConverterInterface
|
|||
throw new \Exception(sprintf('The %s Query class does not exist', $classQuery));
|
||||
}
|
||||
|
||||
$tableMap = $classPeer::getTableMap();
|
||||
$pkColumns = $tableMap->getPrimaryKeyColumns();
|
||||
$tableMap = new $classTableMap();
|
||||
$pkColumns = $tableMap->getPrimaryKeys();
|
||||
|
||||
if (count($pkColumns) == 1) {
|
||||
$this->pk = strtolower($pkColumns[0]->getName());
|
||||
if (count($pkColumns) === 1) {
|
||||
$pk = array_pop($pkColumns);
|
||||
$this->pk = strtolower($pk->getName());
|
||||
}
|
||||
|
||||
$options = $configuration->getOptions();
|
||||
|
||||
// Check route options for converter options, if there are non provided.
|
||||
if (empty($options) && $request->attributes->has('_route') && $this->router && $configuration instanceof ParamConverter) {
|
||||
$converterOption = $this->router->getRouteCollection()->get($request->attributes->get('_route'))->getOption('propel_converter');
|
||||
// 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'])) {
|
||||
// We use the mapping for calling findPk or filterBy
|
||||
foreach ($options['mapping'] as $routeParam => $column) {
|
||||
|
@ -113,21 +110,34 @@ class PropelParamConverter implements ParamConverterInterface
|
|||
}
|
||||
}
|
||||
} else {
|
||||
$this->exclude = isset($options['exclude'])? $options['exclude'] : array();
|
||||
$this->exclude = isset($options['exclude']) ? $options['exclude'] : array();
|
||||
$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
|
||||
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.');
|
||||
$this->withs = isset($options['with']) ? is_array($options['with']) ? $options['with'] : array($options['with']) : array();
|
||||
|
||||
$this->queryMethod = $queryMethod = isset($options['query_method']) ? $options['query_method'] : null;
|
||||
|
||||
if (null !== $this->queryMethod && method_exists($classQuery, $this->queryMethod)) {
|
||||
// find by custom method
|
||||
$query = $this->getQuery($classQuery);
|
||||
// execute a custom query
|
||||
$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.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -142,21 +152,23 @@ class PropelParamConverter implements ParamConverterInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* @param ConfigurationInterface $configuration
|
||||
* @param ParamConverter $configuration
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function supports(ConfigurationInterface $configuration)
|
||||
public function supports(ParamConverter $configuration)
|
||||
{
|
||||
if (null === ($classname = $configuration->getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!class_exists($classname)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Propel Class?
|
||||
$class = new \ReflectionClass($configuration->getClass());
|
||||
if ($class->isSubclassOf('BaseObject')) {
|
||||
if ($class->implementsInterface('\Propel\Runtime\ActiveRecord\ActiveRecordInterface')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -203,7 +215,7 @@ class PropelParamConverter implements ParamConverterInterface
|
|||
try {
|
||||
$query->{'filterBy' . PropelInflector::camelize($column)}($value);
|
||||
$hasCriteria = true;
|
||||
} catch (\PropelException $e) { }
|
||||
} catch (\Exception $e) { }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -223,7 +235,7 @@ class PropelParamConverter implements ParamConverterInterface
|
|||
*
|
||||
* @param string $classQuery
|
||||
*
|
||||
* @return \ModelCriteria
|
||||
* @return ModelCriteria
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
|
@ -263,11 +275,11 @@ class PropelParamConverter implements ParamConverterInterface
|
|||
{
|
||||
switch (trim(str_replace(array('_', 'JOIN'), '', strtoupper($with[1])))) {
|
||||
case 'LEFT':
|
||||
return \Criteria::LEFT_JOIN;
|
||||
return Criteria::LEFT_JOIN;
|
||||
case 'RIGHT':
|
||||
return \Criteria::RIGHT_JOIN;
|
||||
return Criteria::RIGHT_JOIN;
|
||||
case 'INNER':
|
||||
return \Criteria::INNER_JOIN;
|
||||
return Criteria::INNER_JOIN;
|
||||
}
|
||||
|
||||
throw new \Exception(sprintf('ParamConverter : "with" parameter "%s" is invalid,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?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">
|
||||
<column name="id" type="integer" autoIncrement="true" primaryKey="true" />
|
||||
<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="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" />
|
||||
</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" />
|
||||
</foreign-key>
|
||||
</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,16 +5,12 @@
|
|||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<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>
|
||||
|
||||
<services>
|
||||
<service id="propel.converter.propel.orm" class="%propel.converter.propel.class%">
|
||||
<tag name="request.param_converter" converter="propel" priority="1" />
|
||||
|
||||
<call method="setRouter">
|
||||
<argument type="service" id="router" on-invalid="null" />
|
||||
</call>
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
|
|
|
@ -6,36 +6,33 @@
|
|||
|
||||
<parameters>
|
||||
<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.data_collector.class">Symfony\Bridge\Propel1\DataCollector\PropelDataCollector</parameter>
|
||||
<parameter key="propel.build_properties.class">Propel\PropelBundle\DependencyInjection\Properties</parameter>
|
||||
<parameter key="propel.form.type.model.class">Symfony\Bridge\Propel1\Form\Type\ModelType</parameter>
|
||||
<parameter key="propel.twig.extension.syntax.class">Propel\PropelBundle\Twig\Extension\SyntaxExtension</parameter>
|
||||
<parameter key="form.type_guesser.propel.class">Symfony\Bridge\Propel1\Form\PropelTypeGuesser</parameter>
|
||||
<parameter key="propel.security.acl.provider.model.class">Propel\PropelBundle\Security\Acl\AuditableAclProvider</parameter>
|
||||
<parameter key="propel.security.user.provider.class">Symfony\Bridge\Propel1\Security\User\PropelUserProvider</parameter>
|
||||
|
||||
<parameter key="propel.schema_locator.class">Propel\Bundle\PropelBundle\Service\SchemaLocator</parameter>
|
||||
<parameter key="propel.data_collector.class">Propel\Bundle\PropelBundle\DataCollector\PropelDataCollector</parameter>
|
||||
<parameter key="propel.logger.class">Propel\Bundle\PropelBundle\Logger\PropelLogger</parameter>
|
||||
<parameter key="propel.twig.extension.syntax.class">Propel\Bundle\PropelBundle\Twig\Extension\SyntaxExtension</parameter>
|
||||
<parameter key="form.type_guesser.propel.class">Propel\Bundle\PropelBundle\Form\TypeGuesser</parameter>
|
||||
<parameter key="propel.form.type.model.class">Propel\Bundle\PropelBundle\Form\Type\ModelType</parameter>
|
||||
<parameter key="propel.dumper.yaml.class">Propel\Bundle\PropelBundle\DataFixtures\Dumper\YamlDataDumper</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>
|
||||
|
||||
<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%">
|
||||
<service id="propel.logger" class="%propel.logger.class%" public="true">
|
||||
<tag name="monolog.logger" channel="propel" />
|
||||
<argument type="service" id="logger" on-invalid="null" />
|
||||
<argument type="service" id="debug.stopwatch" on-invalid="null" />
|
||||
</service>
|
||||
|
||||
<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.configuration" />
|
||||
</service>
|
||||
|
||||
<service id="propel.form.type.model" class="%propel.form.type.model.class%">
|
||||
<tag name="form.type" alias="model" />
|
||||
<tag name="data_collector" template="@Propel/Collector/propel" id="propel" />
|
||||
</service>
|
||||
|
||||
<service id="propel.twig.extension.syntax" class="%propel.twig.extension.syntax.class%">
|
||||
|
@ -46,13 +43,26 @@
|
|||
<tag name="form.type_guesser" />
|
||||
</service>
|
||||
|
||||
<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 id="propel.form.type.model" class="%propel.form.type.model.class%">
|
||||
<tag name="form.type" alias="model" />
|
||||
</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 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>
|
||||
</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,132 +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')' }
|
||||
model_paths:
|
||||
- /src/Acme/DemoBundle/Model/
|
||||
- /vendor/
|
||||
```
|
||||
|
||||
`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.
|
||||
`model_paths` can be defined to speed up searching for model data. By default it searches in the whole project from project root.
|
||||
|
||||
## 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,129 +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).
|
||||
* [The ModelTranslation](model_translation.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,83 +0,0 @@
|
|||
ModelTranslation
|
||||
================
|
||||
|
||||
The `PropelBundle` provides a model-based implementation of the Translation components' loader and dumper.
|
||||
To make us of this `ModelTranslation` you only need to add the translation resource.
|
||||
|
||||
``` yaml
|
||||
services:
|
||||
translation.loader.propel:
|
||||
class: Propel\PropelBundle\Translation\ModelTranslation
|
||||
arguments:
|
||||
# The model to be used.
|
||||
- 'Acme\Model\Translation\Translation'
|
||||
# The column mappings to interact with the model.
|
||||
-
|
||||
columns:
|
||||
key: 'key'
|
||||
translation: 'translation'
|
||||
locale: 'locale'
|
||||
domain: 'domain'
|
||||
updated_at: 'updated_at'
|
||||
calls:
|
||||
- [ 'registerResources', [ '@translator' ] ]
|
||||
tags:
|
||||
- { name: 'translation.loader', alias: 'propel' }
|
||||
# The dumper tag is optional.
|
||||
- { name: 'translation.dumper', alias: 'propel' }
|
||||
```
|
||||
|
||||
This will add another resource to the translator to be scanned for translations.
|
||||
|
||||
## Translation model
|
||||
|
||||
An example model schema for the translation model:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<database name="translation" defaultIdMethod="native" namespace="Propel\PropelBundle\Tests\Fixtures\Model">
|
||||
<table name="translation">
|
||||
<column name="id" type="integer" autoIncrement="true" primaryKey="true" />
|
||||
<column name="key" type="varchar" size="255" required="true" primaryString="true" />
|
||||
<column name="translation" type="longvarchar" lazyLoad="true" required="true" />
|
||||
<column name="locale" type="varchar" size="255" required="true" />
|
||||
<column name="domain" type="varchar" size="255" required="true" />
|
||||
<column name="updated_at" type="timestamp" />
|
||||
|
||||
<index>
|
||||
<index-column name="domain" />
|
||||
</index>
|
||||
<index>
|
||||
<index-column name="locale" />
|
||||
<index-column name="domain" />
|
||||
</index>
|
||||
|
||||
<unique>
|
||||
<unique-column name="key" />
|
||||
<unique-column name="locale" />
|
||||
<unique-column name="domain" />
|
||||
</unique>
|
||||
</table>
|
||||
</database>
|
||||
```
|
||||
|
||||
### VersionableBehavior
|
||||
|
||||
In order to make use of the `VersionableBehavior` (or similar), you can map the `updated_at` column to the `version_created_at` column:
|
||||
|
||||
``` yaml
|
||||
services:
|
||||
translation.loader.propel:
|
||||
class: Propel\PropelBundle\Translation\ModelTranslation
|
||||
arguments:
|
||||
- 'Acme\Model\Translation\Translation'
|
||||
-
|
||||
columns:
|
||||
updated_at: 'version_created_at'
|
||||
calls:
|
||||
- [ 'registerResources', [ '@translator' ] ]
|
||||
tags:
|
||||
- { name: 'translation.loader', alias: 'propel' }
|
||||
```
|
||||
|
||||
[Back to index](index.markdown)
|
|
@ -1,133 +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 parameters 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
|
||||
|
||||
#### Named converter ####
|
||||
|
||||
If you have a conflict with another ParamConverter you can force the `PropelParamConverter` with the `converter` option.
|
||||
|
||||
``` php
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @ParamConverter("post", converter="propel")
|
||||
*/
|
||||
public function myAction(Post $post)
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
[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##;
|
||||
|
||||
use Propel\PropelBundle\Form\BaseAbstractType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
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)
|
||||
{##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 %}
|
||||
{# the web debug toolbar content #}
|
||||
{% set icon %}
|
||||
<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=" />
|
||||
<span class="sf-toolbar-status">{{ collector.querycount }}</span>
|
||||
{% endset %}
|
||||
{% set text %}
|
||||
<div class="sf-toolbar-info-piece">
|
||||
<b>DB Queries</b>
|
||||
<span>{{ collector.querycount }}</span>
|
||||
</div>
|
||||
<div class="sf-toolbar-info-piece">
|
||||
<b>Query time</b>
|
||||
<span>{{ '%0.2f'|format(collector.time * 1000) }} ms</span>
|
||||
</div>
|
||||
{% endset %}
|
||||
{% include 'WebProfilerBundle:Profiler:toolbar_item.html.twig' with { 'link': profiler_url } %}
|
||||
{% if collector.querycount %}
|
||||
{% set icon %}
|
||||
<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=" />
|
||||
<span class="sf-toolbar-value">{{ collector.querycount }}</span>
|
||||
<span class="sf-toolbar-info-piece-additional-detail">
|
||||
<span class="sf-toolbar-label">in</span>
|
||||
<span class="sf-toolbar-value">{{ '%0.2f'|format(collector.time * 1000) }}</span>
|
||||
<span class="sf-toolbar-label">ms</span>
|
||||
</span>
|
||||
{% endset %}
|
||||
{% set text %}
|
||||
<div class="sf-toolbar-info-piece">
|
||||
<b>DB Queries</b>
|
||||
<span class="sf-toolbar-status {{ collector.querycount > 50 ? 'sf-toolbar-status-yellow' : '' }}">{{ collector.querycount }}</span>
|
||||
</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 %}
|
||||
|
||||
{% block menu %}
|
||||
{# the menu content #}
|
||||
<span class="label">
|
||||
<span class="icon"><img src="{{ asset('bundles/propel/images/profiler/propel.png') }}" alt="" /></span>
|
||||
<span class="label {{ not collector.querycount ? 'disabled' }}">
|
||||
<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>
|
||||
<span class="count">
|
||||
<span>{{ collector.querycount }}</span>
|
||||
<span>{{ '%0.0f'|format(collector.time * 1000) }} ms</span>
|
||||
</span>
|
||||
</span>
|
||||
{% endblock %}
|
||||
|
||||
|
@ -42,7 +48,7 @@
|
|||
color: #464646;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.SQLInfo, .SQLComment {
|
||||
.SQLComment {
|
||||
color: gray;
|
||||
display: block;
|
||||
font-size: 0.9em;
|
||||
|
@ -60,52 +66,80 @@
|
|||
padding: 8px 35px 8px 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#content .SQLExplain h2 {
|
||||
font-size: 17px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h2>Queries</h2>
|
||||
<table summary="Show logged queries">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>SQL queries</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if not collector.querycount %}
|
||||
<tr><td>No queries.</td></tr>
|
||||
{% else %}
|
||||
{% for i, query in collector.queries %}
|
||||
<tr>
|
||||
<td>
|
||||
<a name="propel-query-{{ i }}" ></a>
|
||||
<code>{{ query.sql|format_sql }}</code>
|
||||
{% if app.request.query.has('query') and app.request.query.get('query') == i %}
|
||||
<div class="SQLExplain">
|
||||
{% render controller('PropelBundle:Panel:explain', {
|
||||
'token': token,
|
||||
'panel': 'propel',
|
||||
'query': app.request.query.get('query'),
|
||||
'connection': app.request.query.get('connection')
|
||||
}) %}
|
||||
<h2>Query Metrics</h2>
|
||||
|
||||
{% if not collector.querycount %}
|
||||
<div class="empty">
|
||||
<p>No database queries were performed.</p>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="metrics">
|
||||
<div class="metric">
|
||||
<span class="value">{{ collector.querycount }}</span>
|
||||
<span class="label">Database Queries</span>
|
||||
</div>
|
||||
|
||||
<div class="metric">
|
||||
<span class="value">{{ '%0.2f'|format(collector.time * 1000) }} <span class="unit">ms</span></span>
|
||||
<span class="label">Query time</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Queries</h2>
|
||||
<table summary="Show logged queries">
|
||||
<thead>
|
||||
<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>
|
||||
{% endif %}
|
||||
<div class="SQLInfo">
|
||||
Time: {{ query.time }} - Memory: {{ query.memory }} - Connection: {{ query.connection }}
|
||||
|
||||
{% if app.request.query.get('query', -1) != i %}
|
||||
- <a href="{{ path('_profiler', {'panel': 'propel', 'token': token, 'connection': query.connection, 'query': i}) }}#propel-query-{{ i }}">Explain the query</a>
|
||||
{% if app.request.query.has('query') and app.request.query.get('query') == i %}
|
||||
<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 %}
|
||||
</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 %}
|
||||
|
|
|
@ -10,19 +10,11 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<th>Default connection</th>
|
||||
<td>{{ default_connection }}</td>
|
||||
<td>{{ configuration.runtime.defaultConnection }}</td>
|
||||
<tr>
|
||||
<th>Logging</th>
|
||||
<td>{{ logging ? 'enabled' : 'disabled' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Propel path</th>
|
||||
<td>{{ path }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Phing path</th>
|
||||
<td>{{ phing_path }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
@ -36,7 +28,7 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for name, config in configuration.datasources %}
|
||||
{% for name, config in configuration.database.connections %}
|
||||
<tr>
|
||||
<th rowspan="5" style="vertical-align: top;">
|
||||
{{ name }}
|
||||
|
@ -46,17 +38,17 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<th>DSN</th>
|
||||
<td>{{ config.connection.dsn }}</td>
|
||||
<td>{{ config.dsn }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Class</th>
|
||||
<td>{{ config.connection.classname }}</td>
|
||||
<td>{{ config.classname }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Options</th>
|
||||
<td>
|
||||
<ul>
|
||||
{% for key, value in config.connection.options %}
|
||||
{% for key, value in config.options %}
|
||||
<li>{{ key }} : {{ value }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
@ -66,7 +58,7 @@
|
|||
<th>Attributes</th>
|
||||
<td>
|
||||
<ul>
|
||||
{% for key, value in config.connection.attributes %}
|
||||
{% for key, value in config.attributes %}
|
||||
<li>{{ key }} : {{ value }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
<h2>Explanation</h2>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
{% for label in data[0]|keys %}
|
||||
|
|
|
@ -8,13 +8,16 @@
|
|||
* @license MIT License
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\Security\Acl;
|
||||
namespace Propel\Bundle\PropelBundle\Security\Acl;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\EntryQuery;
|
||||
use Propel\PropelBundle\Model\Acl\ObjectIdentityQuery;
|
||||
use Propel\PropelBundle\Model\Acl\SecurityIdentity;
|
||||
use Propel\Runtime\Collection\ObjectCollection;
|
||||
use Propel\Runtime\Connection\ConnectionInterface;
|
||||
|
||||
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;
|
||||
|
||||
|
@ -41,10 +44,10 @@ class AclProvider implements AclProviderInterface
|
|||
* Constructor.
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface $permissionGrantingStrategy
|
||||
* @param \PropelPDO $con
|
||||
* @param ConnectionInterface $con
|
||||
* @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->connection = $connection;
|
||||
|
@ -163,15 +166,15 @@ class AclProvider implements AclProviderInterface
|
|||
/**
|
||||
* Create an ACL.
|
||||
*
|
||||
* @param \PropelObjectCollection $collection
|
||||
* @param ObjectCollection $collection
|
||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||
* @param array $loadedSecurityIdentities
|
||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $parentAcl
|
||||
* @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);
|
||||
}
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
* @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\ObjectIdentityInterface;
|
||||
|
@ -23,15 +24,15 @@ class AuditableAclProvider extends MutableAclProvider
|
|||
/**
|
||||
* Get an ACL for this provider.
|
||||
*
|
||||
* @param \PropelObjectCollection $collection
|
||||
* @param Propel\Runtime\Collection\ObjectCollection $collection
|
||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||
* @param array $loadedSecurityIdentities
|
||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $parentAcl
|
||||
* @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);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
* @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;
|
||||
|
||||
|
@ -18,13 +20,13 @@ use Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface;
|
|||
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>
|
||||
*/
|
||||
class Acl implements AclInterface
|
||||
{
|
||||
protected $model = 'Propel\PropelBundle\Model\Acl\Entry';
|
||||
protected $model = '\Propel\Bundle\PropelBundle\Model\Acl\Entry';
|
||||
|
||||
protected $classAces = array();
|
||||
protected $classFieldAces = array();
|
||||
|
@ -48,17 +50,17 @@ class Acl implements AclInterface
|
|||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \PropelObjectCollection $entries
|
||||
* @param ObjectCollection $entries
|
||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||
* @param \Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface $permissionGrantingStrategy
|
||||
* @param array $loadedSecurityIdentities
|
||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $parentAcl
|
||||
* @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) {
|
||||
throw new AclException(sprintf('The given collection does not contain models of class "%s" but of class "%s".', $this->model, $entries->getModel()));
|
||||
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->getFullyQualifiedModel()));
|
||||
}
|
||||
|
||||
foreach ($entries as $eachEntry) {
|
||||
|
@ -301,7 +303,7 @@ class Acl implements AclInterface
|
|||
*
|
||||
* @param string $field
|
||||
*
|
||||
* @return \Propel\PropelBundle\Security\Acl\Domain\Acl $this
|
||||
* @return \Propel\Bundle\PropelBundle\Security\Acl\Domain\Acl $this
|
||||
*/
|
||||
protected function updateFields($field)
|
||||
{
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
* @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;
|
||||
|
||||
|
@ -81,7 +81,7 @@ class AuditableAcl extends MutableAcl implements AuditableAclInterface
|
|||
* @param bool $auditSuccess
|
||||
* @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)
|
||||
{
|
||||
|
|
|
@ -8,17 +8,17 @@
|
|||
* @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\PropelBundle\Model\Acl\SecurityIdentity;
|
||||
use Propel\Bundle\PropelBundle\Model\Acl\Entry as ModelEntry;
|
||||
use Propel\Bundle\PropelBundle\Model\Acl\SecurityIdentity;
|
||||
|
||||
use Symfony\Component\Security\Acl\Model\AclInterface;
|
||||
use Symfony\Component\Security\Acl\Model\AuditableEntryInterface;
|
||||
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!
|
||||
*
|
||||
|
@ -41,7 +41,7 @@ class Entry implements AuditableEntryInterface
|
|||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \Propel\PropelBundle\Model\Acl\Entry $entry
|
||||
* @param \Propel\Bundle\PropelBundle\Model\Acl\Entry $entry
|
||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $acl
|
||||
*/
|
||||
public function __construct(ModelEntry $entry, AclInterface $acl)
|
||||
|
|
|
@ -8,15 +8,15 @@
|
|||
* @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\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!
|
||||
*
|
||||
|
@ -31,7 +31,7 @@ class FieldEntry extends Entry implements FieldEntryInterface
|
|||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \Propel\PropelBundle\Model\Acl\Entry $entry
|
||||
* @param \Propel\Bundle\PropelBundle\Model\Acl\Entry $entry
|
||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $acl
|
||||
*/
|
||||
public function __construct(ModelEntry $entry, AclInterface $acl)
|
||||
|
|
|
@ -8,12 +8,15 @@
|
|||
* @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\PropelBundle\Model\Acl\SecurityIdentity;
|
||||
use Propel\PropelBundle\Model\Acl\ObjectIdentity;
|
||||
use Propel\PropelBundle\Model\Acl\ObjectIdentityQuery;
|
||||
use Propel\Runtime\Collection\ObjectCollection;
|
||||
use Propel\Runtime\Connection\ConnectionInterface;
|
||||
|
||||
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;
|
||||
|
||||
|
@ -40,29 +43,29 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* A connection to be used for all changes on the ACL.
|
||||
*
|
||||
* @var \PropelPDO
|
||||
* @var ConnectionInterface
|
||||
*/
|
||||
protected $con;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \PropelObjectCollection $entries
|
||||
* @param ObjectCollection $entries
|
||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||
* @param \Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface $permissionGrantingStrategy
|
||||
* @param array $loadedSecurityIdentities
|
||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $parentAcl
|
||||
* @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);
|
||||
|
||||
|
@ -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.
|
||||
*
|
||||
* @param array $list
|
||||
* @param int $index
|
||||
* @param \Propel\PropelBundle\Model\Acl\Entry\Entry $entry
|
||||
* @param array $list
|
||||
* @param int $index
|
||||
* @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)
|
||||
{
|
||||
|
@ -367,7 +370,7 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
* @param string $strategy
|
||||
* @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)
|
||||
{
|
||||
|
@ -394,7 +397,7 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
* @param array $list
|
||||
* @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)
|
||||
{
|
||||
|
@ -413,7 +416,7 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
* @param array $list
|
||||
* @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)
|
||||
{
|
||||
|
@ -433,7 +436,7 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
* @param array $list
|
||||
* @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)
|
||||
{
|
||||
|
@ -452,7 +455,7 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
* @param array $list
|
||||
* @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)
|
||||
{
|
||||
|
@ -469,7 +472,7 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
* @param array $list
|
||||
* @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)
|
||||
{
|
||||
|
@ -491,7 +494,7 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
* @param bool $granting
|
||||
* @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)
|
||||
{
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue