This commit is contained in:
Benoît Burnichon
2016-04-18 19:25:59 +02:00
parent e2e1fb0e09
commit 24143759a7
20 changed files with 969 additions and 65 deletions

View File

@@ -11,6 +11,7 @@
namespace Alchemy\Phrasea\Controller\Api; namespace Alchemy\Phrasea\Controller\Api;
use Alchemy\Phrasea\Controller\Controller; use Alchemy\Phrasea\Controller\Controller;
use Alchemy\Phrasea\Fractal\ArraySerializer;
use Alchemy\Phrasea\Model\Manipulator\UserManipulator; use Alchemy\Phrasea\Model\Manipulator\UserManipulator;
use Alchemy\Phrasea\Search\SearchResultView; use Alchemy\Phrasea\Search\SearchResultView;
use Alchemy\Phrasea\Search\V2SearchTransformer; use Alchemy\Phrasea\Search\V2SearchTransformer;
@@ -20,7 +21,6 @@ use Alchemy\Phrasea\SearchEngine\SearchEngineOptions;
use Alchemy\Phrasea\SearchEngine\SearchEngineResult; use Alchemy\Phrasea\SearchEngine\SearchEngineResult;
use League\Fractal\Manager; use League\Fractal\Manager;
use League\Fractal\Resource\Item; use League\Fractal\Resource\Item;
use League\Fractal\Serializer\ArraySerializer;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;

View File

@@ -32,6 +32,7 @@ use Alchemy\Phrasea\Core\Version;
use Alchemy\Phrasea\Feed\Aggregate; use Alchemy\Phrasea\Feed\Aggregate;
use Alchemy\Phrasea\Feed\FeedInterface; use Alchemy\Phrasea\Feed\FeedInterface;
use Alchemy\Phrasea\Form\Login\PhraseaRenewPasswordForm; use Alchemy\Phrasea\Form\Login\PhraseaRenewPasswordForm;
use Alchemy\Phrasea\Fractal\ArraySerializer;
use Alchemy\Phrasea\Model\Entities\ApiOauthToken; use Alchemy\Phrasea\Model\Entities\ApiOauthToken;
use Alchemy\Phrasea\Model\Entities\Basket; use Alchemy\Phrasea\Model\Entities\Basket;
use Alchemy\Phrasea\Model\Entities\BasketElement; 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\LazaretFileRepository;
use Alchemy\Phrasea\Model\Repositories\TaskRepository; use Alchemy\Phrasea\Model\Repositories\TaskRepository;
use Alchemy\Phrasea\Record\RecordReferenceCollection; 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\SearchEngineInterface;
use Alchemy\Phrasea\SearchEngine\SearchEngineLogger; use Alchemy\Phrasea\SearchEngine\SearchEngineLogger;
use Alchemy\Phrasea\SearchEngine\SearchEngineOptions; use Alchemy\Phrasea\SearchEngine\SearchEngineOptions;
use Alchemy\Phrasea\SearchEngine\SearchEngineResult; use Alchemy\Phrasea\SearchEngine\SearchEngineResult;
use Alchemy\Phrasea\SearchEngine\SearchEngineSuggestion;
use Alchemy\Phrasea\Status\StatusStructure; use Alchemy\Phrasea\Status\StatusStructure;
use Alchemy\Phrasea\TaskManager\LiveInformation; use Alchemy\Phrasea\TaskManager\LiveInformation;
use Alchemy\Phrasea\Utilities\NullableDateTime; use Alchemy\Phrasea\Utilities\NullableDateTime;
use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManager;
use League\Fractal\Resource\Item;
use Symfony\Component\Form\Form; use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
@@ -1035,24 +1045,18 @@ class V1Controller extends Controller
*/ */
public function searchAction(Request $request) 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 = []; $searchView = $this->buildSearchView($this->doSearch($request));
$stories = [];
/** @var SearchEngineResult $search_result */ $recordTransformer = new RecordTransformer();
foreach ($search_result->getResults() as $record) { $storyTransformer = new StoryTransformer(new SubdefTransformer(), $recordTransformer);
if ($record->isStory()) { $compositeTransformer = new V1SearchCompositeResultTransformer($recordTransformer, $storyTransformer);
$stories[] = $record; $searchTransformer = new V1SearchResultTransformer($compositeTransformer);
} else {
$records[] = $record;
}
}
$ret['results'] = [ $ret = $fractal->createData(new Item($searchView, $searchTransformer))->toArray();
'records' => $this->listRecords($request, $records),
'stories' => $this->listStories($request, $stories),
];
return Result::create($request, $ret)->createResponse(); return Result::create($request, $ret)->createResponse();
} }
@@ -1068,33 +1072,141 @@ class V1Controller extends Controller
*/ */
public function searchRecordsAction(Request $request) 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 */ $searchView = $this->buildSearchRecordsView($this->doSearch($request));
foreach ($search_result->getResults() as $es_record) {
try {
$record = new \record_adapter($this->app, $es_record->getDataboxId(), $es_record->getRecordId());
} catch (\Exception $e) {
continue;
}
$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(); 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 = SearchEngineOptions::fromRequest($this->app, $request);
$options->setFirstResult((int)($request->get('offset_start') ?: 0)); $options->setFirstResult((int)($request->get('offset_start') ?: 0));
$options->setMaxResults((int)$request->get('per_page') ?: 10); $options->setMaxResults((int)$request->get('per_page') ?: 10);
$query = (string) $request->get('query');
$this->getSearchEngine()->resetCache(); $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()); $this->getUserManipulator()->logQuery($this->getAuthenticatedUser(), $search_result->getQuery());
@@ -1111,25 +1223,7 @@ class V1Controller extends Controller
$this->getSearchEngine()->clearCache(); $this->getSearchEngine()->clearCache();
$ret = [ return $search_result;
'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];
} }
/** /**

View File

@@ -0,0 +1,49 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Fractal;
use League\Fractal\Pagination\CursorInterface;
use League\Fractal\Pagination\PaginatorInterface;
use League\Fractal\Resource\ResourceInterface;
use League\Fractal\Serializer\SerializerAbstract;
class ArraySerializer extends SerializerAbstract
{
public function collection($resourceKey, array $data)
{
return $data;
}
public function item($resourceKey, array $data)
{
return $data;
}
public function includedData(ResourceInterface $resource, array $data)
{
return $data;
}
public function meta(array $meta)
{
return [];
}
public function paginator(PaginatorInterface $paginator)
{
return [];
}
public function cursor(CursorInterface $cursor)
{
return [];
}
}

View File

@@ -0,0 +1,35 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Search;
trait CaptionAware
{
/**
* @var CaptionView
*/
private $caption;
/**
* @param CaptionView $caption
*/
public function setCaption(CaptionView $caption)
{
$this->caption = $caption;
}
/**
* @return CaptionView
*/
public function getCaption()
{
return $this->caption;
}
}

