From 0832343c668455b9eb1754983e0cf7856b29de27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Burnichon?= Date: Mon, 18 Apr 2016 19:25:59 +0200 Subject: [PATCH] WIP --- .../Controller/Api/SearchController.php | 2 +- .../Phrasea/Controller/Api/V1Controller.php | 196 +++++++++++++----- .../Phrasea/Fractal/ArraySerializer.php | 49 +++++ lib/Alchemy/Phrasea/Search/CaptionAware.php | 35 ++++ lib/Alchemy/Phrasea/Search/CaptionView.php | 32 +++ .../Phrasea/Search/RecordTransformer.php | 109 ++++++++++ lib/Alchemy/Phrasea/Search/RecordView.php | 53 +++++ .../Phrasea/Search/SearchResultView.php | 49 +++++ .../Phrasea/Search/StoryTransformer.php | 109 ++++++++++ lib/Alchemy/Phrasea/Search/StoryView.php | 63 ++++++ .../Phrasea/Search/SubdefTransformer.php | 21 ++ lib/Alchemy/Phrasea/Search/SubdefView.php | 32 +++ lib/Alchemy/Phrasea/Search/SubdefsAware.php | 52 +++++ .../Search/TechnicalDataTransformer.php | 25 +++ .../Phrasea/Search/TechnicalDataView.php | 34 +++ .../V1SearchCompositeResultTransformer.php | 49 +++++ .../V1SearchRecordsResultTransformer.php | 29 +++ .../Search/V1SearchResultTransformer.php | 31 +++ .../Phrasea/Search/V1SearchTransformer.php | 44 ++++ .../Phrasea/Search/V2SearchTransformer.php | 20 +- 20 files changed, 969 insertions(+), 65 deletions(-) create mode 100644 lib/Alchemy/Phrasea/Fractal/ArraySerializer.php create mode 100644 lib/Alchemy/Phrasea/Search/CaptionAware.php create mode 100644 lib/Alchemy/Phrasea/Search/CaptionView.php create mode 100644 lib/Alchemy/Phrasea/Search/RecordTransformer.php create mode 100644 lib/Alchemy/Phrasea/Search/RecordView.php create mode 100644 lib/Alchemy/Phrasea/Search/StoryTransformer.php create mode 100644 lib/Alchemy/Phrasea/Search/StoryView.php create mode 100644 lib/Alchemy/Phrasea/Search/SubdefTransformer.php create mode 100644 lib/Alchemy/Phrasea/Search/SubdefView.php create mode 100644 lib/Alchemy/Phrasea/Search/SubdefsAware.php create mode 100644 lib/Alchemy/Phrasea/Search/TechnicalDataTransformer.php create mode 100644 lib/Alchemy/Phrasea/Search/TechnicalDataView.php create mode 100644 lib/Alchemy/Phrasea/Search/V1SearchCompositeResultTransformer.php create mode 100644 lib/Alchemy/Phrasea/Search/V1SearchRecordsResultTransformer.php create mode 100644 lib/Alchemy/Phrasea/Search/V1SearchResultTransformer.php create mode 100644 lib/Alchemy/Phrasea/Search/V1SearchTransformer.php diff --git a/lib/Alchemy/Phrasea/Controller/Api/SearchController.php b/lib/Alchemy/Phrasea/Controller/Api/SearchController.php index e9a654cf9e..04a4f4e742 100644 --- a/lib/Alchemy/Phrasea/Controller/Api/SearchController.php +++ b/lib/Alchemy/Phrasea/Controller/Api/SearchController.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\Controller\Api; use Alchemy\Phrasea\Controller\Controller; +use Alchemy\Phrasea\Fractal\ArraySerializer; use Alchemy\Phrasea\Model\Manipulator\UserManipulator; use Alchemy\Phrasea\Search\SearchResultView; use Alchemy\Phrasea\Search\V2SearchTransformer; @@ -20,7 +21,6 @@ use Alchemy\Phrasea\SearchEngine\SearchEngineOptions; use Alchemy\Phrasea\SearchEngine\SearchEngineResult; use League\Fractal\Manager; use League\Fractal\Resource\Item; -use League\Fractal\Serializer\ArraySerializer; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; diff --git a/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php b/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php index c6d3a068a2..7ea64a89cc 100644 --- a/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php +++ b/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php @@ -32,6 +32,7 @@ use Alchemy\Phrasea\Core\Version; use Alchemy\Phrasea\Feed\Aggregate; use Alchemy\Phrasea\Feed\FeedInterface; use Alchemy\Phrasea\Form\Login\PhraseaRenewPasswordForm; +use Alchemy\Phrasea\Fractal\ArraySerializer; use Alchemy\Phrasea\Model\Entities\ApiOauthToken; use Alchemy\Phrasea\Model\Entities\Basket; use Alchemy\Phrasea\Model\Entities\BasketElement; @@ -54,15 +55,24 @@ use Alchemy\Phrasea\Model\Repositories\FeedRepository; use Alchemy\Phrasea\Model\Repositories\LazaretFileRepository; use Alchemy\Phrasea\Model\Repositories\TaskRepository; use Alchemy\Phrasea\Record\RecordReferenceCollection; +use Alchemy\Phrasea\Search\RecordTransformer; +use Alchemy\Phrasea\Search\RecordView; +use Alchemy\Phrasea\Search\SearchResultView; +use Alchemy\Phrasea\Search\StoryTransformer; +use Alchemy\Phrasea\Search\StoryView; +use Alchemy\Phrasea\Search\SubdefTransformer; +use Alchemy\Phrasea\Search\V1SearchCompositeResultTransformer; +use Alchemy\Phrasea\Search\V1SearchRecordsResultTransformer; +use Alchemy\Phrasea\Search\V1SearchResultTransformer; use Alchemy\Phrasea\SearchEngine\SearchEngineInterface; use Alchemy\Phrasea\SearchEngine\SearchEngineLogger; use Alchemy\Phrasea\SearchEngine\SearchEngineOptions; use Alchemy\Phrasea\SearchEngine\SearchEngineResult; -use Alchemy\Phrasea\SearchEngine\SearchEngineSuggestion; use Alchemy\Phrasea\Status\StatusStructure; use Alchemy\Phrasea\TaskManager\LiveInformation; use Alchemy\Phrasea\Utilities\NullableDateTime; use Doctrine\ORM\EntityManager; +use League\Fractal\Resource\Item; use Symfony\Component\Form\Form; use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\HttpFoundation\Request; @@ -1035,24 +1045,18 @@ class V1Controller extends Controller */ public function searchAction(Request $request) { - list($ret, $search_result) = $this->prepareSearchRequest($request); + $fractal = new \League\Fractal\Manager(); + $fractal->setSerializer(new ArraySerializer()); + $fractal->parseIncludes($this->resolveSearchIncludes($request)); - $records = []; - $stories = []; + $searchView = $this->buildSearchView($this->doSearch($request)); - /** @var SearchEngineResult $search_result */ - foreach ($search_result->getResults() as $record) { - if ($record->isStory()) { - $stories[] = $record; - } else { - $records[] = $record; - } - } + $recordTransformer = new RecordTransformer(); + $storyTransformer = new StoryTransformer(new SubdefTransformer(), $recordTransformer); + $compositeTransformer = new V1SearchCompositeResultTransformer($recordTransformer, $storyTransformer); + $searchTransformer = new V1SearchResultTransformer($compositeTransformer); - $ret['results'] = [ - 'records' => $this->listRecords($request, $records), - 'stories' => $this->listStories($request, $stories), - ]; + $ret = $fractal->createData(new Item($searchView, $searchTransformer))->toArray(); return Result::create($request, $ret)->createResponse(); } @@ -1068,33 +1072,141 @@ class V1Controller extends Controller */ public function searchRecordsAction(Request $request) { - list($ret, $search_result) = $this->prepareSearchRequest($request); + $fractal = new \League\Fractal\Manager(); + $fractal->setSerializer(new ArraySerializer()); + $fractal->parseIncludes($this->resolveSearchRecordsIncludes($request)); - /** @var SearchEngineResult $search_result */ - foreach ($search_result->getResults() as $es_record) { - try { - $record = new \record_adapter($this->app, $es_record->getDataboxId(), $es_record->getRecordId()); - } catch (\Exception $e) { - continue; - } + $searchView = $this->buildSearchRecordsView($this->doSearch($request)); - $ret['results'][] = $this->listRecord($request, $record); - } + $searchTransformer = new V1SearchRecordsResultTransformer(new RecordTransformer()); + + $ret = $fractal->createData(new Item($searchView, $searchTransformer))->toArray(); return Result::create($request, $ret)->createResponse(); } - private function prepareSearchRequest(Request $request) + /** + * @param SearchEngineResult $result + * @return SearchResultView + */ + private function buildSearchView(SearchEngineResult $result) + { + + $references = new RecordReferenceCollection($result->getResults()); + + $records = []; + $stories = []; + + foreach ($references->toRecords($this->getApplicationBox()) as $record) { + if ($record->isStory()) { + $stories[] = $record; + } else { + $records[] = $record; + } + } + + $resultView = new SearchResultView($result); + + if ($stories) { + $storyViews = []; + + foreach ($stories as $story) { + $storyViews[] = new StoryView($story); + } + + $resultView->setStories($storyViews); + } + + if ($records) { + $recordViews = []; + + foreach ($records as $record) { + $recordViews[] = new RecordView($record); + } + + $resultView->setRecords($recordViews); + } + + return $resultView; + } + + /** + * @param SearchEngineResult $result + * @return SearchResultView + */ + private function buildSearchRecordsView(SearchEngineResult $result) + { + $references = new RecordReferenceCollection($result->getResults()); + + $recordViews = []; + + foreach ($references->toRecords($this->getApplicationBox()) as $record) { + $recordViews[] = new RecordView($record); + } + + $resultView = new SearchResultView($result); + $resultView->setRecords($recordViews); + + return $resultView; + } + + /** + * Returns requested includes + * + * @param Request $request + * @return string[] + */ + private function resolveSearchIncludes(Request $request) + { + if (!$request->attributes->get('_extended', false)) { + return []; + } + + return [ + 'results.stories.records.subdefs', + 'results.stories.records.metadata', + 'results.stories.records.caption', + 'results.stories.records.status', + 'results.records.subdefs', + 'results.records.metadata', + 'results.records.caption', + 'results.records.status', + ]; + } + + /** + * Returns requested includes + * + * @param Request $request + * @return string[] + */ + private function resolveSearchRecordsIncludes(Request $request) + { + if (!$request->attributes->get('_extended', false)) { + return []; + } + + return [ + 'results.subdefs', + 'results.metadata', + 'results.caption', + 'results.status', + ]; + } + + /** + * @param Request $request + * @return SearchEngineResult + */ + private function doSearch(Request $request) { $options = SearchEngineOptions::fromRequest($this->app, $request); + $options->setFirstResult((int)($request->get('offset_start') ?: 0)); + $options->setMaxResults((int)$request->get('per_page') ?: 10); - $options->setFirstResult((int) ($request->get('offset_start') ?: 0)); - $options->setMaxResults((int) $request->get('per_page') ?: 10); - - $query = (string) $request->get('query'); $this->getSearchEngine()->resetCache(); - $search_result = $this->getSearchEngine()->query($query, $options); + $search_result = $this->getSearchEngine()->query((string)$request->get('query'), $options); $this->getUserManipulator()->logQuery($this->getAuthenticatedUser(), $search_result->getQuery()); @@ -1111,25 +1223,7 @@ class V1Controller extends Controller $this->getSearchEngine()->clearCache(); - $ret = [ - 'offset_start' => $options->getFirstResult(), - 'per_page' => $options->getMaxResults(), - 'available_results' => $search_result->getAvailable(), - 'total_results' => $search_result->getTotal(), - 'error' => (string)$search_result->getError(), - 'warning' => (string)$search_result->getWarning(), - 'query_time' => $search_result->getDuration(), - 'search_indexes' => $search_result->getIndexes(), - 'suggestions' => array_map( - function (SearchEngineSuggestion $suggestion) { - return $suggestion->toArray(); - }, $search_result->getSuggestions()->toArray()), - 'facets' => $search_result->getFacets(), - 'results' => [], - 'query' => $search_result->getQuery(), - ]; - - return [$ret, $search_result]; + return $search_result; } /** diff --git a/lib/Alchemy/Phrasea/Fractal/ArraySerializer.php b/lib/Alchemy/Phrasea/Fractal/ArraySerializer.php new file mode 100644 index 0000000000..5ea77600f2 --- /dev/null +++ b/lib/Alchemy/Phrasea/Fractal/ArraySerializer.php @@ -0,0 +1,49 @@ +caption = $caption; + } + + /** + * @return CaptionView + */ + public function getCaption() + { + return $this->caption; + } +} diff --git a/lib/Alchemy/Phrasea/Search/CaptionView.php b/lib/Alchemy/Phrasea/Search/CaptionView.php new file mode 100644 index 0000000000..a31c584613 --- /dev/null +++ b/lib/Alchemy/Phrasea/Search/CaptionView.php @@ -0,0 +1,32 @@ +caption = $caption; + } + + /** + * @return \caption_record + */ + public function getCaption() + { + return $this->caption; + } +} diff --git a/lib/Alchemy/Phrasea/Search/RecordTransformer.php b/lib/Alchemy/Phrasea/Search/RecordTransformer.php new file mode 100644 index 0000000000..e1948dac14 --- /dev/null +++ b/lib/Alchemy/Phrasea/Search/RecordTransformer.php @@ -0,0 +1,109 @@ +subdefTransformer = $subdefTransformer; + $this->technicalDataTransformer = $technicalDataTransformer; + } + + public function transform(RecordView $recordView) + { + $record = $recordView->getRecord(); + + return [ + 'databox_id' => $record->getDataboxId(), + 'record_id' => $record->getRecordId(), + 'mime_type' => $record->getMimeType(), + 'title' => $record->get_title(), + 'original_name' => $record->get_original_name(), + 'updated_on' => $record->getUpdated()->format(DATE_ATOM), + 'created_on' => $record->getCreated()->format(DATE_ATOM), + 'collection_id' => $record->getCollectionId(), + 'base_id' => $record->getBaseId(), + 'sha256' => $record->getSha256(), + 'phrasea_type' => $record->getType(), + 'uuid' => $record->getUuid(), + ]; + } + + public function includeThumbnail(RecordView $recordView) + { + return $this->item($recordView->getSubdef('thumbnail'), $this->subdefTransformer); + } + + public function includeTechnicalInformations(RecordView $recordView) + { + return $this->collection($recordView->getTechnicalDataView()->getDataSet(), $this->technicalDataTransformer); + } + + public function includeSubdefs(RecordView $recordView) + { + return $this->collection($recordView->getSubdefs(), $this->subdefTransformer); + } + + public function includeMetadata(RecordView $recordView) + { + $ret = []; + + foreach ($recordView->getCaption()->getCaption()->get_fields() as $field) { + $databox_field = $field->get_databox_field(); + + $fieldData = [ + 'meta_structure_id' => $field->get_meta_struct_id(), + 'name' => $field->get_name(), + 'labels' => [ + 'fr' => $databox_field->get_label('fr'), + 'en' => $databox_field->get_label('en'), + 'de' => $databox_field->get_label('de'), + 'nl' => $databox_field->get_label('nl'), + ], + ]; + + foreach ($field->get_values() as $value) { + $data = [ + 'meta_id' => $value->getId(), + 'value' => $value->getValue(), + ]; + + $ret[] = array_replace($fieldData, $data); + } + } + + return $this->collection($recordView->getCaption(), ) + } + + public function includeStatus(RecordView $recordView) + { + } + + public function includeCaption(RecordView $recordView) + { + } +} diff --git a/lib/Alchemy/Phrasea/Search/RecordView.php b/lib/Alchemy/Phrasea/Search/RecordView.php new file mode 100644 index 0000000000..aa97a210bd --- /dev/null +++ b/lib/Alchemy/Phrasea/Search/RecordView.php @@ -0,0 +1,53 @@ +record = $record; + } + + /** + * @return \record_adapter + */ + public function getRecord() + { + return $this->record; + } + + public function setTechnicalDataView(TechnicalDataView $technicalDataView) + { + $this->technicalDataView = $technicalDataView; + } + + /** + * @return TechnicalDataView + */ + public function getTechnicalDataView() + { + return $this->technicalDataView; + } +} diff --git a/lib/Alchemy/Phrasea/Search/SearchResultView.php b/lib/Alchemy/Phrasea/Search/SearchResultView.php index 47c35e0ab3..e4a80edc24 100644 --- a/lib/Alchemy/Phrasea/Search/SearchResultView.php +++ b/lib/Alchemy/Phrasea/Search/SearchResultView.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\Search; use Alchemy\Phrasea\SearchEngine\SearchEngineResult; +use Assert\Assertion; class SearchResultView { @@ -19,6 +20,16 @@ class SearchResultView */ private $result; + /** + * @var StoryView[] + */ + private $stories = []; + + /** + * @var RecordView[] + */ + private $records = []; + public function __construct(SearchEngineResult $result) { $this->result = $result; @@ -31,4 +42,42 @@ class SearchResultView { return $this->result; } + + /** + * @param StoryView[] $stories + * @return void + */ + public function setStories($stories) + { + Assertion::allIsInstanceOf($this->stories, StoryView::class); + + $this->stories = $stories instanceof \Traversable ? iterator_to_array($stories, false) : array_values($stories); + } + + /** + * @return StoryView[] + */ + public function getStories() + { + return $this->stories; + } + + /** + * @param RecordView[] $records + * @return void + */ + public function setRecords($records) + { + Assertion::allIsInstanceOf($records, RecordView::class); + + $this->records = $records instanceof \Traversable ? iterator_to_array($records, false) : array_values($records); + } + + /** + * @return RecordView[] + */ + public function getRecords() + { + return $this->records; + } } diff --git a/lib/Alchemy/Phrasea/Search/StoryTransformer.php b/lib/Alchemy/Phrasea/Search/StoryTransformer.php new file mode 100644 index 0000000000..df73f5580d --- /dev/null +++ b/lib/Alchemy/Phrasea/Search/StoryTransformer.php @@ -0,0 +1,109 @@ +subdefTransformer = $subdefTransformer; + $this->recordTransformer = $recordTransformer; + } + + public function transform(StoryView $storyView) + { + $story = $storyView->getStory(); + + return [ + '@entity@' => 'http://api.phraseanet.com/api/objects/story', + 'databox_id' => $story->getDataboxId(), + 'story_id' => $story->getRecordId(), + 'updated_on' => NullableDateTime::format($story->getUpdated()), + 'created_on' => NullableDateTime::format($story->getUpdated()), + 'collection_id' => $story->getCollectionId(), + 'base_id' => $story->getBaseId(), + 'uuid' => $story->getUuid(), + ]; + } + + public function includeThumbnail(StoryView $storyView) + { + return $this->item($storyView->getSubdef('thumbnail'), $this->subdefTransformer); + } + + public function includeMetadatas(StoryView $storyView) + { + return $this->item($storyView->getCaption(), $this->getCaptionTransformer()); + } + + public function includeRecords(StoryView $storyView) + { + return $this->collection($storyView->getChildren(), $this->recordTransformer); + } + + /** + * @return \Closure + */ + private function getCaptionTransformer() + { + /** + * @param \caption_field[] $fields + * @param string $dcField + * @return string|null + */ + $format = function ($fields, $dcField) { + return isset($fields[$dcField]) ? $fields[$dcField]->get_serialized_values() : null; + }; + + return function (CaptionView $captionView) use ($format) { + $caption = $captionView->getCaption()->getDCFields(); + + return [ + '@entity@' => 'http://api.phraseanet.com/api/objects/story-metadata-bag', + 'dc:contributor' => $format($caption, \databox_Field_DCESAbstract::Contributor), + 'dc:coverage' => $format($caption, \databox_Field_DCESAbstract::Coverage), + 'dc:creator' => $format($caption, \databox_Field_DCESAbstract::Creator), + 'dc:date' => $format($caption, \databox_Field_DCESAbstract::Date), + 'dc:description' => $format($caption, \databox_Field_DCESAbstract::Description), + 'dc:format' => $format($caption, \databox_Field_DCESAbstract::Format), + 'dc:identifier' => $format($caption, \databox_Field_DCESAbstract::Identifier), + 'dc:language' => $format($caption, \databox_Field_DCESAbstract::Language), + 'dc:publisher' => $format($caption, \databox_Field_DCESAbstract::Publisher), + 'dc:relation' => $format($caption, \databox_Field_DCESAbstract::Relation), + 'dc:rights' => $format($caption, \databox_Field_DCESAbstract::Rights), + 'dc:source' => $format($caption, \databox_Field_DCESAbstract::Source), + 'dc:subject' => $format($caption, \databox_Field_DCESAbstract::Subject), + 'dc:title' => $format($caption, \databox_Field_DCESAbstract::Title), + 'dc:type' => $format($caption, \databox_Field_DCESAbstract::Type), + ]; + }; + } +} diff --git a/lib/Alchemy/Phrasea/Search/StoryView.php b/lib/Alchemy/Phrasea/Search/StoryView.php new file mode 100644 index 0000000000..30aebafce3 --- /dev/null +++ b/lib/Alchemy/Phrasea/Search/StoryView.php @@ -0,0 +1,63 @@ +story = $story; + } + + /** + * @return \record_adapter + */ + public function getStory() + { + return $this->story; + } + + /** + * @param RecordView[] $children + */ + public function setChildren($children) + { + Assertion::allIsInstanceOf($children, RecordView::class); + + $this->children = $children instanceof \Traversable ? iterator_to_array($children, false) : array_values($children); + } + + /** + * @return RecordView[] + */ + public function getChildren() + { + return $this->children; + } +} diff --git a/lib/Alchemy/Phrasea/Search/SubdefTransformer.php b/lib/Alchemy/Phrasea/Search/SubdefTransformer.php new file mode 100644 index 0000000000..24cdee94d9 --- /dev/null +++ b/lib/Alchemy/Phrasea/Search/SubdefTransformer.php @@ -0,0 +1,21 @@ +subdef = $subdef; + } + + /** + * @return \media_subdef + */ + public function getSubdef() + { + return $this->subdef; + } +} diff --git a/lib/Alchemy/Phrasea/Search/SubdefsAware.php b/lib/Alchemy/Phrasea/Search/SubdefsAware.php new file mode 100644 index 0000000000..9edf617552 --- /dev/null +++ b/lib/Alchemy/Phrasea/Search/SubdefsAware.php @@ -0,0 +1,52 @@ +subdefs = []; + + foreach ($subdefs as $subdef) { + $this->subdefs[$subdef->getSubdef()->get_name()] = $subdef; + } + } + + /** + * @param string $name + * @return SubdefView + */ + public function getSubdef($name) + { + return $this->subdefs[$name]; + } + + /** + * @return SubdefView + */ + public function getSubdefs() + { + return $this->subdefs; + } +} diff --git a/lib/Alchemy/Phrasea/Search/TechnicalDataTransformer.php b/lib/Alchemy/Phrasea/Search/TechnicalDataTransformer.php new file mode 100644 index 0000000000..6b67aba3b5 --- /dev/null +++ b/lib/Alchemy/Phrasea/Search/TechnicalDataTransformer.php @@ -0,0 +1,25 @@ + $technicalData->getName(), + 'value' => $technicalData->getValue(), + ]; + } +} diff --git a/lib/Alchemy/Phrasea/Search/TechnicalDataView.php b/lib/Alchemy/Phrasea/Search/TechnicalDataView.php new file mode 100644 index 0000000000..16b00cf259 --- /dev/null +++ b/lib/Alchemy/Phrasea/Search/TechnicalDataView.php @@ -0,0 +1,34 @@ +dataSet = $dataSet; + } + + /** + * @return TechnicalDataSet + */ + public function getDataSet() + { + return $this->dataSet; + } +} diff --git a/lib/Alchemy/Phrasea/Search/V1SearchCompositeResultTransformer.php b/lib/Alchemy/Phrasea/Search/V1SearchCompositeResultTransformer.php new file mode 100644 index 0000000000..f8b46894df --- /dev/null +++ b/lib/Alchemy/Phrasea/Search/V1SearchCompositeResultTransformer.php @@ -0,0 +1,49 @@ +recordTransformer = $recordTransformer; + $this->storyTransformer = $storyTransformer; + } + + public function transform() + { + return []; + } + + public function includeRecords(SearchResultView $resultView) + { + return $this->collection($resultView->getRecords(), $this->recordTransformer); + } + + public function includeStories(SearchResultView $resultView) + { + return $this->collection($resultView->getStories(), $this->storyTransformer); + } +} diff --git a/lib/Alchemy/Phrasea/Search/V1SearchRecordsResultTransformer.php b/lib/Alchemy/Phrasea/Search/V1SearchRecordsResultTransformer.php new file mode 100644 index 0000000000..b731ac2495 --- /dev/null +++ b/lib/Alchemy/Phrasea/Search/V1SearchRecordsResultTransformer.php @@ -0,0 +1,29 @@ +recordTransformer = $recordTransformer; + } + + public function includeResults(SearchResultView $resultView) + { + return $this->collection($resultView->getRecords(), $this->recordTransformer); + } +} diff --git a/lib/Alchemy/Phrasea/Search/V1SearchResultTransformer.php b/lib/Alchemy/Phrasea/Search/V1SearchResultTransformer.php new file mode 100644 index 0000000000..1e391eb288 --- /dev/null +++ b/lib/Alchemy/Phrasea/Search/V1SearchResultTransformer.php @@ -0,0 +1,31 @@ +transformer = $transformer; + } + + public function includeResults(SearchResultView $resultView) + { + return $this->item($resultView, $this->transformer); + } +} diff --git a/lib/Alchemy/Phrasea/Search/V1SearchTransformer.php b/lib/Alchemy/Phrasea/Search/V1SearchTransformer.php new file mode 100644 index 0000000000..af60018284 --- /dev/null +++ b/lib/Alchemy/Phrasea/Search/V1SearchTransformer.php @@ -0,0 +1,44 @@ +getResult(); + + return [ + 'offset_start' => $result->getOptions()->getFirstResult(), + 'per_page' => $result->getOptions()->getMaxResults(), + 'available_results' => $result->getAvailable(), + 'total_results' => $result->getTotal(), + 'error' => (string)$result->getError(), + 'warning' => (string)$result->getWarning(), + 'query_time' => $result->getDuration(), + 'search_indexes' => $result->getIndexes(), + 'suggestions' => array_map( + function (SearchEngineSuggestion $suggestion) { + return $suggestion->toArray(); + }, $result->getSuggestions()->toArray()), + 'facets' => $result->getFacets(), + 'query' => $result->getQuery(), + ]; + } + + abstract public function includeResults(SearchResultView $resultView); +} diff --git a/lib/Alchemy/Phrasea/Search/V2SearchTransformer.php b/lib/Alchemy/Phrasea/Search/V2SearchTransformer.php index 1600302536..26c518f2ea 100644 --- a/lib/Alchemy/Phrasea/Search/V2SearchTransformer.php +++ b/lib/Alchemy/Phrasea/Search/V2SearchTransformer.php @@ -15,6 +15,9 @@ use League\Fractal\TransformerAbstract; class V2SearchTransformer extends TransformerAbstract { + protected $availableIncludes = ['results']; + protected $defaultIncludes = ['results']; + public function transform(SearchResultView $searchView) { return [ @@ -28,27 +31,18 @@ class V2SearchTransformer extends TransformerAbstract 'search_indexes' => $searchView->getResult()->getIndexes(), 'facets' => $searchView->getResult()->getFacets(), 'search_type' => $searchView->getResult()->getOptions()->getSearchType(), - 'results' => $this->listResults($searchView->getResult()->getResults()), ]; } - /** - * @param RecordInterface[] $results - * @return array - */ - public function listResults($results) + public function includeResults(SearchResultView $searchView) { - $data = []; - - foreach ($results as $record) { - $data[] = [ + return $this->collection($searchView->getResult()->getResults(), function (RecordInterface $record) { + return [ 'databox_id' => $record->getDataboxId(), 'record_id' => $record->getRecordId(), 'collection_id' => $record->getCollectionId(), 'version' => $record->getUpdated()->getTimestamp(), ]; - } - - return $data; + }); } }