at the end of the day, it was inevitable

This commit is contained in:
Mo Elzubeir
2022-12-09 08:36:26 -06:00
commit 1218570914
1768 changed files with 887087 additions and 0 deletions
@@ -0,0 +1,269 @@
<?php
namespace AppBundle\Controller\V1;
use ApiBundle\Controller\Annotation\Roles;
use AppBundle\Controller\Traits\FormFactoryAwareTrait;
use AppBundle\Controller\Traits\TokenStorageAwareTrait;
use AppBundle\Exception\LimitExceedException;
use AppBundle\Form\SearchRequest\SimpleQuerySearchRequestType;
use AppBundle\Manager\SimpleQuery\SimpleQueryManagerInterface;
use AppBundle\Manager\Source\SourceManagerInterface;
use CacheBundle\Document\Extractor\DocumentContentExtractorInterface;
use Common\Enum\FieldNameEnum;
use Doctrine\ORM\EntityManagerInterface;
use IndexBundle\Model\ArticleDocumentInterface;
use IndexBundle\SearchRequest\SearchRequestBuilderInterface;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use UserBundle\Enum\AppLimitEnum;
use UserBundle\Enum\ThemeOptionExtractEnum;
/**
* Class QueryController
* @package AppBundle\Controller\V1
*
* @Route("/query", service="app.controller.query")
*/
class QueryController extends AbstractV1Controller
{
use
FormFactoryAwareTrait,
TokenStorageAwareTrait;
/**
* @var EntityManagerInterface
*/
private $em;
/**
* @var SourceManagerInterface
*/
private $sourceManager;
/**
* @var SimpleQueryManagerInterface
*/
private $queryManager;
/**
* @var DocumentContentExtractorInterface
*/
private $extractor;
/**
* QueryController constructor.
*
* @param FormFactoryInterface $formFactory A
* FormFactoryInterface
* instance.
* @param EntityManagerInterface $em A
* RestrictionsRepositoryInterface
* instance.
* @param TokenStorageInterface $tokenStorage A
* TokenStorageInterface
* instance.
* @param SourceManagerInterface $sourceManager A
* SourceManagerInterface
* instance.
* @param SimpleQueryManagerInterface $queryManager A
* SimpleQueryManagerInterface
* instance.
* @param DocumentContentExtractorInterface $extractor A
* DocumentContentExtractorInterface
* instance.
*/
public function __construct(
FormFactoryInterface $formFactory,
EntityManagerInterface $em,
TokenStorageInterface $tokenStorage,
SourceManagerInterface $sourceManager,
SimpleQueryManagerInterface $queryManager,
DocumentContentExtractorInterface $extractor
) {
$this->formFactory = $formFactory;
$this->em = $em;
$this->tokenStorage = $tokenStorage;
$this->sourceManager = $sourceManager;
$this->queryManager = $queryManager;
$this->extractor = $extractor;
}
/**
* Make simple search without saving query in database.
* Fetched documents are cached but not indexed.
*
* @Roles("ROLE_SUBSCRIBER")
*
* @Route("/search", methods={ "POST" })
* @ApiDoc(
* resource="Search",
* section="Query",
* input={
* "class"="AppBundle\Form\SearchRequest\SimpleQuerySearchRequestType",
* "name"=false
* },
* output={
* "class"="",
* "data"={
* "documents"={
* "class"="Pagination<CacheBundle\Entity\Document>",
* "groups"={ "document" }
* },
* "advancedFilters"={
* "dataType"="array",
* "required"=true,
* "readonly"=true,
* "description"="Array of advanced filters values for this search request."
* },
* "stats"={
* "dataType"="object",
* "required"=true,
* "readonly"=true,
* "description"="Internal statistics, showed only in staging and local developers machine.",
* "children"={
* "totalOnPage"={
* "dataType"="integer",
* "required"=true,
* "readonly"=true,
* "description"="Total founded document on current page."
* },
* "newDocuments"={
* "dataType"="integer",
* "required"=true,
* "readonly"=true,
* "description"="Number of documents that were not in our database."
* },
* "alreadyExistsDocuments"={
* "dataType"="integer",
* "required"=true,
* "readonly"=true,
* "description"="Number of documents that already in our database."
* },
* "fromCache"={
* "dataType"="boolean",
* "required"=true,
* "readonly"=true,
* "description"="Flag, all documents fetched from our internal cache if set."
* },
* "expiresAt"={
* "dataType"="datetime",
* "required"=true,
* "readonly"=true,
* "description"="When this query is expired."
* }
* }
* }
* }
* },
* statusCodes={
* 200="Search completed.",
* 400="Invalid data provided"
* }
* )
*
* @param Request $request A Request instance.
*
* @return array|\ApiBundle\Response\ViewInterface
*/
public function searchAction(Request $request)
{
$form = $this->createForm(SimpleQuerySearchRequestType::class);
$form->submit($request->request->all());
if ($form->isValid()) {
$user = $this->getCurrentUser();
try {
$user->useLimit(AppLimitEnum::searches());
} catch (LimitExceedException $exception) {
return $this->generateResponse([
'failedRestriction' => AppLimitEnum::SEARCHES,
'restrictions' => $user->getRestrictions(),
], 402);
}
$this->em->persist($user);
$this->em->flush();
/** @var SearchRequestBuilderInterface $builder */
$builder = $form->getData();
$searchRequest = $builder
->setFields([
FieldNameEnum::TITLE,
FieldNameEnum::MAIN,
])
->addSort(FieldNameEnum::PUBLISHED, 'desc')
->build();
$response = $this->queryManager->searchAndCache(
$searchRequest,
$request->request->get('filters', []),
$request->request->get('advancedFilters', [])
);
$query = $response->getQuery();
$response->mapDocuments(function (ArticleDocumentInterface $document) use ($query) {
return $document->mapNormalizedData(function (array $data) use ($query) {
$result = $this->extractor->extract(
$data['content'],
$query->getRaw(),
ThemeOptionExtractEnum::start(),
true
);
$data['content'] = $result->getText() . (
mb_strlen($data['content']) > $result->getLength()
? '...'
: ''
);
return $data;
});
});
$result = [
'documents' => $this->paginate($response, $builder->getPage(), $builder->getLimit()),
'advancedFilters' => $searchRequest->getAvailableAdvancedFilters() ?: (object) [],
];
//
// Return internal statistic.
//
$result['stats'] = [
'newDocuments' => $response->getUniqueCount(),
'alreadyExistsDocuments' => $response->count() - $response->getUniqueCount(),
'fromCache' => $response->isFromCache(),
'expiresAt' => $query->getExpirationDate()->format('c'),
];
//
// Return meta information about query.
//
$sources = $this->sourceManager->getSourcesForQuery($query, [ 'id', 'title', 'type' ]);
$sourceLists = $this->sourceManager->getSourceListsForQuery($query, [ 'id', 'name' ]);
$result['meta'] = [
'type' => 'query',
'status' => 'synced',
'search' => [
'query' => $query->getRaw(),
'filters' => $query->getRawFilters() ?: (object) [],
'advancedFilters' => $query->getRawAdvancedFilters() ?: (object) [],
],
'sources' => $sources,
'sourceLists' => $sourceLists,
];
return $this->generateResponse($result);
}
return $this->generateResponse($form, 400);
}
}