View File

@@ -0,0 +1,32 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Search;
class CaptionView
{
/**
* @var \caption_record
*/
private $caption;
public function __construct(\caption_record $caption)
{
$this->caption = $caption;
}
/**
* @return \caption_record
*/
public function getCaption()
{
return $this->caption;
}
}

View File

@@ -0,0 +1,109 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Search;
use League\Fractal\TransformerAbstract;
class RecordTransformer extends TransformerAbstract
{
protected $availableIncludes = ['thumbnail', 'technical_informations', 'subdefs', 'metadata', 'status', 'caption'];
protected $defaultIncludes = ['thumbnail', 'technical_informations'];
/**
* @var SubdefTransformer
*/
private $subdefTransformer;
/**
* @var TechnicalDataTransformer
*/
private $technicalDataTransformer;
public function __construct(SubdefTransformer $subdefTransformer, TechnicalDataTransformer $technicalDataTransformer)
{
$this->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)
{
}
}

View File

@@ -0,0 +1,53 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Search;
class RecordView
{
use SubdefsAware;
use CaptionAware;
/**
* @var \record_adapter
*/
private $record;
/**
* @var TechnicalDataView
*/
private $technicalDataView;
public function __construct(\record_adapter $record)
{
$this->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;
}
}

View File

@@ -11,6 +11,7 @@
namespace Alchemy\Phrasea\Search; namespace Alchemy\Phrasea\Search;
use Alchemy\Phrasea\SearchEngine\SearchEngineResult; use Alchemy\Phrasea\SearchEngine\SearchEngineResult;
use Assert\Assertion;
class SearchResultView class SearchResultView
{ {
@@ -19,6 +20,16 @@ class SearchResultView
*/ */
private $result; private $result;
/**
* @var StoryView[]
*/
private $stories = [];
/**
* @var RecordView[]
*/
private $records = [];
public function __construct(SearchEngineResult $result) public function __construct(SearchEngineResult $result)
{ {
$this->result = $result; $this->result = $result;
@@ -31,4 +42,42 @@ class SearchResultView
{ {
return $this->result; 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;
}
} }

View File

@@ -0,0 +1,109 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Search;
use Alchemy\Phrasea\Utilities\NullableDateTime;
use League\Fractal\TransformerAbstract;
class StoryTransformer extends TransformerAbstract
{
protected $availableIncludes = ['thumbnail', 'metadatas', 'records'];
protected $defaultIncludes = ['thumbnail', 'metadatas', 'records'];
/**
* @var SubdefTransformer
*/
private $subdefTransformer;
/**
* @var RecordTransformer
*/
private $recordTransformer;
/**
* @param SubdefTransformer $subdefTransformer
* @param RecordTransformer $recordTransformer
*/
public function __construct(SubdefTransformer $subdefTransformer, RecordTransformer $recordTransformer)
{
$this->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),
];
};
}
}

View File

@@ -0,0 +1,63 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Search;
use Assert\Assertion;
class StoryView
{
use SubdefsAware;
use CaptionAware;
/**
* @var \record_adapter
*/
private $story;
/**
* @var RecordView[]
*/
private $children = [];
/**
* @param \record_adapter $story
*/
public function __construct(\record_adapter $story)
{
$this->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;
}
}

View File

