#PHRAS-874 time 2d

type hinting / cs
events renamed / deleted
n+1 removed for status-bits & technical meta
events added (subdef creation / created)
fix : es indexes after all subdefs are created
This commit is contained in:
Jean-Yves Gaulier
2015-12-17 20:07:48 +01:00
parent 621d9dc7a5
commit 80f3285737
43 changed files with 363 additions and 439 deletions

View File

@@ -246,7 +246,7 @@ class File
/**
* Returns an array of AttributeInterface associated to the file
*
* @return array
* @return AttributeInterface[]
*/
public function getAttributes()
{

View File

@@ -20,6 +20,9 @@ use Alchemy\Phrasea\Metadata\Tag\TfBasename;
use Alchemy\Phrasea\Metadata\Tag\TfFilename;
use Alchemy\Phrasea\Metadata\Tag\TfRecordid;
use Alchemy\Phrasea\Border\Attribute\Metadata as MetadataAttr;
use Alchemy\Phrasea\Border\Attribute\MetaField as MetafieldAttr;
use Alchemy\Phrasea\Border\Attribute\Status as StatusAttr;
use Alchemy\Phrasea\Border\Attribute\Story as StoryAttr;
use Alchemy\Phrasea\Model\Entities\LazaretAttribute;
use Alchemy\Phrasea\Model\Entities\LazaretCheck;
use Alchemy\Phrasea\Model\Entities\LazaretFile;
@@ -314,6 +317,7 @@ class Manager
foreach ($file->getAttributes() as $attribute) {
switch ($attribute->getName()) {
case AttributeInterface::NAME_METAFIELD:
/** @var MetafieldAttr $attribute */
$values = $attribute->getValue();
$value = $attribute->getField()->is_multi() ? new Multi($values) : new MonoValue(array_pop($values));
@@ -329,14 +333,17 @@ class Manager
break;
case AttributeInterface::NAME_METADATA:
/** @var MetadataAttr $attribute */
$newMetadata[] = $attribute->getValue();
break;
case AttributeInterface::NAME_STATUS:
/** @var StatusAttr $attribute */
$element->set_binary_status(decbin(bindec($element->get_status()) | bindec($attribute->getValue())));
break;
case AttributeInterface::NAME_STORY:
/** @var StoryAttr $attribute */
$story = $attribute->getValue();
if ( ! $story->hasChild($element)) {
@@ -441,6 +448,8 @@ class Manager
* to Phraseanet
*
* @param File $file The file
*
* @return Manager
*/
protected function addMediaAttributes(File $file)
{

View File

@@ -1,60 +0,0 @@
<?php
namespace Alchemy\Phrasea\Core\Event;
use Symfony\Component\EventDispatcher\Event;
class AccountDeletedEvent extends Event
{
/**
* @var int
*/
private $userId;
/**
* @var string
*/
private $login;
/**
* @var string
*/
private $emailAddress;
/**
* @param int $userId
* @param $login
* @param string $emailAddress
*/
public function __construct($userId, $login, $emailAddress)
{
$this->userId = $userId;
$this->login = $login;
$this->emailAddress = $emailAddress;
}
/**
* @return int
*/
public function getUserId()
{
return $this->userId;
}
/**
* @return string
*/
public function getLogin()
{
return $this->login;
}
/**
* @return string
*/
public function getEmailAddress()
{
return $this->emailAddress;
}
}

View File

@@ -1,9 +0,0 @@
<?php
namespace Alchemy\Phrasea\Core\Event;
use Symfony\Component\EventDispatcher\Event;
class CollectionDisabled extends CollectionRelated
{
}

View File

@@ -1,9 +0,0 @@
<?php
namespace Alchemy\Phrasea\Core\Event;
use Symfony\Component\EventDispatcher\Event;
class CollectionEmptied extends CollectionRelated
{
}

View File

@@ -1,9 +0,0 @@
<?php
namespace Alchemy\Phrasea\Core\Event;
use Symfony\Component\EventDispatcher\Event;
class CollectionEnabled extends CollectionRelated
{
}

View File

@@ -1,9 +0,0 @@
<?php
namespace Alchemy\Phrasea\Core\Event;
use Symfony\Component\EventDispatcher\Event;
class CollectionMounted extends CollectionRelated
{
}

View File

@@ -1,31 +0,0 @@
<?php
namespace Alchemy\Phrasea\Core\Event;
use Symfony\Component\EventDispatcher\Event;
class CollectionRelated extends Event
{
/** @var \collection $collection */
private $collection;
/** @var array|null $args */
protected $args;
/**
* @param \collection|null $collection
* @param array|null $args
*/
public function __construct(\collection $collection, array $args = null)
{
$this->collection = $collection;
$this->args = $args;
}
/**
* @return \collection|null
*/
public function getCollection()
{
return $this->collection;
}
}

View File

@@ -1,13 +0,0 @@
<?php
namespace Alchemy\Phrasea\Core\Event;
use Symfony\Component\EventDispatcher\Event;
class CollectionSettingsChanged extends CollectionRelated
{
public function getSettingsBefore()
{
return $this->args['settings_before'];
}
}

View File

@@ -1,18 +0,0 @@
<?php
namespace Alchemy\Phrasea\Core\Event;
use Symfony\Component\EventDispatcher\Event;
class CollectionUnmounted extends CollectionRelated
{
public function getCollId()
{
return $this->args['coll_id'];
}
public function getName()
{
return $this->args['name'];
}
}

View File

@@ -1,9 +0,0 @@
<?php
namespace Alchemy\Phrasea\Core\Event;
use Symfony\Component\EventDispatcher\Event;
class DataboxCreated extends DataboxRelated
{
}

View File

@@ -1,13 +0,0 @@
<?php
namespace Alchemy\Phrasea\Core\Event;
use Symfony\Component\EventDispatcher\Event;
class DataboxDeleted extends DataboxRelated
{
public function getDbName()
{
return $this->args['dbname'];
}
}

View File

@@ -1,9 +0,0 @@
<?php
namespace Alchemy\Phrasea\Core\Event;
use Symfony\Component\EventDispatcher\Event;
class DataboxMounted extends DataboxRelated
{
}

View File

@@ -1,9 +0,0 @@
<?php
namespace Alchemy\Phrasea\Core\Event;
use Symfony\Component\EventDispatcher\Event;
class DataboxReindexAsked extends DataboxRelated
{
}

View File

@@ -1,29 +0,0 @@
<?php
namespace Alchemy\Phrasea\Core\Event;
use Symfony\Component\EventDispatcher\Event;
class DataboxRelated extends Event
{
/** @var \databox|null $databox */
private $databox;
/** @var array|null $args supplemental parameters specific to an inherited event class */
protected $args;
/**
* @param \databox|null $databox
* @param array|null $args
*/
public function __construct(\databox $databox, array $args = null)
{
$this->databox = $databox;
$this->args = $args;
}
public function getDatabox()
{
return $this->databox;
}
}

View File

@@ -1,13 +0,0 @@
<?php
namespace Alchemy\Phrasea\Core\Event;
use Symfony\Component\EventDispatcher\Event;
class DataboxStructureChanged extends DataboxRelated
{
public function getDomBefore()
{
return $this->args['dom_before'];
}
}

View File

@@ -1,13 +0,0 @@
<?php
namespace Alchemy\Phrasea\Core\Event;
use Symfony\Component\EventDispatcher\Event;
class DataboxThesaurusChanged extends DataboxRelated
{
public function getDomBefore()
{
return $this->args['dom_before'];
}
}

View File

@@ -1,13 +0,0 @@
<?php
namespace Alchemy\Phrasea\Core\Event;
use Symfony\Component\EventDispatcher\Event;
class DataboxTouChanged extends DataboxRelated
{
public function getTouBefore()
{
return $this->args['tou_before'];
}
}

View File

@@ -1,13 +0,0 @@
<?php
namespace Alchemy\Phrasea\Core\Event;
use Symfony\Component\EventDispatcher\Event;
class DataboxUnmounted extends DataboxRelated
{
public function getDbName()
{
return $this->args['dbname'];
}
}

View File

@@ -11,6 +11,6 @@
namespace Alchemy\Phrasea\Core\Event\Record;
class RecordStatusChangedEvent extends RecordEvent
class CollectionChangedEvent extends RecordEvent
{
}

View File

@@ -11,5 +11,5 @@
namespace Alchemy\Phrasea\Core\Event\Record;
class RecordCreatedEvent extends RecordEvent
class CreatedEvent extends RecordEvent
{}

View File

@@ -11,6 +11,6 @@
namespace Alchemy\Phrasea\Core\Event\Record;
class RecordDeletedEvent extends RecordEvent
class DeletedEvent extends RecordEvent
{
}

View File

@@ -11,7 +11,7 @@
namespace Alchemy\Phrasea\Core\Event\Record;
class RecordIndexEvent extends RecordEvent
class IndexEvent extends RecordEvent
{
}

View File

@@ -0,0 +1,16 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Core\Event\Record;
class MediaSubstitutedEvent extends RecordEvent
{
}

View File

@@ -0,0 +1,16 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Core\Event\Record;
class MetadataChangedEvent extends RecordEvent
{
}

View File

@@ -11,6 +11,6 @@
namespace Alchemy\Phrasea\Core\Event\Record;
class RecordMetadataChangedEvent extends RecordEvent
class OriginalNameChangedEvent extends RecordEvent
{
}

View File

@@ -1,16 +0,0 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Core\Event\Record;
class RecordCollectionChangedEvent extends RecordEvent
{
}

View File

@@ -21,6 +21,11 @@ final class RecordEvents
const ORIGINAL_NAME_CHANGED = 'record.original_name_changed';
const STATUS_CHANGED = 'record.status_changed';
// Sub-definitions
const SUB_DEFINITIONS_CREATION = 'record.sub_definitions_creation';
const SUB_DEFINITION_CREATION = 'record.sub_definition_creation';
const SUB_DEFINITION_CREATED = 'record.sub_definition_created';
const SUB_DEFINITIONS_CREATED = 'record.sub_definitions_created';
const SUB_DEFINITION_CREATION_FAILED = 'record.sub_definition_creation_failed';
const MEDIA_SUBSTITUTED = 'record.media_substituted';
}

View File

@@ -1,16 +0,0 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Core\Event\Record;
class RecordMediaSubstitutedEvent extends RecordEvent
{
}

View File

@@ -1,16 +0,0 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Core\Event\Record;
class RecordOriginalNameChangedEvent extends RecordEvent
{
}

View File

@@ -0,0 +1,16 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Core\Event\Record;
class StatusChangedEvent extends RecordEvent
{
}

View File

@@ -0,0 +1,44 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Core\Event\Record;
use MediaVorus\Media\MediaInterface;
class SubDefinitionCreatedEvent extends RecordEvent
{
private $subDefinitionName;
private $media;
public function __construct(\record_adapter $record, $subDefinitionName, MediaInterface $media)
{
parent::__construct($record);
$this->subDefinitionName = $subDefinitionName;
$this->media = $media;
}
/**
* @return string
*/
public function getSubDefinitionName()
{
return $this->subDefinitionName;
}
/**
* @return MediaInterface
*/
public function getMedia()
{
return $this->media;
}
}

View File

@@ -11,7 +11,7 @@
namespace Alchemy\Phrasea\Core\Event\Record;
class RecordSubDefinitionCreatedEvent extends RecordEvent
class SubDefinitionCreationEvent extends RecordEvent
{
private $subDefinitionName;
@@ -22,6 +22,9 @@ class RecordSubDefinitionCreatedEvent extends RecordEvent
$this->subDefinitionName = $subDefinitionName;
}
/**
* @return string
*/
public function getSubDefinitionName()
{
return $this->subDefinitionName;

View File

@@ -0,0 +1,31 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Core\Event\Record;
class SubDefinitionCreationFailedEvent extends RecordEvent
{
private $subDefinitionName;
public function __construct(\record_adapter $record, $subDefinitionName)
{
parent::__construct($record);
$this->subDefinitionName = $subDefinitionName;
}
/**
* @return string
*/
public function getSubDefinitionName()
{
return $this->subDefinitionName;
}
}

View File

@@ -0,0 +1,39 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Core\Event\Record;
use MediaVorus\Media\MediaInterface;
class SubDefinitionsCreatedEvent extends RecordEvent
{
/** @var MediaInterface[] */
private $media;
/**
* @param \record_adapter $record
* @param MediaInterface[] $media
*/
public function __construct(\record_adapter $record, array $media)
{
parent::__construct($record);
$this->media = $media;
}
/**
* @return MediaInterface[]
*/
public function getMedia()
{
return $this->media;
}
}

View File

@@ -0,0 +1,32 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Core\Event\Record;
class SubDefinitionsCreationEvent extends RecordEvent
{
private $subDefinitionsNames;
public function __construct(\record_adapter $record, $subDefinitionsNames)
{
parent::__construct($record);
$this->subDefinitiosnNames = $subDefinitionsNames;
}
/**
* @return string
*/
public function getSubDefinitionsNames()
{
return $this->subDefinitionsNames;
}
}

View File

@@ -12,7 +12,12 @@
namespace Alchemy\Phrasea\Media;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Core\Event\Record\RecordSubDefinitionCreatedEvent;
use Alchemy\Phrasea\Core\Event\Record\RecordEvent;
use Alchemy\Phrasea\Core\Event\Record\SubDefinitionCreatedEvent;
use Alchemy\Phrasea\Core\Event\Record\SubDefinitionsCreatedEvent;
use Alchemy\Phrasea\Core\Event\Record\SubDefinitionCreationEvent;
use Alchemy\Phrasea\Core\Event\Record\SubDefinitionsCreationEvent;
use Alchemy\Phrasea\Core\Event\Record\SubDefinitionCreationFailedEvent;
use Alchemy\Phrasea\Core\Event\Record\RecordEvents;
use MediaAlchemyst\Alchemyst;
use MediaAlchemyst\Specification\SpecificationInterface;
@@ -38,14 +43,28 @@ class SubdefGenerator
$this->mediavorus = $mediavorus;
}
private function dispatch($eventName, RecordEvent $event)
{
$this->app['dispatcher']->dispatch($eventName, $event);
}
public function generateSubdefs(\record_adapter $record, array $wanted_subdefs = null)
{
if (null === $subdefs = $record->get_databox()->get_subdef_structure()->getSubdefGroup($record->get_type())) {
$this->logger->info(sprintf('Nothing to do for %s', $record->get_type()));
if (null === $subdefs = $record->getDatabox()->get_subdef_structure()->getSubdefGroup($record->getType())) {
$this->logger->info(sprintf('Nothing to do for %s', $record->getType()));
return;
return $this;
}
$this->dispatch(
RecordEvents::SUB_DEFINITIONS_CREATION,
new SubDefinitionsCreationEvent(
$record,
$wanted_subdefs
)
);
$mediaCreated = [];
foreach ($subdefs as $subdef) {
$subdefname = $subdef->get_name();
@@ -64,6 +83,14 @@ class SubdefGenerator
$pathdest = $this->generateSubdefPathname($record, $subdef, $pathdest);
$this->dispatch(
RecordEvents::SUB_DEFINITION_CREATION,
new SubDefinitionCreationEvent(
$record,
$subdefname
)
);
$this->logger->addInfo(sprintf('Generating subdef %s to %s', $subdefname, $pathdest));
$this->generateSubdef($record, $subdef, $pathdest);
@@ -71,13 +98,37 @@ class SubdefGenerator
$media = $this->mediavorus->guess($pathdest);
\media_subdef::create($this->app, $record, $subdef->get_name(), $media);
$this->dispatch(
RecordEvents::SUB_DEFINITION_CREATED,
new SubDefinitionCreatedEvent(
$record,
$subdefname,
$mediaCreated[$subdefname] = $media
)
);
}
else {
$this->dispatch(
RecordEvents::SUB_DEFINITION_CREATION_FAILED,
new SubDefinitionCreationFailedEvent(
$record,
$subdefname
)
);
}
$record->clearSubdefCache($subdefname);
$this->app['dispatcher']->dispatch(RecordEvents::SUB_DEFINITION_CREATED, new RecordSubDefinitionCreatedEvent($record, $subdefname));
}
$this->dispatch(
RecordEvents::SUB_DEFINITIONS_CREATED,
new SubDefinitionsCreatedEvent(
$record,
$mediaCreated
)
);
return $this;
}
@@ -92,7 +143,7 @@ class SubdefGenerator
$this->alchemyst->turnInto($record->get_hd_file()->getPathname(), $pathdest, $subdef_class->getSpecs());
} catch (MediaAlchemystException $e) {
$this->logger->error(sprintf('Subdef generation failed for record %d with message %s', $record->get_record_id(), $e->getMessage()));
$this->logger->error(sprintf('Subdef generation failed for record %d with message %s', $record->getRecordId(), $e->getMessage()));
}
}
@@ -104,7 +155,7 @@ class SubdefGenerator
$pathdest = \databox::dispatch($this->filesystem, $subdef->get_path());
}
return $pathdest . $record->get_record_id() . '_' . $subdef->get_name() . '.' . $this->getExtensionFromSpec($subdef->getSpecs());
return $pathdest . $record->getRecordId() . '_' . $subdef->get_name() . '.' . $this->getExtensionFromSpec($subdef->getSpecs());
}
/**

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\Media;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Core\Event\Record\RecordMediaSubstitutedEvent;
use Alchemy\Phrasea\Core\Event\Record\MediaSubstitutedEvent;
use Alchemy\Phrasea\Core\Event\Record\RecordEvents;
use MediaAlchemyst\Alchemyst;
use MediaAlchemyst\Exception\ExceptionInterface as MediaAlchemystException;
@@ -97,6 +97,6 @@ class SubdefSubstituer
$record->rebuild_subdefs();
}
$this->dispatcher->dispatch(RecordEvents::MEDIA_SUBSTITUTED, new RecordMediaSubstitutedEvent($record));
$this->dispatcher->dispatch(RecordEvents::MEDIA_SUBSTITUTED, new MediaSubstitutedEvent($record));
}
}

View File

@@ -13,10 +13,10 @@ namespace Alchemy\Phrasea\SearchEngine\Elastic;
use Alchemy\Phrasea\Core\Event\Collection\CollectionEvent;
use Alchemy\Phrasea\Core\Event\Collection\CollectionEvents;
use Alchemy\Phrasea\Core\Event\Record\RecordDeletedEvent;
use Alchemy\Phrasea\Core\Event\Record\DeletedEvent;
use Alchemy\Phrasea\Core\Event\Record\RecordEvent;
use Alchemy\Phrasea\Core\Event\Record\RecordEvents;
use Alchemy\Phrasea\Core\Event\Record\RecordSubDefinitionCreatedEvent;
use Alchemy\Phrasea\Core\Event\Record\SubDefinitionsCreatedEvent;
use Alchemy\Phrasea\Core\Event\Record\Structure\RecordStructureEvent;
use Alchemy\Phrasea\Core\Event\Record\Structure\RecordStructureEvents;
use Alchemy\Phrasea\Core\Event\Thesaurus\ThesaurusEvent;
@@ -84,7 +84,7 @@ class IndexerSubscriber implements EventSubscriberInterface
RecordEvents::METADATA_CHANGED => 'onRecordChange',
RecordEvents::ORIGINAL_NAME_CHANGED => 'onRecordChange',
RecordEvents::STATUS_CHANGED => 'onRecordChange',
RecordEvents::SUB_DEFINITION_CREATED => 'onRecordChange',
RecordEvents::SUB_DEFINITIONS_CREATED => 'onRecordChange',
RecordEvents::MEDIA_SUBSTITUTED => 'onRecordChange',
ThesaurusEvents::IMPORTED => 'onThesaurusChange',
ThesaurusEvents::FIELD_LINKED => 'onThesaurusChange',
@@ -120,14 +120,13 @@ class IndexerSubscriber implements EventSubscriberInterface
public function onRecordChange(RecordEvent $event)
{
if ($event instanceof RecordSubDefinitionCreatedEvent && $event->getSubDefinitionName() !== 'thumbnail') {
return;
if ($event instanceof SubDefinitionsCreatedEvent) {
$record = $event->getRecord();
$this->getIndexer()->indexRecord($record);
}
$record = $event->getRecord();
$this->getIndexer()->indexRecord($record);
}
public function onRecordDelete(RecordDeletedEvent $event)
public function onRecordDelete(DeletedEvent $event)
{
$record = $event->getRecord();
$this->getIndexer()->deleteRecord($record);

View File

@@ -14,6 +14,7 @@ namespace Alchemy\Phrasea\TaskManager\Job;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Exception\RuntimeException;
use Alchemy\Phrasea\Border\File;
use Alchemy\Phrasea\Border\Manager as borderManager;
use Alchemy\Phrasea\TaskManager\Editor\ArchiveEditor;
use Alchemy\Phrasea\Metadata\Tag as PhraseaTag;
use Alchemy\Phrasea\Border\Attribute as BorderAttribute;
@@ -1080,7 +1081,9 @@ class ArchiveJob extends AbstractJob
$record = $element;
};
$app['border-manager']->process($this->getLazaretSession($app), $file, $postProcess, $force);
/** @var borderManager $borderManager */
$borderManager = $app['border-manager'];
$borderManager->process($this->getLazaretSession($app), $file, $postProcess, $force);
return $record;
}

