mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-23 09:53:15 +00:00
Merge branch 'master' into PHRAS-2688_Pord_41_Prod_workzone_change_type_of_numbering
This commit is contained in:
@@ -115,6 +115,7 @@ use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\Form\FormTypeInterface;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\Process\ExecutableFinder;
|
||||
use Unoconv\UnoconvServiceProvider;
|
||||
use XPDF\PdfToText;
|
||||
use XPDF\XPDFServiceProvider;
|
||||
@@ -237,8 +238,19 @@ class Application extends SilexApplication
|
||||
|
||||
$this->register(new UnicodeServiceProvider());
|
||||
$this->register(new ValidatorServiceProvider());
|
||||
$this->register(new XPDFServiceProvider());
|
||||
$this->setupXpdf();
|
||||
|
||||
if ($this['configuration.store']->isSetup()) {
|
||||
$binariesConfig = $this['conf']->get(['main', 'binaries']);
|
||||
$executableFinder = new ExecutableFinder();
|
||||
$this->register(new XPDFServiceProvider(), [
|
||||
'xpdf.configuration' => [
|
||||
'pdftotext.binaries' => isset($binariesConfig['pdftotext_binary']) ? $binariesConfig['pdftotext_binary'] : $executableFinder->find('pdftotext'),
|
||||
]
|
||||
]);
|
||||
|
||||
$this->setupXpdf();
|
||||
}
|
||||
|
||||
$this->register(new FileServeServiceProvider());
|
||||
$this->register(new ManipulatorServiceProvider());
|
||||
$this->register(new PluginServiceProvider());
|
||||
|
@@ -944,7 +944,7 @@ class V1Controller extends Controller
|
||||
}
|
||||
|
||||
$originalName = $pi['filename'] . '.' . $pi['extension'];
|
||||
$newPathname = $tempfile;
|
||||
$uploadedFilename = $newPathname = $tempfile;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -956,8 +956,11 @@ class V1Controller extends Controller
|
||||
if (!$file->isValid()) {
|
||||
return $this->getBadRequestAction($request, 'Data corrupted, please try again');
|
||||
}
|
||||
|
||||
$uploadedFilename = $file->getPathname();
|
||||
$originalName = $file->getClientOriginalName();
|
||||
$newPathname = $file->getPathname() . '.' . $file->getClientOriginalExtension();
|
||||
|
||||
if (false === rename($file->getPathname(), $newPathname)) {
|
||||
return Result::createError($request, 403, 'Error while renaming file')->createResponse();
|
||||
}
|
||||
@@ -1010,6 +1013,11 @@ class V1Controller extends Controller
|
||||
$nosubdef = $request->get('nosubdefs') === '' || \p4field::isyes($request->get('nosubdefs'));
|
||||
$this->getBorderManager()->process($session, $Package, $callback, $behavior, $nosubdef);
|
||||
|
||||
// remove $newPathname on temporary directory
|
||||
if ($newPathname !== $uploadedFilename) {
|
||||
@rename($newPathname, $uploadedFilename);
|
||||
}
|
||||
|
||||
$ret = ['entity' => null];
|
||||
|
||||
if ($output instanceof \record_adapter) {
|
||||
@@ -1081,6 +1089,11 @@ class V1Controller extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
// remove $newPathname on temporary directory
|
||||
if ($renamedFilename !== $uploadedFilename) {
|
||||
@rename($renamedFilename, $uploadedFilename);
|
||||
}
|
||||
|
||||
return Result::create($request, $ret)->createResponse();
|
||||
}
|
||||
|
||||
@@ -1984,7 +1997,7 @@ class V1Controller extends Controller
|
||||
return $this->getBadRequestAction($request);
|
||||
}
|
||||
|
||||
$datas = substr($datas, 0, ($n)) . $value . substr($datas, ($n + 2));
|
||||
$datas = substr($datas, 0, ($n)) . $value . substr($datas, ($n + 1));
|
||||
}
|
||||
|
||||
$record->setStatus(strrev($datas));
|
||||
|
@@ -463,6 +463,8 @@ class PushController extends Controller
|
||||
}
|
||||
|
||||
try {
|
||||
$manager = $this->getEntityManager();
|
||||
|
||||
$password = $this->getRandomGenerator()->generateString(128);
|
||||
|
||||
$user = $this->getUserManipulator()->createUser($email, $password, $email);
|
||||
@@ -476,12 +478,15 @@ class PushController extends Controller
|
||||
$user->setCompany($request->request->get('company'));
|
||||
}
|
||||
if ($request->request->get('job')) {
|
||||
$user->setCompany($request->request->get('job'));
|
||||
$user->setJob($request->request->get('job'));
|
||||
}
|
||||
if ($request->request->get('form_geonameid')) {
|
||||
$this->getUserManipulator()->setGeonameId($user, $request->request->get('form_geonameid'));
|
||||
if ($request->request->get('city')) {
|
||||
$this->getUserManipulator()->setGeonameId($user, $request->request->get('city'));
|
||||
}
|
||||
|
||||
$manager->persist($user);
|
||||
$manager->flush();
|
||||
|
||||
$result['message'] = $this->app->trans('User successfully created');
|
||||
$result['success'] = true;
|
||||
$result['user'] = $this->formatUser($user);
|
||||
|
@@ -14,6 +14,7 @@ namespace Alchemy\Phrasea\Metadata;
|
||||
use Alchemy\Phrasea\Border\File;
|
||||
use Alchemy\Phrasea\Databox\DataboxRepository;
|
||||
use Alchemy\Phrasea\Metadata\Tag\NoSource;
|
||||
use DateTime;
|
||||
use PHPExiftool\Driver\Metadata\Metadata;
|
||||
|
||||
class PhraseanetMetadataSetter
|
||||
@@ -66,8 +67,16 @@ class PhraseanetMetadataSetter
|
||||
continue;
|
||||
}
|
||||
|
||||
$data['value'] = $value;
|
||||
if ($field->get_type() == 'date') {
|
||||
try {
|
||||
$dateTime = new DateTime($value);
|
||||
$value = $dateTime->format('Y/m/d H:i:s');
|
||||
} catch (\Exception $e) {
|
||||
// $value unchanged
|
||||
}
|
||||
}
|
||||
|
||||
$data['value'] = $value;
|
||||
$metadataInRecordFormat[] = $data;
|
||||
}
|
||||
}
|
||||
|
@@ -30,6 +30,11 @@ class FieldKey implements Key, QueryPostProcessor
|
||||
return $this->getField($context)->getIndexField($raw);
|
||||
}
|
||||
|
||||
public function getFieldType(QueryContext $context)
|
||||
{
|
||||
return $this->getField($context)->getType();
|
||||
}
|
||||
|
||||
public function isValueCompatible($value, QueryContext $context)
|
||||
{
|
||||
return ValueChecker::isValueCompatible($this->getField($context), $value);
|
||||
|
@@ -6,6 +6,7 @@ use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryContext;
|
||||
|
||||
interface Key
|
||||
{
|
||||
public function getFieldType(QueryContext $context);
|
||||
public function getIndexField(QueryContext $context, $raw = false);
|
||||
public function isValueCompatible($value, QueryContext $context);
|
||||
public function __toString();
|
||||
|
@@ -23,6 +23,11 @@ class MetadataKey implements Key
|
||||
return $this->getTag($context)->getIndexField($raw);
|
||||
}
|
||||
|
||||
public function getFieldType(QueryContext $context)
|
||||
{
|
||||
return $this->getTag($context)->getType();
|
||||
}
|
||||
|
||||
public function isValueCompatible($value, QueryContext $context)
|
||||
{
|
||||
return ValueChecker::isValueCompatible($this->getTag($context), $value);
|
||||
|
@@ -52,6 +52,11 @@ class NativeKey implements Key
|
||||
$this->key = $key;
|
||||
}
|
||||
|
||||
public function getFieldType(QueryContext $context)
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function getIndexField(QueryContext $context, $raw = false)
|
||||
{
|
||||
return $this->key;
|
||||
|
@@ -2,18 +2,20 @@
|
||||
|
||||
namespace Alchemy\Phrasea\SearchEngine\Elastic\AST\KeyValue;
|
||||
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\FieldMapping;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\RecordHelper;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Field as StructureField;
|
||||
use Assert\Assertion;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\AST\KeyValue\FieldKey;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\AST\KeyValue\Key;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\AST\Node;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Exception\QueryException;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryContext;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryHelper;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryPostProcessor;
|
||||
|
||||
class RangeExpression extends Node
|
||||
{
|
||||
/** @var FieldKey */
|
||||
private $key;
|
||||
|
||||
private $lower_bound;
|
||||
private $lower_inclusive;
|
||||
private $higher_bound;
|
||||
@@ -55,20 +57,34 @@ class RangeExpression extends Node
|
||||
public function buildQuery(QueryContext $context)
|
||||
{
|
||||
$params = array();
|
||||
if ($this->lower_bound !== null) {
|
||||
$this->assertValueCompatible($this->lower_bound, $context);
|
||||
if ($this->lower_inclusive) {
|
||||
$params['gte'] = $this->lower_bound;
|
||||
} else {
|
||||
$params['gt'] = $this->lower_bound;
|
||||
/** @var StructureField $field */
|
||||
// $field = $this->key->getField($context);
|
||||
$lower_bound = $this->lower_bound;
|
||||
$higher_bound = $this->higher_bound;
|
||||
|
||||
if($this->key->getFieldType($context) === FieldMapping::TYPE_DATE) {
|
||||
if($lower_bound !== null) {
|
||||
$lower_bound = RecordHelper::sanitizeDate($lower_bound);
|
||||
}
|
||||
if($higher_bound !== null) {
|
||||
$higher_bound = RecordHelper::sanitizeDate($higher_bound);
|
||||
}
|
||||
}
|
||||
if ($this->higher_bound !== null) {
|
||||
$this->assertValueCompatible($this->higher_bound, $context);
|
||||
if ($this->higher_inclusive) {
|
||||
$params['lte'] = $this->higher_bound;
|
||||
|
||||
if ($lower_bound !== null) {
|
||||
$this->assertValueCompatible($lower_bound, $context);
|
||||
if ($this->lower_inclusive) {
|
||||
$params['gte'] = $lower_bound;
|
||||
} else {
|
||||
$params['lt'] = $this->higher_bound;
|
||||
$params['gt'] = $lower_bound;
|
||||
}
|
||||
}
|
||||
if ($higher_bound !== null) {
|
||||
$this->assertValueCompatible($higher_bound, $context);
|
||||
if ($this->higher_inclusive) {
|
||||
$params['lte'] = $higher_bound;
|
||||
} else {
|
||||
$params['lt'] = $higher_bound;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -34,6 +34,11 @@ class TimestampKey implements Key, Typed
|
||||
return FieldMapping::TYPE_DATE;
|
||||
}
|
||||
|
||||
public function getFieldType(QueryContext $context)
|
||||
{
|
||||
return FieldMapping::TYPE_DATE;
|
||||
}
|
||||
|
||||
public function getIndexField(QueryContext $context, $raw = false)
|
||||
{
|
||||
return $this->index_field;
|
||||
|
@@ -396,10 +396,10 @@ class ElasticSearchEngine implements SearchEngineInterface
|
||||
if ($options->getDateFields() && ($options->getMaxDate() || $options->getMinDate())) {
|
||||
$range = [];
|
||||
if ($options->getMaxDate()) {
|
||||
$range['lte'] = $options->getMaxDate()->format(FieldMapping::DATE_FORMAT_CAPTION_PHP);
|
||||
$range['lte'] = $options->getMaxDate()->format('Y-m-d');
|
||||
}
|
||||
if ($options->getMinDate()) {
|
||||
$range['gte'] = $options->getMinDate()->format(FieldMapping::DATE_FORMAT_CAPTION_PHP);
|
||||
$range['gte'] = $options->getMinDate()->format('Y-m-d');
|
||||
}
|
||||
|
||||
foreach ($options->getDateFields() as $dateField) {
|
||||
|
@@ -16,8 +16,7 @@ class FieldMapping
|
||||
|
||||
const DATE_FORMAT_MYSQL = 'yyyy-MM-dd HH:mm:ss';
|
||||
const DATE_FORMAT_CAPTION = 'yyyy/MM/dd'; // ES format
|
||||
const DATE_FORMAT_MYSQL_OR_CAPTION = 'yyyy-MM-dd HH:mm:ss||yyyy/MM/dd';
|
||||
const DATE_FORMAT_CAPTION_PHP = 'Y/m/d'; // PHP format
|
||||
const DATE_FORMAT_MYSQL_OR_CAPTION = 'yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||yyyy-MM||yyyy';
|
||||
|
||||
// Core types
|
||||
const TYPE_STRING = 'string';
|
||||
|
@@ -155,15 +155,16 @@ class BulkOperation
|
||||
// nb: results (items) are returned IN THE SAME ORDER as commands were pushed in the stack
|
||||
// so the items[X] match the operationIdentifiers[X]
|
||||
foreach ($response['items'] as $key => $item) {
|
||||
foreach($item as $command=>$result) { // command may be "index" or "delete"
|
||||
if($response['errors'] && $result['status'] >= 400) { // 4xx or 5xx error
|
||||
throw new Exception(sprintf('%d: %s', $key, var_export($result, true)));
|
||||
foreach ($item as $command=>$result) { // command may be "index" or "delete"
|
||||
if ($response['errors'] && $result['status'] >= 400) { // 4xx or 5xx
|
||||
$err = array_key_exists('error', $result) ? var_export($result['error'], true) : ($command . " error " . $result['status']);
|
||||
throw new Exception(sprintf('%d: %s', $key, $err));
|
||||
}
|
||||
}
|
||||
|
||||
$operationIdentifier = $this->operationIdentifiers[$key];
|
||||
|
||||
if(is_string($operationIdentifier) || is_int($operationIdentifier)) { // dont include null keys
|
||||
if (is_string($operationIdentifier) || is_int($operationIdentifier)) { // dont include null keys
|
||||
$callbackData[$operationIdentifier] = $response['items'][$key];
|
||||
}
|
||||
}
|
||||
|
@@ -39,18 +39,13 @@ class MetadataHydrator implements HydratorInterface
|
||||
|
||||
public function hydrateRecords(array &$records)
|
||||
{
|
||||
$sql = <<<SQL
|
||||
(SELECT record_id, ms.name AS `key`, m.value AS value, 'caption' AS type, ms.business AS private
|
||||
FROM metadatas AS m
|
||||
INNER JOIN metadatas_structure AS ms ON (ms.id = m.meta_struct_id)
|
||||
WHERE record_id IN (?))
|
||||
|
||||
UNION
|
||||
|
||||
(SELECT record_id, t.name AS `key`, t.value AS value, 'exif' AS type, 0 AS private
|
||||
FROM technical_datas AS t
|
||||
WHERE record_id IN (?))
|
||||
SQL;
|
||||
$sql = "(SELECT record_id, ms.name AS `key`, m.value AS value, 'caption' AS type, ms.business AS private\n"
|
||||
. " FROM metadatas AS m INNER JOIN metadatas_structure AS ms ON (ms.id = m.meta_struct_id)\n"
|
||||
. " WHERE record_id IN (?))\n"
|
||||
. "UNION\n"
|
||||
. "(SELECT record_id, t.name AS `key`, t.value AS value, 'exif' AS type, 0 AS private\n"
|
||||
. " FROM technical_datas AS t\n"
|
||||
. " WHERE record_id IN (?))\n";
|
||||
|
||||
$ids = array_keys($records);
|
||||
$statement = $this->connection->executeQuery(
|
||||
@@ -62,7 +57,7 @@ SQL;
|
||||
while ($metadata = $statement->fetch()) {
|
||||
// Store metadata value
|
||||
$key = $metadata['key'];
|
||||
$value = $metadata['value'];
|
||||
$value = trim($metadata['value']);
|
||||
|
||||
// Do not keep empty values
|
||||
if ($key === '' || $value === '') {
|
||||
@@ -80,7 +75,7 @@ SQL;
|
||||
case 'caption':
|
||||
// Sanitize fields
|
||||
$value = StringHelper::crlfNormalize($value);
|
||||
$value = $this->sanitizeValue($value, $this->structure->typeOf($key));
|
||||
$value = $this->helper->sanitizeValue($value, $this->structure->typeOf($key));
|
||||
// Private caption fields are kept apart
|
||||
$type = $metadata['private'] ? 'private_caption' : 'caption';
|
||||
// Caption are multi-valued
|
||||
@@ -103,7 +98,7 @@ SQL;
|
||||
}
|
||||
$tag = $this->structure->getMetadataTagByName($key);
|
||||
if ($tag) {
|
||||
$value = $this->sanitizeValue($value, $tag->getType());
|
||||
$value = $this->helper->sanitizeValue($value, $tag->getType());
|
||||
}
|
||||
// EXIF data is single-valued
|
||||
$record['metadata_tags'][$key] = $value;
|
||||
@@ -118,33 +113,6 @@ SQL;
|
||||
$this->clearGpsPositionBuffer();
|
||||
}
|
||||
|
||||
private function sanitizeValue($value, $type)
|
||||
{
|
||||
switch ($type) {
|
||||
case FieldMapping::TYPE_STRING:
|
||||
return str_replace("\0", "", $value);
|
||||
|
||||
case FieldMapping::TYPE_DATE:
|
||||
return $this->helper->sanitizeDate($value);
|
||||
|
||||
case FieldMapping::TYPE_FLOAT:
|
||||
case FieldMapping::TYPE_DOUBLE:
|
||||
return (float) $value;
|
||||
|
||||
case FieldMapping::TYPE_INTEGER:
|
||||
case FieldMapping::TYPE_LONG:
|
||||
case FieldMapping::TYPE_SHORT:
|
||||
case FieldMapping::TYPE_BYTE:
|
||||
return (int) $value;
|
||||
|
||||
case FieldMapping::TYPE_BOOLEAN:
|
||||
return (bool) $value;
|
||||
|
||||
default:
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
private function handleGpsPosition(&$records, $id, $tag_name, $value)
|
||||
{
|
||||
// Get position object
|
||||
|
@@ -11,6 +11,8 @@
|
||||
|
||||
namespace Alchemy\Phrasea\SearchEngine\Elastic\Indexer\Record\Hydrator;
|
||||
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\FieldMapping;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\RecordHelper;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Driver\Connection as DriverConnection;
|
||||
|
||||
@@ -18,31 +20,34 @@ class TitleHydrator implements HydratorInterface
|
||||
{
|
||||
private $connection;
|
||||
|
||||
public function __construct(DriverConnection $connection)
|
||||
/** @var RecordHelper */
|
||||
private $helper;
|
||||
|
||||
public function __construct(DriverConnection $connection, RecordHelper $helper)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
$this->helper = $helper;
|
||||
}
|
||||
|
||||
public function hydrateRecords(array &$records)
|
||||
{
|
||||
$sql = <<<SQL
|
||||
SELECT
|
||||
m.`record_id`,
|
||||
CASE ms.`thumbtitle`
|
||||
WHEN "1" THEN "default"
|
||||
WHEN "0" THEN "default"
|
||||
ELSE ms.`thumbtitle`
|
||||
END AS locale,
|
||||
CASE ms.`thumbtitle`
|
||||
WHEN "0" THEN r.`originalname`
|
||||
ELSE GROUP_CONCAT(m.`value` ORDER BY ms.`thumbtitle`, ms.`sorter` SEPARATOR " - ")
|
||||
END AS title
|
||||
FROM metadatas AS m FORCE INDEX(`record_id`)
|
||||
STRAIGHT_JOIN metadatas_structure AS ms ON (ms.`id` = m.`meta_struct_id`)
|
||||
STRAIGHT_JOIN record AS r ON (r.`record_id` = m.`record_id`)
|
||||
WHERE m.`record_id` IN (?)
|
||||
GROUP BY m.`record_id`, ms.`thumbtitle`
|
||||
SQL;
|
||||
$sql = "SELECT\n"
|
||||
. "m.`record_id`,\n"
|
||||
. " CASE ms.`thumbtitle`\n"
|
||||
. " WHEN '1' THEN 'default'\n"
|
||||
. " WHEN '0' THEN 'default'\n"
|
||||
. " ELSE ms.`thumbtitle`\n"
|
||||
. " END AS locale,\n"
|
||||
. " CASE ms.`thumbtitle`\n"
|
||||
. " WHEN '0' THEN r.`originalname`\n"
|
||||
. " ELSE GROUP_CONCAT(m.`value` ORDER BY ms.`thumbtitle`, ms.`sorter` SEPARATOR ' - ')\n"
|
||||
. " END AS title\n"
|
||||
. "FROM metadatas AS m FORCE INDEX(`record_id`)\n"
|
||||
. "STRAIGHT_JOIN metadatas_structure AS ms ON (ms.`id` = m.`meta_struct_id`)\n"
|
||||
. "STRAIGHT_JOIN record AS r ON (r.`record_id` = m.`record_id`)\n"
|
||||
. "WHERE m.`record_id` IN (?)\n"
|
||||
. "GROUP BY m.`record_id`, ms.`thumbtitle`\n";
|
||||
|
||||
$statement = $this->connection->executeQuery(
|
||||
$sql,
|
||||
array(array_keys($records)),
|
||||
@@ -50,7 +55,7 @@ SQL;
|
||||
);
|
||||
|
||||
while ($row = $statement->fetch()) {
|
||||
$records[$row['record_id']]['title'][$row['locale']] = $row['title'];
|
||||
$records[$row['record_id']]['title'][$row['locale']] = $this->helper->sanitizeValue($row['title'], FieldMapping::TYPE_STRING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -57,6 +57,9 @@ class DateFieldMapping extends ComplexFieldMapping
|
||||
*/
|
||||
protected function getProperties()
|
||||
{
|
||||
return array_merge([ 'format' => $this->format ], parent::getProperties());
|
||||
return array_merge([
|
||||
'format' => $this->format,
|
||||
'ignore_malformed' => true
|
||||
], parent::getProperties());
|
||||
}
|
||||
}
|
||||
|
@@ -89,31 +89,72 @@ class RecordHelper
|
||||
return $this->collectionMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $date
|
||||
* @return bool
|
||||
*/
|
||||
public static function validateDate($date)
|
||||
{
|
||||
$d = DateTime::createFromFormat(FieldMapping::DATE_FORMAT_CAPTION_PHP, $date);
|
||||
|
||||
return $d && $d->format(FieldMapping::DATE_FORMAT_CAPTION_PHP) == $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
* @return null|string
|
||||
*/
|
||||
public static function sanitizeDate($value)
|
||||
{
|
||||
// introduced in https://github.com/alchemy-fr/Phraseanet/commit/775ce804e0257d3a06e4e068bd17330a79eb8370#diff-bee690ed259e0cf73a31dee5295d2edcR286
|
||||
// not sure if it's really needed
|
||||
$v_fix = null;
|
||||
try {
|
||||
$date = new \DateTime($value);
|
||||
|
||||
return $date->format(FieldMapping::DATE_FORMAT_CAPTION_PHP);
|
||||
$a = explode(';', preg_replace('/\D+/', ';', trim($value)));
|
||||
switch (count($a)) {
|
||||
case 1: // yyyy
|
||||
$date = new \DateTime($a[0] . '-01-01'); // will throw if date is not valid
|
||||
$v_fix = $date->format('Y');
|
||||
break;
|
||||
case 2: // yyyy;mm
|
||||
$date = new \DateTime( $a[0] . '-' . $a[1] . '-01');
|
||||
$v_fix = $date->format('Y-m');
|
||||
break;
|
||||
case 3: // yyyy;mm;dd
|
||||
$date = new \DateTime($a[0] . '-' . $a[1] . '-' . $a[2]);
|
||||
$v_fix = $date->format('Y-m-d');
|
||||
break;
|
||||
case 4:
|
||||
$date = new \DateTime($a[0] . '-' . $a[1] . '-' . $a[2] . ' ' . $a[3] . ':00:00');
|
||||
$v_fix = $date->format('Y-m-d H:i:s');
|
||||
break;
|
||||
case 5:
|
||||
$date = new \DateTime($a[0] . '-' . $a[1] . '-' . $a[2] . ' ' . $a[3] . ':' . $a[4] . ':00');
|
||||
$v_fix = $date->format('Y-m-d H:i:s');
|
||||
break;
|
||||
case 6:
|
||||
$date = new \DateTime($a[0] . '-' . $a[1] . '-' . $a[2] . ' ' . $a[3] . ':' . $a[4] . ':' . $a[5]);
|
||||
$v_fix = $date->format('Y-m-d H:i:s');
|
||||
break;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return null;
|
||||
// no-op, v_fix = null
|
||||
}
|
||||
|
||||
return $v_fix;
|
||||
}
|
||||
|
||||
public function sanitizeValue($value, $type)
|
||||
{
|
||||
switch ($type) {
|
||||
case FieldMapping::TYPE_DATE:
|
||||
return self::sanitizeDate($value);
|
||||
|
||||
case FieldMapping::TYPE_FLOAT:
|
||||
case FieldMapping::TYPE_DOUBLE:
|
||||
return (float) $value;
|
||||
|
||||
case FieldMapping::TYPE_INTEGER:
|
||||
case FieldMapping::TYPE_LONG:
|
||||
case FieldMapping::TYPE_SHORT:
|
||||
case FieldMapping::TYPE_BYTE:
|
||||
return (int) $value;
|
||||
|
||||
case FieldMapping::TYPE_BOOLEAN:
|
||||
return (bool) $value;
|
||||
|
||||
case FieldMapping::TYPE_STRING:
|
||||
return str_replace("\0", '', $value);
|
||||
|
||||
default:
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -110,41 +110,50 @@ class QueryHelper
|
||||
}
|
||||
}
|
||||
|
||||
public static function getRangeFromDateString($string)
|
||||
public static function getRangeFromDateString($value)
|
||||
{
|
||||
$formats = ['Y/m/d', 'Y/m', 'Y'];
|
||||
$deltas = ['+1 day', '+1 month', '+1 year'];
|
||||
$to = null;
|
||||
while ($format = array_pop($formats)) {
|
||||
$delta = array_pop($deltas);
|
||||
$from = date_create_from_format($format, $string);
|
||||
if ($from !== false) {
|
||||
// Rewind to start of range
|
||||
$month = 1;
|
||||
$day = 1;
|
||||
switch ($format) {
|
||||
case 'Y/m/d':
|
||||
$day = (int) $from->format('d');
|
||||
case 'Y/m':
|
||||
$month = (int) $from->format('m');
|
||||
case 'Y':
|
||||
$year = (int) $from->format('Y');
|
||||
}
|
||||
date_date_set($from, $year, $month, $day);
|
||||
date_time_set($from, 0, 0, 0);
|
||||
// Create end of the the range
|
||||
$to = date_modify(clone $from, $delta);
|
||||
break;
|
||||
$date_from = null;
|
||||
$date_to = null;
|
||||
try {
|
||||
$a = explode(';', preg_replace('/\D+/', ';', trim($value)));
|
||||
switch (count($a)) {
|
||||
case 1: // yyyy
|
||||
$date_to = clone($date_from = new \DateTime($a[0] . '-01-01 00:00:00')); // will throw if date is not valid
|
||||
$date_to->add(new \DateInterval('P1Y'));
|
||||
break;
|
||||
case 2: // yyyy;mm
|
||||
$date_to = clone($date_from = new \DateTime($a[0] . '-' . $a[1] . '-01 00:00:00')); // will throw if date is not valid
|
||||
$date_to->add(new \DateInterval('P1M'));
|
||||
break;
|
||||
case 3: // yyyy;mm;dd
|
||||
$date_to = clone($date_from = new \DateTime($a[0] . '-' . $a[1] . '-' . $a[2] . ' 00:00:00')); // will throw if date is not valid
|
||||
$date_to->add(new \DateInterval('P1D'));
|
||||
break;
|
||||
case 4:
|
||||
$date_to = clone($date_from = new \DateTime($a[0] . '-' . $a[1] . '-' . $a[2] . ' ' . $a[3] . ':00:00'));
|
||||
$date_to->add(new \DateInterval('PT1H'));
|
||||
break;
|
||||
case 5:
|
||||
$date_to = clone($date_from = new \DateTime($a[0] . '-' . $a[1] . '-' . $a[2] . ' ' . $a[3] . ':' . $a[4] . ':00'));
|
||||
$date_to->add(new \DateInterval('PT1M'));
|
||||
break;
|
||||
case 6:
|
||||
$date_to = clone($date_from = new \DateTime($a[0] . '-' . $a[1] . '-' . $a[2] . ' ' . $a[3] . ':' . $a[4] . ':' . $a[5]));
|
||||
// $date_to->add(new \DateInterval('PT1S')); // no need since precision is 1 sec, a "equal" will be generated when from==to
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
if (!$from || !$to) {
|
||||
throw new \InvalidArgumentException(sprintf('Invalid date "%s".', $string));
|
||||
if ($date_from === null || $date_to === null) {
|
||||
throw new \InvalidArgumentException(sprintf('Invalid date "%s".', $value));
|
||||
}
|
||||
|
||||
return [
|
||||
'from' => $from->format(FieldMapping::DATE_FORMAT_CAPTION_PHP),
|
||||
'to' => $to->format(FieldMapping::DATE_FORMAT_CAPTION_PHP)
|
||||
'from' => $date_from->format('Y-m-d H:i:s'),
|
||||
'to' => $date_to->format('Y-m-d H:i:s')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ namespace Alchemy\Phrasea\SearchEngine\Elastic\Search;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\AST;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Exception\Exception;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\FieldMapping;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Mapping;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\RecordHelper;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Structure;
|
||||
use Hoa\Compiler\Llk\TreeNode;
|
||||
use Hoa\Visitor\Element;
|
||||
@@ -166,6 +166,12 @@ class QueryVisitor implements Visit
|
||||
$key = $node->getChild(0)->accept($this);
|
||||
$boundary = $node->getChild(1)->accept($this);
|
||||
|
||||
if ($this->isDateKey($key)) {
|
||||
if(($v = RecordHelper::sanitizeDate($boundary)) !== null) {
|
||||
$boundary = $v;
|
||||
}
|
||||
}
|
||||
|
||||
switch ($node->getId()) {
|
||||
case NodeTypes::LT_EXPR:
|
||||
return AST\KeyValue\RangeExpression::lessThan($key, $boundary);
|
||||
@@ -195,11 +201,15 @@ class QueryVisitor implements Visit
|
||||
try {
|
||||
// Try to create a range for incomplete dates
|
||||
$range = QueryHelper::getRangeFromDateString($right);
|
||||
return new AST\KeyValue\RangeExpression(
|
||||
$left,
|
||||
$range['from'], true,
|
||||
$range['to'], false
|
||||
);
|
||||
if ($range['from'] === $range['to']) {
|
||||
return new AST\KeyValue\EqualExpression($left, $range['from']);
|
||||
} else {
|
||||
return new AST\KeyValue\RangeExpression(
|
||||
$left,
|
||||
$range['from'], true,
|
||||
$range['to'], false
|
||||
);
|
||||
}
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
// Fall back to equal expression
|
||||
}
|
||||
|
@@ -3,7 +3,6 @@
|
||||
namespace Alchemy\Phrasea\SearchEngine\Elastic\Structure;
|
||||
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\FieldMapping;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Mapping;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\RecordHelper;
|
||||
use Assert\Assertion;
|
||||
|
||||
@@ -20,7 +19,7 @@ class ValueChecker
|
||||
{
|
||||
Assertion::allIsInstanceOf($list, Typed::class);
|
||||
$is_numeric = is_numeric($value);
|
||||
$is_valid_date = RecordHelper::validateDate($value);
|
||||
$is_valid_date = (RecordHelper::sanitizeDate($value) !== null);
|
||||
$filtered = [];
|
||||
foreach ($list as $item) {
|
||||
switch ($item->getType()) {
|
||||
|
@@ -127,7 +127,10 @@ class WriteMetadataJob extends AbstractJob
|
||||
|
||||
// check exiftool known tags to skip Phraseanet:tf-*
|
||||
try {
|
||||
TagFactory::getFromRDFTagname($tagName);
|
||||
$tag = TagFactory::getFromRDFTagname($tagName);
|
||||
if(!$tag->isWritable()) {
|
||||
continue;
|
||||
}
|
||||
} catch (TagUnknown $e) {
|
||||
continue;
|
||||
}
|
||||
@@ -147,21 +150,34 @@ class WriteMetadataJob extends AbstractJob
|
||||
$fieldValue = array_pop($fieldValues);
|
||||
$value = $this->removeNulChar($fieldValue->getValue());
|
||||
|
||||
$value = new Value\Mono($value);
|
||||
// fix the dates edited into phraseanet
|
||||
if($fieldStructure->get_type() === $fieldStructure::TYPE_DATE) {
|
||||
try {
|
||||
$value = self::fixDate($value); // will return NULL if the date is not valid
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$value = null; // do NOT write back to iptc
|
||||
}
|
||||
}
|
||||
|
||||
if($value !== null) { // do not write invalid dates
|
||||
$value = new Value\Mono($value);
|
||||
}
|
||||
}
|
||||
} catch(\Exception $e) {
|
||||
} catch (\Exception $e) {
|
||||
// the field is not set in the record, erase it
|
||||
if ($fieldStructure->is_multi()) {
|
||||
$value = new Value\Multi(array(''));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$value = new Value\Mono('');
|
||||
}
|
||||
}
|
||||
|
||||
$metadata->add(
|
||||
new Metadata\Metadata($fieldStructure->get_tag(), $value)
|
||||
);
|
||||
if($value !== null) { // do not write invalid data
|
||||
$metadata->add(
|
||||
new Metadata\Metadata($fieldStructure->get_tag(), $value)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$writer = $this->getMetadataWriter($jobData->getApplication());
|
||||
@@ -220,4 +236,34 @@ class WriteMetadataJob extends AbstractJob
|
||||
{
|
||||
return str_replace("\0", "", $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* re-format a phraseanet date for iptc writing
|
||||
* return NULL if the date is not valid
|
||||
*
|
||||
* @param string $value
|
||||
* @return string|null
|
||||
*/
|
||||
private static function fixDate($value)
|
||||
{
|
||||
$date = null;
|
||||
try {
|
||||
$a = explode(';', preg_replace('/\D+/', ';', trim($value)));
|
||||
switch (count($a)) {
|
||||
case 3: // yyyy;mm;dd
|
||||
$date = new \DateTime($a[0] . '-' . $a[1] . '-' . $a[2]);
|
||||
$date = $date->format('Y-m-d H:i:s');
|
||||
break;
|
||||
case 6: // yyyy;mm;dd;hh;mm;ss
|
||||
$date = new \DateTime($a[0] . '-' . $a[1] . '-' . $a[2] . ' ' . $a[3] . ':' . $a[4] . ':' . $a[5]);
|
||||
$date = $date->format('Y-m-d H:i:s');
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$date = null;
|
||||
}
|
||||
|
||||
return $date;
|
||||
}
|
||||
}
|
||||
|
4
lib/classes/cache/databox.php
vendored
4
lib/classes/cache/databox.php
vendored
@@ -121,9 +121,9 @@ class cache_databox
|
||||
|
||||
$conn = $app->getApplicationBox()->get_connection();
|
||||
|
||||
$sql = 'UPDATE sitepreff SET memcached_update = :date';
|
||||
$sql = 'UPDATE sitepreff SET memcached_update = current_timestamp()';
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute([':date' => $now]);
|
||||
$stmt->execute();
|
||||
$stmt->closeCursor();
|
||||
|
||||
self::$refreshing = false;
|
||||
|
Reference in New Issue
Block a user