# HG changeset patch # User ymh # Date 1320418789 -3600 # Node ID 11fd7966637442b665fa51609320c36a9abc51b4 # Parent cd389bf882f114246ff986088f5e5fc8d95d6277 add missing files diff -r cd389bf882f1 -r 11fd79666374 Command/CreateSchemaDoctrineCommand.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Command/CreateSchemaDoctrineCommand.php Fri Nov 04 15:59:49 2011 +0100 @@ -0,0 +1,125 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace IRI\Bundle\WikiTagBundle\Command; + +use Symfony\Component\DependencyInjection\ContainerAwareInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; +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 Doctrine\ORM\Tools\SchemaTool; +use Doctrine\ORM\Tools\Console\Command\SchemaTool\CreateCommand; +use Symfony\Bundle\DoctrineBundle\Command\Proxy\DoctrineCommandHelper; + +/** + * Command to execute the SQL needed to generate the database schema for + * a given entity manager. + * + * This file is a direct adaptation of the Symfony\Bundle\DoctrineBundle\Command\Proxy\CreateSchemaDoctrineCommand + * + */ +class CreateSchemaDoctrineCommand extends CreateCommand implements ContainerAwareInterface +{ + protected function configure() + { + parent::configure(); + + $this + ->setName('wikitag:schema:create') + ->setDescription('Executes (or dumps) the SQL needed to generate the database schema') + ->addOption('em', null, InputOption::VALUE_OPTIONAL, 'The entity manager to use for this command') + ->setHelp(<<doctrine:schema:create command executes the SQL needed to +generate the database schema for the default entity manager: + +php app/console doctrine:schema:create + +You can also generate the database schema for a specific entity manager: + +php app/console doctrine:schema:create --em=default + +Finally, instead of executing the SQL, you can output the SQL: + +php app/console doctrine:schema:create --dump-sql +EOT + ); + } + + /** + * @var ContainerInterface + */ + private $container; + + protected function getContainer() + { + if (null === $this->container) { + $this->container = $this->getApplication()->getKernel()->getContainer(); + } + + return $this->container; + } + + /** + * @see ContainerAwareInterface::setContainer() + */ + public function setContainer(ContainerInterface $container = null) + { + $this->container = $container; + } + + + protected function filterCreateSchema($sqls) + { + + // get service + $schema_utils = $this->getContainer()->get("wikitag.shema_utils"); + + $res_sqls = $schema_utils->filter_foreign_key($sqls); + $res_sqls = $schema_utils->filter_index_creation($res_sqls); + + + return $res_sqls; + } + + protected function executeSchemaCommand(InputInterface $input, OutputInterface $output, SchemaTool $schemaTool, array $metadatas) + { + $output->write('ATTENTION: This operation should not be executed in a production environment.' . PHP_EOL . PHP_EOL); + $sqls = $schemaTool->getCreateSchemaSql($metadatas); + + $createSchemaSql = $this->filterCreateSchema($sqls); + + if ($input->getOption('dump-sql') === true) { + + $output->write(implode(';' . PHP_EOL, $createSchemaSql) . PHP_EOL); + } else { + $output->write('Creating database schema...' . PHP_EOL); + $emHelper = $this->getHelper('em'); + + $conn = $emHelper->getEntityManager()->getConnection(); + + foreach ($createSchemaSql as $sql) { + $conn->executeQuery($sql); + } + $output->write('Database schema created successfully!' . PHP_EOL); + } + + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + DoctrineCommandHelper::setApplicationEntityManager($this->getApplication(), $input->getOption('em')); + + parent::execute($input, $output); + } +} diff -r cd389bf882f1 -r 11fd79666374 Command/UpdateSchemaDoctrineCommand.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Command/UpdateSchemaDoctrineCommand.php Fri Nov 04 15:59:49 2011 +0100 @@ -0,0 +1,154 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace IRI\Bundle\WikiTagBundle\Command; + +use Symfony\Component\DependencyInjection\ContainerAwareInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; +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 Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand; +use Doctrine\ORM\Tools\SchemaTool; +use Symfony\Bundle\DoctrineBundle\Command\Proxy\DoctrineCommandHelper; + + +/** + * Command to generate the SQL needed to update the database schema to match + * the current mapping information. + * + * This file is a direct adaptation of the Symfony\Bundle\DoctrineBundle\Command\Proxy\UpdateSchemaDoctrineCommand + * + */ +class UpdateSchemaDoctrineCommand extends UpdateCommand implements ContainerAwareInterface +{ + protected function configure() + { + parent::configure(); + + $this + ->setName('wikitag:schema:update') + ->setDescription('Executes (or dumps) the SQL needed to update the database schema to match the current mapping metadata') + ->addOption('em', null, InputOption::VALUE_OPTIONAL, 'The entity manager to use for this command') + ->setHelp(<<doctrine:schema:update command generates the SQL needed to +synchronize the database schema with the current mapping metadata of the +default entity manager. + +For example, if you add metadata for a new column to an entity, this command +would generate and output the SQL needed to add the new column to the database: + +php app/console doctrine:schema:update --dump-sql + +Alternatively, you can execute the generated queries: + +php app/console doctrine:schema:update --force + +You can also update the database schema for a specific entity manager: + +php app/console doctrine:schema:update --em=default +EOT + ); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + DoctrineCommandHelper::setApplicationEntityManager($this->getApplication(), $input->getOption('em')); + + parent::execute($input, $output); + } + + /** + * @var ContainerInterface + */ + private $container; + + protected function getContainer() + { + if (null === $this->container) { + $this->container = $this->getApplication()->getKernel()->getContainer(); + } + + return $this->container; + } + + /** + * @see ContainerAwareInterface::setContainer() + */ + public function setContainer(ContainerInterface $container = null) + { + $this->container = $container; + } + + + protected function filterUpdateSchema($sqls) + { + + // get service + $schema_utils = $this->getContainer()->get("wikitag.shema_utils"); + + $res_sqls = $schema_utils->filter_foreign_key($sqls); + $res_sqls = $schema_utils->filter_index_creation($res_sqls); + + + return $res_sqls; + } + + protected function executeSchemaCommand(InputInterface $input, OutputInterface $output, SchemaTool $schemaTool, array $metadatas) + { + // Defining if update is complete or not (--complete not defined means $saveMode = true) + $saveMode = ($input->getOption('complete') !== true); + + $sqls = $schemaTool->getUpdateSchemaSql($metadatas, $saveMode); + $sqls = $this->filterUpdateSchema($sqls); + if (0 == count($sqls)) { + $output->writeln('Nothing to update - your database is already in sync with the current entity metadata.'); + + return; + } + + $dumpSql = (true === $input->getOption('dump-sql')); + $force = (true === $input->getOption('force')); + if ($dumpSql && $force) { + throw new \InvalidArgumentException('You can pass either the --dump-sql or the --force option (but not both simultaneously).'); + } + + if ($dumpSql) { + $output->writeln(implode(';' . PHP_EOL, $sqls)); + } else if ($force) { + $output->writeln('Updating database schema...'); + + $emHelper = $this->getHelper('em'); + + $conn = $emHelper->getEntityManager()->getConnection(); + + foreach ($sqls as $sql) { + $conn->executeQuery($sql); + } + $output->writeln(sprintf('Database schema updated successfully! "%s" queries were executed', count($sqls))); + } else { + $output->writeln('ATTENTION: This operation should not be executed in a production environment.'); + $output->writeln(' Use the incremental update to detect changes during development and use'); + $output->writeln(' the SQL DDL provided to manually update your database in production.'); + $output->writeln(''); + + $output->writeln(sprintf('The Schema-Tool would execute "%s" queries to update the database.', count($sqls))); + $output->writeln('Please run the operation by passing one of the following options:'); + + $output->writeln(sprintf(' %s --force to execute the command', $this->getName())); + $output->writeln(sprintf(' %s --dump-sql to dump the SQL statements to the screen', $this->getName())); + } + } + + +} diff -r cd389bf882f1 -r 11fd79666374 Listener/WikiTagDocumentListener.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Listener/WikiTagDocumentListener.php Fri Nov 04 15:59:49 2011 +0100 @@ -0,0 +1,177 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace IRI\Bundle\WikiTagBundle\Listener; + +use Doctrine\DBAL\Schema\Table; + +use Doctrine\ORM\Tools\Event\GenerateSchemaTableEventArgs; +use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs; +use Doctrine\ORM\Tools\ToolEvents; +use Doctrine\Common\EventSubscriber; +use Doctrine\ORM\Events; +use Doctrine\ORM\Event\LoadClassMetadataEventArgs; +use Symfony\Component\DependencyInjection\ContainerInterface; + + +/** + * Doctrine ORM listener updating the document index + * + * @author ymh + * + */ +class WikiTagDocumentListener implements EventSubscriber +{ + + /** + * @var ContainerInterface + */ + private $container; + + /** + * Constructor + * + * @param ContainerInterface $container + */ + public function __construct(ContainerInterface $container) + { + $this->container = $container; + } + + public function getContainer() + { + return $this->container; + } + + public function getSubscribedEvents() + { + return array( + Events::loadClassMetadata, + ToolEvents::postGenerateSchemaTable, + ); + } + + + /** + * + * Enter description here ... + * @param LoadClassMetadataEventArgs $args + */ + public function loadClassMetadata(LoadClassMetadataEventArgs $args) + { + //check that IRI\\Bundle\\WikiTagBundle\\Entity\\Document exists. if not create it and load it + // + $path = $this->container->getParameter('kernel.cache_dir')."/wikitag"; + $file = "$path/IRI/Bundle/WikiTagBundle/Entity/Document.php"; + $config_file = $this->container->getParameter('kernel.root_dir')."/app/config/config.yml"; + + if(file_exists($file) && file_exists($config_file) && (filemtime($file)getContainer()->get("wikitag.shema_utils"); + $classCode = $schema_utils->generateDocumentClass(); + + $logger = $this->container->get('logger'); + $logger->debug("File to generate : $file"); + if(!file_exists(dirname($file)) && !mkdir(dirname($file),0777,true)) + { + throw new Exception("Impossible to create document file"); + } + file_put_contents($file, $classCode); + + $document_schema = $args->getEntityManager()->getClassMetadata("IRI\\Bundle\\WikiTagBundle\\Entity\\Document"); + return; + } + + + $metadata = $args->getClassMetadata(); + if($metadata->name === "IRI\\Bundle\\WikiTagBundle\\Entity\\Document") + { + $document_class = $this->container->getParameter('wiki_tag.document_class'); + + $logger = $this->container->get('logger'); + $logger->debug("DocumentListener: Add ExternalId Mapping"); + + $document_id_column = $this->container->getParameter('wiki_tag.document_id_column'); + + $logger->debug("DocumentListener: external id def : " . print_r($document_id_column, true)); + + /*$target_metadata = $args->getEntityManager()->getClassMetadata($document_class); + $mapping = array_replace(array(), $target_metadata->getFieldMapping($document_id_column)); + $mapping['fieldName'] = 'externalId'; + $mapping['columnName'] = 'external_id'; + $mapping['id'] = false; + $metadata->mapField($mapping);*/ + $metadata->mapOneToOne(array( + 'targetEntity' => $document_class, + 'fieldName' => 'externalId', + 'joinColumns' => array(0=>array( + 'name' => 'external_id', + 'referencedColumnName' => $document_id_column + )), + )); + + //map the fields + $fields = $this->container->getParameter('wiki_tag.fields'); + + $def_columns = array(); + foreach ( $fields as $name => $field_def) + { + if(isset($field_def['type'])) + { + $type = $field_def['type']; + } + if(!isset($type) || is_null($type) || strlen($type) == 0) + { + $type = "text"; + } + $mapping = array('fieldName' => $name, 'type' => $type); + if($type == 'string') + { + if(isset($field_def['length'])) + { + $length = $field_def['length']; + } + if(!isset($length)) + { + $length = 1024; + } + elseif (!is_int($length)) + { + $length = intval($length); + } + $mapping['length'] = $length; + } + $metadata->mapField($mapping); + $def_columns[] = $name; + $metadata->table['indexes']["${name}_document_fulltext_idx"] = array( 'columns' => array("$name",)); + } + $def_columns[] = "tags_str"; + $metadata->table['indexes']["all_document_fulltext_idx"] = array('columns'=> $def_columns); + } + } + + public function postGenerateSchemaTable(GenerateSchemaTableEventArgs $args) + { + + if($args->getClassMetadata()->name === "IRI\\Bundle\\WikiTagBundle\\Entity\\Document") + { + $logger = $this->container->get('logger'); + $logger->debug("Generate schema table ".$args->getClassTable()->getName()); + + $args->getClassTable()->addOption('engine','MyISAM'); + } + } + + +} \ No newline at end of file diff -r cd389bf882f1 -r 11fd79666374 Search/Search.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Search/Search.php Fri Nov 04 15:59:49 2011 +0100 @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace IRI\Bundle\WikiTagBundle\Search; + +use Symfony\Component\DependencyInjection\ContainerAware; +use Symfony\Component\DependencyInjection\ContainerInterface; + +class Search extends ContainerAware +{ + + public function getContainer() + { + return $this->container; + } + + public function __construct(ContainerInterface $container) + { + $this->setContainer($container); + } + + +} \ No newline at end of file diff -r cd389bf882f1 -r 11fd79666374 Utils/SchemaUtils.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Utils/SchemaUtils.php Fri Nov 04 15:59:49 2011 +0100 @@ -0,0 +1,167 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace IRI\Bundle\WikiTagBundle\Utils; + +use Mandango\Mondator\Definition\Definition; +use Mandango\Mondator\Definition\Property; +use Mandango\Mondator\Definition\Method; +use Mandango\Mondator\Dumper; + +class SchemaUtils +{ + /** + * The container for the service + * @var unknown_type + */ + protected $container; + + /** + * Accessor for the container property. + */ + public function getContainer() + { + return $this->container; + } + + /** + * + * construct the shema utils service injects the container + * @param unknown_type $container + */ + public function __construct($container) + { + $this->container = $container; + } + + + + /** + * Return the sql to create the document table full text indexes + * @return array + */ + public function createFullTextIndexes() + { + $sql_code = array(); + $fields = $this->getContainer()->getParameter('wiki_tag.fields'); + $def_columns = array(); + foreach ( $fields as $name => $field_def) + { + if(isset($field_def['type'])) + { + $type = $field_def['type']; + } + if(!isset($type) || is_null($type) || strlen($type) == 0) + { + $type = "text"; + } + + if($type === 'text') + { + $def_column = "$name(4096)"; + } + else + { + $def_column = $name; + } + $def_columns[] = $def_column; + + $sql_code[] = "ALTER IGNORE TABLE wikitag_document DROP INDEX ${name}_document_fulltext_idx"; + $sql_code[] = "ALTER TABLE wikitag_document ADD FULLTEXT INDEX ${name}_document_fulltext_idx ($def_column)"; + } + + $sql_code[] = "ALTER IGNORE TABLE wikitag_document DROP INDEX tags_str_document_fulltext_idx"; + $sql_code[] = "ALTER TABLE wikitag_document ADD FULLTEXT INDEX tags_str_document_fulltext_idx (tags_str)"; + + $sql_code[] = "ALTER IGNORE TABLE wikitag_document DROP INDEX all_document_fulltext_idx"; + $sql_code[] = "ALTER TABLE wikitag_document ADD FULLTEXT INDEX all_document_fulltext_idx (".join(",", $def_columns).")"; + + return $sql_code; + + } + + public function filter_foreign_key(array $sqls) + { + $res_sqls = array(); + //TODO : take the column and table names from the schema + foreach ($sqls as $sql) { + if(!preg_match("/ADD CONSTRAINT .+ FOREIGN KEY \(.*\) REFERENCES wikitag_document\(id\)/i", $sql)) + { + $res_sqls[] = $sql; + } + } + + return $res_sqls; + + } + + public function filter_index_creation(array $sqls) + { + $res_sqls = array(); + + $replace_regexps = array(); + + $fields = $this->getContainer()->getParameter('wiki_tag.fields'); + $field_names = array(); + foreach ( $fields as $name => $field_def) + { + // create regular expression + $replace_regexps[] = "/INDEX (${name}_document_fulltext_idx (?:ON wikitag_document ){0,1}\(${name}\))/"; + $field_names[] = " ?${name},?"; + } + $field_names[] = " ?tags_str,?"; + $replace_regexps[] = "/INDEX (tags_str_document_fulltext_idx (?:ON wikitag_document ){0,1}\(tags_str\))/"; + $replace_regexps[] = "/INDEX (all_document_fulltext_idx (?:ON wikitag_document ){0,1}\((?:".implode("|",$field_names)."){".count($field_names)."}\))/"; + + foreach($sqls as $sql) + { + if(strrpos($sql,"wikitag_document")) + { + $sql = preg_replace($replace_regexps, "FULLTEXT INDEX $1", $sql); + } + $res_sqls[] = $sql; + } + + return $res_sqls; + } + + public function generateDocumentClass() + { + $definition = new Definition('IRI\Bundle\WikiTagBundle\Entity\Document'); + + $definition->setParentClass('\IRI\Bundle\WikiTagBundle\Model\Document'); + + $fields = $this->getContainer()->getParameter('wiki_tag.fields'); + + foreach ( $fields as $name => $field_def) + { + $property = new Property("private", $name, NULL); + $definition->addProperty($property); + + $get_method = new Method("public", "get".ucfirst($name), NULL, <<$name; +EOF + ); + $definition->addMethod($get_method); + + $set_method = new Method("public", "set".ucfirst($name), "\$$name", <<$name = \$$name; +EOF + ); + $definition->addMethod($set_method); + + } + + $dumper = new Dumper($definition); + $classCode = $dumper->dump(); + + return $classCode; + } +} \ No newline at end of file