Lullabot/mpx-php

View on GitHub
src/DataService/CustomFieldDiscovery.php

Summary

Maintainability
A
0 mins
Test Coverage
F
0%
<?php

namespace Lullabot\Mpx\DataService;

use Doctrine\Common\Annotations\Reader;
use Lullabot\Mpx\DataService\Annotation\CustomField;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;

/**
 * Class to discover Custom Field implementations.
 */
class CustomFieldDiscovery implements CustomFieldDiscoveryInterface
{
    /**
     * The array of discovered data services.
     *
     * @var DiscoveredCustomField[]
     */
    private array $customFields = [];

    /**
     * CustomFieldDiscovery constructor.
     *
     * @param string $namespace The namespace of the plugins.
     * @param string $directory The directory of the plugins.
     * @param string $rootDir
     */
    public function __construct(
        private $namespace,
        private $directory,
        /*
         * The root directory to discover from, containing the namespace directory.
         */
        private $rootDir,
        /*
         * The class to use for reading annotations.
         */
        private readonly Reader $annotationReader
    ) {
    }

    public function getCustomFields(): array
    {
        if (!$this->customFields) {
            $this->discoverCustomFields();
        }

        return $this->customFields;
    }

    /**
     * Discovers custom fields.
     */
    private function discoverCustomFields()
    {
        $path = $this->rootDir.'/'.$this->directory;
        $finder = new Finder();
        $finder->files()->in($path);

        /** @var SplFileInfo $file */
        foreach ($finder as $file) {
            $class = $this->classForFile($file);
            /* @var \Lullabot\Mpx\DataService\Annotation\CustomField $annotation */
            $this->registerAnnotation($class);
        }
    }

    /**
     * Given a file path, return the PSR-4 class it should contain.
     *
     * @param SplFileInfo $file The file to generate the class name for.
     *
     * @return string The fully-qualified class name.
     */
    private function classForFile(SplFileInfo $file): string
    {
        $subnamespace = str_replace('/', '\\', $file->getRelativePath());
        if (!empty($subnamespace)) {
            $subnamespace .= '\\';
        }
        $class = $this->namespace.'\\'.$subnamespace.$file->getBasename('.php');

        return $class;
    }

    /**
     * Register an annotation and it's custom fields.
     *
     * @param string $class The class to inspect for a CustomField annotation.
     */
    private function registerAnnotation($class)
    {
        /** @var CustomField $annotation */
        if ($annotation = $this->annotationReader->getClassAnnotation(
            new \ReflectionClass($class),
            \Lullabot\Mpx\DataService\Annotation\CustomField::class
        )) {
            if (!is_subclass_of($class, CustomFieldInterface::class)) {
                throw new \RuntimeException(sprintf('%s must implement %s.', $class, CustomFieldInterface::class));
            }

            $this->customFields[$annotation->service][$annotation->objectType][$annotation->namespace] = new DiscoveredCustomField(
                $class, $annotation
            );
        }
    }
}