View File

@@ -114,25 +114,16 @@ class SubdefsJob extends AbstractJob
$this->log('warning', sprintf("Generate subdefs failed for : sbasid=%s / databox=%s / recordid=%s : %s", $databox->get_sbas_id(), $databox->get_dbname() , $row['record_id'], $e->getMessage()));
}
// subdef created, ask to rewrite metadata
$sql = 'UPDATE record'
. ' SET jeton=(jeton & ~(:flag)), moddate=NOW()'
. ' SET jeton=(jeton & ~(:flag_and)) | :flag_or, moddate=NOW()'
. ' WHERE record_id=:record_id';
$stmt = $conn->prepare($sql);
$stmt->execute([
':record_id' => $row['record_id'],
':flag' => PhraseaTokens::MAKE_SUBDEF
]);
$stmt->closeCursor();
// rewrite metadata
$sql = 'UPDATE record'
. ' SET jeton=(jeton | :flag)'
. ' WHERE record_id=:record_id';
$stmt = $conn->prepare($sql);
$stmt->execute([
':record_id' => $row['record_id'],
':flag' => (PhraseaTokens::WRITE_META_SUBDEF | PhraseaTokens::TO_INDEX)
':flag_and' => PhraseaTokens::MAKE_SUBDEF,
':flag_or' => (PhraseaTokens::WRITE_META_SUBDEF | PhraseaTokens::TO_INDEX)
]);
$stmt->closeCursor();