add missing files
authorymh <ymh.work@gmail.com>
Fri, 04 Nov 2011 15:59:49 +0100
changeset 25 11fd79666374
parent 24 cd389bf882f1
child 26 9eab3e86db7d
child 27 8551d844b4f3
add missing files
Command/CreateSchemaDoctrineCommand.php
Command/UpdateSchemaDoctrineCommand.php
Listener/WikiTagDocumentListener.php
Search/Search.php
Utils/SchemaUtils.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 @@
+<?php
+
+/*
+ * This file is part of the WikiTagBundle package.
+ *
+ * (c) IRI <http://www.iri.centrepompidou.fr/>
+ *
+ * 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(<<<EOT
+The <info>doctrine:schema:create</info> command executes the SQL needed to
+generate the database schema for the default entity manager:
+
+<info>php app/console doctrine:schema:create</info>
+
+You can also generate the database schema for a specific entity manager:
+
+<info>php app/console doctrine:schema:create --em=default</info>
+
+Finally, instead of executing the SQL, you can output the SQL:
+
+<info>php app/console doctrine:schema:create --dump-sql</info>
+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);
+    }
+}
--- /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 @@
+<?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 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(<<<EOT
+The <info>doctrine:schema:update</info> 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:
+
+<info>php app/console doctrine:schema:update --dump-sql</info>
+
+Alternatively, you can execute the generated queries:
+
+<info>php app/console doctrine:schema:update --force</info>
+
+You can also update the database schema for a specific entity manager:
+
+<info>php app/console doctrine:schema:update --em=default</info>
+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! "<info>%s</info>" queries were executed', count($sqls)));
+        } else {
+            $output->writeln('<comment>ATTENTION</comment>: 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 <info>"%s"</info> queries to update the database.', count($sqls)));
+            $output->writeln('Please run the operation by passing one of the following options:');
+    
+            $output->writeln(sprintf('    <info>%s --force</info> to execute the command', $this->getName()));
+            $output->writeln(sprintf('    <info>%s --dump-sql</info> to dump the SQL statements to the screen', $this->getName()));
+        }
+    }
+    
+    
+}
--- /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 @@
+<?php
+/*
+ * This file is part of the WikiTagBundle package.
+ *
+ * (c) IRI <http://www.iri.centrepompidou.fr/>
+ *
+ * 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)<filemtime($config_file)))
+        {
+            unlink($file);
+        }
+        if(!class_exists("\IRI\Bundle\WikiTagBundle\Entity\Document"))
+        {
+            $schema_utils = $this->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
--- /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 @@
+<?php
+/*
+ * This file is part of the WikiTagBundle package.
+ *
+ * (c) IRI <http://www.iri.centrepompidou.fr/>
+ *
+ * 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
--- /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 @@
+<?php
+/*
+ * This file is part of the WikiTagBundle package.
+ *
+ * (c) IRI <http://www.iri.centrepompidou.fr/>
+ *
+ * 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, <<<EOF
+                        return \$this->$name;
+EOF
+            );
+            $definition->addMethod($get_method);
+        
+            $set_method = new Method("public", "set".ucfirst($name), "\$$name", <<<EOF
+                        \$this->$name = \$$name;
+EOF
+            );
+            $definition->addMethod($set_method);
+        
+        }
+        
+        $dumper = new Dumper($definition);
+        $classCode = $dumper->dump();
+        
+        return $classCode;
+    }
+}
\ No newline at end of file