Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\HttpKernel\Bundle; Chris@0: Chris@17: use Symfony\Component\Console\Application; Chris@17: use Symfony\Component\DependencyInjection\Container; Chris@0: use Symfony\Component\DependencyInjection\ContainerAwareTrait; Chris@0: use Symfony\Component\DependencyInjection\ContainerBuilder; Chris@17: use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; Chris@0: use Symfony\Component\Finder\Finder; Chris@0: Chris@0: /** Chris@0: * An implementation of BundleInterface that adds a few conventions Chris@0: * for DependencyInjection extensions and Console commands. Chris@0: * Chris@0: * @author Fabien Potencier Chris@0: */ Chris@0: abstract class Bundle implements BundleInterface Chris@0: { Chris@0: use ContainerAwareTrait; Chris@0: Chris@0: protected $name; Chris@0: protected $extension; Chris@0: protected $path; Chris@0: private $namespace; Chris@0: Chris@0: /** Chris@17: * {@inheritdoc} Chris@0: */ Chris@0: public function boot() Chris@0: { Chris@0: } Chris@0: Chris@0: /** Chris@17: * {@inheritdoc} Chris@0: */ Chris@0: public function shutdown() Chris@0: { Chris@0: } Chris@0: Chris@0: /** Chris@17: * {@inheritdoc} Chris@0: * Chris@0: * This method can be overridden to register compilation passes, Chris@0: * other extensions, ... Chris@0: */ Chris@0: public function build(ContainerBuilder $container) Chris@0: { Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns the bundle's container extension. Chris@0: * Chris@0: * @return ExtensionInterface|null The container extension Chris@0: * Chris@0: * @throws \LogicException Chris@0: */ Chris@0: public function getContainerExtension() Chris@0: { Chris@0: if (null === $this->extension) { Chris@0: $extension = $this->createContainerExtension(); Chris@0: Chris@0: if (null !== $extension) { Chris@0: if (!$extension instanceof ExtensionInterface) { Chris@17: throw new \LogicException(sprintf('Extension %s must implement Symfony\Component\DependencyInjection\Extension\ExtensionInterface.', \get_class($extension))); Chris@0: } Chris@0: Chris@0: // check naming convention Chris@0: $basename = preg_replace('/Bundle$/', '', $this->getName()); Chris@0: $expectedAlias = Container::underscore($basename); Chris@0: Chris@0: if ($expectedAlias != $extension->getAlias()) { Chris@17: throw new \LogicException(sprintf('Users will expect the alias of the default extension of a bundle to be the underscored version of the bundle name ("%s"). You can override "Bundle::getContainerExtension()" if you want to use "%s" or another alias.', $expectedAlias, $extension->getAlias())); Chris@0: } Chris@0: Chris@0: $this->extension = $extension; Chris@0: } else { Chris@0: $this->extension = false; Chris@0: } Chris@0: } Chris@0: Chris@0: if ($this->extension) { Chris@0: return $this->extension; Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@17: * {@inheritdoc} Chris@0: */ Chris@0: public function getNamespace() Chris@0: { Chris@0: if (null === $this->namespace) { Chris@0: $this->parseClassName(); Chris@0: } Chris@0: Chris@0: return $this->namespace; Chris@0: } Chris@0: Chris@0: /** Chris@17: * {@inheritdoc} Chris@0: */ Chris@0: public function getPath() Chris@0: { Chris@0: if (null === $this->path) { Chris@0: $reflected = new \ReflectionObject($this); Chris@17: $this->path = \dirname($reflected->getFileName()); Chris@0: } Chris@0: Chris@0: return $this->path; Chris@0: } Chris@0: Chris@0: /** Chris@17: * {@inheritdoc} Chris@0: */ Chris@0: public function getParent() Chris@0: { Chris@0: } Chris@0: Chris@0: /** Chris@17: * {@inheritdoc} Chris@0: */ Chris@0: final public function getName() Chris@0: { Chris@0: if (null === $this->name) { Chris@0: $this->parseClassName(); Chris@0: } Chris@0: Chris@0: return $this->name; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Finds and registers Commands. Chris@0: * Chris@0: * Override this method if your bundle commands do not follow the conventions: Chris@0: * Chris@0: * * Commands are in the 'Command' sub-directory Chris@0: * * Commands extend Symfony\Component\Console\Command\Command Chris@0: */ Chris@0: public function registerCommands(Application $application) Chris@0: { Chris@0: if (!is_dir($dir = $this->getPath().'/Command')) { Chris@0: return; Chris@0: } Chris@0: Chris@0: if (!class_exists('Symfony\Component\Finder\Finder')) { Chris@0: throw new \RuntimeException('You need the symfony/finder component to register bundle commands.'); Chris@0: } Chris@0: Chris@0: $finder = new Finder(); Chris@0: $finder->files()->name('*Command.php')->in($dir); Chris@0: Chris@0: $prefix = $this->getNamespace().'\\Command'; Chris@0: foreach ($finder as $file) { Chris@0: $ns = $prefix; Chris@0: if ($relativePath = $file->getRelativePath()) { Chris@0: $ns .= '\\'.str_replace('/', '\\', $relativePath); Chris@0: } Chris@0: $class = $ns.'\\'.$file->getBasename('.php'); Chris@0: if ($this->container) { Chris@17: $commandIds = $this->container->hasParameter('console.command.ids') ? $this->container->getParameter('console.command.ids') : []; Chris@0: $alias = 'console.command.'.strtolower(str_replace('\\', '_', $class)); Chris@14: if (isset($commandIds[$alias]) || $this->container->has($alias)) { Chris@0: continue; Chris@0: } Chris@0: } Chris@0: $r = new \ReflectionClass($class); Chris@0: if ($r->isSubclassOf('Symfony\\Component\\Console\\Command\\Command') && !$r->isAbstract() && !$r->getConstructor()->getNumberOfRequiredParameters()) { Chris@14: @trigger_error(sprintf('Auto-registration of the command "%s" is deprecated since Symfony 3.4 and won\'t be supported in 4.0. Use PSR-4 based service discovery instead.', $class), E_USER_DEPRECATED); Chris@14: Chris@0: $application->add($r->newInstance()); Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns the bundle's container extension class. Chris@0: * Chris@0: * @return string Chris@0: */ Chris@0: protected function getContainerExtensionClass() Chris@0: { Chris@0: $basename = preg_replace('/Bundle$/', '', $this->getName()); Chris@0: Chris@0: return $this->getNamespace().'\\DependencyInjection\\'.$basename.'Extension'; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Creates the bundle's container extension. Chris@0: * Chris@0: * @return ExtensionInterface|null Chris@0: */ Chris@0: protected function createContainerExtension() Chris@0: { Chris@0: if (class_exists($class = $this->getContainerExtensionClass())) { Chris@0: return new $class(); Chris@0: } Chris@0: } Chris@0: Chris@0: private function parseClassName() Chris@0: { Chris@0: $pos = strrpos(static::class, '\\'); Chris@0: $this->namespace = false === $pos ? '' : substr(static::class, 0, $pos); Chris@0: if (null === $this->name) { Chris@0: $this->name = false === $pos ? static::class : substr(static::class, $pos + 1); Chris@0: } Chris@0: } Chris@0: }