├── .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 |

Laravel ID Generator

2 |

3 | 4 | 5 | 6 | 7 | 8 |

9 |

Easy way to generate custom ID from database table in Laravel framework

10 | 11 | ![Image description](preview.png) 12 | 13 | ## Support 14 | Buy Me A Coffee 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 | --------------------------------------------------------------------------------