├── .gitignore ├── preview.png ├── src ├── IdGeneratorServiceProvider.php ├── Traits │ └── IdFactory.php └── IdGenerator.php ├── composer.json ├── README.md └── tests └── Unit └── IdGenerateTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | /.idea 3 | /node_modules 4 | /composer.lock 5 | *.txt -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haruncpi/laravel-id-generator/HEAD/preview.png -------------------------------------------------------------------------------- /src/IdGeneratorServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->make('Haruncpi\LaravelIdGenerator\IdGenerator'); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "haruncpi/laravel-id-generator", 3 | "description": "Easy way to generate custom ID in laravel framework", 4 | "license": "cc-by-4.0", 5 | "authors": [ 6 | { 7 | "name": "Md.Harun-Ur-Rashid", 8 | "email": "harun.cox@gmail.com" 9 | } 10 | ], 11 | "minimum-stability": "dev", 12 | "prefer-stable": true, 13 | "require": { 14 | "php": ">=5.6.0" 15 | }, 16 | "autoload": { 17 | "psr-4": { 18 | "Haruncpi\\LaravelIdGenerator\\": "src/" 19 | } 20 | }, 21 | "extra": { 22 | "laravel": { 23 | "providers": [ 24 | "Haruncpi\\LaravelIdGenerator\\IdGeneratorServiceProvider" 25 | ] 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
Easy way to generate custom ID from database table in Laravel framework
10 | 11 |  12 | 13 | ## Support 14 |
15 |
16 | ## Documentation
17 | Get documentation on [laravelarticle.com](https://laravelarticle.com/laravel-custom-id-generator)
18 |
19 | ## Other Packages
20 | - [Laravel Log Reader](https://github.com/haruncpi/laravel-log-reader) - A simple and beautiful laravel log reader.
21 | - [Laravel H](https://github.com/haruncpi/laravel-h) - A helper package for Laravel Framework.
22 | - [Laravel Simple Filemanager](https://github.com/haruncpi/laravel-simple-filemanager) - A simple filemanager for Laravel.
23 | - [Laravel Option Framework](https://github.com/haruncpi/laravel-option-framework) - Option framework for Laravel.
24 |
25 |
26 | Followed Coding Style [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
27 |
--------------------------------------------------------------------------------
/src/Traits/IdFactory.php:
--------------------------------------------------------------------------------
1 | $model->getTable(),
41 | 'length' => self::$idConfig['length'],
42 | 'prefix' => self::$idConfig['prefix'],
43 | ];
44 |
45 | if (isset(self::$idConfig['reset_on_prefix_change'])) {
46 | $config['reset_on_prefix_change'] = self::$idConfig['reset_on_prefix_change'];
47 | }
48 | if (isset(self::$idConfig['field'])) {
49 | $config['field'] = self::$idConfig['field'];
50 | $model[self::$idConfig['field']] = IdGenerator::generate($config);
51 | } else {
52 | $model->id = IdGenerator::generate($config);
53 | }
54 | });
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/tests/Unit/IdGenerateTest.php:
--------------------------------------------------------------------------------
1 | 'ID', 'length' => 10];
15 | IdGenerator::generate($config);
16 | } catch (\Exception $e) {
17 | $this->assertEquals("Must need a table name", $e->getMessage());
18 | }
19 | }
20 |
21 | public function test_prefix_required()
22 | {
23 | try {
24 | $config = ['table' => 'users', 'length' => 10];
25 | IdGenerator::generate($config);
26 | } catch (\Exception $e) {
27 | $this->assertEquals("Must specify a prefix of your ID", $e->getMessage());
28 | }
29 | }
30 |
31 | public function test_ID_length_required()
32 | {
33 | try {
34 | $config = ['table' => 'users', 'prefix' => 10];
35 | IdGenerator::generate($config);
36 | } catch (\Exception $e) {
37 | $this->assertEquals("Must specify the length of ID", $e->getMessage());
38 | }
39 | }
40 |
41 | public function test_table_not_found()
42 | {
43 | try {
44 | $table = "blah";
45 | $config = ['table' => $table, 'prefix' => 'ID', 'length' => 10];
46 | IdGenerator::generate($config);
47 | } catch (\Exception $e) {
48 | $this->assertEquals(0, $e->getCode());
49 | }
50 | }
51 |
52 | public function test_field_not_found()
53 | {
54 | try {
55 | $table = "users";
56 | $field = "emp_id";
57 | $config = ['table' => $table, 'prefix' => 'ID', 'length' => 10, 'field' => $field];
58 | IdGenerator::generate($config);
59 | } catch (\Exception $e) {
60 | $this->assertEquals("$field not found in $table table", $e->getMessage());
61 | }
62 | }
63 |
64 | public function test_invalid_data_type()
65 | {
66 | try {
67 | $table = "users";
68 | $field = "id";
69 | $config = ['table' => $table, 'prefix' => 'ID', 'length' => 10];
70 | IdGenerator::generate($config);
71 | } catch (\Exception $e) {
72 | $this->assertStringContainsString("$field field type is", $e->getMessage());
73 | }
74 | }
75 |
76 | public function test_invalid_length()
77 | {
78 | try {
79 | $table = "users";
80 | $config = ['table' => $table, 'prefix' => 101, 'length' => 25];
81 | IdGenerator::generate($config);
82 | } catch (\Exception $e) {
83 | $this->assertStringContainsString("Generated ID length is bigger then table field length", $e->getMessage());
84 | }
85 | }
86 |
87 | public function test_ID_generated()
88 | {
89 |
90 | $config = ['table' => $this->testTable, 'prefix' => 101, 'length' => 10];
91 | $id = IdGenerator::generate($config);
92 | $this->assertEquals($id, $id);
93 | }
94 |
95 | public function test_ID_incremented()
96 | {
97 | DB::beginTransaction();
98 |
99 | $config = ['table' => $this->testTable, 'prefix' => 101, 'length' => 10];
100 | $id1 = IdGenerator::generate($config);
101 | DB::table($this->testTable)->insert(['id' => $id1]);
102 | $id2 = IdGenerator::generate($config);
103 | DB::table($this->testTable)->insert(['id' => $id2]);
104 |
105 | DB::rollBack();
106 | $this->assertEquals($id1 + 1, $id2);
107 | }
108 |
109 | public function test_ID_reset_on_prefix_change()
110 | {
111 | DB::beginTransaction();
112 | $config_1 = ['table' => $this->testTable, 'prefix' => 101, 'length' => 10, 'reset_on_prefix_change' => true];
113 | $id1 = IdGenerator::generate($config_1);
114 | DB::table($this->testTable)->insert(['id' => $id1]);
115 |
116 | $id2 = IdGenerator::generate($config_1);
117 | DB::table($this->testTable)->insert(['id' => $id2]);
118 |
119 | $config_2 = ['table' => $this->testTable, 'prefix' => 102, 'length' => 10, 'reset_on_prefix_change' => true];
120 | $resetID = IdGenerator::generate($config_2);
121 | DB::table($this->testTable)->insert(['id' => $resetID]);
122 |
123 | DB::rollBack();
124 | $this->assertNotEquals($id2 + 1, $resetID);
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/src/IdGenerator.php:
--------------------------------------------------------------------------------
1 | getDriverName();
27 | $database = DB::connection($connection)->getDatabaseName();
28 |
29 | if ($driver == 'mysql') {
30 | $sql = 'SELECT column_name AS "column_name",data_type AS "data_type",column_type AS "column_type" ';
31 | $sql .= 'FROM information_schema.columns ';
32 | $sql .= 'WHERE table_schema=:database AND table_name=:table';
33 | } else {
34 | // column_type not available in postgres SQL
35 | // table_catalog is database in postgres
36 | $sql = 'SELECT column_name AS "column_name",data_type AS "data_type" FROM information_schema.columns ';
37 | $sql .= 'WHERE table_catalog=:database AND table_name=:table';
38 | }
39 |
40 | $rows = DB::select($sql, ['database' => $database, 'table' => $table]);
41 | $fieldType = null;
42 | $fieldLength = 20;
43 |
44 | foreach ($rows as $col) {
45 | if ($field == $col->column_name) {
46 | $fieldType = $col->data_type;
47 | //column_type not available in postgres SQL
48 | //mysql 8 optional display width for int,bigint numeric field
49 |
50 | if ($driver == 'mysql') {
51 | //example: column_type int(11) to 11
52 | preg_match("/(?<=\().+?(?=\))/", $col->column_type, $tblFieldLength);
53 | if (count($tblFieldLength)) {
54 | $fieldLength = $tblFieldLength[0];
55 | }
56 | }
57 |
58 | break;
59 | }
60 | }
61 |
62 | if ($fieldType == null) {
63 | throw new Exception("$field not found in $table table");
64 | }
65 | return ['type' => $fieldType, 'length' => $fieldLength];
66 | }
67 |
68 | /**
69 | * Main function to generate ID
70 | *
71 | * @param array $configArr configuration to generate ID
72 | *
73 | * @throws Exception if id generation config invalid
74 | * @return string|integer
75 | *
76 | * @since 1.0.0
77 | */
78 | public static function generate($configArr)
79 | {
80 | if (!array_key_exists('table', $configArr) || $configArr['table'] == '') {
81 | throw new Exception('Must need a table name');
82 | }
83 | if (!array_key_exists('length', $configArr) || $configArr['length'] == '') {
84 | throw new Exception('Must specify the length of ID');
85 | }
86 | if (!array_key_exists('prefix', $configArr) || $configArr['prefix'] == '') {
87 | throw new Exception('Must specify a prefix of your ID');
88 | }
89 |
90 | if (array_key_exists('where', $configArr)) {
91 | if (is_string($configArr['where'])) {
92 | throw new Exception('where clause must be an array, you provided string');
93 | }
94 | if (!count($configArr['where'])) {
95 | throw new Exception('where clause must need at least an array');
96 | }
97 | }
98 |
99 | $table = $configArr['table'];
100 | $field = array_key_exists('field', $configArr) ? $configArr['field'] : 'id';
101 | $prefix = $configArr['prefix'];
102 | $resetOnPrefixChange = array_key_exists('reset_on_prefix_change', $configArr)
103 | ? $configArr['reset_on_prefix_change']
104 | : false;
105 | $length = $configArr['length'];
106 |
107 | $fieldInfo = (new self)->getFieldType($table, $field);
108 | $tableFieldType = $fieldInfo['type'];
109 | $tableFieldLength = $fieldInfo['length'];
110 |
111 | if (in_array($tableFieldType, ['int', 'integer', 'bigint', 'numeric']) && !is_numeric($prefix)) {
112 | throw new Exception("$field field type is $tableFieldType but prefix is string");
113 | }
114 |
115 | if ($length > $tableFieldLength) {
116 | throw new Exception('Generated ID length is bigger then table field length');
117 | }
118 |
119 | $prefixLength = strlen($configArr['prefix']);
120 | $idLength = $length - $prefixLength;
121 | $whereString = '';
122 |
123 | if (array_key_exists('where', $configArr)) {
124 | $whereString .= " WHERE ";
125 | foreach ($configArr['where'] as $row) {
126 | $whereString .= $row[0] . "=" . $row[1] . " AND ";
127 | }
128 | }
129 | $whereString = rtrim($whereString, 'AND ');
130 |
131 |
132 | $totalQuery = sprintf("SELECT count(%s) total FROM %s %s", $field, $configArr['table'], $whereString);
133 | $total = DB::select(trim($totalQuery));
134 |
135 | if ($total[0]->total) {
136 | if ($resetOnPrefixChange) {
137 | $maxIdSql = "SELECT MAX(%s) AS maxid FROM %s WHERE %s LIKE %s";
138 | $maxQuery = sprintf($maxIdSql, $field, $table, $field, "'" . $prefix . "%'");
139 | } else {
140 | $maxQuery = sprintf("SELECT MAX(%s) AS maxid FROM %s", $field, $table);
141 | }
142 |
143 | $queryResult = DB::select($maxQuery);
144 | $maxFullId = $queryResult[0]->maxid;
145 |
146 | $maxId = substr($maxFullId, $prefixLength, $idLength);
147 | return $prefix . str_pad((int)$maxId + 1, $idLength, '0', STR_PAD_LEFT);
148 | } else {
149 | return $prefix . str_pad(1, $idLength, '0', STR_PAD_LEFT);
150 | }
151 | }
152 | }
153 |
--------------------------------------------------------------------------------