%PDF- %PDF-
| Direktori : /home/bitrix/www/bitrix/modules/main/lib/numerator/generator/ |
| Current File : //home/bitrix/www/bitrix/modules/main/lib/numerator/generator/sequentnumbergenerator.php |
<?
namespace Bitrix\Main\Numerator\Generator;
use Bitrix\Main\Error;
use Bitrix\Main\Localization\Loc;
use Bitrix\Main\Numerator\Model\NumeratorSequenceTable;
use Bitrix\Main\Result;
use Bitrix\Main\Numerator\Generator\Contract\Sequenceable;
use Bitrix\Main\Numerator\Generator\Contract\UserConfigurable;
Loc::loadMessages(__FILE__);
/**
* Class SequentNumberGenerator
* @package Bitrix\Main\Numerator\Generator
*/
class SequentNumberGenerator extends NumberGenerator implements Sequenceable, UserConfigurable
{
const DAY = 'day';
const MONTH = 'month';
const YEAR = 'year';
const TEMPLATE_WORD_NUMBER = 'NUMBER';
const ERROR_SEQUENCE_NOT_SET = 'ERROR_SEQUENCE_NOT_SET';
protected $start;
protected $step;
protected $periodicBy;
protected $timezone;
protected $nowTime;
/** value stored in database */
protected $nextNumber;
/** calculated value that used for template parsing */
protected $currentNumber;
protected $lastInvocationTime;
protected $numeratorId;
protected $numberHash;
protected $isDirectNumeration;
/** @inheritdoc */
public function setConfig($config)
{
$this->setFromArrayOrDefault('timezone', $config);
if ($this->timezone)
{
date_default_timezone_set($this->timezone);
}
$this->setFromArrayOrDefault('start', $config, 1, 'int');
$this->setFromArrayOrDefault('step', $config, 1, 'int');
$this->setFromArrayOrDefault('isDirectNumeration', $config, false, 'bool');
$this->setFromArrayOrDefault('periodicBy', $config);
$this->setFromArrayOrDefault('nowTime', $config, time());
if (isset($config['numeratorId']))
{
$this->lastInvocationTime = $config['lastInvocationTime'];
$this->numeratorId = $config['numeratorId'];
if ($this->isDirectNumeration)
{
$this->numberHash = $this->numeratorId;
}
}
else
{
$this->nextNumber = $this->start;
}
}
/** @inheritdoc */
public static function getSettingsFields()
{
$timezonesSettings = static::getTimezoneSettings();
foreach ($timezonesSettings as $index => $timezonesSetting)
{
$timezonesSettings[$index]['settingName'] = $timezonesSetting['name'];
unset($timezonesSettings[$index]['name']);
}
return [
[
'settingName' => 'start', 'type' => 'int', 'default' => 1,
'title' => Loc::getMessage('TITLE_BITRIX_MAIN_NUMERATOR_GENERATOR_SEQUENTNUMBERGENERATOR_START'),
],
[
'settingName' => 'step', 'type' => 'int', 'default' => 1,
'title' => Loc::getMessage('TITLE_BITRIX_MAIN_NUMERATOR_GENERATOR_SEQUENTNUMBERGENERATOR_STEP'),
],
[
'settingName' => 'periodicBy', 'type' => 'array',
'title' => Loc::getMessage('TITLE_BITRIX_MAIN_NUMERATOR_GENERATOR_SEQUENTNUMBERGENERATOR_PERIODICBY'),
'values' => [
[
'settingName' => 'default', 'value' => '',
'title' => Loc::getMessage('TITLE_BITRIX_MAIN_NUMERATOR_GENERATOR_SEQUENTNUMBERGENERATOR_PERIODICBY_DEFAULT'),
],
[
'settingName' => self::DAY, 'value' => self::DAY,
'title' => Loc::getMessage('TITLE_BITRIX_MAIN_NUMERATOR_GENERATOR_SEQUENTNUMBERGENERATOR_PERIODICBY_DAY'),
],
[
'settingName' => self::MONTH, 'value' => self::MONTH,
'title' => Loc::getMessage('TITLE_BITRIX_MAIN_NUMERATOR_GENERATOR_SEQUENTNUMBERGENERATOR_PERIODICBY_MONTH'),
],
[
'settingName' => self::YEAR, 'value' => self::YEAR,
'title' => Loc::getMessage('TITLE_BITRIX_MAIN_NUMERATOR_GENERATOR_SEQUENTNUMBERGENERATOR_PERIODICBY_YEAR'),
],
],
],
[
'settingName' => 'timezone', 'type' => 'array', 'values' => $timezonesSettings,
'title' => Loc::getMessage('TITLE_BITRIX_MAIN_NUMERATOR_GENERATOR_SEQUENTNUMBERGENERATOR_TIMEZONE'),
],
[
'settingName' => 'isDirectNumeration', 'type' => 'boolean',
'title' => Loc::getMessage('TITLE_BITRIX_MAIN_NUMERATOR_GENERATOR_SEQUENTNUMBERGENERATOR_ISDIRECTNUMERATION'),
],
];
}
/** @inheritdoc */
public static function getTemplateWordsSettings()
{
return [
static::getPatternFor(static::TEMPLATE_WORD_NUMBER) =>
Loc::getMessage('BITRIX_MAIN_NUMERATOR_GENERATOR_SEQUENTNUMBERGENERATOR_WORD_NUMBER'),
];
}
/** @inheritdoc */
public function getConfig()
{
return [
'start' => $this->start,
'step' => $this->step,
'periodicBy' => $this->periodicBy,
'timezone' => $this->timezone,
'isDirectNumeration' => (bool)$this->isDirectNumeration,
];
}
/**
* @return array
* @throws \Bitrix\Main\ArgumentException
* @throws \Bitrix\Main\DB\SqlQueryException
* @throws \Bitrix\Main\ObjectPropertyException
* @throws \Bitrix\Main\SystemException
*/
private function getSettings()
{
$nextNumberSettings = NumeratorSequenceTable::getSettings($this->numeratorId, $this->getNumberHash());
if (!$nextNumberSettings)
{
$nextNumberSettings = NumeratorSequenceTable::setSettings($this->numeratorId, $this->getNumberHash(), $this->start, $this->nowTime);
}
return $nextNumberSettings;
}
/**
* @return mixed
*/
private function getNumberHash()
{
if ($this->numberHash === null)
{
$this->setNumberHash($this->numeratorId);
}
return $this->numberHash;
}
/** @inheritdoc */
public function parseTemplate($template)
{
for ($tryouts = 0; $tryouts < 50; $tryouts++)
{
$this->nextNumber = $this->currentNumber = null;
$nextNumberSettings = $this->getSettings();
if (!$nextNumberSettings)
{
continue;
}
$affectedRows = $this->updateNextNumberSettings($nextNumberSettings);
if ($affectedRows == 1)
{
break;
}
}
$template = str_replace(static::getPatternFor(static::TEMPLATE_WORD_NUMBER), $this->currentNumber, $template);
return $template;
}
/**
* @param $nextNumberSettings
* @return bool|int
* @throws \Bitrix\Main\DB\SqlQueryException
*/
private function updateNextNumberSettings($nextNumberSettings)
{
$this->lastInvocationTime = $nextNumberSettings['LAST_INVOCATION_TIME'];
$currentNumberForWhereCondition = $this->currentNumber = $nextNumberSettings['NEXT_NUMBER'];
$this->resetCurrentNumberIfNeeded();
$this->nextNumber = $this->currentNumber + $this->step;
$this->lastInvocationTime = $this->nowTime;
return NumeratorSequenceTable::updateSettings(
$this->numeratorId, $this->getNumberHash(),
[
'NEXT_NUMBER' => $this->nextNumber,
'LAST_INVOCATION_TIME' => $this->lastInvocationTime,
],
$currentNumberForWhereCondition);
}
/** @inheritdoc */
public static function getTemplateWordsForParse()
{
return [static::getPatternFor(static::TEMPLATE_WORD_NUMBER)];
}
/** @inheritdoc */
public function parseTemplateForPreview($template)
{
return str_replace(static::getPatternFor(static::TEMPLATE_WORD_NUMBER), $this->getNextNumber($this->numeratorId), $template);
}
/** @inheritdoc */
public function getNextNumber($numeratorId)
{
if (!$numeratorId)
{
return null;
}
$this->numeratorId = $numeratorId;
$nextNumberSettings = NumeratorSequenceTable::getSettings($this->numeratorId, $this->getNumberHash());
if ($nextNumberSettings)
{
return $nextNumberSettings['NEXT_NUMBER'];
}
else
{
return $this->start;
}
}
/**
* @return string
*/
public static function getAvailableForType()
{
return 'DEFAULT';
}
/*** @inheritdoc */
public function setNextNumber($numeratorId, $newNumber, $whereNumber)
{
$this->nextNumber = $newNumber;
$sequence = NumeratorSequenceTable::getSettings($numeratorId, $this->getNumberHash());
if (!$sequence)
{
return (new Result())->addError(new Error(Loc::getMessage('NUMERATOR_UPDATE_SEQUENT_IS_NOT_SET_YET')));
}
$affectedRows = NumeratorSequenceTable::updateSettings($numeratorId, $this->getNumberHash(),
[
'NEXT_NUMBER' => $this->nextNumber,
],
$whereNumber);
if ($affectedRows == 1)
{
return new Result();
}
return (new Result())->addError(new Error(Loc::getMessage('NUMERATOR_SEQUENT_DEFAULT_INTERNAL_ERROR')));
}
/**
* set current number to its start position if generator is periodic and period has been just changed
*/
private function resetCurrentNumberIfNeeded()
{
if ($this->periodicBy)
{
if ($this->periodicBy == static::YEAR && $this->isHasChanged(static::YEAR))
{
$this->currentNumber = $this->start;
}
if ($this->periodicBy == static::MONTH)
{
if ($this->isHasChanged(static::MONTH) || $this->isSameMonthButDifferentYear())
{
$this->currentNumber = $this->start;
}
}
if ($this->periodicBy == static::DAY)
{
if ($this->isHasChanged(static::DAY)
|| $this->isSameDayButDifferent(static::MONTH)
|| $this->isSameDayButDifferent(static::YEAR))
{
$this->currentNumber = $this->start;
}
}
}
}
/**
* @return bool
*/
private function isSameMonthButDifferentYear()
{
return date('m', $this->lastInvocationTime) == date('m', $this->nowTime) && $this->isHasChanged(static::YEAR);
}
/**
* @param $interval
* @return bool
*/
private function isSameDayButDifferent($interval)
{
if ($interval == static::MONTH)
{
return date('d', $this->lastInvocationTime) == date('d', $this->nowTime) && $this->isHasChanged(static::MONTH);
}
if ($interval == static::YEAR)
{
return date('d', $this->lastInvocationTime) == date('d', $this->nowTime) && $this->isHasChanged(static::YEAR);
}
return false;
}
/**
* @param $interval
* @return bool
*/
private function isHasChanged($interval)
{
if ($interval == static::MONTH)
{
return date('m', $this->lastInvocationTime) != date('m', $this->nowTime);
}
if ($interval == static::DAY)
{
return date('d', $this->lastInvocationTime) != date('d', $this->nowTime);
}
if ($interval == static::YEAR)
{
return date('Y', $this->lastInvocationTime) != date('Y', $this->nowTime);
}
return false;
}
/**
* @return array
*/
private static function getTimezoneSettings()
{
$timezones = \CTimeZone::GetZones();
$settings = [];
foreach ($timezones as $timezoneValue => $timezoneName)
{
$settings[] = ['name' => $timezoneName, 'value' => $timezoneValue,];
}
return $settings;
}
/** @inheritdoc */
public function validateConfig($config)
{
$result = new Result();
return $result;
}
/** @inheritdoc */
public function setNumberHash($numberHash)
{
if (!is_string($numberHash) && !is_int($numberHash))
{
return;
}
if ($this->numberHash === null)
{
$this->numberHash = (string)$numberHash;
}
}
}