@@ -0,0 +1,21 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Search;
use League\Fractal\TransformerAbstract;
class SubdefTransformer extends TransformerAbstract
{
public function transform(SubdefView $subdefView)
{
return [];
}
}

View File

@@ -0,0 +1,32 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Search;
class SubdefView
{
/**
* @var \media_subdef
*/
private $subdef;
public function __construct(\media_subdef $subdef)
{
$this->subdef = $subdef;
}
/**
* @return \media_subdef
*/
public function getSubdef()
{
return $this->subdef;
}
}

View File

@@ -0,0 +1,52 @@
<?php
/**
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Search;
use Assert\Assertion;
trait SubdefsAware
{
/**
* @var SubdefView[]
*/
private $subdefs;
/**
* @param SubdefView[] $subdefs
*/
public function setSubdefs($subdefs)
{
Assertion::allIsInstanceOf($subdefs, SubdefView::class);
$this->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;
}
}

View File

@@ -0,0 +1,25 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Search;
use Alchemy\Phrasea\Media\TechnicalData;
use League\Fractal\TransformerAbstract;
class TechnicalDataTransformer extends TransformerAbstract
{
public function transform(TechnicalData $technicalData)
{
return [
'name' => $technicalData->getName(),
'value' => $technicalData->getValue(),
];
}
}

View File

@@ -0,0 +1,34 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Search;
use Alchemy\Phrasea\Media\TechnicalDataSet;
class TechnicalDataView
{
/**
* @var TechnicalDataSet
*/
private $dataSet;
public function __construct(TechnicalDataSet $dataSet)
{
$this->dataSet = $dataSet;
}
/**
* @return TechnicalDataSet
*/
public function getDataSet()
{
return $this->dataSet;
}
}

View File

@@ -0,0 +1,49 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Search;
use League\Fractal\TransformerAbstract;
class V1SearchCompositeResultTransformer extends TransformerAbstract
{
protected $availableIncludes = ['stories', 'records'];
protected $defaultIncludes = ['stories', 'records'];
/**
* @var RecordTransformer
*/
private $recordTransformer;
/**
* @var StoryTransformer
*/
private $storyTransformer;
public function __construct(RecordTransformer $recordTransformer, StoryTransformer $storyTransformer)
{
$this->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);
}
}

View File

@@ -0,0 +1,29 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Search;
class V1SearchRecordsResultTransformer extends V1SearchTransformer
{
/**
* @var RecordTransformer
*/
private $recordTransformer;
public function __construct(RecordTransformer $recordTransformer)
{
$this->recordTransformer = $recordTransformer;
}
public function includeResults(SearchResultView $resultView)
{
return $this->collection($resultView->getRecords(), $this->recordTransformer);
}
}

View File

@@ -0,0 +1,31 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Search;
use League\Fractal\TransformerAbstract;
class V1SearchResultTransformer extends V1SearchTransformer
{
/**
* @var TransformerAbstract
*/
private $transformer;
public function __construct(TransformerAbstract $transformer)
{
$this->transformer = $transformer;
}
public function includeResults(SearchResultView $resultView)
{
return $this->item($resultView, $this->transformer);
}
}

View File

@@ -0,0 +1,44 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Search;
use Alchemy\Phrasea\SearchEngine\SearchEngineSuggestion;
use League\Fractal\TransformerAbstract;
abstract class V1SearchTransformer extends TransformerAbstract
{
protected $availableIncludes = ['results'];
protected $defaultIncludes = ['results'];
public function transform(SearchResultView $resultView)
{
$result = $resultView->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);
}

View File

@@ -15,6 +15,9 @@ use League\Fractal\TransformerAbstract;
class V2SearchTransformer extends TransformerAbstract class V2SearchTransformer extends TransformerAbstract
{ {
protected $availableIncludes = ['results'];
protected $defaultIncludes = ['results'];
public function transform(SearchResultView $searchView) public function transform(SearchResultView $searchView)
{ {
return [ return [
@@ -28,27 +31,18 @@ class V2SearchTransformer extends TransformerAbstract
'search_indexes' => $searchView->getResult()->getIndexes(), 'search_indexes' => $searchView->getResult()->getIndexes(),
'facets' => $searchView->getResult()->getFacets(), 'facets' => $searchView->getResult()->getFacets(),
'search_type' => $searchView->getResult()->getOptions()->getSearchType(), 'search_type' => $searchView->getResult()->getOptions()->getSearchType(),
'results' => $this->listResults($searchView->getResult()->getResults()),
]; ];
} }
/** public function includeResults(SearchResultView $searchView)
* @param RecordInterface[] $results
* @return array
*/
public function listResults($results)
{ {
$data = []; return $this->collection($searchView->getResult()->getResults(), function (RecordInterface $record) {
return [
foreach ($results as $record) {
$data[] = [
'databox_id' => $record->getDataboxId(), 'databox_id' => $record->getDataboxId(),
'record_id' => $record->getRecordId(), 'record_id' => $record->getRecordId(),
'collection_id' => $record->getCollectionId(), 'collection_id' => $record->getCollectionId(),
'version' => $record->getUpdated()->getTimestamp(), 'version' => $record->getUpdated()->getTimestamp(),
]; ];
} });
return $data;
} }
} }