diff --git a/lib/Alchemy/Phrasea/Application.php b/lib/Alchemy/Phrasea/Application.php
index bfe2070327..bd109378f8 100644
--- a/lib/Alchemy/Phrasea/Application.php
+++ b/lib/Alchemy/Phrasea/Application.php
@@ -114,6 +114,7 @@ use Alchemy\Phrasea\Core\Provider\RepositoriesServiceProvider;
use Alchemy\Phrasea\Core\Provider\SearchEngineServiceProvider;
use Alchemy\Phrasea\Core\Provider\SerializerServiceProvider;
use Alchemy\Phrasea\Core\Provider\SessionHandlerServiceProvider;
+use Alchemy\Phrasea\Core\Provider\StatusServiceProvider;
use Alchemy\Phrasea\Core\Provider\SubdefServiceProvider;
use Alchemy\Phrasea\Core\Provider\TasksServiceProvider;
use Alchemy\Phrasea\Core\Provider\TemporaryFilesystemServiceProvider;
@@ -237,7 +238,7 @@ class Application extends SilexApplication
$this->register(new FeedServiceProvider());
$this->register(new FtpServiceProvider());
$this->register(new GeonamesServiceProvider());
-
+ $this->register(new StatusServiceProvider());
$this['geonames.server-uri'] = $this->share(function (Application $app) {
return $app['conf']->get(['registry', 'webservices', 'geonames-server'], 'http://geonames.alchemyasp.com/');
});
diff --git a/lib/Alchemy/Phrasea/Controller/Admin/Root.php b/lib/Alchemy/Phrasea/Controller/Admin/Root.php
index 8379fca5cd..302a314f63 100644
--- a/lib/Alchemy/Phrasea/Controller/Admin/Root.php
+++ b/lib/Alchemy/Phrasea/Controller/Admin/Root.php
@@ -263,7 +263,7 @@ class Root implements ControllerProviderInterface
$databox = $app['phraseanet.appbox']->get_databox($databox_id);
- $status = $databox->get_statusbits();
+ $statusStructure = $databox->getStatusStructure();
switch ($errorMsg = $request->query->get('error')) {
case 'rights':
@@ -283,8 +283,8 @@ class Root implements ControllerProviderInterface
break;
}
- if (isset($status[$bit])) {
- $status = $status[$bit];
+ if ($statusStructure->hasStatus($bit)) {
+ $status = $statusStructure->getStatus($bit);
} else {
$status = [
"labeloff" => '',
@@ -320,10 +320,12 @@ class Root implements ControllerProviderInterface
$app->abort(403);
}
+ $databox = $app['phraseanet.appbox']->get_databox($databox_id);
+
$error = false;
try {
- \databox_status::deleteStatus($app, $app['phraseanet.appbox']->get_databox($databox_id), $bit);
+ $app['status.provider']->deleteStatus($databox->getStatusStructure(), $bit);
} catch (\Exception $e) {
$error = true;
}
@@ -349,7 +351,9 @@ class Root implements ControllerProviderInterface
'labels_off' => $request->request->get('labels_off', []),
];
- \databox_status::updateStatus($app, $databox_id, $bit, $properties);
+ $databox = $app['phraseanet.appbox']->get_databox($databox_id);
+
+ $app['status.provider']->updateStatus($databox->getStatusStructure(), $bit, $properties);
if (null !== $request->request->get('delete_icon_off')) {
\databox_status::deleteIcon($app, $databox_id, $bit, 'off');
diff --git a/lib/Alchemy/Phrasea/Controller/Api/V1.php b/lib/Alchemy/Phrasea/Controller/Api/V1.php
index 364e780651..55bee046b5 100644
--- a/lib/Alchemy/Phrasea/Controller/Api/V1.php
+++ b/lib/Alchemy/Phrasea/Controller/Api/V1.php
@@ -11,6 +11,7 @@
namespace Alchemy\Phrasea\Controller\Api;
+use Alchemy\Phrasea\Status\StatusStructure;
use Silex\ControllerProviderInterface;
use Alchemy\Phrasea\Cache\Cache as CacheInterface;
use Alchemy\Phrasea\Core\PhraseaEvents;
@@ -437,7 +438,7 @@ class V1 implements ControllerProviderInterface
*/
public function get_databox_status(Application $app, Request $request, $databox_id)
{
- $ret = ["status" => $this->list_databox_status($app['phraseanet.appbox']->get_databox($databox_id)->get_statusbits())];
+ $ret = ["status" => $this->list_databox_status($app['phraseanet.appbox']->get_databox($databox_id)->getStatusStructure())];
return Result::create($request, $ret)->createResponse();
}
@@ -757,7 +758,7 @@ class V1 implements ControllerProviderInterface
{
$record = $app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id);
- $ret = ["status" => $this->list_record_status($app['phraseanet.appbox']->get_databox($databox_id), $record->get_status())];
+ $ret = ["status" => $this->list_record_status($record)];
return Result::create($request, $ret)->createResponse();
}
@@ -836,7 +837,7 @@ class V1 implements ControllerProviderInterface
{
$databox = $app['phraseanet.appbox']->get_databox($databox_id);
$record = $databox->get_record($record_id);
- $status_bits = $databox->get_statusbits();
+ $statusStructure = $databox->getStatusStructure();
$status = $request->get('status');
@@ -852,7 +853,7 @@ class V1 implements ControllerProviderInterface
if (!in_array($value, ['0', '1'])) {
return $this->getBadRequest($app, $request);
}
- if (!isset($status_bits[$n])) {
+ if (!$statusStructure->hasStatus($n)) {
return $this->getBadRequest($app, $request);
}
@@ -861,7 +862,7 @@ class V1 implements ControllerProviderInterface
$record->set_binary_status(strrev($datas));
- $ret = ["status" => $this->list_record_status($databox, $record->get_status())];
+ $ret = ["status" => $this->list_record_status($record)];
return Result::create($request, $ret)->createResponse();
}
@@ -1304,13 +1305,11 @@ class V1 implements ControllerProviderInterface
*
* @return array
*/
- private function list_record_status(\databox $databox, $status)
+ private function list_record_status(\record_adapter $record)
{
- $status = strrev($status);
-
$ret = [];
- foreach ($databox->get_statusbits() as $bit => $status_datas) {
- $ret[] = ['bit' => $bit, 'state' => !!substr($status, ($bit - 1), 1)];
+ foreach ($record->getStatusStructure() as $bit => $status) {
+ $ret[] = ['bit' => $bit, 'state' => \databox_status::bitIsSet($record->getStatusBitField(), $bit)];
}
return $ret;
@@ -1502,11 +1501,25 @@ class V1 implements ControllerProviderInterface
*
* @return array
*/
- private function list_databox_status(array $status)
+ private function list_databox_status(StatusStructure $statusStructure)
{
$ret = [];
- foreach ($status as $n => $datas) {
- $ret[] = ['bit' => $n, 'label_on' => $datas['labelon'], 'label_off' => $datas['labeloff'], 'labels' => ['en' => $datas['labels_on_i18n']['en'], 'fr' => $datas['labels_on_i18n']['fr'], 'de' => $datas['labels_on_i18n']['de'], 'nl' => $datas['labels_on_i18n']['nl'],], 'img_on' => $datas['img_on'], 'img_off' => $datas['img_off'], 'searchable' => !!$datas['searchable'], 'printable' => !!$datas['printable'],];
+ foreach ($statusStructure as $bit => $status) {
+ $ret[] = [
+ 'bit' => $bit,
+ 'label_on' => $status['labelon'],
+ 'label_off' => $status['labeloff'],
+ 'labels' => [
+ 'en' => $status['labels_on_i18n']['en'],
+ 'fr' => $status['labels_on_i18n']['fr'],
+ 'de' => $status['labels_on_i18n']['de'],
+ 'nl' => $status['labels_on_i18n']['nl'],
+ ],
+ 'img_on' => $status['img_on'],
+ 'img_off' => $status['img_off'],
+ 'searchable' => (bool) $status['searchable'],
+ 'printable' => (bool) $status['printable'],
+ ];
}
return $ret;
diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Edit.php b/lib/Alchemy/Phrasea/Controller/Prod/Edit.php
index 5f31d96430..4d91f935d7 100644
--- a/lib/Alchemy/Phrasea/Controller/Prod/Edit.php
+++ b/lib/Alchemy/Phrasea/Controller/Prod/Edit.php
@@ -39,8 +39,7 @@ class Edit implements ControllerProviderInterface
$records = RecordsRequest::fromRequest($app, $request, RecordsRequest::FLATTEN_YES_PRESERVE_STORIES, ['canmodifrecord']);
$thesaurus = false;
- $status = $ids = $elements = $suggValues =
- $fields = $JSFields = [];
+ $status = $ids = $elements = $suggValues = $fields = $JSFields = [];
$databox = null;
$multipleDataboxes = count($records->databoxes()) > 1;
@@ -120,16 +119,16 @@ class Edit implements ControllerProviderInterface
* generate javascript status
*/
if ($app['acl']->get($app['authentication']->getUser())->has_right('changestatus')) {
- $dbstatus = \databox_status::getDisplayStatus($app);
- if (isset($dbstatus[$databox->get_sbas_id()])) {
- foreach ($dbstatus[$databox->get_sbas_id()] as $n => $statbit) {
- $status[$n] = [];
- $status[$n]['label0'] = $statbit['labels_off_i18n'][$app['locale']];
- $status[$n]['label1'] = $statbit['labels_on_i18n'][$app['locale']];
- $status[$n]['img_off'] = $statbit['img_off'];
- $status[$n]['img_on'] = $statbit['img_on'];
- $status[$n]['_value'] = 0;
- }
+ $statusStructure = $databox->getStatusStructure();
+ foreach ($statusStructure as $statbit) {
+ $bit = $statbit['bit'];
+
+ $status[$bit] = [];
+ $status[$bit]['label0'] = $statbit['labels_off_i18n'][$app['locale']];
+ $status[$bit]['label1'] = $statbit['labels_on_i18n'][$app['locale']];
+ $status[$bit]['img_off'] = $statbit['img_off'];
+ $status[$bit]['img_on'] = $statbit['img_on'];
+ $status[$bit]['_value'] = 0;
}
}
diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Property.php b/lib/Alchemy/Phrasea/Controller/Prod/Property.php
index fde68a2d82..afdf8910c8 100644
--- a/lib/Alchemy/Phrasea/Controller/Prod/Property.php
+++ b/lib/Alchemy/Phrasea/Controller/Prod/Property.php
@@ -64,49 +64,42 @@ class Property implements ControllerProviderInterface
}
$records = RecordsRequest::fromRequest($app, $request, false, ['chgstatus']);
- $databoxStatus = \databox_status::getDisplayStatus($app);
- $statusBit = $nRec = [];
- foreach ($records as $record) {
- //perform logic
- $sbasId = $record->get_databox()->get_sbas_id();
-
- if (!isset($nRec[$sbasId])) {
- $nRec[$sbasId] = ['stories' => 0, 'records' => 0];
- }
-
- $nRec[$sbasId]['records']++;
-
- if ($record->is_grouping()) {
- $nRec[$sbasId]['stories']++;
- }
-
- if (!isset($statusBit[$sbasId])) {
- $statusBit[$sbasId] = isset($databoxStatus[$sbasId]) ? $databoxStatus[$sbasId] : [];
-
- foreach (array_keys($statusBit[$sbasId]) as $bit) {
- $statusBit[$sbasId][$bit]['nset'] = 0;
- }
- }
-
- $status = strrev($record->get_status());
-
- foreach (array_keys($statusBit[$sbasId]) as $bit) {
- $statusBit[$sbasId][$bit]["nset"] += substr($status, $bit, 1) !== "0" ? 1 : 0;
- }
+ if (count($records->databoxes()) > 1) {
+ return new Response($app['twig']->render('prod/actions/Property/index.html.twig', [
+ 'records' => $records
+ ]));
}
- foreach ($records->databoxes() as $databox) {
- $sbasId = $databox->get_sbas_id();
- foreach ($statusBit[$sbasId] as $bit => $values) {
- $statusBit[$sbasId][$bit]["status"] = $values["nset"] == 0 ? 0 : ($values["nset"] == $nRec[$sbasId]['records'] ? 1 : 2);
+ $databox = current($records->databoxes());
+ $statusStructure = $databox->getStatusStructure();
+ $recordsStatuses = [];
+
+ foreach ($records->received() as $record) {
+ foreach ($statusStructure as $status) {
+ $bit = $status['bit'];
+
+ if (!isset($recordsStatuses[$bit])) {
+ $recordsStatuses[$bit] = $status;
+ }
+
+ $statusSet = \databox_status::bitIsSet($record->getStatusBitField(), $bit);
+
+ if (!isset($recordsStatuses[$bit]['flag'])) {
+ $recordsStatuses[$bit]['flag'] = (int) $statusSet;
+ }
+
+ // if flag property was already set and the value is different from the previous one
+ // it means that records share different value for the same flag
+ if ($recordsStatuses[$bit]['flag'] !== (int) $statusSet) {
+ $recordsStatuses[$bit]['flag'] = 2;
+ }
}
}
return new Response($app['twig']->render('prod/actions/Property/index.html.twig', [
'records' => $records,
- 'statusBit' => $statusBit,
- 'nRec' => $nRec
+ 'status' => $recordsStatuses
]));
}
diff --git a/lib/Alchemy/Phrasea/Core/Provider/StatusServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/StatusServiceProvider.php
new file mode 100644
index 0000000000..f95d7c94cb
--- /dev/null
+++ b/lib/Alchemy/Phrasea/Core/Provider/StatusServiceProvider.php
@@ -0,0 +1,39 @@
+share(function() use ($app) {
+ return new CacheStatusStructureProvider(
+ $app['cache'],
+ new XmlStatusStructureProvider($app['root.path'], $app['locales.available'])
+ );
+ });
+
+ $app['factory.status-structure'] = $app->share(function() use ($app) {
+ return new StatusStructureFactory($app['status.provider']);
+ });
+ }
+
+ public function boot(Application $app)
+ {
+ }
+}
diff --git a/lib/Alchemy/Phrasea/Helper/User/Edit.php b/lib/Alchemy/Phrasea/Helper/User/Edit.php
index d7732d5790..8359eed2a8 100644
--- a/lib/Alchemy/Phrasea/Helper/User/Edit.php
+++ b/lib/Alchemy/Phrasea/Helper/User/Edit.php
@@ -256,16 +256,16 @@ class Edit extends \Alchemy\Phrasea\Helper\Helper
$sbas_id = \phrasea::sbasFromBas($this->app, $this->base_id);
$databox = $this->app['phraseanet.appbox']->get_databox($sbas_id);
- $status = $databox->get_statusbits();
+ $statusStructure = $databox->getStatusStructure();
- foreach ($status as $bit => $datas) {
+ foreach ($statusStructure as $bit => $status) {
$tbits_left[$bit]["nset"] = 0;
- $tbits_left[$bit]["name"] = $datas['labels_off_i18n'][$this->app['locale']];
- $tbits_left[$bit]["icon"] = $datas["img_off"];
+ $tbits_left[$bit]["name"] = $status['labels_off_i18n'][$this->app['locale']];
+ $tbits_left[$bit]["icon"] = $status["img_off"];
$tbits_right[$bit]["nset"] = 0;
- $tbits_right[$bit]["name"] = $datas['labels_on_i18n'][$this->app['locale']];
- $tbits_right[$bit]["icon"] = $datas["img_on"];
+ $tbits_right[$bit]["name"] = $status['labels_on_i18n'][$this->app['locale']];
+ $tbits_right[$bit]["icon"] = $status["img_on"];
}
$vand_and = $vand_or = $vxor_and = $vxor_or = "0000";
diff --git a/lib/Alchemy/Phrasea/Model/Entities/ElasticsearchRecord.php b/lib/Alchemy/Phrasea/Model/Entities/ElasticsearchRecord.php
index 0d5a7ed9e5..817a1ddc22 100644
--- a/lib/Alchemy/Phrasea/Model/Entities/ElasticsearchRecord.php
+++ b/lib/Alchemy/Phrasea/Model/Entities/ElasticsearchRecord.php
@@ -293,17 +293,16 @@ class ElasticsearchRecord implements RecordInterface, MutableRecordInterface
$this->flags = $flags;
}
- public function setStatus($status)
+ public function setStatusBitField($status)
{
$this->status = $status;
}
/**
- * Get status of current current as 32 bits binary string
*
- * Eg: 00000000001011100000000000011111
+ * @return integer
*/
- public function getStatus()
+ public function getStatusBitField()
{
return $this->status;
}
diff --git a/lib/Alchemy/Phrasea/Model/Entities/User.php b/lib/Alchemy/Phrasea/Model/Entities/User.php
index 4c91f2ecc8..30930e7a19 100644
--- a/lib/Alchemy/Phrasea/Model/Entities/User.php
+++ b/lib/Alchemy/Phrasea/Model/Entities/User.php
@@ -426,7 +426,7 @@ class User
self::GENDER_MISS,
self::GENDER_MR,
self::GENDER_MRS
- ], true)) {
+ ])) {
throw new InvalidArgumentException(sprintf("Invalid gender %s.", $gender));
}
diff --git a/lib/Alchemy/Phrasea/Model/MutableRecordInterface.php b/lib/Alchemy/Phrasea/Model/MutableRecordInterface.php
index 6c6ed8d30f..f2aacdb9e5 100644
--- a/lib/Alchemy/Phrasea/Model/MutableRecordInterface.php
+++ b/lib/Alchemy/Phrasea/Model/MutableRecordInterface.php
@@ -34,8 +34,8 @@ interface MutableRecordInterface
/** @param string $uuid */
public function setUuid($uuid);
- /** @param string $status */
- public function setStatus($status);
+ /** @param integer $status */
+ public function setStatusBitField($status);
/** @param \DateTime $updated */
public function setUpdated(\DateTime $updated = null);
diff --git a/lib/Alchemy/Phrasea/Model/RecordInterface.php b/lib/Alchemy/Phrasea/Model/RecordInterface.php
index f964fa7603..ddc4542632 100644
--- a/lib/Alchemy/Phrasea/Model/RecordInterface.php
+++ b/lib/Alchemy/Phrasea/Model/RecordInterface.php
@@ -55,8 +55,8 @@ interface RecordInterface
/** @return string */
public function getUuid();
- /** @return string */
- public function getStatus();
+ /** @return integer */
+ public function getStatusBitField();
/** @return ArrayCollection */
public function getExif();
diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php
index d9c6bd4299..48ac97c96b 100644
--- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php
+++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php
@@ -435,9 +435,11 @@ class ElasticSearchEngine implements SearchEngineInterface
return ['bool' => ['must_not' => ['match_all' => new \stdClass()]]];
}
- $flagNamesMap = $this->getFlagsKey($this->app['phraseanet.appbox']);
+ $appbox = $this->app['phraseanet.appbox'];
+
+ $flagNamesMap = $this->getFlagsKey($appbox);
// Get flags rules
- $flagRules = $this->getFlagsRules($acl, $grantedCollections);
+ $flagRules = $this->getFlagsRules($appbox, $acl, $grantedCollections);
// Get intersection between collection ACLs and collection chosen by end user
$aclRules = $this->getACLsByCollection($flagRules, $flagNamesMap);
@@ -531,23 +533,25 @@ class ElasticSearchEngine implements SearchEngineInterface
$flags = [];
foreach ($appbox->get_databoxes() as $databox) {
$databoxId = $databox->get_sbas_id();
- $status = $databox->get_statusbits();
- foreach($status as $bit => $stat) {
- $flags[$databoxId][$bit] = RecordHelper::normalizeFlagKey($stat['labelon']);
+ $statusStructure = $databox->getStatusStructure();
+ foreach($statusStructure as $bit => $status) {
+ $flags[$databoxId][$bit] = RecordHelper::normalizeFlagKey($status['labelon']);
}
}
return $flags;
}
- private function getFlagsRules(\ACL $acl, array $collections)
+ private function getFlagsRules(\appbox $appbox, \ACL $acl, array $collections)
{
$rules = [];
foreach ($collections as $collectionId) {
$databoxId = \phrasea::sbasFromBas($this->app, $collectionId);
+ $databox = $appbox->get_databox($databoxId);
+
$mask_xor = $acl->get_mask_xor($collectionId);
$mask_and = $acl->get_mask_and($collectionId);
- foreach (range(0, 31) as $bit) {
+ foreach ($databox->getStatusStructure()->getBits() as $bit) {
$rules[$databoxId][$collectionId][$bit] = $this->computeAccess(
$mask_xor,
$mask_and,
diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticsearchRecordHydrator.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticsearchRecordHydrator.php
index a105926f4e..75b4372318 100644
--- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticsearchRecordHydrator.php
+++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticsearchRecordHydrator.php
@@ -37,7 +37,7 @@ class ElasticsearchRecordHydrator
$updatedOn = igorw\get_in($data, ['updated_on']);
$record->setUpdated($updatedOn ? new \DateTime($updatedOn) : $updatedOn);
$record->setUuid(igorw\get_in($data, ['uuid'], ''));
- $record->setStatus(igorw\get_in($data, ['flags_bitmask'], 0));
+ $record->setStatusBitField(igorw\get_in($data, ['flags_bit_value'], 0));
$record->setTitles(new ArrayCollection((array) igorw\get_in($data, ['title'], [])));
$record->setCaption(new ArrayCollection((array) igorw\get_in($data, ['caption'], [])));
$record->setExif(new ArrayCollection((array) igorw\get_in($data, ['exif'], [])));
diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Indexer/RecordIndexer.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Indexer/RecordIndexer.php
index d8dc9d58e0..ccef87c4e2 100644
--- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Indexer/RecordIndexer.php
+++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Indexer/RecordIndexer.php
@@ -250,6 +250,7 @@ class RecordIndexer
$mapping->add('caption', $captionMapping);
$privateCaptionMapping = new Mapping();
$mapping->add('private_caption', $privateCaptionMapping);
+
foreach ($this->getFieldsStructure() as $name => $params) {
$m = $params['private'] ? $privateCaptionMapping : $captionMapping;
$m->add($name, $params['type']);
@@ -319,7 +320,7 @@ class RecordIndexer
$mapping = new Mapping();
foreach ($this->appbox->get_databoxes() as $databox) {
- foreach ($databox->get_statusbits() as $bit => $status) {
+ foreach ($databox->getStatusStructure() as $bit => $status) {
$key = RecordHelper::normalizeFlagKey($status['labelon']);
// We only add to mapping new statuses
if (!$mapping->has($key)) {
@@ -345,10 +346,10 @@ class RecordIndexer
$structure = $this->getFieldsStructure();
$databox = $this->appbox->get_databox($record['databox_id']);
- foreach ($databox->get_statusbits() as $bit => $status) {
+ foreach ($databox->getStatusStructure() as $bit => $status) {
$key = RecordHelper::normalizeFlagKey($status['labelon']);
- $record['flags'][$key] = \databox_status::bitIsSet($record['flags_bitmask'], $bit);
+ $record['flags'][$key] = \databox_status::bitIsSet($record['flags_bit_value'], $bit);
}
foreach ($dateFields as $field) {
diff --git a/lib/Alchemy/Phrasea/SearchEngine/SphinxSearch/SphinxSearchEngine.php b/lib/Alchemy/Phrasea/SearchEngine/SphinxSearch/SphinxSearchEngine.php
index 4eb9c78618..686e125f92 100644
--- a/lib/Alchemy/Phrasea/SearchEngine/SphinxSearch/SphinxSearchEngine.php
+++ b/lib/Alchemy/Phrasea/SearchEngine/SphinxSearch/SphinxSearchEngine.php
@@ -647,7 +647,7 @@ class SphinxSearchEngine implements SearchEngineInterface
*/
$status_opts = $options->getStatus();
foreach ($options->getDataboxes() as $databox) {
- foreach ($databox->get_statusbits() as $n => $status) {
+ foreach ($databox->getStatusStructure() as $n => $status) {
if (!array_key_exists($n, $status_opts))
continue;
if (!array_key_exists($databox->get_sbas_id(), $status_opts[$n]))
diff --git a/lib/Alchemy/Phrasea/Status/CacheStatusStructureProvider.php b/lib/Alchemy/Phrasea/Status/CacheStatusStructureProvider.php
new file mode 100644
index 0000000000..77e81bcfbe
--- /dev/null
+++ b/lib/Alchemy/Phrasea/Status/CacheStatusStructureProvider.php
@@ -0,0 +1,72 @@
+cache = $cache;
+ $this->provider = $provider;
+ }
+
+ public function getStructure(\databox $databox)
+ {
+ if (false !== ($status = $this->cache->fetch($this->get_cache_key($databox->get_sbas_id())))) {
+
+ return new StatusStructure($databox, new ArrayCollection(json_decode($status, true)));
+ }
+
+ $structure = $this->provider->getStructure($databox);
+
+ $this->cache->save($this->get_cache_key($databox->get_sbas_id()), json_encode($structure->toArray()));
+
+ return $structure;
+ }
+
+ public function deleteStatus(StatusStructure $structure, $bit)
+ {
+ $databox = $structure->getDatabox();
+
+ $this->provider->deleteStatus($structure, $bit);
+
+ $this->cache->save($this->get_cache_key($databox->get_sbas_id()), json_encode($structure->toArray()));
+
+ return $structure;
+ }
+
+ public function updateStatus(StatusStructure $structure, $bit, array $properties)
+ {
+ $databox = $structure->getDatabox();
+
+ $this->provider->updateStatus($structure, $bit, $properties);
+
+ $this->cache->save($this->get_cache_key($databox->get_sbas_id()), json_encode($structure->toArray()));
+
+ return $structure;
+ }
+
+ private function get_cache_key($databox_id)
+ {
+ return sprintf('status_%s', $databox_id);
+ }
+}
diff --git a/lib/Alchemy/Phrasea/Status/StatusStructure.php b/lib/Alchemy/Phrasea/Status/StatusStructure.php
new file mode 100644
index 0000000000..6496536267
--- /dev/null
+++ b/lib/Alchemy/Phrasea/Status/StatusStructure.php
@@ -0,0 +1,145 @@
+databox = $databox;
+ $this->status = $status ?: new ArrayCollection();
+
+ $unique_id = md5(implode('-', array(
+ $this->databox->get_host(),
+ $this->databox->get_port(),
+ $this->databox->get_dbname()
+ )));
+
+ // path to status icon
+ $this->path = __DIR__ . "/../../../../config/status/" . $unique_id;
+ // url to status icon
+ $this->url = "/custom/status/" . $unique_id;
+ }
+
+ public function getIterator()
+ {
+ return $this->status->getIterator();
+ }
+
+ /**
+ * Get url to status icons
+ *
+ * @return string
+ */
+ public function getUrl()
+ {
+ return $this->url;
+ }
+
+ /**
+ * Get path to status icons
+ *
+ * @return string
+ */
+ public function getPath()
+ {
+ return $this->path;
+ }
+
+ /**
+ * Get databox where belong status
+ *
+ * @return \databox
+ */
+ public function getDatabox()
+ {
+ return $this->databox;
+ }
+
+ /**
+ * Get the bits used in structure
+ * $
+ * @return array[] int
+ */
+ public function getBits()
+ {
+ return $this->status->getKeys();
+ }
+
+ /**
+ * Set new status at nth position
+ *
+ * @param int $nthBit
+ * @param array $status
+ *
+ * @return $this
+ */
+ public function setStatus($nthBit, array $status)
+ {
+ $this->status->set($nthBit, $status);
+
+ return $this;
+ }
+
+ /**
+ * Check whether structure has nth status set
+ *
+ * @param int $nthBit
+ *
+ * @return bool
+ */
+ public function hasStatus($nthBit)
+ {
+ return $this->status->containsKey($nthBit);
+ }
+
+ /**
+ * Get status at nth position
+ *
+ * @param int $nthBit
+ *
+ * @return array|null
+ */
+ public function getStatus($nthBit)
+ {
+ return $this->status->get($nthBit);
+ }
+
+ /**
+ * Remove status at nth position
+ *
+ * @param int $nthBit
+ *
+ * @return $this
+ */
+ public function removeStatus($nthBit)
+ {
+ $this->status->remove($nthBit);
+
+ return $this;
+ }
+
+ public function toArray()
+ {
+ return $this->status->toArray();
+ }
+}
diff --git a/lib/Alchemy/Phrasea/Status/StatusStructureFactory.php b/lib/Alchemy/Phrasea/Status/StatusStructureFactory.php
new file mode 100644
index 0000000000..73f9963a1a
--- /dev/null
+++ b/lib/Alchemy/Phrasea/Status/StatusStructureFactory.php
@@ -0,0 +1,57 @@
+provider = $provider;
+ }
+
+ /**
+ * Get the status structure according to the given databox
+ *
+ * @param \databox $databox
+ *
+ * @return StatusStructure
+ */
+ public function getStructure(\databox $databox)
+ {
+ $databox_id = $databox->get_sbas_id();
+
+ if (isset($this->statusStructure[$databox_id])) {
+ return $this->statusStructure[$databox_id];
+ }
+
+ $this->statusStructure[$databox_id] = $this->provider->getStructure($databox);
+
+ return $this->statusStructure[$databox_id];
+ }
+}
diff --git a/lib/Alchemy/Phrasea/Status/StatusStructureProviderInterface.php b/lib/Alchemy/Phrasea/Status/StatusStructureProviderInterface.php
new file mode 100644
index 0000000000..3311072a5f
--- /dev/null
+++ b/lib/Alchemy/Phrasea/Status/StatusStructureProviderInterface.php
@@ -0,0 +1,47 @@
+rootPath = $rootPath;
+ $this->locales = $locales;
+ $this->fs = $fs ?: new Filesystem();
+ }
+
+ public function getStructure(\databox $databox)
+ {
+ $statusStructure = new StatusStructure($databox);
+
+ $xmlPref = $databox->get_structure();
+ $sxe = simplexml_load_string($xmlPref);
+
+ if ($sxe === false) {
+ throw new \Exception('Failed to load database XML structure');
+ }
+
+ foreach ($sxe->statbits->bit as $sb) {
+ $bit = (int) ($sb['n']);
+ if ($bit < 4 && $bit > 31) {
+ continue;
+ }
+
+ $status = [];
+
+ $status['bit'] = $bit;
+
+ $status['labeloff'] = (string) $sb['labelOff'];
+ $status['labelon'] = (string) $sb['labelOn'];
+
+ foreach ($this->locales as $code => $language) {
+ $status['labels_on'][$code] = null;
+ $status['labels_off'][$code] = null;
+ }
+
+ foreach ($sb->label as $label) {
+ $status['labels_'.$label['switch']][(string) $label['code']] = (string) $label;
+ }
+
+ foreach ($this->locales as $code => $language) {
+ $status['labels_on_i18n'][$code] = '' !== trim($status['labels_on'][$code]) ? $status['labels_on'][$code] : $status['labelon'];
+ $status['labels_off_i18n'][$code] = '' !== trim($status['labels_off'][$code]) ? $status['labels_off'][$code] : $status['labeloff'];
+ }
+
+ $status['img_off'] = null;
+ $status['img_on'] = null;
+
+ if (is_file($statusStructure->getPath() . '-stat_' . $bit . '_0.gif')) {
+ $status['img_off'] = $statusStructure->getUrl() . '-stat_' . $bit . '_0.gif?etag='.md5_file($statusStructure->getPath() . '-stat_' . $bit . '_0.gif');
+ $status['path_off'] = $statusStructure->getPath() . '-stat_' . $bit . '_0.gif';
+ }
+ if (is_file($statusStructure->getPath() . '-stat_' . $bit . '_1.gif')) {
+ $status['img_on'] = $statusStructure->getUrl() . '-stat_' . $bit . '_1.gif?etag='.md5_file($statusStructure->getPath() . '-stat_' . $bit . '_1.gif');
+ $status['path_on'] = $statusStructure->getPath() . '-stat_' . $bit . '_1.gif';
+ }
+
+ $status['searchable'] = isset($sb['searchable']) ? (int) $sb['searchable'] : 0;
+ $status['printable'] = isset($sb['printable']) ? (int) $sb['printable'] : 0;
+
+ $statusStructure->setStatus($bit, $status);
+ }
+
+ return $statusStructure;
+ }
+
+ public function deleteStatus(StatusStructure $statusStructure, $bit)
+ {
+ $databox = $statusStructure->getDatabox();
+
+ if (false === $statusStructure->hasStatus($bit)) {
+ return false;
+ }
+
+ $doc = $databox->get_dom_structure();
+
+ if (!$doc) {
+ return false;
+ }
+
+ $xpath = $databox->get_xpath_structure();
+ $entries = $xpath->query('/record/statbits/bit[@n=' . $bit . ']');
+
+ foreach ($entries as $sbit) {
+ if ($p = $sbit->previousSibling) {
+ if ($p->nodeType == XML_TEXT_NODE && $p->nodeValue == '\n\t\t')
+ $p->parentNode->removeChild($p);
+ }
+ if ($sbit->parentNode->removeChild($sbit)) {
+ $sql = 'UPDATE record SET status = status&(~(1<<' . $bit . '))';
+ $stmt = $databox->get_connection()->prepare($sql);
+ $stmt->execute();
+ $stmt->closeCursor();
+ }
+ }
+
+ $databox->saveStructure($doc);
+
+ $status = $statusStructure->getStatus($bit);
+
+ if (null !== $status['img_off']) {
+ $this->fs->remove($status['path_off']);
+ }
+
+ if (null !== $status['img_on']) {
+ $this->fs->remove($status['path_on']);
+ }
+
+ $statusStructure->removeStatus($bit);
+
+ return $statusStructure;
+ }
+
+ public function updateStatus(StatusStructure $statusStructure, $bit, array $properties)
+ {
+ $databox = $statusStructure->getDatabox();
+
+ if (false === $statusStructure->hasStatus($bit)) {
+ $statusStructure->setStatus($bit, []);
+ }
+
+ $doc = $databox->get_dom_structure();
+
+ if (!$doc) {
+ return false;
+ }
+
+ $xpath = $databox->get_xpath_structure();
+ $entries = $xpath->query('/record/statbits');
+
+ if ($entries->length == 0) {
+ $statbits = $doc->documentElement->appendChild($doc->createElement('statbits'));
+ } else {
+ $statbits = $entries->item(0);
+ }
+
+ if ($statbits) {
+ $entries = $xpath->query('/record/statbits/bit[@n=' . $bit . ']');
+
+ if ($entries->length >= 1) {
+ foreach ($entries as $k => $sbit) {
+ if ($p = $sbit->previousSibling) {
+ if ($p->nodeType == XML_TEXT_NODE && $p->nodeValue == '\n\t\t')
+ $p->parentNode->removeChild($p);
+ }
+ $sbit->parentNode->removeChild($sbit);
+ }
+ }
+
+ $sbit = $statbits->appendChild($doc->createElement('bit'));
+
+ if ($n = $sbit->appendChild($doc->createAttribute('n'))) {
+ $n->value = $bit;
+ }
+
+ if ($labOn = $sbit->appendChild($doc->createAttribute('labelOn'))) {
+ $labOn->value = $properties['labelon'];
+ }
+
+ if ($searchable = $sbit->appendChild($doc->createAttribute('searchable'))) {
+ $searchable->value = $properties['searchable'];
+ }
+
+ if ($printable = $sbit->appendChild($doc->createAttribute('printable'))) {
+ $printable->value = $properties['printable'];
+ }
+
+ if ($labOff = $sbit->appendChild($doc->createAttribute('labelOff'))) {
+ $labOff->value = $properties['labeloff'];
+ }
+
+ foreach ($properties['labels_off'] as $code => $label) {
+ $labelTag = $sbit->appendChild($doc->createElement('label'));
+ $switch = $labelTag->appendChild($doc->createAttribute('switch'));
+ $switch->value = 'off';
+ $codeTag = $labelTag->appendChild($doc->createAttribute('code'));
+ $codeTag->value = $code;
+ $labelTag->appendChild($doc->createTextNode($label));
+ }
+
+ foreach ($properties['labels_on'] as $code => $label) {
+ $labelTag = $sbit->appendChild($doc->createElement('label'));
+ $switch = $labelTag->appendChild($doc->createAttribute('switch'));
+ $switch->value = 'on';
+ $codeTag = $labelTag->appendChild($doc->createAttribute('code'));
+ $codeTag->value = $code;
+ $labelTag->appendChild($doc->createTextNode($label));
+ }
+ }
+
+ $databox->saveStructure($doc);
+
+ $status = $statusStructure->getStatus($bit);
+
+ $status['labelon'] = $properties['labelon'];
+ $status['labeloff'] = $properties['labeloff'];
+ $status['searchable'] = (Boolean) $properties['searchable'];
+ $status['printable'] = (Boolean) $properties['printable'];
+
+ if (!isset($properties['img_on'])) {
+ $status['img_on'] = null;
+ }
+
+ if (!isset($properties['img_off'])) {
+ $status['img_off'] = null;
+ }
+
+ $statusStructure->setStatus($bit, $status);
+
+ return $statusStructure;
+ }
+}
diff --git a/lib/Alchemy/Phrasea/Twig/PhraseanetExtension.php b/lib/Alchemy/Phrasea/Twig/PhraseanetExtension.php
index 0624d7d3c2..d42c14cb76 100644
--- a/lib/Alchemy/Phrasea/Twig/PhraseanetExtension.php
+++ b/lib/Alchemy/Phrasea/Twig/PhraseanetExtension.php
@@ -37,9 +37,41 @@ class PhraseanetExtension extends \Twig_Extension
new \Twig_SimpleFunction('collection_logo', array($this, 'getCollectionLogo'), array(
'is_safe' => array('html')
)),
+ new \Twig_SimpleFunction('record_flags', array($this, 'getRecordFlags'))
);
}
+ public function getRecordFlags(RecordInterface $record)
+ {
+ $recordStatuses = [];
+ $databox = $this->app['phraseanet.appbox']->get_databox($record->getDataboxId());
+
+ $structure = $databox->getStatusStructure()->toArray();
+
+ if (!$this->isGrantedOnCollection($record->getBaseId(), '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;
+ }
+
public function isGrantedOnDatabox($databoxId, $rights)
{
if (false === ($this->app['authentication']->getUser() instanceof User)) {
diff --git a/lib/classes/ACL.php b/lib/classes/ACL.php
index 303a888abb..b855ebfe1b 100644
--- a/lib/classes/ACL.php
+++ b/lib/classes/ACL.php
@@ -210,7 +210,7 @@ class ACL implements cache_cacheableInterface
public function has_status_access_to_record(RecordInterface $record)
{
- return 0 === ((bindec($record->getStatus()) ^ $this->get_mask_xor($record->getBaseId())) & $this->get_mask_and($record->getBaseId()));
+ return 0 === ((bindec($record->getStatusBitField()) ^ $this->get_mask_xor($record->getBaseId())) & $this->get_mask_and($record->getBaseId()));
}
public function has_access_to_subdef(RecordInterface $record, $subdef_name)
diff --git a/lib/classes/databox.php b/lib/classes/databox.php
index fbcb27922d..3e865e9709 100644
--- a/lib/classes/databox.php
+++ b/lib/classes/databox.php
@@ -307,9 +307,9 @@ class databox extends base
*
* @return databox_status
*/
- public function get_statusbits()
+ public function getStatusStructure()
{
- return databox_status::getStatus($this->app, $this->id);
+ return $this->app['factory.status-structure']->getStructure($this);
}
/**
diff --git a/lib/classes/databox/status.php b/lib/classes/databox/status.php
index 575762879d..a3d429ebed 100644
--- a/lib/classes/databox/status.php
+++ b/lib/classes/databox/status.php
@@ -11,385 +11,101 @@
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\SearchEngine\Elastic\RecordHelper;
-use MediaAlchemyst\Specification\Image as ImageSpecification;
use Symfony\Component\HttpFoundation\File\UploadedFile;
+use Alchemy\Phrasea\Exception\InvalidArgumentException;
+use MediaAlchemyst\Specification\Image as ImageSpecification;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
+use Alchemy\Phrasea\Model\RecordInterface;
class databox_status
{
- /**
- *
- * @var Array
- */
- private static $_status = [];
-
- /**
- *
- * @var Array
- */
- protected static $_statuses;
-
- /**
- *
- * @var Array
- */
- private $status = [];
-
- /**
- *
- * @var string
- */
- private $path = '';
-
- /**
- *
- * @var string
- */
- private $url = '';
-
- /**
- *
- * @param int $sbas_id
- * @return status
- */
- private function __construct(Application $app, $sbas_id)
- {
- $this->status = [];
-
- $path = $url = false;
-
- $sbas_params = phrasea::sbas_params($app);
-
- if ( ! isset($sbas_params[$sbas_id])) {
- return;
- }
-
- $uniqid = md5(implode('-', [
- $sbas_params[$sbas_id]["host"],
- $sbas_params[$sbas_id]["port"],
- $sbas_params[$sbas_id]["dbname"]
- ]));
-
- $path = $this->path = $app['root.path'] . "/config/status/" . $uniqid;
- $url = $this->url = "/custom/status/" . $uniqid;
-
- $databox = $app['phraseanet.appbox']->get_databox((int) $sbas_id);
- $xmlpref = $databox->get_structure();
- $sxe = simplexml_load_string($xmlpref);
-
- if ($sxe !== false) {
-
- foreach ($sxe->statbits->bit as $sb) {
- $bit = (int) ($sb["n"]);
- if ($bit < 4 && $bit > 31)
- continue;
-
- $this->status[$bit]["labeloff"] = (string) $sb['labelOff'];
- $this->status[$bit]["labelon"] = (string) $sb['labelOn'];
-
- foreach ($app['locales.available'] as $code => $language) {
- $this->status[$bit]['labels_on'][$code] = null;
- $this->status[$bit]['labels_off'][$code] = null;
- }
-
- foreach ($sb->label as $label) {
- $this->status[$bit]['labels_'.$label['switch']][(string) $label['code']] = (string) $label;
- }
-
- foreach ($app['locales.available'] as $code => $language) {
- $this->status[$bit]['labels_on_i18n'][$code] = '' !== trim($this->status[$bit]['labels_on'][$code]) ? $this->status[$bit]['labels_on'][$code] : $this->status[$bit]["labelon"];
- $this->status[$bit]['labels_off_i18n'][$code] = '' !== trim($this->status[$bit]['labels_off'][$code]) ? $this->status[$bit]['labels_off'][$code] : $this->status[$bit]["labeloff"];
- }
-
- $this->status[$bit]["img_off"] = null;
- $this->status[$bit]["img_on"] = null;
-
- if (is_file($path . "-stat_" . $bit . "_0.gif")) {
- $this->status[$bit]["img_off"] = $url . "-stat_" . $bit . "_0.gif?etag=".md5_file($path . "-stat_" . $bit . "_0.gif");
- $this->status[$bit]["path_off"] = $path . "-stat_" . $bit . "_0.gif";
- }
- if (is_file($path . "-stat_" . $bit . "_1.gif")) {
- $this->status[$bit]["img_on"] = $url . "-stat_" . $bit . "_1.gif?etag=".md5_file($path . "-stat_" . $bit . "_1.gif");
- $this->status[$bit]["path_on"] = $path . "-stat_" . $bit . "_1.gif";
- }
-
- $this->status[$bit]["searchable"] = isset($sb['searchable']) ? (int) $sb['searchable'] : 0;
- $this->status[$bit]["printable"] = isset($sb['printable']) ? (int) $sb['printable'] : 0;
- }
- }
- ksort($this->status);
-
- return $this;
- }
-
- public static function getStatus(Application $app, $sbas_id)
- {
-
- if ( ! isset(self::$_status[$sbas_id]))
- self::$_status[$sbas_id] = new databox_status($app, $sbas_id);
-
-
- return self::$_status[$sbas_id]->status;
- }
-
- public static function getDisplayStatus(Application $app)
- {
- if (self::$_statuses) {
- return self::$_statuses;
- }
-
- $sbas_ids = $app['acl']->get($app['authentication']->getUser())->get_granted_sbas();
-
- $statuses = [];
-
- foreach ($sbas_ids as $databox) {
- try {
- $statuses[$databox->get_sbas_id()] = $databox->get_statusbits();
- } catch (\Exception $e) {
-
- }
- }
-
- self::$_statuses = $statuses;
-
- return self::$_statuses;
- }
-
public static function getSearchStatus(Application $app)
{
- $statuses = $see_all = [];
- $databoxes = $app['acl']->get($app['authentication']->getUser())->get_granted_sbas();
-
- foreach ($databoxes as $databox) {
+ $see_all = $structures = $stats = [];
+ foreach ($app['acl']->get($app['authentication']->getUser())->get_granted_sbas() as $databox) {
$see_all[$databox->get_sbas_id()] = false;
-
foreach ($databox->get_collections() as $collection) {
if ($app['acl']->get($app['authentication']->getUser())->has_right_on_base($collection->get_base_id(), 'chgstatus')) {
$see_all[$databox->get_sbas_id()] = true;
break;
}
}
-
- try {
- $statuses[$databox->get_sbas_id()] = $databox->get_statusbits();
- } catch (\Exception $e) {
-
- }
+ $structures[$databox->get_sbas_id()] = $databox->getStatusStructure();
}
- $stats = [];
+ foreach ($structures as $databox_id => $structure) {
+ if (false === $see_all[$databox_id]) {
+ $structure = array_filter(function($status) {
+ return (bool) $status['searchable'];
+ }, $structure->toArray());
+ }
- foreach ($statuses as $databox_id => $status) {
- $canSeeAll = isset($see_all[$databox_id]) ? $see_all[$databox_id] : false;
- $canSeeThis = $app['acl']->get($app['authentication']->getUser())->has_right_on_sbas($databox_id, 'bas_modify_struct');
+ foreach($structure as $bit => $status) {
+ $key = RecordHelper::normalizeFlagKey($status['labelon']);
- $canAccess = $canSeeAll || $canSeeThis;
-
- foreach ($status as $bit => $props) {
- if (!$props['searchable'] && !$canAccess) {
- continue;
+ if (isset($stats[$key])) {
+ $status = $stats[$key];
}
- $stats[$databox_id][$bit] = array(
- 'name' => RecordHelper::normalizeFlagKey($props['labelon']),
- 'labeloff' => $props['labeloff'],
- 'labelon' => $props['labelon'],
- 'labels_on_i18n' => $props['labels_on_i18n'],
- 'labels_off_i18n' => $props['labels_off_i18n'],
- 'imgoff' => $props['img_off'],
- 'imgon' => $props['img_on']
- );
+
+ $status['sbas'][] = $databox_id;
+ $status['bit'] = $bit;
+
+ $stats[$key] = $status;
}
}
-
return $stats;
}
- public static function getPath(Application $app, $sbas_id)
+ public static function deleteIcon(Application $app, $databox_id, $bit, $switch)
{
- if ( ! isset(self::$_status[$sbas_id])) {
- self::$_status[$sbas_id] = new databox_status($app, $sbas_id);
+ $databox = $app['phraseanet.appbox']->get_databox($databox_id);
+
+ $statusStructure = $app['factory.status-structure']->getStructure($databox);
+
+ if (!$statusStructure->hasStatus($bit)) {
+ throw new InvalidArgumentException(sprintf('bit %s does not exists on database %s', $bit, $statusStructure->getDatabox()->get_dbname()));
}
- return self::$_status[$sbas_id]->path;
- }
-
- public static function getUrl(Application $app, $sbas_id)
- {
- if ( ! isset(self::$_status[$sbas_id])) {
- self::$_status[$sbas_id] = new databox_status($app, $sbas_id);
- }
-
- return self::$_status[$sbas_id]->url;
- }
-
- public static function deleteStatus(Application $app, \databox $databox, $bit)
- {
- $status = self::getStatus($app, $databox->get_sbas_id());
-
- if (isset($status[$bit])) {
- $doc = $databox->get_dom_structure();
- if ($doc) {
- $xpath = $databox->get_xpath_structure();
- $entries = $xpath->query("/record/statbits/bit[@n=" . $bit . "]");
-
- foreach ($entries as $sbit) {
- if ($p = $sbit->previousSibling) {
- if ($p->nodeType == XML_TEXT_NODE && $p->nodeValue == "\n\t\t")
- $p->parentNode->removeChild($p);
- }
- if ($sbit->parentNode->removeChild($sbit)) {
- $sql = 'UPDATE record SET status = status&(~(1<<' . $bit . '))';
- $stmt = $databox->get_connection()->prepare($sql);
- $stmt->execute();
- $stmt->closeCursor();
- }
- }
-
- $databox->saveStructure($doc);
-
- if (null !== $status[$bit]['img_off']) {
- $app['filesystem']->remove($status[$bit]['path_off']);
- }
-
- if (null !== $status[$bit]['img_on']) {
- $app['filesystem']->remove($status[$bit]['path_on']);
- }
-
- unset(self::$_status[$databox->get_sbas_id()]->status[$bit]);
-
- $app['dispatcher']->dispatch(RecordStructureEvents::STATUS_BIT_DELETED, new StatusBitDeletedEvent($databox, $bit));
-
- return true;
- }
- }
-
- return false;
- }
-
- public static function updateStatus(Application $app, $sbas_id, $bit, $properties)
- {
- self::getStatus($app, $sbas_id);
-
- $databox = $app['phraseanet.appbox']->get_databox((int) $sbas_id);
-
- $doc = $databox->get_dom_structure($sbas_id);
- if ($doc) {
- $xpath = $databox->get_xpath_structure($sbas_id);
- $entries = $xpath->query("/record/statbits");
- if ($entries->length == 0) {
- $statbits = $doc->documentElement->appendChild($doc->createElement("statbits"));
- } else {
- $statbits = $entries->item(0);
- }
-
- if ($statbits) {
- $entries = $xpath->query("/record/statbits/bit[@n=" . $bit . "]");
-
- if ($entries->length >= 1) {
- foreach ($entries as $k => $sbit) {
- if ($p = $sbit->previousSibling) {
- if ($p->nodeType == XML_TEXT_NODE && $p->nodeValue == "\n\t\t")
- $p->parentNode->removeChild($p);
- }
- $sbit->parentNode->removeChild($sbit);
- }
- }
-
- $sbit = $statbits->appendChild($doc->createElement("bit"));
-
- if ($n = $sbit->appendChild($doc->createAttribute("n"))) {
- $n->value = $bit;
- }
-
- if ($labOn = $sbit->appendChild($doc->createAttribute("labelOn"))) {
- $labOn->value = $properties['labelon'];
- }
-
- if ($searchable = $sbit->appendChild($doc->createAttribute("searchable"))) {
- $searchable->value = $properties['searchable'];
- }
-
- if ($printable = $sbit->appendChild($doc->createAttribute("printable"))) {
- $printable->value = $properties['printable'];
- }
-
- if ($labOff = $sbit->appendChild($doc->createAttribute("labelOff"))) {
- $labOff->value = $properties['labeloff'];
- }
-
- foreach ($properties['labels_off'] as $code => $label) {
- $labelTag = $sbit->appendChild($doc->createElement("label"));
- $switch = $labelTag->appendChild($doc->createAttribute("switch"));
- $switch->value = 'off';
- $codeTag = $labelTag->appendChild($doc->createAttribute("code"));
- $codeTag->value = $code;
- $labelTag->appendChild($doc->createTextNode($label));
- }
-
- foreach ($properties['labels_on'] as $code => $label) {
- $labelTag = $sbit->appendChild($doc->createElement("label"));
- $switch = $labelTag->appendChild($doc->createAttribute("switch"));
- $switch->value = 'on';
- $codeTag = $labelTag->appendChild($doc->createAttribute("code"));
- $codeTag->value = $code;
- $labelTag->appendChild($doc->createTextNode($label));
- }
- }
-
- $databox->saveStructure($doc);
-
- self::$_status[$sbas_id]->status[$bit]["labelon"] = $properties['labelon'];
- self::$_status[$sbas_id]->status[$bit]["labeloff"] = $properties['labeloff'];
- self::$_status[$sbas_id]->status[$bit]["searchable"] = (Boolean) $properties['searchable'];
- self::$_status[$sbas_id]->status[$bit]["printable"] = (Boolean) $properties['printable'];
-
- if ( ! isset(self::$_status[$sbas_id]->status[$bit]['img_on'])) {
- self::$_status[$sbas_id]->status[$bit]['img_on'] = null;
- }
-
- if ( ! isset(self::$_status[$sbas_id]->status[$bit]['img_off'])) {
- self::$_status[$sbas_id]->status[$bit]['img_off'] = null;
- }
-
- $properties = self::$_status[$sbas_id]->status[$bit];
- $app['dispatcher']->dispatch(RecordStructureEvents::STATUS_BIT_UPDATED, new StatusBitUpdatedEvent($databox, $bit, $properties));
- }
-
- return false;
- }
-
- public static function deleteIcon(Application $app, $sbas_id, $bit, $switch)
- {
- $status = self::getStatus($app, $sbas_id);
+ $status = $statusStructure->getStatus($bit);
$switch = in_array($switch, ['on', 'off']) ? $switch : false;
- if (! $switch) {
+ if (!$switch) {
return false;
}
- if ($status[$bit]['img_' . $switch]) {
- if (isset($status[$bit]['path_' . $switch])) {
- $app['filesystem']->remove($status[$bit]['path_' . $switch]);
+ if ($status['img_' . $switch]) {
+ if (isset($status['path_' . $switch])) {
+ $app['filesystem']->remove($status['path_' . $switch]);
}
- $status[$bit]['img_' . $switch] = false;
- unset($status[$bit]['path_' . $switch]);
+ $status['img_' . $switch] = false;
+ unset($status['path_' . $switch]);
}
return true;
}
- public static function updateIcon(Application $app, $sbas_id, $bit, $switch, UploadedFile $file)
+ public static function updateIcon(Application $app, $databox_id, $bit, $switch, UploadedFile $file)
{
+ $databox = $app['phraseanet.appbox']->get_databox($databox_id);
+
+ $statusStructure = $app['factory.status-structure']->getStructure($databox);
+
+ if (!$statusStructure->hasStatus($bit)) {
+ throw new InvalidArgumentException(sprintf('bit %s does not exists', $bit));
+ }
+
+ $status = $statusStructure->getStatus($bit);
+
$switch = in_array($switch, ['on', 'off']) ? $switch : false;
- if (! $switch) {
+ if (!$switch) {
throw new Exception_InvalidArgument();
}
- $url = self::getUrl($app, $sbas_id);
- $path = self::getPath($app, $sbas_id);
+ $url = $statusStructure->getUrl();
+ $path = $statusStructure->getPath();
if ($file->getSize() >= 65535) {
throw new Exception_Upload_FileTooBig();
@@ -399,7 +115,7 @@ class databox_status
throw new Exception_Upload_Error();
}
- self::deleteIcon($app, $sbas_id, $bit, $switch);
+ self::deleteIcon($app, $databox_id, $bit, $switch);
$name = "-stat_" . $bit . "_" . ($switch == 'on' ? '1' : '0') . ".gif";
@@ -427,8 +143,8 @@ class databox_status
}
- self::$_status[$sbas_id]->status[$bit]['img_' . $switch] = $url . $name;
- self::$_status[$sbas_id]->status[$bit]['path_' . $switch] = $filePath;
+ $status['img_' . $switch] = $url . $name;
+ $status['path_' . $switch] = $filePath;
return true;
}
@@ -607,13 +323,8 @@ class databox_status
return $status;
}
- public static function purge()
+ public static function bitIsSet($bitValue, $nthBit)
{
- self::$_status = self::$_statuses = [];
- }
-
- public static function bitIsSet($bitMask, $nthBit)
- {
- return (bool) ($bitMask & (1 << $nthBit));
+ return (bool) ($bitValue & (1 << $nthBit));
}
}
diff --git a/lib/classes/record/adapter.php b/lib/classes/record/adapter.php
index 2d40a6aee3..6ba47873ec 100644
--- a/lib/classes/record/adapter.php
+++ b/lib/classes/record/adapter.php
@@ -29,6 +29,7 @@ use Doctrine\ORM\EntityManager;
use Doctrine\Common\Collections\ArrayCollection;
use MediaVorus\MediaVorus;
use Rhumsaa\Uuid\Uuid;
+use Alchemy\Phrasea\Status\StatusStructure;
use Alchemy\Phrasea\Model\RecordInterface;
use Symfony\Component\HttpFoundation\File\File as SymfoFile;
use Alchemy\Phrasea\Core\PhraseaTokens;
@@ -381,61 +382,6 @@ class record_adapter implements RecordInterface, cache_cacheableInterface
return $this->getSubdfefByDeviceAndMime($devices, $mimes);
}
- /**
- *
- * @return string
- */
- public function get_status_icons()
- {
- $dstatus = databox_status::getDisplayStatus($this->app);
- $sbas_id = $this->get_sbas_id();
-
- $status = '';
-
- if (isset($dstatus[$sbas_id])) {
- foreach ($dstatus[$sbas_id] as $n => $statbit) {
- if ($statbit['printable'] == '0' &&
- !$this->app['acl']->get($this->app['authentication']->getUser())->has_right_on_base($this->base_id, 'chgstatus')) {
- continue;
- }
-
- $x = (substr((strrev($this->get_status())), $n, 1));
-
- $source0 = "/skins/icons/spacer.gif";
- $style0 = "visibility:hidden;display:none;";
- $source1 = "/skins/icons/spacer.gif";
- $style1 = "visibility:hidden;display:none;";
- if ($statbit["img_on"]) {
- $source1 = $statbit["img_on"];
- $style1 = "visibility:auto;display:none;";
- }
- if ($statbit["img_off"]) {
- $source0 = $statbit["img_off"];
- $style0 = "visibility:auto;display:none;";
- }
- if ($x == '1') {
- if ($statbit["img_on"]) {
- $style1 = "visibility:auto;display:inline;";
- }
- } else {
- if ($statbit["img_off"]) {
- $style0 = "visibility:auto;display:inline;";
- }
- }
- $status .= 'base_id . '_'
- . $this->record_id . '_' . $n . '_1" ' .
- 'src="' . $source1 . '" title="' . $statbit['labels_on_i18n'][$this->app['locale']] . '"/>';
- $status .= '
base_id . '_'
- . $this->record_id . '_' . $n . '_0" ' .
- 'src="' . $source0 . '" title="' . $statbit['labels_off_i18n'][$this->app['locale']] . '"/>';
- }
- }
-
- return $status;
- }
-
/**
* Returns the type of the document
*
@@ -1601,8 +1547,6 @@ class record_adapter implements RecordInterface, cache_cacheableInterface
}
$databox = $this->get_databox();
- \cache_databox::update($this->app, $this->get_sbas_id(), 'record', $this->get_record_id());
-
return $databox->delete_data_from_cache($this->get_cache_key($option));
}
@@ -1947,9 +1891,9 @@ class record_adapter implements RecordInterface, cache_cacheableInterface
}
/** {@inheritdoc} */
- public function getStatus()
+ public function getStatusBitField()
{
- return $this->get_status();
+ return bindec($this->get_status());
}
/** {@inheritdoc} */
diff --git a/templates/web/admin/statusbit.html.twig b/templates/web/admin/statusbit.html.twig
index 0a15ca07d8..f410040bdd 100644
--- a/templates/web/admin/statusbit.html.twig
+++ b/templates/web/admin/statusbit.html.twig
@@ -1,4 +1,4 @@
-{% set status = databox.get_statusbits() %}
+{% set statusStructure = databox.getStatusStructure() %}
{% set databox_id = databox.get_sbas_id() %}