├── .gitignore ├── README.md ├── composer.json └── src ├── FirebirdConnection.php ├── FirebirdConnector.php ├── FirebirdQueryBuilder.php ├── FirebirdQueryGrammar.php ├── FirebirdSchemaGrammar.php └── FirebirdServiceProvider.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | .idea 3 | composer.lock 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Firebird database driver for Laravel 6, 7, 8 and 9. 2 | 3 | Package inspired by [jacquestvanzuydam/laravel-firebird](https://github.com/jacquestvanzuydam/laravel-firebird) but simplified, modernized and made compatible with Laravel 6, 7 and 8. 4 | 5 | I do not create my own Firebird databases, only read from existing ones so the INSERT and UPDATE support may be spotty. 6 | 7 | ### Installation 8 | ``` 9 | composer require kkszymanowski/laravel-6-firebird 10 | ``` 11 | Add you database configuration in `config/database.php` 12 | ```php 13 | 'connections' => [ 14 | 'myFirebirdConnection' => [ 15 | 'driver' => 'firebird', 16 | 'host' => env('DB_FIREBIRD_HOST', 'localhost'), 17 | 'port' => env('DB_FIREBIRD_PORT', '3050'), 18 | 'database' => env('DB_FIREBIRD_DATABASE', '/path_to/database.fdb'), 19 | 'username' => env('DB_FIREBIRD_USERNAME', 'SYSDBA'), 20 | 'password' => env('DB_FIREBIRD_PASSWORD', 'masterkey'), 21 | 'charset' => env('DB_FIREBIRD_CHARSET', 'UTF8'), 22 | ], 23 | 24 | // ... 25 | ], 26 | ``` 27 | Add the `DB_FIREBIRD_*` environment variables to your `.env` file, for example: 28 | ``` 29 | DB_FIREBIRD_HOST=192.168.0.1 30 | DB_FIREBIRD_PORT=3050 31 | DB_FIREBIRD_DATABASE=C:/DB.FDB 32 | DB_FIREBIRD_USERNAME=user 33 | DB_FIREBIRD_PASSWORD=password 34 | DB_FIREBIRD_CHARSET=ISO-8859-2 35 | ``` 36 | 37 | ### Usage 38 | #### Eloquent as model 39 | To override your default database connection define `$connection` name in your Eloquent Model 40 | ```php 41 | /** 42 | * The connection name for the model. 43 | * 44 | * @var string 45 | */ 46 | protected $connection = 'myFirebirdConnection'; 47 | ``` 48 | After defining connection name you can use it in normal way as you use Eloquent: 49 | ```php 50 | $user = User::where('id', 1)->get(); 51 | 52 | $users = User::all(); 53 | ``` 54 | 55 | #### DB Query 56 | Each time you have to define connection name (if it isn't your default one), for example: 57 | ```php 58 | $sql = 'SELECT * FROM USERS WHERE id = :id'; 59 | $bindings = ['id' => 1]; 60 | $user = DB::connection('myFirebirdConnection')->select($sql, $bindings); 61 | 62 | $users = DB::connection('myFirebirdConnection')->table('USERS')->select('*')->get(); 63 | ``` 64 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kkszymanowski/laravel-6-firebird", 3 | "description": "A Firebird database package for Laravel 6", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Kuba Szymanowski", 8 | "email": "kubaszymanowski@gmail.com" 9 | }, 10 | { 11 | "name": "Jacques van Zuydam", 12 | "email": "jtvanzuydam@gmail.com" 13 | } 14 | ], 15 | "minimum-stability": "dev", 16 | "prefer-stable": true, 17 | "require": { 18 | "php": ">=7.2.0", 19 | "ext-pdo": "*", 20 | "illuminate/support": ">=6.0", 21 | "illuminate/database": ">=6.0" 22 | }, 23 | "extra": { 24 | "laravel": { 25 | "providers": [ 26 | "Firebird\\FirebirdServiceProvider" 27 | ] 28 | } 29 | }, 30 | "autoload":{ 31 | "psr-4": { 32 | "Firebird\\": "src/" 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/FirebirdConnection.php: -------------------------------------------------------------------------------- 1 | withTablePrefix(new FirebirdSchemaGrammar()); 27 | } 28 | 29 | /** 30 | * Get a new query builder instance. 31 | * 32 | * @return FirebirdQueryBuilder 33 | */ 34 | public function query() 35 | { 36 | return new FirebirdQueryBuilder( 37 | $this, $this->getQueryGrammar(), $this->getPostProcessor() 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/FirebirdConnector.php: -------------------------------------------------------------------------------- 1 | getOptions($config); 22 | $path = $config['database']; 23 | $charset = $config['charset']; 24 | $uri = $config['host']; 25 | $port = $config['port'] ?? null; 26 | 27 | if($port) { 28 | $uri .= '/' . $port; 29 | } 30 | 31 | return $this->createConnection("firebird:dbname=$uri:$path;charSet=$charset", $config, $options); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/FirebirdQueryBuilder.php: -------------------------------------------------------------------------------- 1 | 0; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/FirebirdQueryGrammar.php: -------------------------------------------------------------------------------- 1 | aggregate)) return; 43 | $select = ''; 44 | if (count($columns) > 0 && $query->limit == null && $query->aggregate == null) { 45 | $select = $query->distinct ? 'select distinct ' : 'select '; 46 | } 47 | 48 | return $select . $this->columnize($columns); 49 | } 50 | 51 | /** 52 | * Compile a select query into SQL. 53 | * 54 | * @param Builder $query 55 | * @return string 56 | */ 57 | public function compileSelect(Builder $query) 58 | { 59 | if (is_null($query->columns)) $query->columns = array('*'); 60 | 61 | return trim($this->concatenate($this->compileComponents($query))); 62 | } 63 | 64 | /** 65 | * Compile an aggregated select clause. 66 | * 67 | * @param Builder $query 68 | * @param array $aggregate 69 | * @return string 70 | */ 71 | protected function compileAggregate(Builder $query, $aggregate) 72 | { 73 | $column = $this->columnize($aggregate['columns']); 74 | 75 | // If the query has a "distinct" constraint and we're not asking for all columns 76 | // we need to prepend "distinct" onto the column name so that the query takes 77 | // it into account when it performs the aggregating operations on the data. 78 | if ($query->distinct && $column !== '*') { 79 | $column = 'distinct ' . $column; 80 | } 81 | 82 | return 'select ' . $aggregate['function'] . '(' . $column . ') as aggregate'; 83 | } 84 | 85 | /** 86 | * Compile first instead of limit 87 | * 88 | * @param Builder $query 89 | * @param int $limit 90 | * @return string 91 | */ 92 | protected function compileLimit(Builder $query, $limit) 93 | { 94 | return 'select first ' . (int)$limit; 95 | } 96 | 97 | /** 98 | * Compile skip instead of offset 99 | * 100 | * @param Builder $query 101 | * @param int $limit 102 | * @return string 103 | */ 104 | protected function compileOffset(Builder $query, $limit) 105 | { 106 | return 'skip ' . (int)$limit; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/FirebirdSchemaGrammar.php: -------------------------------------------------------------------------------- 1 | getColumns($blueprint)); 47 | 48 | $sql = 'create table '.$this->wrapTable($blueprint)." ($columns)"; 49 | 50 | return $sql; 51 | } 52 | 53 | /** 54 | * Compile a drop table command. 55 | * 56 | * @param Blueprint $blueprint 57 | * @param Fluent $command 58 | * @return string 59 | */ 60 | public function compileDrop(Blueprint $blueprint, Fluent $command) 61 | { 62 | return 'drop table '.$this->wrapTable($blueprint); 63 | } 64 | 65 | /** 66 | * Compile a primary key command. 67 | * 68 | * @param Blueprint $blueprint 69 | * @param Fluent $command 70 | * @return string 71 | */ 72 | public function compilePrimary(Blueprint $blueprint, Fluent $command) 73 | { 74 | $command->name(null); 75 | 76 | return $this->compileKey($blueprint, $command, 'primary key'); 77 | } 78 | 79 | /** 80 | * Compile a unique key command. 81 | * 82 | * @param Blueprint $blueprint 83 | * @param Fluent $command 84 | * @return string 85 | */ 86 | public function compileUnique(Blueprint $blueprint, Fluent $command) 87 | { 88 | $columns = $this->columnize($command->columns); 89 | 90 | $table = $this->wrapTable($blueprint); 91 | 92 | return "CREATE UNIQUE INDEX ".strtoupper(substr($command->index, 0, 31))." ON {$table} ($columns)"; 93 | } 94 | 95 | /** 96 | * Compile a plain index key command. 97 | * 98 | * @param Blueprint $blueprint 99 | * @param Fluent $command 100 | * @return string 101 | */ 102 | public function compileIndex(Blueprint $blueprint, Fluent $command) 103 | { 104 | $columns = $this->columnize($command->columns); 105 | 106 | $table = $this->wrapTable($blueprint); 107 | 108 | return "CREATE INDEX ".strtoupper(substr($command->index, 0, 31))." ON {$table} ($columns)"; 109 | } 110 | 111 | /** 112 | * Compile an index creation command. 113 | * 114 | * @param Blueprint $blueprint 115 | * @param Fluent $command 116 | * @param string $type 117 | * @return string 118 | */ 119 | protected function compileKey(Blueprint $blueprint, Fluent $command, $type) 120 | { 121 | $columns = $this->columnize($command->columns); 122 | 123 | $table = $this->wrapTable($blueprint); 124 | 125 | return "alter table {$table} add {$type} ($columns)"; 126 | } 127 | 128 | /** 129 | * Compile a foreign key command. 130 | * 131 | * @param Blueprint $blueprint 132 | * @param Fluent $command 133 | * @return string 134 | */ 135 | public function compileForeign(Blueprint $blueprint, Fluent $command) 136 | { 137 | $table = $this->wrapTable($blueprint); 138 | 139 | $on = $this->wrapTable($command->on); 140 | 141 | // We need to prepare several of the elements of the foreign key definition 142 | // before we can create the SQL, such as wrapping the tables and convert 143 | // an array of columns to comma-delimited strings for the SQL queries. 144 | $columns = $this->columnize($command->columns); 145 | 146 | $onColumns = $this->columnize((array) $command->references); 147 | 148 | $sql = "alter table {$table} add constraint ".strtoupper(substr($command->index, 0, 31))." "; 149 | 150 | $sql .= "foreign key ({$columns}) references {$on} ({$onColumns})"; 151 | 152 | // Once we have the basic foreign key creation statement constructed we can 153 | // build out the syntax for what should happen on an update or delete of 154 | // the affected columns, which will get something like "cascade", etc. 155 | if ( ! is_null($command->onDelete)) 156 | { 157 | $sql .= " on delete {$command->onDelete}"; 158 | } 159 | 160 | if ( ! is_null($command->onUpdate)) 161 | { 162 | $sql .= " on update {$command->onUpdate}"; 163 | } 164 | 165 | return $sql; 166 | } 167 | 168 | /** 169 | * Compile a drop foreign key command. 170 | * 171 | * @param Blueprint $blueprint 172 | * @param Fluent $command 173 | * @return string 174 | */ 175 | public function compileDropForeign(Blueprint $blueprint, Fluent $command) 176 | { 177 | $table = $this->wrapTable($blueprint); 178 | 179 | return "alter table {$table} drop constraint {$command->index}"; 180 | } 181 | 182 | /** 183 | * Get the SQL for a nullable column modifier. 184 | * 185 | * @param Blueprint $blueprint 186 | * @param Fluent $column 187 | * @return string|null 188 | */ 189 | protected function modifyNullable(Blueprint $blueprint, Fluent $column) 190 | { 191 | return $column->nullable ? '' : ' not null'; 192 | } 193 | 194 | /** 195 | * Get the SQL for a default column modifier. 196 | * 197 | * @param Blueprint $blueprint 198 | * @param Fluent $column 199 | * @return string|null 200 | */ 201 | protected function modifyDefault(Blueprint $blueprint, Fluent $column) 202 | { 203 | if ( ! is_null($column->default)) 204 | { 205 | return " default ".$this->getDefaultValue($column->default); 206 | } 207 | } 208 | 209 | /** 210 | * Create the column definition for a char type. 211 | * 212 | * @param Fluent $column 213 | * @return string 214 | */ 215 | protected function typeChar(Fluent $column) 216 | { 217 | return 'VARCHAR'; 218 | } 219 | 220 | /** 221 | * Create the column definition for a string type. 222 | * 223 | * @param Fluent $column 224 | * @return string 225 | */ 226 | protected function typeString(Fluent $column) 227 | { 228 | return 'VARCHAR ('.$column->length.')'; 229 | } 230 | 231 | /** 232 | * Create the column definition for a text type. 233 | * 234 | * @param Fluent $column 235 | * @return string 236 | */ 237 | protected function typeText(Fluent $column) 238 | { 239 | return 'BLOB SUB_TYPE TEXT'; 240 | } 241 | 242 | /** 243 | * Create the column definition for a medium text type. 244 | * 245 | * @param Fluent $column 246 | * @return string 247 | */ 248 | protected function typeMediumText(Fluent $column) 249 | { 250 | return 'BLOB SUB_TYPE TEXT'; 251 | } 252 | 253 | /** 254 | * Create the column definition for a long text type. 255 | * 256 | * @param Fluent $column 257 | * @return string 258 | */ 259 | protected function typeLongText(Fluent $column) 260 | { 261 | return 'BLOB SUB_TYPE TEXT'; 262 | } 263 | 264 | /** 265 | * Create the column definition for a integer type. 266 | * 267 | * @param Fluent $column 268 | * @return string 269 | */ 270 | protected function typeInteger(Fluent $column) 271 | { 272 | return 'INTEGER'; 273 | } 274 | 275 | /** 276 | * Create the column definition for a big integer type. 277 | * 278 | * @param Fluent $column 279 | * @return string 280 | */ 281 | protected function typeBigInteger(Fluent $column) 282 | { 283 | return 'INTEGER'; 284 | } 285 | 286 | /** 287 | * Create the column definition for a medium integer type. 288 | * 289 | * @param Fluent $column 290 | * @return string 291 | */ 292 | protected function typeMediumInteger(Fluent $column) 293 | { 294 | return 'INTEGER'; 295 | } 296 | 297 | /** 298 | * Create the column definition for a tiny integer type. 299 | * 300 | * @param Fluent $column 301 | * @return string 302 | */ 303 | protected function typeTinyInteger(Fluent $column) 304 | { 305 | return 'SMALLINT'; 306 | } 307 | 308 | /** 309 | * Create the column definition for a small integer type. 310 | * 311 | * @param Fluent $column 312 | * @return string 313 | */ 314 | protected function typeSmallInteger(Fluent $column) 315 | { 316 | return 'SMALLINT'; 317 | } 318 | 319 | /** 320 | * Create the column definition for a float type. 321 | * 322 | * @param Fluent $column 323 | * @return string 324 | */ 325 | protected function typeFloat(Fluent $column) 326 | { 327 | return 'FLOAT'; 328 | } 329 | 330 | /** 331 | * Create the column definition for a double type. 332 | * 333 | * @param Fluent $column 334 | * @return string 335 | */ 336 | protected function typeDouble(Fluent $column) 337 | { 338 | return 'DOUBLE'; 339 | } 340 | 341 | /** 342 | * Create the column definition for a decimal type. 343 | * 344 | * @param Fluent $column 345 | * @return string 346 | */ 347 | protected function typeDecimal(Fluent $column) 348 | { 349 | return 'DECIMAL'; 350 | } 351 | 352 | /** 353 | * Create the column definition for a boolean type. 354 | * 355 | * @param Fluent $column 356 | * @return string 357 | */ 358 | protected function typeBoolean(Fluent $column) 359 | { 360 | return 'CHAR(1)'; 361 | } 362 | 363 | /** 364 | * Create the column definition for an enum type. 365 | * 366 | * @param Fluent $column 367 | * @return string 368 | */ 369 | protected function typeEnum(Fluent $column) 370 | { 371 | return 'VARCHAR'; 372 | } 373 | 374 | /** 375 | * Create the column definition for a json type. 376 | * 377 | * @param Fluent $column 378 | * @return string 379 | */ 380 | protected function typeJson(Fluent $column) 381 | { 382 | return 'BLOB SUB_TYPE 0'; 383 | } 384 | 385 | /** 386 | * Create the column definition for a date type. 387 | * 388 | * @param Fluent $column 389 | * @return string 390 | */ 391 | protected function typeDate(Fluent $column) 392 | { 393 | return 'TIMESTAMP'; 394 | } 395 | 396 | /** 397 | * Create the column definition for a date-time type. 398 | * 399 | * @param Fluent $column 400 | * @return string 401 | */ 402 | protected function typeDateTime(Fluent $column) 403 | { 404 | return 'TIMESTAMP'; 405 | } 406 | 407 | /** 408 | * Create the column definition for a time type. 409 | * 410 | * @param Fluent $column 411 | * @return string 412 | */ 413 | protected function typeTime(Fluent $column) 414 | { 415 | return 'TIMESTAMP'; 416 | } 417 | 418 | /** 419 | * Create the column definition for a timestamp type. 420 | * 421 | * @param Fluent $column 422 | * @return string 423 | */ 424 | protected function typeTimestamp(Fluent $column) 425 | { 426 | return 'TIMESTAMP'; 427 | } 428 | 429 | /** 430 | * Create the column definition for a binary type. 431 | * 432 | * @param Fluent $column 433 | * @return string 434 | */ 435 | protected function typeBinary(Fluent $column) 436 | { 437 | return 'BLOB SUB_TYPE 0'; 438 | } 439 | } 440 | -------------------------------------------------------------------------------- /src/FirebirdServiceProvider.php: -------------------------------------------------------------------------------- 1 | connect($config); 30 | 31 | return new FirebirdConnection($pdo, $database, $prefix, $config); 32 | }); 33 | } 34 | } 35 | --------------------------------------------------------------------------------