-
Notifications
You must be signed in to change notification settings - Fork 17
/
AutoNumber.php
127 lines (115 loc) · 3.66 KB
/
AutoNumber.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
<?php
namespace mdm\autonumber;
use Yii;
use yii\db\ActiveRecord;
/**
* This is the model class for table "auto_number".
*
* @property string $group
* @property string $template
* @property integer $number
*
* @author Misbahul D Munir <[email protected]>
* @since 1.0
*/
class AutoNumber extends ActiveRecord
{
/**
* @inheritdoc
*/
public static function tableName()
{
return '{{%auto_number}}';
}
/**
* @inheritdoc
*/
public function rules()
{
return [
[['optimistic_lock', 'number'], 'default', 'value' => 1],
[['group'], 'required'],
[['number'], 'integer'],
[['group'], 'string']
];
}
/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'template' => 'Template Num',
'number' => 'Number',
];
}
/**
* @inheritdoc
*/
public function optimisticLock()
{
return 'optimistic_lock';
}
/**
*
* @param string $format value inner `{}` will evaluate as date. Number of digit represented as number of `?`.
* @param bool $alnum if true will generate alfanumeric value. If false generate only number.
* @param int $digit For compatibility purpose.
* @param array $group For compatibility purpose.
* @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 = (string)$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;
}
}