Skip to content

Commit

Permalink
Merge pull request #2 from mdmsoft/new-format
Browse files Browse the repository at this point in the history
New format
  • Loading branch information
mdmunir authored Oct 17, 2019
2 parents 0a2d759 + 42145ed commit 1f7395a
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 70 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/nbproject/*
67 changes: 67 additions & 0 deletions AutoNumber.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,71 @@ public function optimisticLock()
{
return 'optimistic_lock';
}

/**
*
* @param string $format
* @param bool $alnum
* @param int $digit
* @param array $group
* @return string
*/
public static function generate($format, $alnum = false, $digit = null, array $group = [])
{
if ($format) {
$format = preg_replace_callback('/\{([^\}]+)\}/', function($matchs) {
return date($matchs[1]);
}, $format);
}

if (empty($group) && strlen($format) < 32) {
$key = $format;
} else {
$group['value'] = $format;
$key = md5(serialize($group));
}

$command = Yii::$app->db->createCommand();
$command->setSql('SELECT [[number]] FROM {{auto_number}} WHERE [[group]]=:key');
$counter = $command->bindValue(':key', $key)->queryScalar() + 1;
$command->upsert('auto_number', ['group' => $key, 'number' => $counter, 'optimistic_lock' => 1, 'update_time' => time()])->execute();
$number = $alnum ? strtoupper(base_convert($counter, 10, 36)) : (string) $counter;

if ($format === null) {
$result = $number;
} elseif ($digit) {
$number = str_pad($number, $digit, '0', STR_PAD_LEFT);
$result = str_replace('?', $number, $format);
} else {
$places = [];
$total = 0;
$result = preg_replace_callback('/\?+/', function($matchs) use(&$places, &$total) {
$n = strlen($matchs[0]);
$i = count($places);
$places[] = $n;
$total += $n;
return "<[~{$i}~]>";
}, $format);

if ($total > 1) {
$number = str_pad($number, $total, '0', STR_PAD_LEFT);
$parts = [];
for ($i = count($places) - 1; $i >= 0; $i--) {
if ($i == 0) {
$parts[0] = $number;
} else {
$parts[$i] = substr($number, -$places[$i]);
$number = substr($number, 0, -$places[$i]);
}
}
$result = preg_replace_callback('/<\[~(\d+)~\]>/', function($matchs) use(&$parts) {
$i = $matchs[1];
return $parts[$i];
}, $result);
} else {
$result = str_replace('?', $number, $format);
}
}
return $result;
}
}
38 changes: 8 additions & 30 deletions AutonumberValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ class AutonumberValidator extends \yii\validators\Validator
*/
public $group;

/**
* @var bool
*/
public $alnum;

/**
* @var boolean
*/
Expand Down Expand Up @@ -101,39 +106,12 @@ public function beforeSave($event)
$value = is_callable($this->format) ? call_user_func($this->format, $object, $attribute) : $this->format;
}

$group = md5(serialize([
$group = [
'class' => $this->unique ? get_class($object) : false,
'group' => $this->group,
'attribute' => $attribute,
'value' => $value
]));

$model = AutoNumber::findOne($group);
if ($model) {
$number = $model->number + 1;
} else {
$model = new AutoNumber([
'group' => $group
]);
$number = 1;
}
$model->update_time = time();
$model->number = $number;

if ($value === null) {
$object->$attribute = $number;
} else {
$object->$attribute = str_replace('?', $this->digit ? sprintf("%0{$this->digit}d", $number) : $number, $value);
}

];
$object->$attribute = AutoNumber::generate($value, $this->alnum, $this->digit, $group);
self::$_executed[$id] = true;
try {
$model->save(false);
} catch (\Exception $exc) {
$event->isValid = false;
if ($this->throwIsStale || !($exc instanceof StaleObjectException)) {
throw $exc;
}
}
}
}
40 changes: 9 additions & 31 deletions Behavior.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ class Behavior extends \yii\behaviors\AttributeBehavior
*/
public $attribute;

/**
*
* @var bool If set `true` formated number will return alfabet and numeric.
*/
public $alnum = false;

/**
* @inheritdoc
*/
Expand All @@ -71,39 +77,11 @@ protected function getValue($event)
} else {
$value = is_callable($this->value) ? call_user_func($this->value, $event) : $this->value;
}
$group = md5(serialize([
$group = [
'class' => $this->unique ? get_class($this->owner) : false,
'group' => $this->group,
'attribute' => $this->attribute,
'value' => $value
]));
do {
$repeat = false;
try {
$model = AutoNumber::findOne($group);
if ($model) {
$number = $model->number + 1;
} else {
$model = new AutoNumber([
'group' => $group
]);
$number = 1;
}
$model->update_time = time();
$model->number = $number;
$model->save(false);
} catch (Exception $exc) {
if ($exc instanceof StaleObjectException) {
$repeat = true;
} else {
throw $exc;
}
}
} while ($repeat);
if ($value === null) {
return $number;
} else {
return str_replace('?', $this->digit ? sprintf("%0{$this->digit}d", $number) : $number, $value);
}
];
return AutoNumber::generate($value, $this->alnum, $this->digit, $group);
}
}
36 changes: 27 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ Once the extension is installed, simply modify your ActiveRecord class:
```php
public function behaviors()
{
return [
[
'class' => 'mdm\autonumber\Behavior',
'attribute' => 'sales_num', // required
'group' => $this->id_branch, // optional
'value' => 'SA.'.date('Y-m-d').'.?' , // format auto number. '?' will be replaced with generated number
'digit' => 4 // optional, default to null.
],
];
return [
[
'class' => 'mdm\autonumber\Behavior',
'attribute' => 'sales_num', // required
'group' => $this->id_branch, // optional
'value' => 'SA.'.date('Y-m-d').'.?' , // format auto number. '?' will be replaced with generated number
'digit' => 4 // optional, default to null.
],
];
}

// it will set value $model->sales_num as 'SA.2014-06-25.0001'
Expand All @@ -76,4 +76,22 @@ public function rules()
}
```

New Format
----------

Since version 1.5 we introduce new format of number. Now we use `{}` to evaluate as date and number of digit represented as number of `?`.

```php
public function rules()
{
return [
[['sales_num'], 'autonumber', 'format' => 'SA/{Y/m}/?.???'],
...
];
}

// it will set value $model->sales_num as 'SA/2019/10/0.001'
```


- [Api Documentation](http://mdmsoft.github.io/yii2-autonumber/index.html)

0 comments on commit 1f7395a

Please sign in to comment.