symfony-doge/veslo

View on GitHub
src/SanityBundle/Vacancy/Indexer/Cockroach.php

Summary

Maintainability
B
4 hrs
Test Coverage
<?php

/*
 * This file is part of the Veslo project <https://github.com/symfony-doge/veslo>.
 *
 * (C) 2019 Pavel Petrov <itnelo@gmail.com>.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @license https://opensource.org/licenses/GPL-3.0 GPL-3.0
 */

declare(strict_types=1);

namespace Veslo\SanityBundle\Vacancy\Indexer;

use Closure;
use Psr\Log\LoggerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Veslo\AnthillBundle\Dto\Vacancy\Collector\AcceptanceDto;
use Veslo\AnthillBundle\Entity\Repository\VacancyRepository;
use Veslo\AnthillBundle\Entity\Vacancy;
use Veslo\AppBundle\Workflow\Vacancy\PitInterface;
use Veslo\AppBundle\Workflow\Vacancy\Worker\Iteration;
use Veslo\AppBundle\Workflow\Vacancy\WorkerInterface;
use Veslo\SanityBundle\Vacancy\AnalyserInterface;
use Veslo\SanityBundle\Vacancy\Index\Creator as IndexCreator;

/**
 * Delivers a vacancy to the Ministry of Truth for analysis and sanity index calculation
 *
 *           .--.       .--.
 *       _  `    \     /    `  _
 *        `\.===. \.^./ .===./`
 *               \/`"`\/
 *            ,  |     |  ,
 *           / `\|`-.-'|/` \
 *          /    |  \  |    \
 *       .-' ,-'`|   ; |`'-, '-.
 *           |   |    \|   |
 *           |   |    ;|   |
 *           |   \    //   |
 *           |    `._//'   |
 *          .'             `.
 *       _,'                 `,_
 *       `                     `
 */
class Cockroach implements WorkerInterface
{
    /**
     * Logger
     *
     * @var LoggerInterface
     */
    private $logger;

    /**
     * Vacancy repository
     *
     * @var VacancyRepository
     */
    private $vacancyRepository;

    /**
     * Performs a contextual analysis of vacancy data
     *
     * @var AnalyserInterface
     */
    private $vacancyAnalyser;

    /**
     * Creates sanity index entities in the local storage by dto provided by analysers
     *
     * @var IndexCreator
     */
    private $sanityIndexCreator;

    /**
     * Converts a sanity index data to array format for third-party services (e.g. logger)
     *
     * @var NormalizerInterface
     */
    private $sanityIndexNormalizer;

    /**
     * Cockroach constructor.
     *
     * @param LoggerInterface     $logger                Logger
     * @param VacancyRepository   $vacancyRepository     Vacancy repository
     * @param AnalyserInterface   $vacancyAnalyser       Performs a contextual analysis of vacancy data
     * @param IndexCreator        $sanityIndexCreator    Creates sanity index entities in the local storage
     * @param NormalizerInterface $sanityIndexNormalizer Converts a sanity index data to array for third-party services
     */
    public function __construct(
        LoggerInterface $logger,
        VacancyRepository $vacancyRepository,
        AnalyserInterface $vacancyAnalyser,
        IndexCreator $sanityIndexCreator,
        NormalizerInterface $sanityIndexNormalizer
    ) {
        $this->logger                = $logger;
        $this->vacancyRepository     = $vacancyRepository;
        $this->vacancyAnalyser       = $vacancyAnalyser;
        $this->sanityIndexCreator    = $sanityIndexCreator;
        $this->sanityIndexNormalizer = $sanityIndexNormalizer;
    }

    /**
     * Performs vacancy indexation iteration
     *
     * @param PitInterface $pit        Vacancy indexation queue
     * @param int          $iterations Indexing iterations count, at least one expected
     *
     * @return int
     */
    public function deliver(PitInterface $pit, int $iterations = 1): int
    {
        $sourceName = get_class($pit);

        $this->logger->debug('Indexing started.', ['source' => $sourceName, 'iterations' => $iterations]);

        $iteration     = Closure::fromCallable([$this, 'deliverIteration']);
        $iterationLoop = new Iteration\Loop($this, $iteration, 'An error has been occurred during vacancy indexing.');

        $successfulIterations = $iterationLoop->execute($pit, $iterations);

        $this->logger->debug(
            'Indexing completed.',
            [
                'source'     => $sourceName,
                'iterations' => $iterations,
                'successful' => $successfulIterations,
            ]
        );

        return $successfulIterations;
    }

    /**
     * {@inheritdoc}
     */
    public function getLogger(): ?LoggerInterface
    {
        return $this->logger;
    }

    /**
     * Returns positive if vacancy is successfully indexed
     *
     * @param PitInterface $pit Vacancy indexation queue
     *
     * @return bool Positive, if vacancy data was successfully indexed, negative otherwise
     */
    private function deliverIteration(PitInterface $pit): bool
    {
        $sourceName = get_class($pit);

        /** @var AcceptanceDto $acceptance */
        $acceptance = $pit->poll();

        if (!$acceptance instanceof AcceptanceDto) {
            $this->logger->debug(
                'No more vacancies to index.',
                [
                    'source' => $sourceName,
                    'input'  => gettype($acceptance),
                ]
            );

            return false;
        }

        $vacancyId = $acceptance->getVacancyId();

        /** @var Vacancy $vacancy */
        $vacancy = $this->vacancyRepository->require($vacancyId);

        $indexDto    = $this->vacancyAnalyser->analyse($vacancy);
        $sanityIndex = $this->sanityIndexCreator->createByDto($indexDto);

        $sanityIndexNormalized = $this->sanityIndexNormalizer->normalize($sanityIndex);

        $this->logger->info(
            'Vacancy indexed.',
            [
                'source'    => $sourceName,
                'vacancyId' => $vacancyId,
                'index'     => $sanityIndexNormalized,
            ]
        );

        return true;
    }
}