mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-10 11:33:17 +00:00

* expose cli fix parent publication * translate and yarn.lock file * some css fix * expose search publication title filter * display nb items * trigger only from more than 3 character * do not display publication in to his parent list * trigger search publication on empty search
434 lines
14 KiB
PHP
434 lines
14 KiB
PHP
<?php
|
|
|
|
namespace Alchemy\Phrasea\Twig;
|
|
|
|
use Alchemy\Phrasea\Application;
|
|
use Alchemy\Phrasea\Collection\CollectionHelper;
|
|
use Alchemy\Phrasea\Http\StaticFile\StaticMode;
|
|
use Alchemy\Phrasea\Model\Entities\ElasticsearchRecord;
|
|
use Alchemy\Phrasea\Model\Entities\User;
|
|
use Alchemy\Phrasea\Model\RecordInterface;
|
|
use Alchemy\Phrasea\Model\Repositories\UserRepository;
|
|
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Flag;
|
|
|
|
class PhraseanetExtension extends \Twig_Extension
|
|
{
|
|
/** @var Application */
|
|
private $app;
|
|
|
|
public function __construct(Application $app)
|
|
{
|
|
$this->app = $app;
|
|
}
|
|
|
|
public function getFilters()
|
|
{
|
|
return array(
|
|
new \Twig_SimpleFilter('sort_collections', array(CollectionHelper::class, 'sort')),
|
|
new \Twig_SimpleFilter('date_duration', array($this, 'getDuration')),
|
|
new \Twig_SimpleFilter('json_to_array', array($this, 'jsonToArray')),
|
|
);
|
|
}
|
|
|
|
public function getFunctions()
|
|
{
|
|
return array(
|
|
new \Twig_SimpleFunction('user_setting', array($this, 'getUserSetting')),
|
|
new \Twig_SimpleFunction('record_thumbnail_url', array($this, 'getThumbnailUrl')),
|
|
new \Twig_SimpleFunction('record_subdef_url', array($this, 'getSubdefUrl')),
|
|
new \Twig_SimpleFunction('record_subdef_size', array($this, 'getSubdefSize')),
|
|
new \Twig_SimpleFunction('record_doctype_icon', array($this, 'getDoctypeIcon'), array(
|
|
'is_safe' => array('html')
|
|
)),
|
|
new \Twig_SimpleFunction('has_access_subdef', array($this, 'hasAccessSubDefinition')),
|
|
new \Twig_SimpleFunction('record_thumbnailgif_url', array($this, 'getThumbnailGifUrl')),
|
|
new \Twig_SimpleFunction('granted_on_collection', array($this, 'isGrantedOnCollection')),
|
|
new \Twig_SimpleFunction('granted_on_databox', array($this, 'isGrantedOnDatabox')),
|
|
new \Twig_SimpleFunction('collection_logo', array($this, 'getCollectionLogo'), array(
|
|
'is_safe' => array('html')
|
|
)),
|
|
new \Twig_SimpleFunction('record_flags', array($this, 'getRecordFlags')),
|
|
new \Twig_SimpleFunction('border_checker_from_fqcn', array($this, 'getCheckerFromFQCN')),
|
|
new \Twig_SimpleFunction('caption_field', array($this, 'getCaptionField')),
|
|
new \Twig_SimpleFunction('caption_field_label', array($this, 'getCaptionFieldLabel')),
|
|
new \Twig_SimpleFunction('caption_field_gui_visible', array($this, 'getCaptionFieldGuiVisible')),
|
|
new \Twig_SimpleFunction('caption_field_order', array($this, 'getCaptionFieldOrder')),
|
|
|
|
new \Twig_SimpleFunction('flag_slugify', array(Flag::class, 'normalizeName')),
|
|
new \Twig_SimpleFunction('user_display_name', array($this, 'getUserDisplayName')),
|
|
);
|
|
}
|
|
|
|
public function getGlobals()
|
|
{
|
|
return [
|
|
// change this version when you change JS file to force the navigation to reload js file
|
|
'assetFileVersion' => 106
|
|
];
|
|
|
|
}
|
|
|
|
public function getDuration(int $interval)
|
|
{
|
|
$t = round($interval);
|
|
return sprintf('%02d h %02d m %02d s', ($t/3600),($t/60 %60), $t%60);
|
|
}
|
|
|
|
/**
|
|
* get localized field's label
|
|
* @param RecordInterface $record
|
|
* @param $fieldName
|
|
* @return string - the name label
|
|
*/
|
|
public function getCaptionFieldLabel(RecordInterface $record, $fieldName)
|
|
{
|
|
if ($record) {
|
|
/** @var \appbox $appbox */
|
|
$appbox = $this->app['phraseanet.appbox'];
|
|
$databox = $appbox->get_databox($record->getDataboxId());
|
|
foreach ($databox->get_meta_structure() as $meta) {
|
|
/** @var \databox_field $meta */
|
|
if ($meta->get_name() === $fieldName) {
|
|
return $meta->get_label($this->app['locale']);
|
|
}
|
|
}
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* get localized field's gui_visible
|
|
* @param RecordInterface $record
|
|
* @param $fieldName
|
|
* @return string - the name gui_visible
|
|
*/
|
|
public function getCaptionFieldGuiVisible(RecordInterface $record, $fieldName)
|
|
{
|
|
if ($record) {
|
|
/** @var \appbox $appbox */
|
|
$appbox = $this->app['phraseanet.appbox'];
|
|
$databox = $appbox->get_databox($record->getDataboxId());
|
|
foreach ($databox->get_meta_structure() as $meta) {
|
|
/** @var \databox_field $meta */
|
|
if ($meta->get_name() === $fieldName) {
|
|
return $meta->get_gui_visible($this->app['locale']);
|
|
}
|
|
}
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
public function getCaptionField(RecordInterface $record, $field, $value)
|
|
{
|
|
if ($record instanceof ElasticsearchRecord) {
|
|
$highlights = $record->getHighlight();
|
|
if (false === isset($highlights[$field])) {
|
|
return implode('; ', (array) $value);
|
|
}
|
|
|
|
$highlightValue = $highlights[$field];
|
|
|
|
// if field is multivalued, merge highlighted values with captions ones
|
|
if (is_array($value) && count($value) > 1) {
|
|
$highlightValue = array_merge($highlightValue, array_diff($value, array_map(function($value) {
|
|
return str_replace(array('[[em]]', '[[/em]]'), array('', ''), $value);
|
|
}, $highlightValue)));
|
|
}
|
|
|
|
return implode('; ', (array) $highlightValue);
|
|
}
|
|
|
|
return implode('; ', (array) $value);
|
|
}
|
|
|
|
/**
|
|
* @param RecordInterface $record
|
|
* @param bool $businessFields
|
|
* @return array
|
|
*/
|
|
public function getCaptionFieldOrder(RecordInterface $record, $businessFields)
|
|
{
|
|
static $orders = [];
|
|
|
|
$databoxId = $record->getDataboxId();
|
|
$orderKey = (bool) $businessFields ? 'business' : 'public';
|
|
|
|
if (!isset($orders[$databoxId][$orderKey])) {
|
|
/** @var \appbox $appbox */
|
|
$appbox = $this->app['phraseanet.appbox'];
|
|
$databox = $appbox->get_databox($databoxId);
|
|
|
|
$orders[$databoxId] = $this->retrieveDataboxFieldOrderings($databox);
|
|
}
|
|
|
|
return $orders[$databoxId][$orderKey];
|
|
}
|
|
|
|
/**
|
|
* @param \databox $databox
|
|
* @return array
|
|
*/
|
|
private function retrieveDataboxFieldOrderings(\databox $databox)
|
|
{
|
|
$publicOrder = [];
|
|
$businessOrder = [];
|
|
|
|
foreach ($databox->get_meta_structure() as $field) {
|
|
$fieldName = $field->get_name();
|
|
|
|
if (!$field->isBusiness()) {
|
|
$publicOrder[] = $fieldName;
|
|
}
|
|
|
|
$businessOrder[] = $fieldName;
|
|
};
|
|
|
|
return [
|
|
'public' => $publicOrder,
|
|
'business' => $businessOrder,
|
|
];
|
|
}
|
|
|
|
public function getRecordFlags(RecordInterface $record)
|
|
{
|
|
$recordStatuses = [];
|
|
/** @var \appbox $appbox */
|
|
$appbox = $this->app['phraseanet.appbox'];
|
|
$databox = $appbox->get_databox($record->getDataboxId());
|
|
|
|
$structure = $databox->getStatusStructure()->toArray();
|
|
|
|
if (!$this->isGrantedOnCollection($record->getBaseId(), [\ACL::CHGSTATUS])) {
|
|
$structure = array_filter($structure, function($status) {
|
|
return (bool) $status['printable'];
|
|
});
|
|
}
|
|
|
|
$bitValue = $record->getStatusBitField();
|
|
|
|
foreach ($structure as $status) {
|
|
$on = \databox_status::bitIsSet($bitValue, $status['bit']);
|
|
|
|
if (null === ($on ? $status['img_on'] : $status['img_off'])) {
|
|
continue;
|
|
}
|
|
|
|
$recordStatuses[] = [
|
|
'path' => ($on ? $status['img_on'] : $status['img_off']),
|
|
'labels' => ($on ? $status['labels_on_i18n'] : $status['labels_off_i18n'])
|
|
];
|
|
}
|
|
|
|
return $recordStatuses;
|
|
}
|
|
|
|
/**
|
|
* returns true if user is authenticated and has all the passed rights on the base
|
|
* todo : wtf $rights is an array since it's never called with more than 1 right in it ?
|
|
*
|
|
* @param $baseId
|
|
* @param array $rights
|
|
* @return bool
|
|
* @throws \Exception
|
|
*/
|
|
public function isGrantedOnCollection($baseId, Array $rights)
|
|
{
|
|
if (false === ($this->app->getAuthenticatedUser() instanceof User)) {
|
|
|
|
return false;
|
|
}
|
|
|
|
$acl = $this->app->getAclForUser($this->app->getAuthenticatedUser());
|
|
foreach ($rights as $right) {
|
|
if (! $acl->has_right_on_base($baseId, $right)) {
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public function isGrantedOnDatabox($databoxId, $rights)
|
|
{
|
|
if (false === ($this->app->getAuthenticatedUser() instanceof User)) {
|
|
|
|
return false;
|
|
}
|
|
|
|
$rights = (array)$rights;
|
|
foreach ($rights as $right) {
|
|
if (false === $this->app->getAclForUser($this->app->getAuthenticatedUser())->has_right_on_sbas($databoxId, $right)) {
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public function getCollectionLogo($baseId)
|
|
{
|
|
if (false === $this->app['filesystem']->exists(sprintf('%s/config/minilogos/%s', $this->app['root.path'], $baseId))) {
|
|
|
|
return '';
|
|
}
|
|
|
|
return sprintf(
|
|
'<img title="%s" src="/custom/minilogos/%s" />',
|
|
\phrasea::bas_labels($baseId, $this->app),
|
|
$baseId
|
|
);
|
|
}
|
|
|
|
public function hasAccessSubDefinition(RecordInterface $record, $subDefinition)
|
|
{
|
|
if (false === ($this->app->getAuthenticatedUser() instanceof User)) {
|
|
|
|
return false;
|
|
}
|
|
|
|
return $this->app->getAclForUser($this->app->getAuthenticatedUser())->has_access_to_subdef($record, $subDefinition);
|
|
}
|
|
|
|
public function getDoctypeIcon(RecordInterface $record)
|
|
{
|
|
$src = $title = '';
|
|
if ($record->isStory()) {
|
|
$src = '/assets/common/images/icons/icon_story.gif';
|
|
$title = $this->app['translator']->trans('reportage');
|
|
|
|
return sprintf('<img src="%s" title="%s" />', $src, $title);
|
|
}
|
|
|
|
switch ($record->getType()) {
|
|
case 'image':
|
|
$src = '/assets/common/images/icons/icon_image.png';
|
|
$title = $this->app['translator']->trans('image');
|
|
break;
|
|
case 'document':
|
|
$src = '/assets/common/images/icons/icon_document.png';
|
|
$title = $this->app['translator']->trans('document');
|
|
break;
|
|
case 'video':
|
|
$src = '/assets/common/images/icons/icon_video.png';
|
|
$title = $this->app['translator']->trans('video');
|
|
break;
|
|
case 'audio':
|
|
$src = '/assets/common/images/icons/icon_audio.png';
|
|
$title = $this->app['translator']->trans('audio');
|
|
break;
|
|
case 'flash':
|
|
$src = '/assets/common/images/icons/icon_flash.png';
|
|
$title = $this->app['translator']->trans('flash');
|
|
break;
|
|
}
|
|
|
|
return sprintf('<img src="%s" title="%s" />', $src, $title);
|
|
}
|
|
|
|
public function getThumbnailUrl(RecordInterface $record)
|
|
{
|
|
return $this->getSubdefUrl($record, 'thumbnail');
|
|
}
|
|
|
|
public function getSubdefUrl(RecordInterface $record, $subdefName)
|
|
{
|
|
/** @var StaticMode $staticMode */
|
|
$staticMode = $this->app['phraseanet.static-file'];
|
|
|
|
if ($record instanceof ElasticsearchRecord) {
|
|
$subdefs = $record->getSubdefs();
|
|
if (isset($subdefs[$subdefName])) {
|
|
$thumbnail = $subdefs[$subdefName];
|
|
if (null !== $path = $thumbnail['path']) {
|
|
if (is_string($path) && '' !== $path) {
|
|
$etag = dechex(crc32(dechex($record->getVersion() ^ 0x5A5A5A5A)));
|
|
return $staticMode->getUrl($path, $etag);
|
|
}
|
|
}
|
|
}
|
|
} elseif ($record instanceof \record_adapter) {
|
|
if (null !== $thumbnail = $record->get_subdef($subdefName)) {
|
|
if ('' !== $path = $thumbnail->getRealPath()) {
|
|
$etag = $thumbnail->getEtag();
|
|
return $staticMode->getUrl($path, $etag);
|
|
}
|
|
}
|
|
}
|
|
|
|
$path = sprintf('/assets/common/images/icons/substitution/%s.png',
|
|
str_replace('/', '_', $record->getMimeType())
|
|
);
|
|
|
|
return $path;
|
|
}
|
|
|
|
public function getThumbnailGifUrl(RecordInterface $record)
|
|
{
|
|
return $this->getSubdefUrl($record, 'thumbnailgif');
|
|
}
|
|
|
|
public function getSubdefSize(RecordInterface $record, $subdefName)
|
|
{
|
|
$ret = null;
|
|
|
|
if ($record instanceof ElasticsearchRecord) {
|
|
$subdefs = $record->getSubdefs();
|
|
if (isset($subdefs[$subdefName])) {
|
|
$subdef = $subdefs[$subdefName];
|
|
if (isset($subdef['width']) && $subdef['width'] !== null && isset($subdef['height']) && $subdef['height'] !== null) {
|
|
$ret = [
|
|
'width' => $subdef['width'],
|
|
'height' => $subdef['height']
|
|
];
|
|
}
|
|
}
|
|
} elseif ($record instanceof \record_adapter) {
|
|
if (null !== $subdef = $record->get_subdef($subdefName)) {
|
|
$ret = [
|
|
'width' => $subdef->get_width(),
|
|
'height' => $subdef->get_height()
|
|
];
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
public function jsonToArray($string)
|
|
{
|
|
return json_decode($string, true);
|
|
}
|
|
|
|
public function getUserSetting($setting, $default = null)
|
|
{
|
|
if (false === ($this->app->getAuthenticatedUser() instanceof User)) {
|
|
|
|
return $default;
|
|
}
|
|
|
|
return $this->app['settings']->getUserSetting($this->app->getAuthenticatedUser(), $setting, $default);
|
|
}
|
|
|
|
public function getCheckerFromFQCN($checkerFQCN)
|
|
{
|
|
return $this->app['border-manager']->getCheckerFromFQCN($checkerFQCN);
|
|
}
|
|
|
|
public function getUserDisplayName($userId)
|
|
{
|
|
/** @var User $user */
|
|
$user = $this->app['repo.users']->find($userId);
|
|
|
|
return ($user == null) ? '' : $user->getDisplayName();
|
|
}
|
|
|
|
public function getName()
|
|
{
|
|
return 'phraseanet';
|
|
}
|
|
}
|