<?php 
 
/* 
 * This file is part of Sulu. 
 * 
 * (c) Sulu GmbH 
 * 
 * This source file is subject to the MIT license that is bundled 
 * with this source code in the file LICENSE. 
 */ 
 
namespace Sulu\Component\DocumentManager\Subscriber\Phpcr; 
 
use Sulu\Component\DocumentManager\Event\ConfigureOptionsEvent; 
use Sulu\Component\DocumentManager\Event\FindEvent; 
use Sulu\Component\DocumentManager\Event\HydrateEvent; 
use Sulu\Component\DocumentManager\Events; 
use Sulu\Component\DocumentManager\Exception\DocumentManagerException; 
use Sulu\Component\DocumentManager\Exception\DocumentNotFoundException; 
use Sulu\Component\DocumentManager\MetadataFactoryInterface; 
use Sulu\Component\DocumentManager\NodeManager; 
use Symfony\Component\EventDispatcher\EventDispatcherInterface; 
use Symfony\Component\EventDispatcher\EventSubscriberInterface; 
 
/** 
 * This class is responsible for finding documents. 
 */ 
class FindSubscriber implements EventSubscriberInterface 
{ 
    /** 
     * @var MetadataFactoryInterface 
     */ 
    private $metadataFactory; 
 
    /** 
     * @var NodeManager 
     */ 
    private $nodeManager; 
 
    /** 
     * @var EventDispatcherInterface 
     */ 
    private $eventDispatcher; 
 
    public function __construct( 
        MetadataFactoryInterface $metadataFactory, 
        NodeManager $nodeManager, 
        EventDispatcherInterface $eventDispatcher 
    ) { 
        $this->metadataFactory = $metadataFactory; 
        $this->nodeManager = $nodeManager; 
        $this->eventDispatcher = $eventDispatcher; 
    } 
 
    public static function getSubscribedEvents() 
    { 
        return [ 
            Events::FIND => ['handleFind', 500], 
            Events::CONFIGURE_OPTIONS => 'configureOptions', 
        ]; 
    } 
 
    public function configureOptions(ConfigureOptionsEvent $event) 
    { 
        $options = $event->getOptions(); 
        $options->setDefaults([ 
            'type' => null, 
        ]); 
    } 
 
    /** 
     * @throws DocumentManagerException 
     * @throws DocumentNotFoundException 
     */ 
    public function handleFind(FindEvent $event) 
    { 
        $options = $event->getOptions(); 
        $aliasOrClass = $options['type']; 
        $node = $this->nodeManager->find($event->getId()); 
 
        $hydrateEvent = new HydrateEvent($node, $event->getLocale(), $options); 
        $this->eventDispatcher->dispatch($hydrateEvent, Events::HYDRATE); 
        $document = $hydrateEvent->getDocument(); 
 
        if ($aliasOrClass) { 
            $this->checkAliasOrClass($aliasOrClass, $document); 
        } 
 
        $event->setDocument($hydrateEvent->getDocument()); 
    } 
 
    private function checkAliasOrClass($aliasOrClass, $document) 
    { 
        if ($this->metadataFactory->hasAlias($aliasOrClass)) { 
            $class = $this->metadataFactory->getMetadataForAlias($aliasOrClass)->getClass(); 
        } elseif (!\class_exists($aliasOrClass)) { 
            throw new DocumentManagerException(\sprintf( 
                'Unknown class specified and no alias exists for "%s", known aliases: "%s"', 
                $aliasOrClass, \implode('", "', $this->metadataFactory->getAliases()) 
            )); 
        } else { 
            $class = $aliasOrClass; 
        } 
 
        if (\get_class($document) !== $class) { 
            throw new DocumentNotFoundException(\sprintf( 
                'Requested document of type "%s" but got document of type "%s"', 
                $aliasOrClass, 
                \get_class($document) 
            )); 
        } 
    } 
}