Compare commits
No commits in common. "1.1.0" and "4.0" have entirely different histories.
13
.gitignore
vendored
13
.gitignore
vendored
|
@ -1,4 +1,9 @@
|
|||
Model/*/map
|
||||
Model/*/om
|
||||
vendor
|
||||
composer.lock
|
||||
# Propel2 generated base classes, those are environment dependent
|
||||
/Model/Base
|
||||
/Model/Map
|
||||
/Model/**/Base
|
||||
/Model/**/Map
|
||||
|
||||
# Composer
|
||||
/vendor
|
||||
/composer.lock
|
||||
|
|
33
.travis.yml
33
.travis.yml
|
@ -1,14 +1,33 @@
|
|||
sudo: false
|
||||
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 7.0
|
||||
- 7.1
|
||||
- 7.2
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache/files
|
||||
|
||||
env:
|
||||
- SYMFONY_VERSION=origin/master
|
||||
- SYMFONY_VERSION="^3.0"
|
||||
- SYMFONY_VERSION="^4.0"
|
||||
|
||||
before_script:
|
||||
- curl -s http://getcomposer.org/installer | php
|
||||
- php composer.phar --dev install
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
||||
script: phpunit --coverage-text
|
||||
exclude:
|
||||
- php: 7.0
|
||||
env: SYMFONY_VERSION="^4.0"
|
||||
|
||||
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,84 +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;
|
||||
|
||||
/**
|
||||
* Return the package prefix for a given bundle.
|
||||
*
|
||||
* @param Bundle $bundle
|
||||
* @param string $baseDirectory The base directory to exclude from prefix.
|
||||
*
|
||||
* @return string
|
||||
* @var InputInterface
|
||||
*/
|
||||
protected function getPackagePrefix(Bundle $bundle, $baseDirectory = '')
|
||||
{
|
||||
$parts = explode(DIRECTORY_SEPARATOR, realpath($bundle->getPath()));
|
||||
$length = count(explode('\\', $bundle->getNamespace())) * (-1);
|
||||
protected $input;
|
||||
|
||||
$prefix = implode(DIRECTORY_SEPARATOR, array_slice($parts, 0, $length));
|
||||
$prefix = ltrim(str_replace($baseDirectory, '', $prefix), DIRECTORY_SEPARATOR);
|
||||
/**
|
||||
* @var OutputInterface
|
||||
*/
|
||||
protected $output;
|
||||
|
||||
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);
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
|
||||
$this->checkConfiguration();
|
||||
$this->input = $input;
|
||||
$this->output = $output;
|
||||
$this->cacheDir = $kernel->getCacheDir().'/propel';
|
||||
|
||||
if ($input->hasArgument('bundle') && '@' === substr($input->getArgument('bundle'), 0, 1)) {
|
||||
$this->bundle = $this
|
||||
|
@ -96,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 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
|
||||
|
@ -214,19 +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->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'];
|
||||
}
|
||||
|
@ -239,168 +168,205 @@ 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;
|
||||
} else if ("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.
|
||||
*
|
||||
* @return string The current Propel cache directory.
|
||||
*/
|
||||
protected function getCacheDir()
|
||||
{
|
||||
|
@ -408,52 +374,43 @@ 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));
|
||||
}
|
||||
|
||||
$output->writeln(sprintf('Use connection named <comment>%s</comment> in <comment>%s</comment> environment.',
|
||||
$name, $this->getApplication()->getKernel()->getEnvironment()));
|
||||
$result = '';
|
||||
while ($to && false === strpos($from, $to)) {
|
||||
$result .= '../';
|
||||
$to = substr($to, 0, strrpos($to, '/'));
|
||||
}
|
||||
|
||||
return array($name, $defaultConfig);
|
||||
return !$to /*we reached root*/ ? $result . substr($from, 1) : $result. substr($from, strlen($to) + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the database name from a given DSN
|
||||
*
|
||||
* @param string $dsn A DSN
|
||||
* @return string The database name extracted from the given DSN
|
||||
* @param string $dsn A DSN
|
||||
* @return string The database name extracted from the given DSN
|
||||
*/
|
||||
protected function parseDbName($dsn)
|
||||
{
|
||||
preg_match('#dbname=([a-zA-Z0-9\_]+)#', $dsn, $matches);
|
||||
preg_match('#(dbname|Database)=([a-zA-Z0-9\_]+)#', $dsn, $matches);
|
||||
|
||||
if (isset($matches[1])) {
|
||||
return $matches[1];
|
||||
if (isset($matches[2])) {
|
||||
return $matches[2];
|
||||
}
|
||||
|
||||
// e.g. SQLite
|
||||
|
@ -461,151 +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,
|
||||
), $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'];
|
||||
}
|
||||
}
|
||||
|
|
136
Command/AclInitCommand.php
Normal file
136
Command/AclInitCommand.php
Normal file
|
@ -0,0 +1,136 @@
|
|||
<?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;
|
||||
use Symfony\Component\Console\Output\Output;
|
||||
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
/**
|
||||
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||
*/
|
||||
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_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.
|
||||
|
||||
<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:acl:init')
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$outputDir = realpath($this->getApplication()->getKernel()->getRootDir().'/../');
|
||||
|
||||
// Generate ACL model
|
||||
$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, 'model:build');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Prepare SQL
|
||||
$sqlBuildCmd = new \Propel\Generator\Command\SqlBuildCommand();
|
||||
$sqlBuildArgs = array(
|
||||
'--connection' => $this->getConnections($input->getOption('connection')),
|
||||
'--output-dir' => $this->getCacheDir(),
|
||||
);
|
||||
|
||||
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, 'sql:build');
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
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(
|
||||
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,40 +8,35 @@
|
|||
* @license MIT License
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\Command;
|
||||
namespace Propel\Bundle\PropelBundle\Command;
|
||||
|
||||
use Propel\PropelBundle\Command\AbstractCommand;
|
||||
use Propel\PropelBundle\Command\ModelBuildCommand;
|
||||
use Propel\PropelBundle\Command\SqlBuildCommand;
|
||||
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
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');
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,26 +47,34 @@ class BuildCommand extends AbstractCommand
|
|||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if (!$input->getOption('sql')) {
|
||||
$modelCommand = new ModelBuildCommand();
|
||||
$modelCommand->setApplication($this->getApplication());
|
||||
$modelCommand->execute($input, $output);
|
||||
$in = new ArrayInput(array(
|
||||
'command' => 'propel:model:build',
|
||||
'--connection' => $input->getOption('connection'),
|
||||
'--verbose' => $input->getOption('verbose')
|
||||
));
|
||||
$cmd = $this->getApplication()->find('propel:model:build');
|
||||
$cmd->run($in, $output);
|
||||
}
|
||||
|
||||
if (!$input->getOption('classes')) {
|
||||
$sqlCommand = new SqlBuildCommand();
|
||||
$sqlCommand->setApplication($this->getApplication());
|
||||
$sqlCommand->execute($input, $output);
|
||||
$in = new ArrayInput(array(
|
||||
'command' => 'propel:build:sql',
|
||||
'--connection' => $input->getOption('connection'),
|
||||
'--verbose' => $input->getOption('verbose'),
|
||||
));
|
||||
$cmd = $this->getApplication()->find('propel:sql:build');
|
||||
$cmd->run($in, $output);
|
||||
}
|
||||
|
||||
if ($input->getOption('insert-sql')) {
|
||||
$insertCommand = new SqlInsertCommand();
|
||||
$insertCommand->setApplication($this->getApplication());
|
||||
|
||||
// By-pass the '--force' required option
|
||||
$this->addOption('force', '', InputOption::VALUE_NONE, '');
|
||||
$input->setOption('force', true);
|
||||
|
||||
$insertCommand->execute($input, $output);
|
||||
$in = new ArrayInput(array(
|
||||
'command' => 'propel:sql:insert',
|
||||
'--connection' => $input->getOption('connection'),
|
||||
'--force' => true,
|
||||
'--verbose' => $input->getOption('verbose'),
|
||||
));
|
||||
$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,10 +44,9 @@ class DatabaseCreateCommand extends AbstractCommand
|
|||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->writeSection($output, '[Propel] You are running the command: propel:database:create');
|
||||
|
||||
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>');
|
||||
|
@ -52,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 catched',
|
||||
'',
|
||||
$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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,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.'#',
|
||||
'dbname='.strtolower($config['adapter']),
|
||||
$config['connection']['dsn']
|
||||
$config['dsn'] = preg_replace(
|
||||
'#;?(dbname|Database)='.$dbName.'#',
|
||||
'',
|
||||
$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,53 +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)
|
||||
{
|
||||
$this->writeSection($output, '[Propel] You are running the command: propel:database:drop');
|
||||
|
||||
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 catched',
|
||||
'',
|
||||
$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,13 +8,12 @@
|
|||
* @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;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
|
||||
/**
|
||||
* FixturesDumpCommand.
|
||||
|
@ -27,7 +26,7 @@ class FixturesDumpCommand extends AbstractCommand
|
|||
* Default fixtures directory.
|
||||
* @var string
|
||||
*/
|
||||
private $defaultFixturesDir = 'app/propel/fixtures';
|
||||
protected $defaultFixturesDir = 'app/propel/fixtures';
|
||||
|
||||
/**
|
||||
* @see Command
|
||||
|
@ -35,50 +34,49 @@ 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')
|
||||
->setHelp(<<<EOT
|
||||
The <info>propel:fixtures:dump</info> dumps data from database into YAML fixtures file.
|
||||
|
||||
<info>php app/console propel:fixtures:dump</info>
|
||||
|
||||
The <info>--connection</info> parameter allows you to change the connection to use.
|
||||
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)
|
||||
{
|
||||
$this->writeSection($output, '[Propel] You are running the command: propel:fixtures:dump');
|
||||
$fixtureDir = $input->getOption('dir') ?: $this->defaultFixturesDir;
|
||||
$path = realpath($this->getApplication()->getKernel()->getRootDir() . '/../') . '/' . $fixtureDir;
|
||||
|
||||
list($name, $defaultConfig) = $this->getConnection($input, $output);
|
||||
|
||||
$path = realpath($this->getApplication()->getKernel()->getRootDir() . '/../') . '/' . $this->defaultFixturesDir;
|
||||
$filename = $path . '/fixtures_' . time() . '.yml';
|
||||
|
||||
$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;
|
||||
if (!file_exists($path)) {
|
||||
$output->writeln("<info>The $path folder does not exists.</info>");
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
$output->writeln('');
|
||||
$output->writeln(sprintf('>> <info>File+</info> %s', $filename));
|
||||
$filename = $path . '/fixtures_' . time() . '.yml';
|
||||
$dumper = $this->getContainer()->get('propel.dumper.yaml');
|
||||
|
||||
$dumper->dump($filename, $input->getOption('connection'));
|
||||
|
||||
$this->writeNewFile($output, $filename);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -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,19 +95,25 @@ 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)
|
||||
{
|
||||
$this->writeSection($output, '[Propel] You are running the command: propel:fixtures:load');
|
||||
|
||||
$this->filesystem = new Filesystem();
|
||||
|
||||
if (null !== $this->bundle) {
|
||||
|
@ -128,33 +122,29 @@ EOT
|
|||
$this->absoluteFixturesPath = realpath($this->getApplication()->getKernel()->getRootDir() . '/../' . $input->getOption('dir'));
|
||||
}
|
||||
|
||||
if ($input->getOption('verbose')) {
|
||||
$this->additionalPhingArgs[] = 'verbose';
|
||||
}
|
||||
|
||||
if (!$this->absoluteFixturesPath && !file_exists($this->absoluteFixturesPath)) {
|
||||
return $this->writeSection($output, array(
|
||||
'The fixtures directory "' . $this->absoluteFixturesPath . '" does not exist.'
|
||||
), '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)) {
|
||||
$output->writeln('<info>No SQL fixtures found.</info>');
|
||||
$output->writeln('No <info>SQL</info> fixtures found.');
|
||||
}
|
||||
}
|
||||
|
||||
if ($input->getOption('xml') || $noOptions) {
|
||||
if (-1 === $this->loadFixtures($input, $output, 'xml')) {
|
||||
$output->writeln('<info>No XML fixtures found.</info>');
|
||||
$output->writeln('No <info>XML</info> fixtures found.');
|
||||
}
|
||||
}
|
||||
|
||||
if ($input->getOption('yml') || $noOptions) {
|
||||
if (-1 === $this->loadFixtures($input, $output, 'yml')) {
|
||||
$output->writeln('<info>No YAML fixtures found.</info>');
|
||||
$output->writeln('No <info>YML</info> fixtures found.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -162,9 +152,9 @@ EOT
|
|||
/**
|
||||
* Load fixtures
|
||||
*
|
||||
* @param \Symfony\Component\Console\Input\InputInterface $input
|
||||
* @param \Symfony\Component\Console\Input\InputInterface $input
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
* @return void
|
||||
* @param string $type If specified, only fixtures with the given type will be loaded (yml, xml).
|
||||
*/
|
||||
protected function loadFixtures(InputInterface $input, OutputInterface $output, $type = null)
|
||||
{
|
||||
|
@ -178,32 +168,19 @@ 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());
|
||||
$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');
|
||||
$nb = $loader->load($datas, $connectionName);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->writeSection(
|
||||
$output,
|
||||
sprintf('<comment>%s</comment> %s fixtures file%s loaded.', $nb, strtoupper($type), $nb > 1 ? 's' : ''),
|
||||
'fg=white;bg=black'
|
||||
);
|
||||
$output->writeln(sprintf('<comment>%s</comment> %s fixtures file%s loaded.', $nb, strtoupper($type), $nb > 1 ? 's' : ''));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -211,36 +188,35 @@ EOT
|
|||
/**
|
||||
* Load SQL fixtures
|
||||
*
|
||||
* @param \Symfony\Component\Console\Input\InputInterface $input
|
||||
* @param \Symfony\Component\Console\Input\InputInterface $input
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
* @return void
|
||||
*/
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -252,60 +228,60 @@ EOT
|
|||
/**
|
||||
* Prepare the cache directory
|
||||
*
|
||||
* @param string $tmpdir The temporary directory path.
|
||||
* @param string $tmpdir The temporary directory path.
|
||||
*/
|
||||
protected function prepareCache($tmpdir)
|
||||
{
|
||||
// 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) {
|
||||
$this->writeSection($output, array(
|
||||
'', 'All SQL statements have been inserted.'
|
||||
), 'fg=green;bg=black');
|
||||
// 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fixtures files to load.
|
||||
*
|
||||
* @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.
|
||||
* @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.
|
||||
*
|
||||
* @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);
|
||||
|
||||
|
@ -326,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');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
|
||||
|
||||
/**
|
||||
* This file is part of the PropelBundle package.
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
|
@ -9,64 +8,91 @@
|
|||
* @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\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;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
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);
|
||||
|
||||
|
@ -85,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);
|
||||
}
|
||||
|
@ -97,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();
|
||||
}
|
||||
}
|
|
@ -1,59 +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;
|
||||
|
||||
/**
|
||||
* GraphvizCommand.
|
||||
*
|
||||
* @author William DURAND <william.durand1@gmail.com>
|
||||
*/
|
||||
class GraphvizCommand extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* @see Command
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDescription('Generates Graphviz file for your project')
|
||||
->setHelp(<<<EOT
|
||||
The <info>propel:graphviz</info> generates Graphviz file for your project.
|
||||
|
||||
<info>php app/console propel:graphviz</info>
|
||||
EOT
|
||||
)
|
||||
->setName('propel:graphviz')
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Command
|
||||
*
|
||||
* @throws \InvalidArgumentException When the target directory does not exist
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->writeSection($output, '[Propel] You are running the command: propel:graphviz');
|
||||
|
||||
$dest = $this->getApplication()->getKernel()->getRootDir() . '/propel/graph/';
|
||||
|
||||
$this->callPhing('graphviz', array(
|
||||
'propel.graph.dir' => $dest,
|
||||
));
|
||||
|
||||
$output->writeln(sprintf('Graphviz file is in <info>%s</info>.', $dest));
|
||||
}
|
||||
}
|
55
Command/GraphvizGenerateCommand.php
Normal file
55
Command/GraphvizGenerateCommand.php
Normal file
|
@ -0,0 +1,55 @@
|
|||
<?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\GraphvizGenerateCommand as BaseGraphvizGenerateCommand;
|
||||
|
||||
/**
|
||||
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||
*/
|
||||
class GraphvizGenerateCommand extends WrappedCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this
|
||||
->setName('propel:graphviz:generate')
|
||||
->setDescription('Generate Graphviz files (.dot)')
|
||||
|
||||
->addOption('output-dir', null, InputOption::VALUE_REQUIRED, 'The output directory', BaseGraphvizGenerateCommand::DEFAULT_OUTPUT_DIRECTORY)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createSubCommandInstance()
|
||||
{
|
||||
return new BaseGraphvizGenerateCommand();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getSubCommandArguments(InputInterface $input)
|
||||
{
|
||||
return array(
|
||||
'--output-dir' => $input->getOption('output-dir'),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,100 +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\InputArgument;
|
||||
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 InitAclCommand extends SqlInsertCommand
|
||||
{
|
||||
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')
|
||||
->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.
|
||||
|
||||
<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:init:acl')
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->writeSection($output, '[Propel] You are running the command: propel:init:acl');
|
||||
if ($input->getOption('verbose')) {
|
||||
$this->additionalPhingArgs[] = 'verbose';
|
||||
}
|
||||
|
||||
// Generate ACL model
|
||||
if (true == $result = $this->callPhing('om')) {
|
||||
$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');
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Prepare SQL directory
|
||||
$sqlDirectory = $this->getSqlDir();
|
||||
$filesystem = new Filesystem();
|
||||
$filesystem->remove($sqlDirectory);
|
||||
$filesystem->mkdir($sqlDirectory);
|
||||
|
||||
if (true == $result = $this->callPhing('build-sql', array('propel.sql.dir' => $sqlDirectory))) {
|
||||
$this->writeSection(
|
||||
$output,
|
||||
'<comment>1</comment> <info>SQL file has been generated.</info>',
|
||||
'bg=black'
|
||||
);
|
||||
} else {
|
||||
$this->writeTaskError($output, 'build-sql');
|
||||
return 2;
|
||||
}
|
||||
|
||||
return parent::execute($input, $output);
|
||||
}
|
||||
|
||||
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()
|
||||
);
|
||||
}
|
||||
}
|
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,52 +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\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')
|
||||
->setHelp(<<<EOT
|
||||
The <info>propel:migration:generate-diff</info> command compares the current database structure and the available schemas. If there is a difference, it creates a migration file.
|
||||
|
||||
<info>php app/console propel:migration:generate-diff</info>
|
||||
EOT
|
||||
)
|
||||
->setName('propel:migration:generate-diff')
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Command
|
||||
*
|
||||
* @throws \InvalidArgumentException When the target directory does not exist
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->callPhing('diff');
|
||||
|
||||
$this->writeSummary($output, 'propel-sql-diff');
|
||||
}
|
||||
}
|
|
@ -8,63 +8,58 @@
|
|||
* @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 Symfony\Component\Console\Output\Output;
|
||||
|
||||
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');
|
||||
} else if($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,62 +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\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
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')
|
||||
->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()
|
||||
{
|
||||
$this->writeSection($output, '[Propel] You are running the command: propel:model:build');
|
||||
return new BaseModelBuildCommand();
|
||||
}
|
||||
|
||||
if ($input->getOption('verbose')) {
|
||||
$this->additionalPhingArgs[] = 'verbose';
|
||||
}
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getSubCommandArguments(InputInterface $input)
|
||||
{
|
||||
$outputDir = $this->getApplication()->getKernel()->getRootDir().'/../';
|
||||
|
||||
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 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
|
||||
{
|
||||
static public 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,90 +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;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
$this->writeSection($output, '[Propel] You are running the command: propel:reverse');
|
||||
|
||||
if ($input->getOption('verbose')) {
|
||||
$this->additionalPhingArgs[] = 'verbose';
|
||||
}
|
||||
|
||||
list($name, $defaultConfig) = $this->getConnection($input, $output);
|
||||
|
||||
$ret = $this->callPhing('reverse', array(
|
||||
'propel.project' => $name,
|
||||
'propel.database' => $defaultConfig['adapter'],
|
||||
'propel.database.url' => $defaultConfig['connection']['dsn'],
|
||||
'propel.database.user' => $defaultConfig['connection']['user'],
|
||||
'propel.database.password' => isset($defaultConfig['connection']['password']) ? $defaultConfig['connection']['password'] : '',
|
||||
));
|
||||
|
||||
if (true === $ret) {
|
||||
$filesystem = new Filesystem();
|
||||
$generated = $this->getCacheDir().'/schema.xml';
|
||||
$filename = $name . '_reversed_schema.xml';
|
||||
$destFile = $this->getApplication()->getKernel()->getRootDir() . '/propel/generated-schemas/' . $filename;
|
||||
|
||||
if (file_exists($generated)) {
|
||||
$filesystem->copy($generated, $destFile);
|
||||
$output->writeln(array(
|
||||
'',
|
||||
sprintf('>> <info>File+</info> %s', $destFile),
|
||||
));
|
||||
} else {
|
||||
$output->writeln(array('', 'No generated files.'));
|
||||
}
|
||||
} else {
|
||||
$this->writeTaskError($output, 'reverse');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,94 +8,51 @@
|
|||
* @license MIT License
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\Command;
|
||||
namespace Propel\Bundle\PropelBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Output\Output;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
use Propel\PropelBundle\Command\AbstractCommand;
|
||||
|
||||
/**
|
||||
* 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
|
||||
)
|
||||
$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()
|
||||
{
|
||||
$this->writeSection($output, '[Propel] You are running the command: propel:sql:build');
|
||||
return new \Propel\Generator\Command\SqlBuildCommand();
|
||||
}
|
||||
|
||||
if ($input->getOption('verbose')) {
|
||||
$this->additionalPhingArgs[] = 'verbose';
|
||||
}
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getSubCommandArguments(InputInterface $input)
|
||||
{
|
||||
$defaultSqlDir = $this->getContainer()->getParameter('propel.configuration')['paths']['sqlDir'];
|
||||
|
||||
$finder = new Finder();
|
||||
$filesystem = new Filesystem();
|
||||
|
||||
$sqlDir = $this->getApplication()->getKernel()->getRootDir(). DIRECTORY_SEPARATOR . 'propel'. DIRECTORY_SEPARATOR . 'sql';
|
||||
|
||||
$filesystem->remove($sqlDir);
|
||||
$filesystem->mkdir($sqlDir);
|
||||
|
||||
// Execute the task
|
||||
$ret = $this->callPhing('build-sql', array(
|
||||
'propel.sql.dir' => $sqlDir
|
||||
));
|
||||
|
||||
if (true === $ret) {
|
||||
$files = $finder->name('*')->in($sqlDir);
|
||||
|
||||
$nbFiles = 0;
|
||||
foreach ($files as $file) {
|
||||
$this->writeNewFile($output, (string) $file);
|
||||
|
||||
if ('sql' === pathinfo($file->getFilename(), PATHINFO_EXTENSION)) {
|
||||
$nbFiles++;
|
||||
}
|
||||
}
|
||||
|
||||
$this->writeSection(
|
||||
$output,
|
||||
sprintf('<comment>%d</comment> <info>SQL file%s ha%s been generated.</info>',
|
||||
$nbFiles, $nbFiles > 1 ? 's' : '', $nbFiles > 1 ? 've' : 's'
|
||||
),
|
||||
'bg=black'
|
||||
);
|
||||
} 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 array(
|
||||
'--connection' => $this->getConnections($input->getOption('connection')),
|
||||
'--output-dir' => $input->getOption('sql-dir') ?: $defaultSqlDir,
|
||||
'--overwrite' => $input->getOption('overwrite')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,131 +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';
|
||||
|
||||
$this->writeSection($output, '[Propel] You are running the command: propel:sql:insert');
|
||||
|
||||
if ($input->getOption('force')) {
|
||||
if ($input->getOption('verbose')) {
|
||||
$this->additionalPhingArgs[] = 'verbose';
|
||||
}
|
||||
|
||||
$connections = $this->getConnections();
|
||||
$sqlDir = $this->getSqlDir();
|
||||
|
||||
$manager = new \PropelSqlManager();
|
||||
$manager->setWorkingDirectory($sqlDir);
|
||||
$manager->setConnections($connections);
|
||||
|
||||
if ($input->getOption('connection')) {
|
||||
list($name, $config) = $this->getConnection($input, $output);
|
||||
$this->doSqlInsert($manager, $output, $name);
|
||||
} else {
|
||||
foreach ($connections as $name => $config) {
|
||||
$output->writeln(sprintf('Use connection named <comment>%s</comment> in <comment>%s</comment> environment.',
|
||||
$name, $this->getApplication()->getKernel()->getEnvironment()));
|
||||
$this->doSqlInsert($manager, $output, $name);
|
||||
}
|
||||
}
|
||||
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) {
|
||||
$this->writeSection(
|
||||
$output,
|
||||
'<info>All SQL statements have been inserted.</info>',
|
||||
'bg=black'
|
||||
);
|
||||
} else {
|
||||
$this->writeSection(
|
||||
$output,
|
||||
'<comment>No SQL statements found.</comment>',
|
||||
'bg=black'
|
||||
);
|
||||
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,125 +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)
|
||||
{
|
||||
$this->writeSection($output, '[Propel] You are running the command: propel:table:drop');
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
list($name, $config) = $this->getConnection($input, $output);
|
||||
$connection = \Propel::getConnection($name);
|
||||
$adapter = \Propel::getDB($name);
|
||||
|
||||
$showStatement = $connection->prepare('SHOW TABLES;');
|
||||
$showStatement->execute();
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
$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 catched',
|
||||
'',
|
||||
$e->getMessage()
|
||||
), 'fg=white;bg=red');
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$output->writeln('<error>You have to use the "--force" option to drop some tables.</error>');
|
||||
|
||||
$showStatement = $connection->prepare('SHOW TABLES;');
|
||||
$showStatement->execute();
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
$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,10 +8,12 @@
|
|||
* @license MIT License
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\Controller;
|
||||
namespace Propel\Bundle\PropelBundle\Controller;
|
||||
|
||||
use Symfony\Bridge\Propel1\DataCollector\PropelDataCollector;
|
||||
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;
|
||||
|
||||
/**
|
||||
|
@ -19,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'),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -44,15 +41,15 @@ class PanelController extends ContainerAware
|
|||
/**
|
||||
* Renders the profiler panel for the given token.
|
||||
*
|
||||
* @param string $token The profiler token
|
||||
* @param string $connection The connection name
|
||||
* @param string $token The profiler token
|
||||
* @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);
|
||||
|
@ -63,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,10 +8,10 @@
|
|||
* @license MIT License
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\DataFixtures;
|
||||
|
||||
use \Propel;
|
||||
namespace Propel\Bundle\PropelBundle\DataFixtures;
|
||||
|
||||
use Propel\Runtime\Map\DatabaseMap;
|
||||
use Propel\Runtime\Propel;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
/**
|
||||
|
@ -23,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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -53,7 +62,7 @@ abstract class AbstractDataHandler
|
|||
/**
|
||||
* Load Map builders.
|
||||
*
|
||||
* @param string $connectionName A connection name.
|
||||
* @param string $connectionName A connection name.
|
||||
*/
|
||||
protected function loadMapBuilders($connectionName = null)
|
||||
{
|
||||
|
@ -62,27 +71,46 @@ abstract class AbstractDataHandler
|
|||
}
|
||||
|
||||
$this->dbMap = Propel::getDatabaseMap($connectionName);
|
||||
|
||||
if (0 === count($this->dbMap->getTables())) {
|
||||
$finder = new Finder();
|
||||
$files = $finder->files()->name('*TableMap.php')->in($this->getRootDir() . '/../')->exclude('Tests');
|
||||
$files = $finder
|
||||
->files()->name('*TableMap.php')
|
||||
->in($this->getModelSearchPaths($connectionName))
|
||||
->notName('TableMap.php')
|
||||
->exclude('PropelBundle')
|
||||
->exclude('Tests');
|
||||
|
||||
foreach ($files as $file) {
|
||||
$class = $this->guessFullClassName($file->getRelativePath(), basename($file, '.php'));
|
||||
|
||||
if (null !== $class) {
|
||||
if (null !== $class && $this->isInDatabase($class, $connectionName)) {
|
||||
$this->dbMap->addTableFromMapClass($class);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a table is in a database
|
||||
*
|
||||
* @param string $class
|
||||
* @param string $connectionName
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
protected function isInDatabase($class, $connectionName)
|
||||
{
|
||||
return constant($class.'::DATABASE_NAME') === $connectionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to find a valid class with its namespace based on the filename.
|
||||
* Based on the PSR-0 standard, the namespace should be the directory structure.
|
||||
*
|
||||
* @param string $path The relative path of the file.
|
||||
* @param string $shortClassName The short class name aka the filename without extension.
|
||||
* @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)
|
||||
{
|
||||
|
@ -106,4 +134,27 @@ abstract class AbstractDataHandler
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the search path for models out of the configuration.
|
||||
*
|
||||
* @param string $connectionName A connection name.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function getModelSearchPaths($connectionName)
|
||||
{
|
||||
$searchPath = array();
|
||||
|
||||
if (!empty($this->datasources['database']['connections'][$connectionName]['model_paths'])) {
|
||||
$modelPaths = $this->datasources['database']['connections'][$connectionName]['model_paths'];
|
||||
foreach ($modelPaths as $modelPath) {
|
||||
$searchPath[] = $this->getRootDir() . '/../' . $modelPath;
|
||||
}
|
||||
} else {
|
||||
$searchPath[] = $this->getRootDir() . '/../';
|
||||
}
|
||||
|
||||
return $searchPath;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,13 +8,12 @@
|
|||
* @license MIT License
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\DataFixtures\Dumper;
|
||||
namespace Propel\Bundle\PropelBundle\DataFixtures\Dumper;
|
||||
|
||||
use \PDO;
|
||||
use \Propel;
|
||||
use \BaseObject;
|
||||
|
||||
use Propel\PropelBundle\DataFixtures\AbstractDataHandler;
|
||||
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.
|
||||
|
@ -56,7 +55,7 @@ abstract class AbstractDataDumper extends AbstractDataHandler implements DataDum
|
|||
* Dumps data to fixture from a given connection and
|
||||
* returns an array.
|
||||
*
|
||||
* @param string $connectionName The connection name
|
||||
* @param string $connectionName The connection name
|
||||
* @return array
|
||||
*/
|
||||
protected function getDataAsArray()
|
||||
|
@ -70,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;
|
||||
|
@ -108,15 +107,19 @@ 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);
|
||||
}
|
||||
|
||||
foreach ($resultsSets as $rows) {
|
||||
if(count($rows) > 0 && !isset($dumpData[$tableName])) {
|
||||
if (count($rows) > 0 && !isset($dumpData[$tableName])) {
|
||||
$dumpData[$tableName] = array();
|
||||
|
||||
foreach ($rows as $row) {
|
||||
|
@ -148,16 +151,19 @@ abstract class AbstractDataDumper extends AbstractDataHandler implements DataDum
|
|||
$values[$col] = $relatedTable->getPhpName().'_'.$row[$col];
|
||||
$values[$col] = strlen($row[$col]) ? $relatedTable->getPhpName().'_'.$row[$col] : '';
|
||||
}
|
||||
}
|
||||
elseif (!$isPrimaryKey || ($isPrimaryKey && !$tableMap->isUseIdGenerator())) {
|
||||
if (!empty($row[$col]) && 'ARRAY' === $column->getType()) {
|
||||
} elseif (!$isPrimaryKey || ($isPrimaryKey && !$tableMap->isUseIdGenerator())) {
|
||||
if (!empty($row[$col]) && PropelTypes::PHP_ARRAY === $column->getType()) {
|
||||
$serialized = substr($row[$col], 2, -2);
|
||||
$row[$col] = $serialized ? explode(' | ', $serialized) : array();
|
||||
$row[$col] = $serialized ? explode(' | ', $serialized) : array();
|
||||
}
|
||||
|
||||
// We did not want auto incremented primary keys
|
||||
$values[$col] = $row[$col];
|
||||
}
|
||||
|
||||
if (PropelTypes::OBJECT === $column->getType()) {
|
||||
$values[$col] = unserialize($row[$col]);
|
||||
}
|
||||
}
|
||||
|
||||
if (count($primaryKeys) > 1 || (count($primaryKeys) > 0 && count($foreignKeys) > 0)) {
|
||||
|
@ -177,7 +183,7 @@ abstract class AbstractDataDumper extends AbstractDataHandler implements DataDum
|
|||
* Fixes the ordering of foreign key data, by outputting data
|
||||
* a foreign key depends on before the table with the foreign key.
|
||||
*
|
||||
* @param array $classes The array with the class names
|
||||
* @param array $classes The array with the class names
|
||||
* @return array
|
||||
*/
|
||||
protected function fixOrderingOfForeignKeyData($classes)
|
||||
|
@ -185,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()) {
|
||||
|
@ -214,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.
|
||||
|
@ -20,8 +20,8 @@ interface DataDumperInterface
|
|||
/**
|
||||
* Dumps data to fixtures from a given connection.
|
||||
*
|
||||
* @param string $filename The file name to write data.
|
||||
* @param string $connectionName The Propel connection name.
|
||||
* @param string $filename The file name to write data.
|
||||
* @param string $connectionName The Propel connection name.
|
||||
*/
|
||||
function dump($filename, $connectionName = null);
|
||||
public function dump($filename, $connectionName = null);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* @license MIT License
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\DataFixtures\Dumper;
|
||||
namespace Propel\Bundle\PropelBundle\DataFixtures\Dumper;
|
||||
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
|
@ -24,6 +24,11 @@ class YamlDataDumper extends AbstractDataDumper
|
|||
*/
|
||||
protected function transformArrayToData($data)
|
||||
{
|
||||
return Yaml::dump($data, 3);
|
||||
return Yaml::dump(
|
||||
$data,
|
||||
$inline = 3,
|
||||
$indent = 4,
|
||||
Yaml::DUMP_OBJECT
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,18 +8,15 @@
|
|||
* @license MIT License
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\DataFixtures\Loader;
|
||||
namespace Propel\Bundle\PropelBundle\DataFixtures\Loader;
|
||||
|
||||
use \Propel;
|
||||
use \BasePeer;
|
||||
use \BaseObject;
|
||||
use \ColumnMap;
|
||||
use \PropelException;
|
||||
|
||||
use Propel\PropelBundle\DataFixtures\AbstractDataHandler;
|
||||
use Propel\PropelBundle\Util\PropelInflector;
|
||||
|
||||
use Symfony\Component\Finder\Finder;
|
||||
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.
|
||||
|
@ -41,7 +38,7 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
|||
/**
|
||||
* Transforms a file containing data in an array.
|
||||
*
|
||||
* @param string $file A filename.
|
||||
* @param string $file A filename.
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function transformDataToArray($file);
|
||||
|
@ -60,16 +57,19 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
|||
try {
|
||||
$this->con->beginTransaction();
|
||||
|
||||
$datas = array();
|
||||
foreach ($files as $file) {
|
||||
$datas = $this->transformDataToArray($file);
|
||||
$content = $this->transformDataToArray($file);
|
||||
|
||||
if (count($datas) > 0) {
|
||||
$this->deleteCurrentData($datas);
|
||||
$this->loadDataFromArray($datas);
|
||||
if (count($content) > 0) {
|
||||
$datas = array_merge_recursive($datas, $content);
|
||||
$nbFiles++;
|
||||
}
|
||||
}
|
||||
|
||||
$this->deleteCurrentData($datas);
|
||||
$this->loadDataFromArray($datas);
|
||||
|
||||
$this->con->commit();
|
||||
} catch (\Exception $e) {
|
||||
$this->con->rollBack();
|
||||
|
@ -82,7 +82,7 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
|||
/**
|
||||
* Deletes current data.
|
||||
*
|
||||
* @param array $data The data to delete
|
||||
* @param array $data The data to delete
|
||||
*/
|
||||
protected function deleteCurrentData($data = null)
|
||||
{
|
||||
|
@ -93,18 +93,28 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
|||
if (in_array($class, $this->deletedClasses)) {
|
||||
continue;
|
||||
}
|
||||
$this->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));
|
||||
}
|
||||
/**
|
||||
* Delete data for a given class, and for its ancestors (if any).
|
||||
*
|
||||
* @param string $class Class name to delete
|
||||
*/
|
||||
protected function deleteClassData($class)
|
||||
{
|
||||
$tableMap = $this->dbMap->getTable(constant(constant($class.'::TABLE_MAP').'::TABLE_NAME'));
|
||||
$tableMap->doDeleteAll($this->con);
|
||||
|
||||
// bypass the soft_delete behavior if enabled
|
||||
$deleteMethod = method_exists($peerClass, 'doForceDeleteAll') ? 'doForceDeleteAll' : 'doDeleteAll';
|
||||
call_user_func(array($peerClass, $deleteMethod), $this->con);
|
||||
$this->deletedClasses[] = $class;
|
||||
|
||||
$this->deletedClasses[] = $class;
|
||||
// Remove ancestors data
|
||||
if (false !== ($parentClass = get_parent_class(get_parent_class($class)))) {
|
||||
$reflectionClass = new \ReflectionClass($parentClass);
|
||||
if (!$reflectionClass->isAbstract()) {
|
||||
$this->deleteClassData($parentClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -112,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)
|
||||
{
|
||||
|
@ -121,17 +131,20 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
|||
}
|
||||
|
||||
foreach ($data as $class => $datas) {
|
||||
$class = trim($class);
|
||||
$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));
|
||||
|
@ -139,28 +152,30 @@ 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) {
|
||||
try {
|
||||
if (is_array($value) && 's' === substr($name, -1)) {
|
||||
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) {
|
||||
// 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 ('ARRAY' !== $tableMap->getColumn($name)->getType()) {
|
||||
throw $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 (PropelTypes::PHP_ARRAY !== $tableMap->getColumn($name)->getType()
|
||||
&& PropelTypes::OBJECT !== $tableMap->getColumn($name)->getType()) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -168,7 +183,7 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
|||
$isARealColumn = true;
|
||||
if ($tableMap->hasColumn($name)) {
|
||||
$column = $tableMap->getColumn($name);
|
||||
} else if ($tableMap->hasColumnByPhpName($name)) {
|
||||
} elseif ($tableMap->hasColumnByPhpName($name)) {
|
||||
$column = $tableMap->getColumnByPhpName($name);
|
||||
} else {
|
||||
$isARealColumn = false;
|
||||
|
@ -176,10 +191,13 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
|||
|
||||
// foreign key?
|
||||
if ($isARealColumn) {
|
||||
// self referencing entry
|
||||
if ($column->isPrimaryKey() && null !== $value) {
|
||||
if (isset($this->object_references[$class.'_'.$value])) {
|
||||
$obj = $this->object_references[$class.'_'.$value];
|
||||
/*
|
||||
* A column, which is a PrimaryKey (self referencing, e.g. versionable behavior),
|
||||
* 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[$this->cleanObjectRef($class.'_'.$value)])) {
|
||||
$obj = $this->object_references[$this->cleanObjectRef($class.'_'.$value)];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
@ -187,21 +205,25 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
if (false !== $pos = array_search($name, $column_names)) {
|
||||
$obj->setByPosition($pos, $value);
|
||||
}
|
||||
elseif (is_callable(array($obj, $method = 'set'.ucfirst(PropelInflector::camelize($name))))) {
|
||||
} elseif (is_callable(array($obj, $method = 'set'.ucfirst(PropelInflector::camelize($name))))) {
|
||||
$obj->$method($value);
|
||||
} else {
|
||||
throw new \InvalidArgumentException(sprintf('Column "%s" does not exist for class "%s".', $name, $class));
|
||||
|
@ -210,10 +232,34 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
|||
|
||||
$obj->save($this->con);
|
||||
|
||||
// save the object for future reference
|
||||
if (method_exists($obj, 'getPrimaryKey')) {
|
||||
$this->object_references[$class.'_'.$key] = $obj;
|
||||
}
|
||||
$this->saveParentReference($class, $key, $obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ActiveRecordInterface $obj A Propel object
|
||||
*/
|
||||
protected function saveParentReference($class, $key, &$obj)
|
||||
{
|
||||
if (!method_exists($obj, 'getPrimaryKey')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -221,19 +267,24 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
|||
/**
|
||||
* 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->getPhpName();
|
||||
$middleClass = $middleTable->getClassname();
|
||||
$tableName = constant(constant(get_class($obj).'::TABLE_MAP').'::TABLE_NAME');
|
||||
|
||||
foreach ($middleTable->getColumns() as $column) {
|
||||
if ($column->isForeignKey() && constant(constant(get_class($obj).'::PEER').'::TABLE_NAME') != $column->getRelatedTableName()) {
|
||||
$relatedClass = $this->dbMap->getTable($column->getRelatedTableName())->getPhpName();
|
||||
break;
|
||||
if ($column->isForeignKey()) {
|
||||
if ($tableName !== $column->getRelatedTableName()) {
|
||||
$relatedClass = $this->dbMap->getTable($column->getRelatedTableName())->getClassname();
|
||||
$relatedSetter = 'set' . $column->getRelation()->getName();
|
||||
} else {
|
||||
$setter = 'set' . $column->getRelation()->getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,11 +292,8 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
|||
throw new \InvalidArgumentException(sprintf('Unable to find the many-to-many relationship for object "%s".', get_class($obj)));
|
||||
}
|
||||
|
||||
$setter = 'set'.get_class($obj);
|
||||
$relatedSetter = 'set'.$relatedClass;
|
||||
|
||||
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)
|
||||
);
|
||||
|
@ -253,8 +301,13 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
|||
|
||||
$middle = new $middleClass();
|
||||
$middle->$setter($obj);
|
||||
$middle->$relatedSetter($this->object_references[$relatedClass.'_'.$value]);
|
||||
$middle->save();
|
||||
$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.
|
||||
|
@ -20,8 +20,8 @@ interface DataLoaderInterface
|
|||
/**
|
||||
* Loads data from a set of files.
|
||||
*
|
||||
* @param array $files A set of files containing datas to load.
|
||||
* @param string $connectionName The Propel connection name
|
||||
* @param array $files A set of files containing datas to load.
|
||||
* @param string $connectionName The Propel connection name
|
||||
*/
|
||||
function load($files = array(), $connectionName);
|
||||
public function load($files = array(), $connectionName);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -28,7 +28,7 @@ class XmlDataLoader extends AbstractDataLoader
|
|||
}
|
||||
|
||||
/**
|
||||
* @param SimpleXMLElement $xml
|
||||
* @param SimpleXMLElement $xml
|
||||
* @return array
|
||||
*/
|
||||
protected function simpleXmlToArray($xml)
|
||||
|
@ -39,7 +39,7 @@ class XmlDataLoader extends AbstractDataLoader
|
|||
// First make a valid key which is the Ns (Namespace) attribute
|
||||
// + the element name (the class name)
|
||||
foreach ($value->attributes() as $subkey => $subvalue) {
|
||||
if ('Namespace' === (string)$subkey) {
|
||||
if ('Namespace' === (string) $subkey) {
|
||||
$key = $subvalue . '\\' . $key;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
* @license MIT License
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\DataFixtures\Loader;
|
||||
namespace Propel\Bundle\PropelBundle\DataFixtures\Loader;
|
||||
|
||||
use Faker\Generator;
|
||||
use Symfony\Component\Yaml\ParseException;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
/**
|
||||
|
@ -19,11 +21,58 @@ use Symfony\Component\Yaml\Yaml;
|
|||
*/
|
||||
class YamlDataLoader extends AbstractDataLoader
|
||||
{
|
||||
/**
|
||||
* @var \Faker\Generator
|
||||
*/
|
||||
private $faker;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct($rootDir, array $datasources, Generator $faker = null)
|
||||
{
|
||||
parent::__construct($rootDir, $datasources);
|
||||
|
||||
$this->faker = $faker;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function transformDataToArray($file)
|
||||
{
|
||||
if (strpos($file, "\n") === false && is_file($file)) {
|
||||
if (false === is_readable($file)) {
|
||||
throw new ParseException(sprintf('Unable to parse "%s" as the file is not readable.', $file));
|
||||
}
|
||||
|
||||
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) {
|
||||
echo $text . "\n";
|
||||
};
|
||||
}
|
||||
|
||||
ob_start();
|
||||
$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
|
||||
$file = is_array($retval) ? $retval : $content;
|
||||
|
||||
// if an array is returned by the config file assume it's in plain php form else in YAML
|
||||
if (is_array($file)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
return Yaml::parse($file);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,217 +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
|
||||
* ...
|
||||
*/
|
||||
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()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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')->defaultValue('mysql')->end()
|
||||
->scalarNode('user')->defaultValue('root')->end()
|
||||
->scalarNode('password')->defaultValue('')->end()
|
||||
->scalarNode('dsn')->defaultValue('')->end()
|
||||
->scalarNode('classname')->defaultValue($this->debug ? 'DebugPDO' : 'PropelPDO')->end()
|
||||
->arrayNode('slaves')
|
||||
->useAttributeAsKey('name')
|
||||
->prototype('array')
|
||||
->children()
|
||||
->scalarNode('user')->defaultValue('root')->end()
|
||||
->scalarNode('password')->defaultValue('')->end()
|
||||
->scalarNode('dsn')->defaultValue('')->end()
|
||||
->scalarNode('classname')->defaultValue($this->debug ? 'DebugPDO' : 'PropelPDO')->end()
|
||||
->end()
|
||||
->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('option')
|
||||
->children()
|
||||
->arrayNode('options')
|
||||
->useAttributeAsKey('key')
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->end()
|
||||
->fixXmlConfig('attribute')
|
||||
->children()
|
||||
->arrayNode('attributes')
|
||||
->useAttributeAsKey('key')
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->end()
|
||||
->fixXmlConfig('setting')
|
||||
->children()
|
||||
->arrayNode('settings')
|
||||
->useAttributeAsKey('key')
|
||||
->prototype('array')
|
||||
->useAttributeAsKey('key')
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->end()
|
||||
->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')->defaultValue('mysql')->end()
|
||||
->scalarNode('user')->defaultValue('root')->end()
|
||||
->scalarNode('password')->defaultValue('')->end()
|
||||
->scalarNode('dsn')->defaultValue('')->end()
|
||||
->scalarNode('classname')->defaultValue($this->debug ? 'DebugPDO' : 'PropelPDO')->end()
|
||||
->arrayNode('slaves')
|
||||
->useAttributeAsKey('name')
|
||||
->prototype('array')
|
||||
->children()
|
||||
->arrayNode('runtime')
|
||||
->addDefaultsIfNotSet()
|
||||
->fixXmlConfig('connection')
|
||||
->children()
|
||||
->scalarNode('defaultConnection')->end()
|
||||
->arrayNode('connections')
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->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()
|
||||
->arrayNode('profiler')
|
||||
->children()
|
||||
->scalarNode('driver')->defaultValue('mysql')->end()
|
||||
->scalarNode('user')->defaultValue('root')->end()
|
||||
->scalarNode('password')->defaultValue('')->end()
|
||||
->scalarNode('dsn')->defaultValue('')->end()
|
||||
->scalarNode('classname')->defaultValue($this->debug ? 'DebugPDO' : 'PropelPDO')->end()
|
||||
->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()
|
||||
->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('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,15 +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\DependencyInjection\Reference;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\Config\Definition\Processor;
|
||||
|
||||
/**
|
||||
* PropelExtension loads the PropelBundle configuration.
|
||||
|
@ -33,102 +31,35 @@ class PropelExtension extends Extension
|
|||
*/
|
||||
public function load(array $configs, ContainerBuilder $container)
|
||||
{
|
||||
$processor = new Processor();
|
||||
$configuration = new Configuration($container->getParameter('kernel.debug'));
|
||||
$config = $processor->processConfiguration($configuration, $configs);
|
||||
$configuration = $this->getConfiguration($configs, $container);
|
||||
$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');
|
||||
}
|
||||
|
||||
if (isset($config['build_properties']) && is_array($config['build_properties'])) {
|
||||
$buildProperties = $config['build_properties'];
|
||||
} else {
|
||||
$buildProperties = array();
|
||||
}
|
||||
|
||||
$container->getDefinition('propel.build_properties')->setArguments(array($buildProperties));
|
||||
|
||||
if (!empty($config['dbal'])) {
|
||||
$this->dbalLoad($config['dbal'], $container);
|
||||
$loader->load('security.xml');
|
||||
$loader->load('console.xml');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
public function getConfiguration(array $config, ContainerBuilder $container)
|
||||
{
|
||||
if (empty($config['default_connection'])) {
|
||||
$keys = array_keys($config['connections']);
|
||||
$config['default_connection'] = reset($keys);
|
||||
}
|
||||
|
||||
$connectionName = $config['default_connection'];
|
||||
$container->setParameter('propel.dbal.default_connection', $connectionName);
|
||||
|
||||
if (0 === count($config['connections'])) {
|
||||
$config['connections'] = array($connectionName => $config);
|
||||
}
|
||||
|
||||
$c = array();
|
||||
foreach ($config['connections'] as $name => $conf) {
|
||||
$c['datasources'][$name]['adapter'] = $conf['driver'];
|
||||
if (!empty($conf['slaves'])) {
|
||||
$c['datasources'][$name]['slaves']['connection'] = $conf['slaves'];
|
||||
}
|
||||
|
||||
foreach (array('dsn', 'user', 'password', 'classname', 'options', 'attributes', 'settings') as $att) {
|
||||
if (isset($conf[$att])) {
|
||||
$c['datasources'][$name]['connection'][$att] = $conf[$att];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Alias the default connection if not defined
|
||||
if (!isset($c['datasources']['default'])) {
|
||||
$c['datasources']['default'] = $c['datasources'][$connectionName];
|
||||
}
|
||||
|
||||
$container->getDefinition('propel.configuration')->setArguments(array($c));
|
||||
return new Configuration($container->getParameter('kernel.debug'), $container->getParameter('kernel.root_dir'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -141,16 +72,6 @@ class PropelExtension extends Extension
|
|||
return __DIR__.'/../Resources/config/schema';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the namespace to be used for this extension (XML namespace).
|
||||
*
|
||||
* @return string The XML namespace
|
||||
*/
|
||||
public function getNamespace()
|
||||
{
|
||||
return 'http://www.symfony-project.org/schema/dic/propel';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the recommended alias to use in XML.
|
||||
*
|
||||
|
|
|
@ -1,44 +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()
|
||||
;
|
||||
}
|
||||
}
|
72
Form/BaseAbstractType.php
Normal file
72
Form/BaseAbstractType.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 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();
|
||||
|
||||
public function __construct($mergeOptions = null)
|
||||
{
|
||||
if ($mergeOptions) {
|
||||
$this->mergeOptions($mergeOptions);
|
||||
}
|
||||
}
|
||||
|
||||
public function setOption($name, $value)
|
||||
{
|
||||
$this->options[$name] = $value;
|
||||
}
|
||||
|
||||
public function getOption($name)
|
||||
{
|
||||
return $this->options[$name];
|
||||
}
|
||||
|
||||
public function setOptions($options)
|
||||
{
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
public function getOptions()
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
public function mergeOptions($options)
|
||||
{
|
||||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults($this->options);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
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
|
||||
*/
|
||||
static public 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,9 +29,9 @@ 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
|
||||
*/
|
||||
static public function fromAclEntry(EntryInterface $aclEntry)
|
||||
public static function fromAclEntry(EntryInterface $aclEntry)
|
||||
{
|
||||
$entry = new self();
|
||||
|
||||
|
@ -64,12 +64,12 @@ 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
|
||||
*/
|
||||
static public function toAclEntry(Entry $modelEntry, AclInterface $acl)
|
||||
public static function toAclEntry(Entry $modelEntry, AclInterface $acl)
|
||||
{
|
||||
if (null === $modelEntry->getFieldName()) {
|
||||
return new AclEntry($modelEntry, $acl);
|
||||
|
|
|
@ -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;
|
||||
|
@ -23,13 +27,13 @@ class EntryQuery extends BaseEntryQuery
|
|||
*
|
||||
* @see find()
|
||||
*
|
||||
* @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 \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity An ACL related ObjectIdentity.
|
||||
* @param array $securityIdentities A list of SecurityIdentity to filter by.
|
||||
* @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,11 +23,11 @@ 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
|
||||
*/
|
||||
static public function toAclIdentity(SecurityIdentity $securityIdentity)
|
||||
public static function toAclIdentity(SecurityIdentity $securityIdentity)
|
||||
{
|
||||
$identifier = $securityIdentity->getIdentifier();
|
||||
|
||||
|
@ -34,7 +36,7 @@ class SecurityIdentity extends BaseSecurityIdentity
|
|||
throw new \InvalidArgumentException('The given identifier does not resolve to a UserSecurityIdentity.');
|
||||
}
|
||||
|
||||
list($class, $username) = explode('-', $identifier);
|
||||
list($class, $username) = explode('-', $identifier, 2);
|
||||
|
||||
return new UserSecurityIdentity($username, $class);
|
||||
}
|
||||
|
@ -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
|
||||
*/
|
||||
static public 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,50 +1,38 @@
|
|||
PropelBundle
|
||||
============
|
||||
|
||||
[![Build Status](https://secure.travis-ci.org/propelorm/PropelBundle.png)](http://travis-ci.org/propelorm/PropelBundle)
|
||||
|
||||
This is the official implementation of [Propel](http://www.propelorm.org/) in Symfony2.
|
||||
|
||||
## Branching model
|
||||
|
||||
As `Propel2` will be released in the near future, we are migrating the branching model of this bundle in advance!
|
||||
|
||||
* The `1.0` branch will contain Propel *1.6* integration for Symfony *2.0* (*currently 2.0 branch*).
|
||||
* The `1.1` branch will contain Propel *1.6* integration for Symfony *2.1* (*currently master 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 the `master` branch, switch to the `1.1` branch.
|
||||
* If you depend on the `2.0` branch, switch to the `1.0` branch.
|
||||
|
||||
We will keep all branches in sync until `Propel2` will be released.
|
||||
|
||||
## Features
|
||||
|
||||
* Generation of model classes based on an XML schema (not YAML) placed under `BundleName/Resources/config/*schema.xml`.
|
||||
* 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/cookbook/working-with-existing-databases.html).
|
||||
* Integration to the Symfony2 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.
|
||||
* Schema Inheritance.
|
||||
* Symfony2 ACL.
|
||||
|
||||
For documentation, see:
|
||||
|
||||
Resources/doc/
|
||||
|
||||
[Read the documentation](https://github.com/propelorm/PropelBundle/blob/master/Resources/doc/README.markdown)
|
||||
|
||||
For license, see:
|
||||
|
||||
Resources/meta/LICENSE
|
||||
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 Symfony.
|
||||
|
||||
## Branching model
|
||||
|
||||
As `Propel2` will be released in the near future, we are migrating the branching model of this bundle in advance!
|
||||
|
||||
* 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.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
|
||||
|
||||
* Generation of model classes based on an XML schema (not YAML) placed under `BundleName/Resources/*schema.xml`;
|
||||
* Insertion of SQL statements;
|
||||
* Runtime autoloading of Propel and generated classes;
|
||||
* Propel runtime initialization through the XML configuration;
|
||||
* [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.
|
||||
|
||||
[Read the documentation](http://propelorm.org/documentation/)
|
||||
|
||||
For license, see:
|
||||
|
||||
Resources/meta/LICENSE
|
||||
|
|
|
@ -1,36 +1,144 @@
|
|||
<?php
|
||||
|
||||
namespace Propel\PropelBundle\Request\ParamConverter;
|
||||
namespace Propel\Bundle\PropelBundle\Request\ParamConverter;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* PropelConverter.
|
||||
* PropelParamConverter
|
||||
*
|
||||
* This convert action parameter to a Propel Object
|
||||
* there is two option for this converter:
|
||||
*
|
||||
* mapping : take an array of routeParam => column
|
||||
* exclude : take an array of routeParam to exclude from the conversion process
|
||||
*
|
||||
*
|
||||
* @author Jérémie Augustin <jeremie.augustin@pixel-cookers.com>
|
||||
*/
|
||||
class PropelParamConverter implements ParamConverterInterface
|
||||
{
|
||||
/**
|
||||
* the pk column (e.g. id)
|
||||
* @var string
|
||||
*/
|
||||
protected $pk;
|
||||
|
||||
public function apply(Request $request, ConfigurationInterface $configuration)
|
||||
/**
|
||||
* list of column/value to use with filterBy
|
||||
* @var array
|
||||
*/
|
||||
protected $filters = array();
|
||||
|
||||
/**
|
||||
* list of route parameters to exclude from the conversion process
|
||||
* @var array
|
||||
*/
|
||||
protected $exclude = array();
|
||||
|
||||
/**
|
||||
* list of with option use to hydrate related object
|
||||
* @var array
|
||||
*/
|
||||
protected $withs;
|
||||
|
||||
/**
|
||||
* name of method use to call a query method
|
||||
* @var string
|
||||
*/
|
||||
protected $queryMethod;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $hasWith = false;
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param ParamConverter $configuration
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws \LogicException
|
||||
* @throws NotFoundHttpException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function apply(Request $request, ParamConverter $configuration)
|
||||
{
|
||||
$classQuery = $configuration->getClass() . 'Query';
|
||||
$class = $configuration->getClass();
|
||||
$classQuery = $class . 'Query';
|
||||
$classTableMap = $class::TABLE_MAP;
|
||||
$this->filters = array();
|
||||
$this->exclude = array();
|
||||
|
||||
if (!class_exists($classQuery)) {
|
||||
throw new \Exception(sprintf('The %s Query class does not exist', $classQuery));
|
||||
}
|
||||
$options = $configuration->getOptions();
|
||||
$exclude = isset($options['exclude'])? $options['exclude'] : array();
|
||||
|
||||
// find by Pk
|
||||
if (in_array('id', $exclude) || false === $object = $this->findPk($classQuery, $request)) {
|
||||
// find by criteria
|
||||
if (false === $object = $this->findOneBy($classQuery, $request, $exclude)) {
|
||||
throw new \LogicException('Unable to guess how to get a Propel object from the request information.');
|
||||
$tableMap = new $classTableMap();
|
||||
$pkColumns = $tableMap->getPrimaryKeys();
|
||||
|
||||
if (count($pkColumns) === 1) {
|
||||
$pk = array_pop($pkColumns);
|
||||
$this->pk = strtolower($pk->getName());
|
||||
}
|
||||
|
||||
$options = $configuration->getOptions();
|
||||
|
||||
// Check request attributes for converter options, if there are non provided.
|
||||
if (empty($options) && $request->attributes->has('propel_converter') && $configuration instanceof ParamConverter) {
|
||||
$converterOption = $request->attributes->get('propel_converter');
|
||||
if (!empty($converterOption[$configuration->getName()])) {
|
||||
$options = $converterOption[$configuration->getName()];
|
||||
}
|
||||
}
|
||||
if (isset($options['mapping'])) {
|
||||
// We use the mapping for calling findPk or filterBy
|
||||
foreach ($options['mapping'] as $routeParam => $column) {
|
||||
if ($request->attributes->has($routeParam)) {
|
||||
if ($this->pk === $column) {
|
||||
$this->pk = $routeParam;
|
||||
} else {
|
||||
$this->filters[$column] = $request->attributes->get($routeParam);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->exclude = isset($options['exclude']) ? $options['exclude'] : array();
|
||||
$this->filters = $request->attributes->all();
|
||||
}
|
||||
|
||||
if (array_key_exists($configuration->getName(), $this->filters)) {
|
||||
unset($this->filters[$configuration->getName()]);
|
||||
}
|
||||
|
||||
$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.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,27 +147,75 @@ class PropelParamConverter implements ParamConverterInterface
|
|||
}
|
||||
|
||||
$request->attributes->set($configuration->getName(), $object);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function findPk($classQuery, Request $request)
|
||||
/**
|
||||
* @param ParamConverter $configuration
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function supports(ParamConverter $configuration)
|
||||
{
|
||||
if (!$request->attributes->has('id')) {
|
||||
if (null === ($classname = $configuration->getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $classQuery::create()->findPk($request->attributes->get('id'));
|
||||
if (!class_exists($classname)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Propel Class?
|
||||
$class = new \ReflectionClass($configuration->getClass());
|
||||
if ($class->implementsInterface('\Propel\Runtime\ActiveRecord\ActiveRecordInterface')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function findOneBy($classQuery, Request $request, $exclude)
|
||||
/**
|
||||
* Try to find the object with the id
|
||||
*
|
||||
* @param string $classQuery the query class
|
||||
* @param Request $request
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function findPk($classQuery, Request $request)
|
||||
{
|
||||
$query = $classQuery::create();
|
||||
if (in_array($this->pk, $this->exclude) || !$request->attributes->has($this->pk)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$query = $this->getQuery($classQuery);
|
||||
|
||||
if (!$this->hasWith) {
|
||||
return $query->findPk($request->attributes->get($this->pk));
|
||||
} else {
|
||||
return $query->filterByPrimaryKey($request->attributes->get($this->pk))->find()->getFirst();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to find the object with all params from the $request
|
||||
*
|
||||
* @param string $classQuery the query class
|
||||
* @param Request $request
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function findOneBy($classQuery, Request $request)
|
||||
{
|
||||
$query = $this->getQuery($classQuery);
|
||||
$hasCriteria = false;
|
||||
foreach ($request->attributes->all() as $key => $value) {
|
||||
if (!in_array($key, $exclude)) {
|
||||
foreach ($this->filters as $column => $value) {
|
||||
if (!in_array($column, $this->exclude)) {
|
||||
try {
|
||||
$query->{'filterBy' . ucfirst($key)}($value);
|
||||
$query->{'filterBy' . PropelInflector::camelize($column)}($value);
|
||||
$hasCriteria = true;
|
||||
} catch (\PropelException $e) { }
|
||||
} catch (\Exception $e) { }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,23 +223,68 @@ class PropelParamConverter implements ParamConverterInterface
|
|||
return false;
|
||||
}
|
||||
|
||||
return $query->findOne();
|
||||
if (!$this->hasWith) {
|
||||
return $query->findOne();
|
||||
} else {
|
||||
return $query->find()->getFirst();
|
||||
}
|
||||
}
|
||||
|
||||
public function supports(ConfigurationInterface $configuration)
|
||||
/**
|
||||
* Init the query class with optional joinWith
|
||||
*
|
||||
* @param string $classQuery
|
||||
*
|
||||
* @return ModelCriteria
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function getQuery($classQuery)
|
||||
{
|
||||
if (null === ($classname = $configuration->getClass())) {
|
||||
return false;
|
||||
}
|
||||
if (!class_exists($classname)) {
|
||||
return false;
|
||||
}
|
||||
// Propel Class?
|
||||
$class = new \ReflectionClass($configuration->getClass());
|
||||
if ($class->isSubclassOf('BaseObject')) {
|
||||
return true;
|
||||
$query = $classQuery::create();
|
||||
|
||||
foreach ($this->withs as $with) {
|
||||
if (is_array($with)) {
|
||||
if (2 == count($with)) {
|
||||
$query->joinWith($with[0], $this->getValidJoin($with));
|
||||
$this->hasWith = true;
|
||||
} else {
|
||||
throw new \Exception(sprintf('ParamConverter : "with" parameter "%s" is invalid,
|
||||
only string relation name (e.g. "Book") or an array with two keys (e.g. {"Book", "LEFT_JOIN"}) are allowed',
|
||||
var_export($with, true)));
|
||||
}
|
||||
} else {
|
||||
$query->joinWith($with);
|
||||
$this->hasWith = true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the valid join Criteria base on the with parameter
|
||||
*
|
||||
* @param array $with
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function getValidJoin($with)
|
||||
{
|
||||
switch (trim(str_replace(array('_', 'JOIN'), '', strtoupper($with[1])))) {
|
||||
case 'LEFT':
|
||||
return Criteria::LEFT_JOIN;
|
||||
case 'RIGHT':
|
||||
return Criteria::RIGHT_JOIN;
|
||||
case 'INNER':
|
||||
return Criteria::INNER_JOIN;
|
||||
}
|
||||
|
||||
throw new \Exception(sprintf('ParamConverter : "with" parameter "%s" is invalid,
|
||||
only "left", "right" or "inner" are allowed for join option',
|
||||
var_export($with, true)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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,12 +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" priority="10" />
|
||||
<tag name="request.param_converter" converter="propel" priority="1" />
|
||||
</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,456 +0,0 @@
|
|||
# PropelBundle #
|
||||
|
||||
This is the official implementation of [Propel](http://www.propelorm.org/) in Symfony2.
|
||||
|
||||
## Installation ##
|
||||
|
||||
* 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
|
||||
|
||||
* Register this bundle in the `AppKernel` class:
|
||||
|
||||
``` php
|
||||
public function registerBundles()
|
||||
{
|
||||
$bundles = array(
|
||||
...
|
||||
|
||||
// PropelBundle
|
||||
new Propel\PropelBundle\PropelBundle(),
|
||||
// register your bundles
|
||||
new Sensio\HelloBundle\HelloBundle(),
|
||||
);
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
* 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',
|
||||
));
|
||||
```
|
||||
|
||||
|
||||
## Sample Configuration ##
|
||||
|
||||
### Project configuration ###
|
||||
|
||||
``` yaml
|
||||
# in app/config/config.yml
|
||||
propel:
|
||||
path: "%kernel.root_dir%/../vendor/propel"
|
||||
phing_path: "%kernel.root_dir%/../vendor/phing"
|
||||
# logging: %kernel.debug%
|
||||
# build_properties:
|
||||
# xxxxx.xxxxx: xxxxxx
|
||||
# xxxxx.xxxxx: xxxxxx
|
||||
|
||||
# in app/config/config*.yml
|
||||
propel:
|
||||
dbal:
|
||||
driver: mysql
|
||||
user: root
|
||||
password: null
|
||||
dsn: mysql:host=localhost;dbname=test;charset=UTF8
|
||||
options: {}
|
||||
attributes: {}
|
||||
# default_connection: default
|
||||
# connections:
|
||||
# default:
|
||||
# driver: mysql
|
||||
# user: root
|
||||
# password: null
|
||||
# dsn: mysql:host=localhost;dbname=test
|
||||
# slaves:
|
||||
# slave_server_1:
|
||||
# user: root
|
||||
# password: null
|
||||
# dsn: mysql:host=localhost;dbname=test_slave_1
|
||||
#
|
||||
# options:
|
||||
# ATTR_PERSISTENT: false
|
||||
# attributes:
|
||||
# ATTR_EMULATE_PREPARES: true
|
||||
# settings:
|
||||
# charset: { value: UTF8 }
|
||||
# queries: { query: 'INSERT INTO BAR ('hey', 'there')' }
|
||||
```
|
||||
|
||||
`options`, `attributes` and `settings` are parts of the runtime configuration. See [Runtime Configuration File](http://www.propelorm.org/reference/runtime-configuration.html) documentation for more explanation.
|
||||
|
||||
|
||||
### Build properties ###
|
||||
|
||||
You can define _build properties_ by creating a `propel.ini` file in `app/config` and put build properties (see [Build properties Reference](http://www.propelorm.org/reference/buildtime-configuration.html)).
|
||||
|
||||
``` ini
|
||||
# in app/config/propel.ini
|
||||
xxxx.xxxx.xxxx = XXXX
|
||||
````
|
||||
|
||||
But you can follow the Symfony2 way by adding build properties in `app/config/config.yml`:
|
||||
|
||||
``` yaml
|
||||
# in app/config/config.yml
|
||||
propel:
|
||||
build_properties:
|
||||
xxxxx.xxxx.xxxxx: XXXX
|
||||
xxxxx.xxxx.xxxxx: XXXX
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
### Sample Schema ###
|
||||
|
||||
Place the following schema in `src/Sensio/HelloBundle/Resources/config/schema.xml` :
|
||||
|
||||
``` xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<database name="default" namespace="Sensio\HelloBundle\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>
|
||||
```
|
||||
|
||||
|
||||
Commands
|
||||
--------
|
||||
|
||||
### Build Process ###
|
||||
|
||||
Call the application console with the `propel:build` command:
|
||||
|
||||
> php app/console propel:build [--classes] [--sql] [--insert-sql]
|
||||
|
||||
|
||||
### Insert SQL ###
|
||||
|
||||
Call the application console with the `propel:sql:insert` command:
|
||||
|
||||
> php app/console propel:sql:insert [--force]
|
||||
|
||||
Note that the `--force` option is needed to actually execute the SQL statements.
|
||||
|
||||
|
||||
### Use The Model Classes ###
|
||||
|
||||
Use the Model classes as any other class in Symfony2. Just use the correct namespace, and Symfony2 will autoload them:
|
||||
|
||||
class HelloController extends Controller
|
||||
{
|
||||
public function indexAction($name)
|
||||
{
|
||||
$author = new \Sensio\HelloBundle\Model\Author();
|
||||
$author->setFirstName($name);
|
||||
$author->save();
|
||||
|
||||
return $this->render('HelloBundle:Hello:index.html.twig', array('name' => $name, 'author' => $author));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
### Migrations ###
|
||||
|
||||
Generates SQL diff between the XML schemas and the current database structure:
|
||||
|
||||
> php app/console propel:migration:generate-diff
|
||||
|
||||
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
|
||||
|
||||
|
||||
### 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
|
||||
|
||||
|
||||
### Fixtures ###
|
||||
|
||||
You can load your own fixtures by using the following command:
|
||||
|
||||
> php app/console propel:fixtures:load [-d|--dir[="..."]] [--xml] [--sql] [--yml] [--connection[="..."]] [bundle]
|
||||
|
||||
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.
|
||||
If none of this parameter are set all files YAML, XML and SQL in the directory will be load.
|
||||
|
||||
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>
|
||||
```
|
||||
|
||||
A valid _YAML fixtures file_ is:
|
||||
|
||||
``` yaml
|
||||
\Awesome\Object:
|
||||
o1:
|
||||
Title: My title
|
||||
MyFoo: bar
|
||||
|
||||
\Awesome\Related:
|
||||
r1:
|
||||
ObjectId: o1
|
||||
Description: Hello world !
|
||||
```
|
||||
|
||||
You can load all fixtures files from a given _bundle_:
|
||||
|
||||
> php app/console propel:fixtures:load @MySuperBundle
|
||||
|
||||
|
||||
You can dump data 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 this files by using the `propel:fixtures:load` command.
|
||||
|
||||
|
||||
### Graphviz ###
|
||||
|
||||
You can generate **Graphviz** file for your project by using the following command line:
|
||||
|
||||
> php app/console propel:graphviz
|
||||
|
||||
It will write files in `app/propel/graph/`.
|
||||
|
||||
|
||||
### Database ###
|
||||
|
||||
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.
|
||||
|
||||
### Table ###
|
||||
|
||||
You can drop one or several **table**:
|
||||
|
||||
> 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.
|
||||
|
||||
|
||||
### 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 @MySuperBundle Book Author
|
||||
|
||||
|
||||
## PropelParamConverter ##
|
||||
|
||||
You can use the Propel ParamConverter with the 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)
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
## UniqueObjectValidator ##
|
||||
|
||||
In a form, if you want to validate the unicity of a field in a table you have to use the UniqueObjectValidator.
|
||||
The only way to use it is in a validation.yml file, like this:
|
||||
|
||||
``` yaml
|
||||
BundleNamespace\Model\User:
|
||||
constraints:
|
||||
- Propel\PropelBundle\Validator\Constraints\UniqueObject: username
|
||||
```
|
||||
|
||||
For validate the unicity of more than just one fields:
|
||||
|
||||
``` yaml
|
||||
BundleNamespace\Model\User:
|
||||
constraints:
|
||||
- Propel\PropelBundle\Validator\Constraints\UniqueObject: [username, login]
|
||||
```
|
||||
|
||||
As many validator of this type as you want can be used.
|
||||
|
||||
## 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.
|
||||
|
||||
## 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:init:acl` 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.
|
Binary file not shown.
Before Width: | Height: | Size: 2.4 KiB |
|
@ -3,32 +3,26 @@
|
|||
namespace ##NAMESPACE##;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class ##CLASS## extends AbstractType
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(FormBuilder $builder, array $options)
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{##BUILD_CODE##
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefaultOptions()
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
return array(
|
||||
$resolver->setDefaults([
|
||||
'data_class' => '##FQCN##',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return '##TYPE_NAME##';
|
||||
'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 'PropelBundle:Panel:explain' with {
|
||||
'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 '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 %}
|
||||
|
@ -13,4 +11,4 @@
|
|||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</table>
|
||||
|
|
|
@ -8,19 +8,18 @@
|
|||
* @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\PropelBundle\Security\Acl\Domain\Entry;
|
||||
use Propel\PropelBundle\Security\Acl\Domain\FieldEntry;
|
||||
use Propel\Bundle\PropelBundle\Model\Acl\EntryQuery;
|
||||
use Propel\Bundle\PropelBundle\Model\Acl\ObjectIdentityQuery;
|
||||
use Propel\Bundle\PropelBundle\Model\Acl\SecurityIdentity;
|
||||
|
||||
use Propel\Bundle\PropelBundle\Security\Acl\Domain\Acl;
|
||||
|
||||
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
|
||||
use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity;
|
||||
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
|
||||
|
||||
use Symfony\Component\Security\Acl\Exception\AclNotFoundException;
|
||||
|
||||
|
@ -45,10 +44,10 @@ class AclProvider implements AclProviderInterface
|
|||
* Constructor.
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface $permissionGrantingStrategy
|
||||
* @param \PropelPDO $con
|
||||
* @param \Symfony\Component\Security\Acl\Model\AclCacheInterface $cache
|
||||
* @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;
|
||||
|
@ -59,7 +58,7 @@ class AclProvider implements AclProviderInterface
|
|||
* Retrieves all child object identities from the database.
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $parentObjectIdentity
|
||||
* @param bool $directChildrenOnly
|
||||
* @param bool $directChildrenOnly
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
|
@ -90,7 +89,7 @@ class AclProvider implements AclProviderInterface
|
|||
* @throws \Symfony\Component\Security\Acl\Exception\AclNotFoundException
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||
* @param array $securityIdentities
|
||||
* @param array $securityIdentities
|
||||
*
|
||||
* @return \Symfony\Component\Security\Acl\Model\AclInterface
|
||||
*/
|
||||
|
@ -149,7 +148,7 @@ class AclProvider implements AclProviderInterface
|
|||
*
|
||||
* @throws \Symfony\Component\Security\Acl\Exception\AclNotFoundException When at least one object identity is missing its ACL.
|
||||
*
|
||||
* @param array $objectIdentities an array of ObjectIdentityInterface implementations
|
||||
* @param array $objectIdentities an array of ObjectIdentityInterface implementations
|
||||
* @param array $securityIdentities an array of SecurityIdentityInterface implementations
|
||||
*
|
||||
* @return \SplObjectStorage mapping the passed object identities to ACLs
|
||||
|
@ -167,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
|
||||
* @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,16 +24,16 @@ 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
|
||||
* @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,26 +8,25 @@
|
|||
* @license MIT License
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\Security\Acl\Domain;
|
||||
namespace Propel\Bundle\PropelBundle\Security\Acl\Domain;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\SecurityIdentity;
|
||||
use Propel\Runtime\Collection\ObjectCollection;
|
||||
|
||||
use Symfony\Component\Security\Acl\Exception\Exception as AclException;
|
||||
|
||||
use Symfony\Component\Security\Acl\Model\AclInterface;
|
||||
use Symfony\Component\Security\Acl\Model\EntryInterface;
|
||||
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
|
||||
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();
|
||||
|
@ -51,17 +50,17 @@ class Acl implements AclInterface
|
|||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \PropelObjectCollection $entries
|
||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||
* @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 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) {
|
||||
|
@ -178,10 +177,10 @@ class Acl implements AclInterface
|
|||
/**
|
||||
* Determines whether field access is granted
|
||||
*
|
||||
* @param string $field
|
||||
* @param array $masks
|
||||
* @param array $securityIdentities
|
||||
* @param bool $administrativeMode
|
||||
* @param string $field
|
||||
* @param array $masks
|
||||
* @param array $securityIdentities
|
||||
* @param bool $administrativeMode
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
|
@ -195,9 +194,9 @@ class Acl implements AclInterface
|
|||
*
|
||||
* @throws \Symfony\Component\Security\Acl\Exception\NoAceFoundException when no ACE was applicable for this request
|
||||
*
|
||||
* @param array $masks
|
||||
* @param array $securityIdentities
|
||||
* @param bool $administrativeMode
|
||||
* @param array $masks
|
||||
* @param array $securityIdentities
|
||||
* @param bool $administrativeMode
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
|
@ -304,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,14 +8,10 @@
|
|||
* @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\ObjectIdentityInterface;
|
||||
use Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface;
|
||||
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
|
||||
use Symfony\Component\Security\Acl\Model\AuditableAclInterface;
|
||||
|
||||
/**
|
||||
|
@ -27,8 +23,8 @@ class AuditableAcl extends MutableAcl implements AuditableAclInterface
|
|||
* Updates auditing for class-based ACE
|
||||
*
|
||||
* @param integer $index
|
||||
* @param bool $auditSuccess
|
||||
* @param bool $auditFailure
|
||||
* @param bool $auditSuccess
|
||||
* @param bool $auditFailure
|
||||
*/
|
||||
public function updateClassAuditing($index, $auditSuccess, $auditFailure)
|
||||
{
|
||||
|
@ -39,9 +35,9 @@ class AuditableAcl extends MutableAcl implements AuditableAclInterface
|
|||
* Updates auditing for class-field-based ACE
|
||||
*
|
||||
* @param integer $index
|
||||
* @param string $field
|
||||
* @param bool $auditSuccess
|
||||
* @param bool $auditFailure
|
||||
* @param string $field
|
||||
* @param bool $auditSuccess
|
||||
* @param bool $auditFailure
|
||||
*/
|
||||
public function updateClassFieldAuditing($index, $field, $auditSuccess, $auditFailure)
|
||||
{
|
||||
|
@ -53,8 +49,8 @@ class AuditableAcl extends MutableAcl implements AuditableAclInterface
|
|||
* Updates auditing for object-based ACE
|
||||
*
|
||||
* @param integer $index
|
||||
* @param bool $auditSuccess
|
||||
* @param bool $auditFailure
|
||||
* @param bool $auditSuccess
|
||||
* @param bool $auditFailure
|
||||
*/
|
||||
public function updateObjectAuditing($index, $auditSuccess, $auditFailure)
|
||||
{
|
||||
|
@ -65,9 +61,9 @@ class AuditableAcl extends MutableAcl implements AuditableAclInterface
|
|||
* Updates auditing for object-field-based ACE
|
||||
*
|
||||
* @param integer $index
|
||||
* @param string $field
|
||||
* @param bool $auditSuccess
|
||||
* @param bool $auditFailure
|
||||
* @param string $field
|
||||
* @param bool $auditSuccess
|
||||
* @param bool $auditFailure
|
||||
*/
|
||||
public function updateObjectFieldAuditing($index, $field, $auditSuccess, $auditFailure)
|
||||
{
|
||||
|
@ -81,11 +77,11 @@ class AuditableAcl extends MutableAcl implements AuditableAclInterface
|
|||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @param array $list
|
||||
* @param int $index
|
||||
* @param bool $auditSuccess
|
||||
* @param bool $auditFailure
|
||||
* @param int $index
|
||||
* @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)
|
||||
{
|
||||
|
@ -104,4 +100,4 @@ class AuditableAcl extends MutableAcl implements AuditableAclInterface
|
|||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
@ -189,4 +189,4 @@ class Entry implements AuditableEntryInterface
|
|||
{
|
||||
return $this->auditSuccess;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
@ -98,4 +98,4 @@ class FieldEntry extends Entry implements FieldEntryInterface
|
|||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,18 +8,20 @@
|
|||
* @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;
|
||||
|
||||
use Symfony\Component\Security\Acl\Model\AclInterface;
|
||||
use Symfony\Component\Security\Acl\Model\MutableAclInterface;
|
||||
use Symfony\Component\Security\Acl\Model\EntryInterface;
|
||||
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
|
||||
use Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface;
|
||||
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
|
||||
|
@ -41,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 \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||
* @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 array $loadedSecurityIdentities
|
||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $parentAcl
|
||||
* @param bool $inherited
|
||||
* @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);
|
||||
|
||||
|
@ -125,7 +127,7 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
* Deletes a class-field-based ACE
|
||||
*
|
||||
* @param integer $index
|
||||
* @param string $field
|
||||
* @param string $field
|
||||
*/
|
||||
public function deleteClassFieldAce($index, $field)
|
||||
{
|
||||
|
@ -149,7 +151,7 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
* Deletes an object-field-based ACE
|
||||
*
|
||||
* @param integer $index
|
||||
* @param string $field
|
||||
* @param string $field
|
||||
*/
|
||||
public function deleteObjectFieldAce($index, $field)
|
||||
{
|
||||
|
@ -163,10 +165,10 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
* Inserts a class-based ACE
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\SecurityIdentityInterface $securityIdentity
|
||||
* @param integer $mask
|
||||
* @param integer $index
|
||||
* @param bool $granting
|
||||
* @param string $strategy
|
||||
* @param integer $mask
|
||||
* @param integer $index
|
||||
* @param bool $granting
|
||||
* @param string $strategy
|
||||
*/
|
||||
public function insertClassAce(SecurityIdentityInterface $securityIdentity, $mask, $index = 0, $granting = true, $strategy = null)
|
||||
{
|
||||
|
@ -176,12 +178,12 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
/**
|
||||
* Inserts a class-field-based ACE
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $field
|
||||
* @param \Symfony\Component\Security\Acl\Model\SecurityIdentityInterface $securityIdentity
|
||||
* @param integer $mask
|
||||
* @param integer $index
|
||||
* @param boolean $granting
|
||||
* @param string $strategy
|
||||
* @param integer $mask
|
||||
* @param integer $index
|
||||
* @param boolean $granting
|
||||
* @param string $strategy
|
||||
*/
|
||||
public function insertClassFieldAce($field, SecurityIdentityInterface $securityIdentity, $mask, $index = 0, $granting = true, $strategy = null)
|
||||
{
|
||||
|
@ -196,10 +198,10 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
* Inserts an object-based ACE
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\SecurityIdentityInterface $securityIdentity
|
||||
* @param integer $mask
|
||||
* @param integer $index
|
||||
* @param boolean $granting
|
||||
* @param string $strategy
|
||||
* @param integer $mask
|
||||
* @param integer $index
|
||||
* @param boolean $granting
|
||||
* @param string $strategy
|
||||
*/
|
||||
public function insertObjectAce(SecurityIdentityInterface $securityIdentity, $mask, $index = 0, $granting = true, $strategy = null)
|
||||
{
|
||||
|
@ -209,12 +211,12 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
/**
|
||||
* Inserts an object-field-based ACE
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $field
|
||||
* @param \Symfony\Component\Security\Acl\Model\SecurityIdentityInterface $securityIdentity
|
||||
* @param integer $mask
|
||||
* @param integer $index
|
||||
* @param boolean $granting
|
||||
* @param string $strategy
|
||||
* @param integer $mask
|
||||
* @param integer $index
|
||||
* @param boolean $granting
|
||||
* @param string $strategy
|
||||
*/
|
||||
public function insertObjectFieldAce($field, SecurityIdentityInterface $securityIdentity, $mask, $index = 0, $granting = true, $strategy = null)
|
||||
{
|
||||
|
@ -230,7 +232,7 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
*
|
||||
* @param integer $index
|
||||
* @param integer $mask
|
||||
* @param string $strategy if null the strategy should not be changed
|
||||
* @param string $strategy if null the strategy should not be changed
|
||||
*/
|
||||
public function updateClassAce($index, $mask, $strategy = null)
|
||||
{
|
||||
|
@ -241,9 +243,9 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
* Updates a class-field-based ACE
|
||||
*
|
||||
* @param integer $index
|
||||
* @param string $field
|
||||
* @param string $field
|
||||
* @param integer $mask
|
||||
* @param string $strategy if null the strategy should not be changed
|
||||
* @param string $strategy if null the strategy should not be changed
|
||||
*/
|
||||
public function updateClassFieldAce($index, $field, $mask, $strategy = null)
|
||||
{
|
||||
|
@ -258,7 +260,7 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
*
|
||||
* @param integer $index
|
||||
* @param integer $mask
|
||||
* @param string $strategy if null the strategy should not be changed
|
||||
* @param string $strategy if null the strategy should not be changed
|
||||
*/
|
||||
public function updateObjectAce($index, $mask, $strategy = null)
|
||||
{
|
||||
|
@ -269,9 +271,9 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
* Updates an object-field-based ACE
|
||||
*
|
||||
* @param integer $index
|
||||
* @param string $field
|
||||
* @param string $field
|
||||
* @param integer $mask
|
||||
* @param string $strategy if null the strategy should not be changed
|
||||
* @param string $strategy if null the strategy should not be changed
|
||||
*/
|
||||
public function updateObjectFieldAce($index, $field, $mask, $strategy = null)
|
||||
{
|
||||
|
@ -336,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)
|
||||
{
|
||||
|
@ -362,13 +364,13 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
/**
|
||||
* Update a single ACE of this ACL.
|
||||
*
|
||||
* @param array $list
|
||||
* @param int $index
|
||||
* @param int $mask
|
||||
* @param array $list
|
||||
* @param int $index
|
||||
* @param int $mask
|
||||
* @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)
|
||||
{
|
||||
|
@ -395,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)
|
||||
{
|
||||
|
@ -412,9 +414,9 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
* @throws \OutOfBoundsException
|
||||
*
|
||||
* @param array $list
|
||||
* @param int $index
|
||||
* @param int $index
|
||||
*
|
||||
* @return \Propel\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
||||
* @return \Propel\Bundle\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
||||
*/
|
||||
protected function isWithinBounds(array &$list, $index)
|
||||
{
|
||||
|
@ -434,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)
|
||||
{
|
||||
|
@ -450,10 +452,10 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @param array $list
|
||||
* @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)
|
||||
{
|
||||
|
@ -468,9 +470,9 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
* Order the given list to have numeric indexes from 0..x
|
||||
*
|
||||
* @param array $list
|
||||
* @param int $index The right boundary to which the list is valid.
|
||||
* @param int $index The right boundary to which the list is valid.
|
||||
*
|
||||
* @return \Propel\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
||||
* @return \Propel\Bundle\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
||||
*/
|
||||
protected function reorderList(array &$list, $index)
|
||||
{
|
||||
|
@ -485,14 +487,14 @@ class MutableAcl extends Acl implements MutableAclInterface
|
|||
/**
|
||||
* Create a new ACL Entry.
|
||||
*
|
||||
* @param int $mask
|
||||
* @param int $index
|
||||
* @param int $mask
|
||||
* @param int $index
|
||||
* @param \Symfony\Component\Security\Acl\Model\SecurityIdentityInterface $securityIdentity
|
||||
* @param string $strategy
|
||||
* @param bool $granting
|
||||
* @param string $field
|
||||
* @param string $strategy
|
||||
* @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)
|
||||
{
|
||||
|
|
|
@ -8,24 +8,28 @@
|
|||
* @license MIT License
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\Security\Acl;
|
||||
namespace Propel\Bundle\PropelBundle\Security\Acl;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\Entry as ModelEntry;
|
||||
use Propel\PropelBundle\Model\Acl\EntryPeer;
|
||||
use Propel\PropelBundle\Model\Acl\EntryQuery;
|
||||
use Propel\PropelBundle\Model\Acl\SecurityIdentity;
|
||||
use Propel\PropelBundle\Model\Acl\ObjectIdentity;
|
||||
use Propel\PropelBundle\Model\Acl\ObjectIdentityQuery;
|
||||
use Propel\Runtime\ActiveQuery\Criteria;
|
||||
use Propel\Runtime\Collection\ObjectCollection;
|
||||
use Propel\Runtime\Connection\ConnectionInterface;
|
||||
use Propel\Runtime\Propel;
|
||||
use Propel\Runtime\ServiceContainer\ServiceContainerInterface;
|
||||
|
||||
use Propel\PropelBundle\Security\Acl\Domain\Acl;
|
||||
use Propel\PropelBundle\Security\Acl\Domain\MutableAcl;
|
||||
use Propel\PropelBundle\Security\Acl\Domain\Entry;
|
||||
use Propel\Bundle\PropelBundle\Model\Acl\Entry as ModelEntry;
|
||||
use Propel\Bundle\PropelBundle\Model\Acl\Map\EntryTableMap;
|
||||
use Propel\Bundle\PropelBundle\Model\Acl\EntryQuery;
|
||||
use Propel\Bundle\PropelBundle\Model\Acl\SecurityIdentity;
|
||||
use Propel\Bundle\PropelBundle\Model\Acl\ObjectIdentity;
|
||||
use Propel\Bundle\PropelBundle\Model\Acl\ObjectIdentityQuery;
|
||||
|
||||
use Propel\Bundle\PropelBundle\Security\Acl\Domain\Acl;
|
||||
use Propel\Bundle\PropelBundle\Security\Acl\Domain\MutableAcl;
|
||||
use Propel\Bundle\PropelBundle\Security\Acl\Domain\Entry;
|
||||
|
||||
use Symfony\Component\Security\Acl\Exception\AclAlreadyExistsException;
|
||||
use Symfony\Component\Security\Acl\Exception\Exception as AclException;
|
||||
|
||||
use Symfony\Component\Security\Acl\Domain\FieldEntry;
|
||||
|
||||
use Symfony\Component\Security\Acl\Model\AclInterface;
|
||||
use Symfony\Component\Security\Acl\Model\EntryInterface;
|
||||
use Symfony\Component\Security\Acl\Model\FieldEntryInterface;
|
||||
|
@ -47,14 +51,14 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
|
|||
* Constructor.
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface $permissionGrantingStrategy
|
||||
* @param \PropelPDO $connection
|
||||
* @param \Symfony\Component\Security\Acl\Model\AclCacheInterface $cache
|
||||
* @param ConnectionInterface $connection
|
||||
* @param \Symfony\Component\Security\Acl\Model\AclCacheInterface $cache
|
||||
*/
|
||||
public function __construct(PermissionGrantingStrategyInterface $permissionGrantingStrategy, \PropelPDO $connection = null, AclCacheInterface $cache = null)
|
||||
public function __construct(PermissionGrantingStrategyInterface $permissionGrantingStrategy, ConnectionInterface $connection = null, AclCacheInterface $cache = null)
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
if (null === $connection) {
|
||||
$connection = \Propel::getConnection(EntryPeer::DATABASE_NAME, \Propel::CONNECTION_WRITE);
|
||||
$connection = Propel::getConnection(EntryTableMap::DATABASE_NAME, ServiceContainerInterface::CONNECTION_WRITE);
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
|
@ -68,7 +72,7 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
|
|||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||
*
|
||||
* @return \Propel\PropelBundle\Security\Acl\Domain\MutableAcl
|
||||
* @return \Propel\Bundle\PropelBundle\Security\Acl\Domain\MutableAcl
|
||||
*/
|
||||
public function createAcl(ObjectIdentityInterface $objectIdentity)
|
||||
{
|
||||
|
@ -165,7 +169,7 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
|
|||
public function updateAcl(MutableAclInterface $acl)
|
||||
{
|
||||
if (!$acl instanceof MutableAcl) {
|
||||
throw new \InvalidArgumentException('The given ACL is not tracked by this provider. Please provide \Propel\PropelBundle\Security\Acl\Domain\MutableAcl only.');
|
||||
throw new \InvalidArgumentException('The given ACL is not tracked by this provider. Please provide \Propel\Bundle\PropelBundle\Security\Acl\Domain\MutableAcl only.');
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -186,7 +190,7 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
|
|||
);
|
||||
}
|
||||
|
||||
foreach ($modelEntries as &$eachEntry) {
|
||||
foreach ($modelEntries as $eachEntry) {
|
||||
if (!in_array($eachEntry->getId(), $keepEntries)) {
|
||||
$eachEntry->delete($this->connection);
|
||||
}
|
||||
|
@ -225,9 +229,9 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
|
|||
/**
|
||||
* Persist the given ACEs.
|
||||
*
|
||||
* @param array $accessControlEntries
|
||||
* @param \Propel\PropelBundle\Model\Acl\ObjectIdentity $objectIdentity
|
||||
* @param bool $object
|
||||
* @param array $accessControlEntries
|
||||
* @param \Propel\Bundle\PropelBundle\Model\Acl\ObjectIdentity $objectIdentity
|
||||
* @param bool $object
|
||||
*
|
||||
* @return array The IDs of the persisted ACEs.
|
||||
*/
|
||||
|
@ -282,7 +286,7 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
|
|||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\EntryInterface $ace
|
||||
*
|
||||
* @return \Propel\PropelBundle\Model\Acl\Entry|null
|
||||
* @return \Propel\Bundle\PropelBundle\Model\Acl\Entry|null
|
||||
*/
|
||||
protected function getPersistedAce(EntryInterface $ace, ObjectIdentity $objectIdentity, $object = false)
|
||||
{
|
||||
|
@ -306,13 +310,13 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
|
|||
if (true === $object) {
|
||||
$ukQuery->filterByObjectIdentity($objectIdentity);
|
||||
} else {
|
||||
$ukQuery->filterByObjectIdentityId(null, \Criteria::ISNULL);
|
||||
$ukQuery->filterByObjectIdentityId(null, Criteria::ISNULL);
|
||||
}
|
||||
|
||||
if ($ace instanceof FieldEntryInterface) {
|
||||
$ukQuery->filterByFieldName($ace->getField());
|
||||
} else {
|
||||
$ukQuery->filterByFieldName(null, \Criteria::ISNULL);
|
||||
$ukQuery->filterByFieldName(null, Criteria::ISNULL);
|
||||
}
|
||||
|
||||
return $ukQuery->findOne($this->connection);
|
||||
|
@ -321,16 +325,16 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
|
|||
/**
|
||||
* Get an ACL for this provider.
|
||||
*
|
||||
* @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
|
||||
* @param array $loadedSecurityIdentities
|
||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $parentAcl
|
||||
* @param bool $inherited
|
||||
*
|
||||
* @return \Propel\PropelBundle\Security\Acl\Domain\MutableAcl
|
||||
* @return \Propel\Bundle\PropelBundle\Security\Acl\Domain\MutableAcl
|
||||
*/
|
||||
protected function getAcl(\PropelObjectCollection $collection, ObjectIdentityInterface $objectIdentity, array $loadedSecurityIdentities = array(), AclInterface $parentAcl = null, $inherited = true)
|
||||
protected function getAcl(ObjectCollection $collection, ObjectIdentityInterface $objectIdentity, array $loadedSecurityIdentities = array(), AclInterface $parentAcl = null, $inherited = true)
|
||||
{
|
||||
return new MutableAcl($collection, $objectIdentity, $this->permissionGrantingStrategy, $loadedSecurityIdentities, $parentAcl, $inherited, $this->connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
103
Security/User/PropelUserProvider.php
Normal file
103
Security/User/PropelUserProvider.php
Normal file
|
@ -0,0 +1,103 @@
|
|||
<?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\Security\User;
|
||||
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
|
||||
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
|
||||
|
||||
/**
|
||||
* Provides easy to use provisioning for Propel model users.
|
||||
*
|
||||
* @author William DURAND <william.durand1@gmail.com>
|
||||
*/
|
||||
class PropelUserProvider implements UserProviderInterface
|
||||
{
|
||||
/**
|
||||
* A Model class name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $class;
|
||||
|
||||
/**
|
||||
* A Query class name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $queryClass;
|
||||
|
||||
/**
|
||||
* A property to use to retrieve the user.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $property;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @param string $class The User model class.
|
||||
* @param string|null $property The property to use to retrieve a user.
|
||||
*/
|
||||
public function __construct($class, $property = null)
|
||||
{
|
||||
$this->class = $class;
|
||||
$this->queryClass = $class.'Query';
|
||||
$this->property = $property;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadUserByUsername($username)
|
||||
{
|
||||
$queryClass = $this->queryClass;
|
||||
$query = $queryClass::create();
|
||||
|
||||
if (null !== $this->property) {
|
||||
$filter = 'filterBy'.ucfirst($this->property);
|
||||
$query->$filter($username);
|
||||
} else {
|
||||
$query->filterByUsername($username);
|
||||
}
|
||||
|
||||
if (null === $user = $query->findOne()) {
|
||||
throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function refreshUser(UserInterface $user)
|
||||
{
|
||||
if (!$user instanceof $this->class) {
|
||||
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
|
||||
}
|
||||
|
||||
$queryClass = $this->queryClass;
|
||||
|
||||
return $queryClass::create()->findPk($user->getPrimaryKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsClass($class)
|
||||
{
|
||||
return $class === $this->class;
|
||||
}
|
||||
}
|
90
Service/SchemaLocator.php
Normal file
90
Service/SchemaLocator.php
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?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\Service;
|
||||
|
||||
use Symfony\Component\Config\FileLocatorInterface;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
||||
|
||||
class SchemaLocator
|
||||
{
|
||||
protected $fileLocator;
|
||||
protected $configuration;
|
||||
|
||||
public function __construct(FileLocatorInterface $fileLocator, array $configuration)
|
||||
{
|
||||
$this->fileLocator = $fileLocator;
|
||||
$this->configuration = $configuration;
|
||||
}
|
||||
|
||||
public function locateFromBundlesAndConfiguration(array $bundles)
|
||||
{
|
||||
$schemas = $this->locateFromBundles($bundles);
|
||||
|
||||
$path = $this->configuration['paths']['schemaDir'].'/schema.xml';
|
||||
if (file_exists($path)) {
|
||||
$schema = new \SplFileInfo($path);
|
||||
$schemas[(string) $schema] = array(null, $schema);
|
||||
}
|
||||
|
||||
return $schemas;
|
||||
}
|
||||
|
||||
public function locateFromBundles(array $bundles)
|
||||
{
|
||||
$schemas = array();
|
||||
foreach ($bundles as $bundle) {
|
||||
$schemas = array_merge($schemas, $this->locateFromBundle($bundle));
|
||||
}
|
||||
|
||||
return $schemas;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\HttpKernel\Bundle\BundleInterface
|
||||
*/
|
||||
public function locateFromBundle(BundleInterface $bundle)
|
||||
{
|
||||
$finalSchemas = array();
|
||||
|
||||
if (is_dir($dir = $bundle->getPath().'/Resources/config')) {
|
||||
$finder = new Finder();
|
||||
$schemas = $finder->files()->name('*schema.xml')->followLinks()->in($dir);
|
||||
|
||||
if (iterator_count($schemas)) {
|
||||
foreach ($schemas as $schema) {
|
||||
$logicalName = $this->transformToLogicalName($schema, $bundle);
|
||||
$finalSchema = new \SplFileInfo($this->fileLocator->locate($logicalName));
|
||||
|
||||
$finalSchemas[(string) $finalSchema] = array($bundle, $finalSchema);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $finalSchemas;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \SplFileInfo $schema
|
||||
* @param BundleInterface $bundle
|
||||
* @return string
|
||||
*/
|
||||
protected function transformToLogicalName(\SplFileInfo $schema, BundleInterface $bundle)
|
||||
{
|
||||
$schemaPath = str_replace(
|
||||
$bundle->getPath(). DIRECTORY_SEPARATOR . 'Resources' . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR,
|
||||
'',
|
||||
$schema->getRealPath()
|
||||
);
|
||||
|
||||
return sprintf('%s/Resources/config/%s', $bundle->getName(), $schemaPath);
|
||||
}
|
||||
}
|
|
@ -8,12 +8,14 @@
|
|||
* @license MIT License
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\Tests;
|
||||
namespace Propel\Bundle\PropelBundle\Tests;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\AclClass;
|
||||
use Propel\PropelBundle\Model\Acl\Entry;
|
||||
use Propel\PropelBundle\Model\Acl\ObjectIdentity as ModelObjectIdentity;
|
||||
use Propel\PropelBundle\Security\Acl\MutableAclProvider;
|
||||
use Propel\Generator\Util\QuickBuilder;
|
||||
|
||||
use Propel\Bundle\PropelBundle\Model\Acl\AclClass;
|
||||
use Propel\Bundle\PropelBundle\Model\Acl\Entry;
|
||||
use Propel\Bundle\PropelBundle\Model\Acl\ObjectIdentity as ModelObjectIdentity;
|
||||
use Propel\Bundle\PropelBundle\Security\Acl\MutableAclProvider;
|
||||
|
||||
use Symfony\Component\Security\Core\Role\Role;
|
||||
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
|
||||
|
@ -34,23 +36,22 @@ class AclTestCase extends TestCase
|
|||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->loadPropelQuickBuilder();
|
||||
|
||||
$schema = file_get_contents(__DIR__.'/../Resources/acl_schema.xml');
|
||||
|
||||
$builder = new \PropelQuickBuilder();
|
||||
$builder->setSchema($schema);
|
||||
if (!class_exists('Propel\PropelBundle\Model\Acl\map\AclClassTableMap')) {
|
||||
$builder->setClassTargets(array('tablemap', 'peer', 'object', 'query'));
|
||||
if (!class_exists('Propel\Bundle\PropelBundle\Model\Acl\Map\AclClassTableMap')) {
|
||||
$classTargets = array('tablemap', 'object', 'query');
|
||||
} else {
|
||||
$builder->setClassTargets(array());
|
||||
$classTargets = array();
|
||||
}
|
||||
|
||||
$this->con = $builder->build();
|
||||
$builder = new QuickBuilder();
|
||||
$builder->setSchema($schema);
|
||||
|
||||
$this->con = $builder->build($dsn = null, $user = null, $pass = null, $adapter = null, $classTargets);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Propel\PropelBundle\Model\Acl\ObjectIdentity
|
||||
* @return \Propel\Bundle\PropelBundle\Model\Acl\ObjectIdentity
|
||||
*/
|
||||
protected function createModelObjectIdentity($identifier)
|
||||
{
|
||||
|
@ -93,7 +94,7 @@ class AclTestCase extends TestCase
|
|||
|
||||
protected function getAclObjectIdentity($identifier = 1)
|
||||
{
|
||||
return new ObjectIdentity($identifier, 'Propel\PropelBundle\Tests\Fixtures\Model\Book');
|
||||
return new ObjectIdentity($identifier, 'Propel\Bundle\PropelBundle\Tests\Fixtures\Model\Book');
|
||||
}
|
||||
|
||||
protected function getRoleSecurityIdentity($role = 'ROLE_USER')
|
||||
|
|
|
@ -1,269 +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\Tests\Command;
|
||||
|
||||
use Propel\PropelBundle\Tests\TestCase;
|
||||
use Propel\PropelBundle\Command\AbstractCommand;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
/**
|
||||
* @author William Durand <william.durand1@gmail.com>
|
||||
*/
|
||||
class AbstractCommandTest extends TestCase
|
||||
{
|
||||
protected $command;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->command = new TestableAbstractCommand('testable-command');
|
||||
}
|
||||
|
||||
public function testParseDbName()
|
||||
{
|
||||
$dsn = 'mydsn#dbname=foo';
|
||||
$this->assertEquals('foo', $this->command->parseDbName($dsn));
|
||||
}
|
||||
|
||||
public function testParseDbNameWithoutDbName()
|
||||
{
|
||||
$this->assertNull($this->command->parseDbName('foo'));
|
||||
}
|
||||
|
||||
public function testTransformToLogicalName()
|
||||
{
|
||||
$bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\BundleInterface');
|
||||
$bundle
|
||||
->expects($this->once())
|
||||
->method('getName')
|
||||
->will($this->returnValue('MySuperBundle'));
|
||||
$bundle
|
||||
->expects($this->once())
|
||||
->method('getPath')
|
||||
->will($this->returnValue('/Users/foo/project/src/My/SuperBundle'));
|
||||
|
||||
$schema = $this
|
||||
->getMockBuilder('\SplFileInfo')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$schema
|
||||
->expects($this->once())
|
||||
->method('getRealPath')
|
||||
->will($this->returnValue('/Users/foo/project/src/My/SuperBundle/Resources/config/my-schema.xml'));
|
||||
|
||||
$expected = '@MySuperBundle/Resources/config/my-schema.xml';
|
||||
|
||||
$this->assertEquals($expected, $this->command->transformToLogicalName($schema, $bundle));
|
||||
}
|
||||
|
||||
public function testTransformToLogicalNameWithSubDir()
|
||||
{
|
||||
$bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\BundleInterface');
|
||||
$bundle
|
||||
->expects($this->once())
|
||||
->method('getName')
|
||||
->will($this->returnValue('MySuperBundle'));
|
||||
$bundle
|
||||
->expects($this->once())
|
||||
->method('getPath')
|
||||
->will($this->returnValue('/Users/foo/project/src/My/SuperBundle'));
|
||||
|
||||
$schema = $this
|
||||
->getMockBuilder('\SplFileInfo')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$schema
|
||||
->expects($this->once())
|
||||
->method('getRealPath')
|
||||
->will($this->returnValue('/Users/foo/project/src/My/SuperBundle/Resources/config/propel/my-schema.xml'));
|
||||
|
||||
$expected = '@MySuperBundle/Resources/config/propel/my-schema.xml';
|
||||
|
||||
$this->assertEquals($expected, $this->command->transformToLogicalName($schema, $bundle));
|
||||
}
|
||||
|
||||
public function testGetSchemasFromBundle()
|
||||
{
|
||||
$bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\BundleInterface');
|
||||
$bundle
|
||||
->expects($this->once())
|
||||
->method('getName')
|
||||
->will($this->returnValue('MySuperBundle'));
|
||||
$bundle
|
||||
->expects($this->exactly(2))
|
||||
->method('getPath')
|
||||
->will($this->returnValue(__DIR__ . '/../Fixtures/src/My/SuperBundle'));
|
||||
|
||||
$aSchema = realpath(__DIR__ . '/../Fixtures/src/My/SuperBundle/Resources/config/a-schema.xml');
|
||||
|
||||
// hack to by pass the file locator
|
||||
$this->command->setLocateResponse($aSchema);
|
||||
|
||||
$schemas = $this->command->getSchemasFromBundle($bundle);
|
||||
|
||||
$this->assertNotNull($schemas);
|
||||
$this->assertTrue(is_array($schemas));
|
||||
$this->assertCount(1, $schemas);
|
||||
$this->assertArrayHasKey($aSchema, $schemas);
|
||||
$this->assertSame($bundle, $schemas[$aSchema][0]);
|
||||
$this->assertEquals(new \SplFileInfo($aSchema), $schemas[$aSchema][1]);
|
||||
}
|
||||
|
||||
public function testGetSchemasFromBundleWithNoSchema()
|
||||
{
|
||||
$bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\BundleInterface');
|
||||
$bundle
|
||||
->expects($this->once())
|
||||
->method('getPath')
|
||||
->will($this->returnValue(__DIR__ . '/../Fixtures/src/My/SecondBundle'));
|
||||
|
||||
$schemas = $this->command->getSchemasFromBundle($bundle);
|
||||
|
||||
$this->assertNotNull($schemas);
|
||||
$this->assertTrue(is_array($schemas));
|
||||
$this->assertCount(0, $schemas);
|
||||
}
|
||||
|
||||
public function testGetFinalSchemasWithNoSchemaInBundles()
|
||||
{
|
||||
$bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\BundleInterface');
|
||||
$kernel = $this->getMock('Symfony\Component\HttpKernel\KernelInterface');
|
||||
|
||||
$bundle
|
||||
->expects($this->once())
|
||||
->method('getPath')
|
||||
->will($this->returnValue(__DIR__ . '/../Fixtures/src/My/SecondBundle'));
|
||||
|
||||
$kernel
|
||||
->expects($this->once())
|
||||
->method('getBundles')
|
||||
->will($this->returnValue(array($bundle)));
|
||||
|
||||
$schemas = $this->command->getFinalSchemas($kernel);
|
||||
|
||||
$this->assertNotNull($schemas);
|
||||
$this->assertTrue(is_array($schemas));
|
||||
$this->assertCount(0, $schemas);
|
||||
}
|
||||
|
||||
public function testGetFinalSchemas()
|
||||
{
|
||||
$bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\BundleInterface');
|
||||
$kernel = $this->getMock('Symfony\Component\HttpKernel\KernelInterface');
|
||||
|
||||
$bundle
|
||||
->expects($this->once())
|
||||
->method('getName')
|
||||
->will($this->returnValue('MySuperBundle'));
|
||||
$bundle
|
||||
->expects($this->exactly(2))
|
||||
->method('getPath')
|
||||
->will($this->returnValue(__DIR__ . '/../Fixtures/src/My/SuperBundle'));
|
||||
|
||||
$aSchema = realpath(__DIR__ . '/../Fixtures/src/My/SuperBundle/Resources/config/a-schema.xml');
|
||||
|
||||
// hack to by pass the file locator
|
||||
$this->command->setLocateResponse($aSchema);
|
||||
|
||||
$kernel
|
||||
->expects($this->once())
|
||||
->method('getBundles')
|
||||
->will($this->returnValue(array($bundle)));
|
||||
|
||||
$schemas = $this->command->getFinalSchemas($kernel);
|
||||
|
||||
$this->assertNotNull($schemas);
|
||||
$this->assertTrue(is_array($schemas));
|
||||
$this->assertCount(1, $schemas);
|
||||
$this->assertArrayHasKey($aSchema, $schemas);
|
||||
$this->assertSame($bundle, $schemas[$aSchema][0]);
|
||||
$this->assertEquals(new \SplFileInfo($aSchema), $schemas[$aSchema][1]);
|
||||
}
|
||||
|
||||
public function testGetFinalSchemasWithGivenBundle()
|
||||
{
|
||||
$bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\BundleInterface');
|
||||
$kernel = $this->getMock('Symfony\Component\HttpKernel\KernelInterface');
|
||||
|
||||
$bundle
|
||||
->expects($this->once())
|
||||
->method('getName')
|
||||
->will($this->returnValue('MySuperBundle'));
|
||||
$bundle
|
||||
->expects($this->exactly(2))
|
||||
->method('getPath')
|
||||
->will($this->returnValue(__DIR__ . '/../Fixtures/src/My/SuperBundle'));
|
||||
|
||||
$aSchema = realpath(__DIR__ . '/../Fixtures/src/My/SuperBundle/Resources/config/a-schema.xml');
|
||||
|
||||
// hack to by pass the file locator
|
||||
$this->command->setLocateResponse($aSchema);
|
||||
|
||||
$kernel
|
||||
->expects($this->never())
|
||||
->method('getBundles');
|
||||
|
||||
$schemas = $this->command->getFinalSchemas($kernel, $bundle);
|
||||
|
||||
$this->assertNotNull($schemas);
|
||||
$this->assertTrue(is_array($schemas));
|
||||
$this->assertCount(1, $schemas);
|
||||
$this->assertArrayHasKey($aSchema, $schemas);
|
||||
$this->assertSame($bundle, $schemas[$aSchema][0]);
|
||||
$this->assertEquals(new \SplFileInfo($aSchema), $schemas[$aSchema][1]);
|
||||
}
|
||||
}
|
||||
|
||||
class TestableAbstractCommand extends AbstractCommand
|
||||
{
|
||||
private $locate;
|
||||
|
||||
public function setLocateResponse($locate)
|
||||
{
|
||||
$this->locate = $locate;
|
||||
}
|
||||
|
||||
public function getContainer()
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function get($service)
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function locate($file)
|
||||
{
|
||||
return $this->locate;
|
||||
}
|
||||
|
||||
public function parseDbName($dsn)
|
||||
{
|
||||
return parent::parseDbName($dsn);
|
||||
}
|
||||
|
||||
public function transformToLogicalName(\SplFileInfo $schema, BundleInterface $bundle)
|
||||
{
|
||||
return parent::transformToLogicalName($schema, $bundle);
|
||||
}
|
||||
|
||||
public function getSchemasFromBundle(BundleInterface $bundle)
|
||||
{
|
||||
return parent::getSchemasFromBundle($bundle);
|
||||
}
|
||||
|
||||
public function getFinalSchemas(KernelInterface $kernel, BundleInterface $bundle = null)
|
||||
{
|
||||
return parent::getFinalSchemas($kernel, $bundle);
|
||||
}
|
||||
}
|
|
@ -1,77 +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\Tests\Command;
|
||||
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
|
||||
use Propel\PropelBundle\Tests\TestCase;
|
||||
use Propel\PropelBundle\Command\FixturesLoadCommand;
|
||||
|
||||
/**
|
||||
* @author Kévin Gomez <contact@kevingomez.fr>
|
||||
*/
|
||||
class FixturesLoadCommandTest extends TestCase
|
||||
{
|
||||
protected $command;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->command = new TestableFixturesLoadCommand('testable-command');
|
||||
|
||||
// let's create some dummy fixture files
|
||||
$this->fixtures_dir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'propel';
|
||||
$this->fixtures_files = array(
|
||||
'10_foo.yml', '20_bar.yml', '15_biz.yml', '18_boo.sql', '42_baz.sql'
|
||||
);
|
||||
|
||||
$this->filesystem = new Filesystem();
|
||||
$this->filesystem->mkdir($this->fixtures_dir);
|
||||
foreach ($this->fixtures_files as $file)
|
||||
{
|
||||
$this->filesystem->touch($this->fixtures_dir . DIRECTORY_SEPARATOR . $file);
|
||||
}
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
$this->filesystem->remove($this->fixtures_dir);
|
||||
}
|
||||
|
||||
public function testOrderedFixturesFiles()
|
||||
{
|
||||
$this->assertEquals(
|
||||
array('10_foo.yml', '15_biz.yml', '20_bar.yml',),
|
||||
$this->cleanFixtureIterator($this->command->getFixtureFiles('yml', $this->fixtures_dir))
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array('18_boo.sql', '42_baz.sql',),
|
||||
$this->cleanFixtureIterator($this->command->getFixtureFiles('sql', $this->fixtures_dir))
|
||||
);
|
||||
}
|
||||
|
||||
protected function cleanFixtureIterator($file_iterator)
|
||||
{
|
||||
$tmp_dir = $this->fixtures_dir;
|
||||
|
||||
return array_map(function($file) use($tmp_dir) {
|
||||
return str_replace($tmp_dir . DIRECTORY_SEPARATOR, '', $file);
|
||||
}, array_keys(iterator_to_array($file_iterator)));
|
||||
}
|
||||
}
|
||||
|
||||
class TestableFixturesLoadCommand extends FixturesLoadCommand
|
||||
{
|
||||
public function getFixtureFiles($type = 'sql', $in = null)
|
||||
{
|
||||
return parent::getFixtureFiles($type, $in);
|
||||
}
|
||||
}
|
|
@ -1,73 +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\Tests\Command;
|
||||
|
||||
use Propel\PropelBundle\Command\GeneratorAwareCommand;
|
||||
use Propel\PropelBundle\Tests\TestCase;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* @author William Durand <william.durand1@gmail.com>
|
||||
*/
|
||||
class GeneratorAwareCommandTest extends TestCase
|
||||
{
|
||||
protected $container;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->container = $this->getContainer();
|
||||
$this->container->setParameter('propel.path', __DIR__ . '/../../vendor/propel/propel1');
|
||||
}
|
||||
|
||||
public function testGetDatabasesFromSchema()
|
||||
{
|
||||
$command = new GeneratorAwareCommandTestable('testable-command');
|
||||
$command->setContainer($this->container);
|
||||
$databases = $command->getDatabasesFromSchema(new \SplFileInfo(__DIR__ . '/../Fixtures/schema.xml'));
|
||||
|
||||
$this->assertTrue(is_array($databases));
|
||||
|
||||
foreach ($databases as $database) {
|
||||
$this->assertInstanceOf('\Database', $database);
|
||||
}
|
||||
|
||||
$bookstore = $databases[0];
|
||||
$this->assertEquals(1, count($bookstore->getTables()));
|
||||
|
||||
foreach ($bookstore->getTables() as $table) {
|
||||
$this->assertInstanceOf('\Table', $table);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GeneratorAwareCommandTestable extends GeneratorAwareCommand
|
||||
{
|
||||
protected $container;
|
||||
|
||||
public function setContainer(ContainerInterface $container = null)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
protected function getContainer()
|
||||
{
|
||||
return $this->container;
|
||||
}
|
||||
|
||||
public function getDatabasesFromSchema(\SplFileInfo $file)
|
||||
{
|
||||
$this->loadPropelGenerator();
|
||||
|
||||
return parent::getDatabasesFromSchema($file);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue