. */ namespace Doctrine\ORM\Tools; use Doctrine\ORM\Mapping\ClassMetadataInfo, Doctrine\ORM\Mapping\ClassMetadata, Doctrine\ORM\Mapping\MappingException, Doctrine\ORM\Mapping\Driver\Driver, Doctrine\ORM\Mapping\Driver\AnnotationDriver, Doctrine\ORM\EntityManager; /** * Class to read metadata mapping information from multiple sources into an array * of ClassMetadataInfo instances. * * The difference between this class and the ClassMetadataFactory is that this * is just a tool for reading in the mapping information from files without * having it bound to the actual ORM and the mapping information referenced by * the EntityManager. This allows us to read any source of mapping information * and return a single array of aggregated ClassMetadataInfo instances. * * These arrays are used for exporting the mapping information to the supported * mapping drivers, generating entities, generating repositories, etc. * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org * @since 2.0 * @version $Revision$ * @author Benjamin Eberlei * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel */ class ClassMetadataReader { private static $_mappingDrivers = array( 'annotation' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver', 'yaml' => 'Doctrine\ORM\Mapping\Driver\YamlDriver', 'yml' => 'Doctrine\ORM\Mapping\Driver\YamlDriver', 'xml' => 'Doctrine\ORM\Mapping\Driver\XmlDriver', 'php' => 'Doctrine\ORM\Mapping\Driver\PhpDriver', 'database' => 'Doctrine\ORM\Mapping\Driver\DatabaseDriver' ); private $_mappingSources = array(); private $_em; /** * Register a new mapping driver class under a specified name * * @param string $name * @param string $class */ public static function registerMappingDriver($name, $class) { self::$_mappingDrivers[$name] = $class; } /** * Optionally set the EntityManager instance to get the AnnotationDriver * from instead of creating a new instance of the AnnotationDriver * * @param EntityManager $em * @return void */ public function setEntityManager(EntityManager $em) { $this->_em = $em; } /** * Get an array of ClassMetadataInfo instances for all the configured mapping * directories. Reads the mapping directories and populates ClassMetadataInfo * instances. * * @return array $classes */ public function getMetadatas() { $classes = array(); foreach ($this->_mappingSources as $d) { list($source, $driver) = $d; $allClasses = $driver->getAllClassNames(); foreach ($allClasses as $className) { if (class_exists($className, false)) { $metadata = new ClassMetadata($className); } else { $metadata = new ClassMetadataInfo($className); } $driver->loadMetadataForClass($className, $metadata); if ( ! $metadata->isMappedSuperclass) { $classes[$metadata->name] = $metadata; } } } return $classes; } /** * Add a new mapping directory to the array of directories to convert and export * to another format * * @param string $source The source for the mapping * @param string $type The type of mapping files (yml, xml, etc.) * @return void */ public function addMappingSource($source, $type = null) { if ($type === null) { $type = $this->_determineSourceType($source); } if ( ! isset(self::$_mappingDrivers[$type])) { throw ExportException::invalidMappingDriverType($type); } $source = $this->_getSourceByType($type, $source); $driver = $this->_getMappingDriver($type, $source); $this->_mappingSources[] = array($source, $driver); } /** * Get an instance of a mapping driver * * @param string $type The type of mapping driver (yaml, xml, annotation, etc.) * @param string $source The source for the driver * @return AbstractDriver $driver */ private function _getMappingDriver($type, $source = null) { if ($source instanceof \Doctrine\ORM\Mapping\Driver\Driver) { return $source; } if ( ! isset(self::$_mappingDrivers[$type])) { return false; } $class = self::$_mappingDrivers[$type]; if (is_subclass_of($class, 'Doctrine\ORM\Mapping\Driver\AbstractFileDriver')) { if (is_null($source)) { throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath(); } $driver = new $class($source); } else if ($class == 'Doctrine\ORM\Mapping\Driver\AnnotationDriver') { $reader = new \Doctrine\Common\Annotations\AnnotationReader(new \Doctrine\Common\Cache\ArrayCache); $reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\'); $driver = new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($reader, $source); } else { $driver = new $class($source); } return $driver; } private function _determineSourceType($source) { // If the --from= is a directory lets determine if it is // annotations, yaml, xml, etc. if (is_dir($source)) { $source = realpath($source); // Find the files in the directory $files = glob($source . '/*.*'); if ( ! $files) { throw new \InvalidArgumentException( sprintf('No mapping files found in "%s"', $source) ); } // Get the contents of the first file $contents = file_get_contents($files[0]); // Check if it has a class definition in it for annotations if (preg_match("/class (.*)/", $contents)) { return 'annotation'; // Otherwise lets determine the type based on the extension of the // first file in the directory (yml, xml, etc) } else { $info = pathinfo($files[0]); return $info['extension']; } // Nothing special for database } else if ($source == 'database') { return 'database'; } } private function _getSourceByType($type, $source) { $source = realpath($source); // If --from==database then the source is an instance of SchemaManager // for the current EntityMAnager if ($type == 'database' && $this->_em) { return $this->_em->getConnection()->getSchemaManager(); // If source is annotation then lets try and find the existing annotation // driver for the source instead of re-creating a new instance } else if ($type == 'annotation') { if ($this->_em) { $metadataDriverImpl = $this->_em->getConfiguration()->getMetadataDriverImpl(); // Find the annotation driver in the chain of drivers if ($metadataDriverImpl instanceof DriverChain) { foreach ($metadataDriverImpl->getDrivers() as $namespace => $driver) { if ($this->_isAnnotationDriverForPath($driver, $source)) { return $driver; } } } else if ($this->_isAnnotationDriverForPath($metadataDriverImpl, $source)) { return $metadataDriverImpl; } else if ($metadataDriverImpl instanceof AnnotationDriver) { $metadataDriverImpl->addPaths(array($source)); return $metadataDriverImpl; } else { return $source; } } else { return $source; } } else { return $source; } } /** * Check to see if the given metadata driver is the annotation driver for the * given directory path * * @param Driver $driver * @param string $path * @return boolean */ private function _isAnnotationDriverForPath(Driver $driver, $path) { if ( ! $driver instanceof AnnotationDriver) { return false; } if (in_array(realpath($path), $driver->getPaths())) { return true; } else { return false; } } }