├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── config └── extended.php ├── pint.json ├── resources └── views │ └── .gitkeep └── src ├── DatabaseQueryBuilder ├── BoundaryConstraints.php └── ConditionalConstraints.php ├── LaravelExtendedServiceProvider.php ├── Mixins ├── BuilderMixin.php ├── StrMixin.php └── StringableMixin.php └── Support ├── CallInClosure.php ├── Enums ├── HasName.php └── HasValue.php └── InteractsWithDatabase.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `laravel-extended` will be documented in this file. 4 | 5 | ## v1.2.1 - 2024-09-19 6 | 7 | ### What's Changed 8 | 9 | * Feature/enums name value by @onursimsek in https://github.com/onursimsek/laravel-extended/pull/7 10 | 11 | **Full Changelog**: https://github.com/onursimsek/laravel-extended/compare/1.2.0...1.2.1 12 | 13 | ## v1.2.0 - 2024-09-19 14 | 15 | ### What's Changed 16 | 17 | * Improve tests by @mertasan in https://github.com/onursimsek/laravel-extended/pull/6 18 | 19 | ### New Contributors 20 | 21 | * @mertasan made their first contribution in https://github.com/onursimsek/laravel-extended/pull/6 22 | 23 | **Full Changelog**: https://github.com/onursimsek/laravel-extended/compare/1.1.1...1.2.0 24 | 25 | ## v1.1.1 - 2024-09-17 26 | 27 | ### What's Changed 28 | 29 | * Add InteractsWithDatabase usage to README by @onursimsek in https://github.com/onursimsek/laravel-extended/pull/5 30 | 31 | **Full Changelog**: https://github.com/onursimsek/laravel-extended/compare/1.1.0...1.1.1 32 | 33 | ## v1.1.0 - 2024-09-17 34 | 35 | ### What's Changed 36 | 37 | * Phpstan fix by @onursimsek in https://github.com/onursimsek/laravel-extended/pull/3 38 | * Interacts with database by @onursimsek in https://github.com/onursimsek/laravel-extended/pull/4 39 | 40 | **Full Changelog**: https://github.com/onursimsek/laravel-extended/compare/1.0.0...1.1.0 41 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Onur Şimşek 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Package Image 5 | 6 | 7 | # Extend your Laravel project with mixins and mores 8 | 9 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/onursimsek/laravel-extended.svg?style=flat-square)](https://packagist.org/packages/onursimsek/laravel-extended) 10 | [![MIT Licensed](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) 11 | [![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/onursimsek/laravel-extended/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/onursimsek/laravel-extended/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain) 12 | [![Tests](https://github.com/onursimsek/laravel-extended/actions/workflows/run-tests.yml/badge.svg)](https://github.com/onursimsek/laravel-extended/actions) 13 | [![Total Downloads](https://img.shields.io/packagist/dt/onursimsek/laravel-extended.svg?style=flat-square)](https://packagist.org/packages/onursimsek/) 14 | 15 | ## Installation 16 | 17 | You can install the package via composer: 18 | 19 | ```bash 20 | composer require onursimsek/laravel-extended 21 | ``` 22 | 23 | ## Contents 24 | 25 | - [Illuminate\Database\Query\Builder](#extended-illuminatedatabasequerybuilder) 26 | - [Illuminate\Support\Str](#extended-illuminatesupportstr) 27 | - [Illuminate\Support\Stringable](#extended-illuminatesupportstringable) 28 | - [Useful Traits](#useful-traits) 29 | - [InteractsWithDatabase](#interactswithdatabase) 30 | - [beginTransaction](#begintransactionstring-connections-void) 31 | - [commit](#commitstring-connections-void) 32 | - [commitAll](#commitall-void) 33 | - [rollBack](#rollbackstring-connections-void) 34 | - [rollBack](#rollbackall-void) 35 | - [Example](#interactswithdatabase-example) 36 | - [HasName](#hasname) 37 | - [names](#names) 38 | - [HasValue](#hasvalue) 39 | - [value](#values-and-names) 40 | 41 | ## Usage 42 | 43 | ### Extended Illuminate\Database\Query\Builder 44 | 45 | ```php 46 | Product::whereGreaterThan('price', 500)->get(); 47 | // select * from products where price > 500 48 | Product::whereGreaterThanOrEqual('price', 500)->get(); 49 | // select * from products where price >= 500 50 | 51 | Product::whereLessThan('price', 500)->get(); 52 | // select * from products where price < 500 53 | Product::whereLessThanOrEqual('price', 500)->get(); 54 | // select * from products where price <= 500 55 | 56 | Product::whereColumnGreaterThan('price', 'amount')->get(); 57 | // select * from products where price > amount 58 | Product::whereColumnGreaterThanOrEqual('price', 'amount')->get(); 59 | // select * from products where price >= amount 60 | 61 | Product::whereColumnLessThan('price', 'amount')->get(); 62 | // select * from products where price < amount 63 | Product::whereColumnLessThanOrEqual('price', 'amount')->get(); 64 | // select * from products where price <= amount 65 | 66 | Product::whenWhere(false, 'is_active')->get(); 67 | // select * from products 68 | Product::whenWhere(true, 'is_active')->get(); 69 | // select * from products where is_active = 1 70 | ``` 71 | 72 | ### Extended Illuminate\Support\Str 73 | 74 | ```php 75 | use Illuminate\Support\Str; 76 | 77 | Str::squishBetween("I\twill kiss\t\nyou!", 'kiss', 'you'); 78 | // I will kiss you! 79 | Str::replaceBetween('I will kiss you!', 'will', 'you', 'miss'); 80 | // I will miss you! 81 | Str::replaceBetweenMatch('I will kiss you!', 'will', 'you', '/k(.*)s/', 'hug'); 82 | // I will hug you! 83 | ``` 84 | 85 | ### Extended Illuminate\Support\Stringable 86 | 87 | ```php 88 | use Illuminate\Support\Str; 89 | 90 | Str::of("I\twill kiss\t\nyou!")->squishBetween('kiss', 'you'); 91 | // I will kiss you! 92 | Str::of('I will kiss you!')->replaceBetween('will', 'you', 'miss'); 93 | // I will miss you! 94 | Str::of('I will kiss you!')->replaceBetweenMatch('will', 'you', '/k(.*)s/', 'hug'); 95 | // I will hug you! 96 | ``` 97 | 98 | ## Useful Traits 99 | 100 | ### InteractsWithDatabase 101 | 102 | This trait provides an easy way to manage database transactions across multiple connections. It allows you to **begin**, 103 | **commit**, and **roll back** transactions. 104 | 105 | #### beginTransaction(string ...$connections): void 106 | 107 | This method starts a transaction on the specified database connections. If no connections are provided, the default 108 | database connection specified in your Laravel configuration will be used. 109 | 110 | ```php 111 | $this->beginTransaction(); // Starts transaction on default connection 112 | $this->beginTransaction('mysql', 'sqlite'); // Starts transactions on the 'mysql' and 'sqlite' connections 113 | ``` 114 | 115 | #### commit(string ...$connections): void 116 | 117 | This method commits a transaction on the specified connections. If no connections are specified, nothing will happen. 118 | 119 | ```php 120 | $this->commit(); // No action taken (no specific connection provided) 121 | $this->commit('mysql', 'sqlite'); // Commits the transactions on the 'mysql' and 'sqlite' connections 122 | ``` 123 | 124 | #### commitAll(): void 125 | This method commits transactions on all connections that have begun a transaction during the lifetime of the object. 126 | 127 | ```php 128 | $this->commitAll(); // Commits all active transactions 129 | ``` 130 | 131 | #### rollBack(string ...$connections): void 132 | This method rolls back a transaction on the specified connections. 133 | 134 | ```php 135 | $this->rollBack(); // Rolls back on the default connection 136 | $this->rollBack('mysql', 'sqlite'); // Rolls back on the 'mysql' and 'sqlite' connections 137 | ``` 138 | 139 | #### rollBackAll(): void 140 | This method rolls back transactions on all connections that have begun a transaction during the lifetime of the object. 141 | 142 | ```php 143 | $this->rollBackAll(); // Rolls back all active transactions 144 | ``` 145 | 146 | #### InteractsWithDatabase Example 147 | 148 | ```php 149 | namespace App\Http\Controllers\Controller; 150 | 151 | use OnurSimsek\LaravelExtended\Support\InteractsWithDatabase; 152 | 153 | class Controller 154 | { 155 | use InteractsWithDatabase; 156 | 157 | public function store() 158 | { 159 | $this->beginTransaction('mysql', 'pgsql'); 160 | 161 | try { 162 | // Your data processing logic 163 | 164 | $this->commitAll(); // Commit the transactions if everything goes well 165 | } catch (\Exception $e) { 166 | $this->rollBackAll(); // Roll back if an error occurs 167 | throw $e; 168 | } 169 | } 170 | } 171 | ``` 172 | 173 | ### HasName 174 | 175 | This trait converts the **names** of _UnitEnum_ into an array. 176 | 177 | #### names() 178 | 179 | ```php 180 | enum Status 181 | { 182 | use HasName; 183 | 184 | case Active; 185 | case Inactive; 186 | } 187 | 188 | Status::names(); // ['Active', 'Inactive'] 189 | ``` 190 | 191 | ### HasValue 192 | 193 | #### values() and names() 194 | 195 | This trait converts the **names** and **values** of _BackedEnum_ into an array 196 | 197 | ```php 198 | enum Status: string 199 | { 200 | use HasValue; 201 | 202 | case Active = 'active'; 203 | case Inactive = 'inactive'; 204 | } 205 | 206 | Status::names(); // ['Active', 'Inactive'] 207 | Status::values(); // ['active', 'inactive'] 208 | ``` 209 | 210 | ## Testing 211 | 212 | ```bash 213 | composer test 214 | ``` 215 | 216 | ## Changelog 217 | 218 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 219 | 220 | ## Contributing 221 | 222 | Please see [CONTRIBUTING](CONTRIBUTING.md) for details. 223 | 224 | ## Security Vulnerabilities 225 | 226 | Please review [our security policy](../../security/policy) on how to report security vulnerabilities. 227 | 228 | ## Credits 229 | 230 | - [Onur Şimşek](https://github.com/onursimsek) 231 | - [All Contributors](../../contributors) 232 | 233 | ## License 234 | 235 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 236 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "onursimsek/laravel-extended", 3 | "description": "This is my package laravel-extended", 4 | "keywords": [ 5 | "Onur Şimşek", 6 | "laravel", 7 | "laravel-extended" 8 | ], 9 | "homepage": "https://github.com/onursimsek/laravel-extended", 10 | "license": "MIT", 11 | "authors": [ 12 | { 13 | "name": "Onur Şimşek", 14 | "email": "posta@onursimsek.com", 15 | "role": "Developer" 16 | } 17 | ], 18 | "require": { 19 | "php": "^8.2|^8.3", 20 | "illuminate/contracts": "^10.0||^11.0" 21 | }, 22 | "require-dev": { 23 | "laravel/pint": "^1.14", 24 | "nunomaduro/collision": "^8.1.1||^7.10.0", 25 | "larastan/larastan": "^2.9", 26 | "orchestra/testbench": "^9.0.0||^8.22.0", 27 | "pestphp/pest": "^2.34", 28 | "pestphp/pest-plugin-arch": "^2.7", 29 | "pestphp/pest-plugin-laravel": "^2.3", 30 | "phpstan/extension-installer": "^1.3", 31 | "phpstan/phpstan-deprecation-rules": "^1.1", 32 | "phpstan/phpstan-phpunit": "^1.3" 33 | }, 34 | "autoload": { 35 | "psr-4": { 36 | "OnurSimsek\\LaravelExtended\\": "src/" 37 | } 38 | }, 39 | "autoload-dev": { 40 | "psr-4": { 41 | "OnurSimsek\\LaravelExtended\\Tests\\": "tests/", 42 | "Workbench\\App\\": "workbench/app/", 43 | "Workbench\\Database\\Factories\\": "workbench/database/factories/", 44 | "Workbench\\Database\\Seeders\\": "workbench/database/seeders/" 45 | } 46 | }, 47 | "scripts": { 48 | "post-autoload-dump": [ 49 | "@clear", 50 | "@prepare", 51 | "@composer run prepare" 52 | ], 53 | "clear": "@php vendor/bin/testbench package:purge-skeleton --ansi", 54 | "prepare": "@php vendor/bin/testbench package:discover --ansi", 55 | "build": "@php vendor/bin/testbench workbench:build --ansi", 56 | "start": [ 57 | "Composer\\Config::disableProcessTimeout", 58 | "@composer run build", 59 | "@php vendor/bin/testbench serve" 60 | ], 61 | "analyse": "vendor/bin/phpstan analyse", 62 | "test": "vendor/bin/pest --parallel", 63 | "test-coverage": "vendor/bin/pest --coverage", 64 | "test-coverage-text": "vendor/bin/pest --coverage-text", 65 | "format": "vendor/bin/pint", 66 | "serve": [ 67 | "Composer\\Config::disableProcessTimeout", 68 | "@build", 69 | "@php vendor/bin/testbench serve --ansi" 70 | ], 71 | "lint": [ 72 | "@php vendor/bin/pint --ansi", 73 | "@php vendor/bin/phpstan analyse --verbose --ansi" 74 | ] 75 | }, 76 | "config": { 77 | "sort-packages": true, 78 | "allow-plugins": { 79 | "pestphp/pest-plugin": true, 80 | "phpstan/extension-installer": true 81 | } 82 | }, 83 | "extra": { 84 | "laravel": { 85 | "providers": [ 86 | "OnurSimsek\\LaravelExtended\\LaravelExtendedServiceProvider" 87 | ] 88 | } 89 | }, 90 | "minimum-stability": "dev", 91 | "prefer-stable": true 92 | } 93 | -------------------------------------------------------------------------------- /config/extended.php: -------------------------------------------------------------------------------- 1 | true, 5 | \Illuminate\Support\Str::class => true, 6 | ]; 7 | -------------------------------------------------------------------------------- /pint.json: -------------------------------------------------------------------------------- 1 | { 2 | "preset": "psr12" 3 | } 4 | -------------------------------------------------------------------------------- /resources/views/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onursimsek/laravel-extended/0174bfa254c78c29d73db370d5b9fb963e71c50a/resources/views/.gitkeep -------------------------------------------------------------------------------- /src/DatabaseQueryBuilder/BoundaryConstraints.php: -------------------------------------------------------------------------------- 1 | '; 14 | 15 | private const GREATER_THAN_OR_EQUAL = '>='; 16 | 17 | private const LESS = '<'; 18 | 19 | private const LESS_THAN_OR_EQUAL = '<='; 20 | 21 | public function whereGreaterThan(): Closure 22 | { 23 | return $this->whereClosure(self::GREATER); 24 | } 25 | 26 | public function whereGreaterThanOrEqual(): Closure 27 | { 28 | return $this->whereClosure(self::GREATER_THAN_OR_EQUAL); 29 | } 30 | 31 | public function whereLessThan(): Closure 32 | { 33 | return $this->whereClosure(self::LESS); 34 | } 35 | 36 | public function whereLessThanOrEqual(): Closure 37 | { 38 | return $this->whereClosure(self::LESS_THAN_OR_EQUAL); 39 | } 40 | 41 | private function whereClosure(string $operator): Closure 42 | { 43 | return function (string $column, $value) use ($operator) { 44 | return $this->where($column, $operator, $value); 45 | }; 46 | } 47 | 48 | public function whereColumnGreaterThan(): Closure 49 | { 50 | return $this->whereColumnClosure(self::GREATER); 51 | } 52 | 53 | public function whereColumnGreaterThanOrEqual(): Closure 54 | { 55 | return $this->whereColumnClosure(self::GREATER_THAN_OR_EQUAL); 56 | } 57 | 58 | public function whereColumnLessThan(): Closure 59 | { 60 | return $this->whereColumnClosure(self::LESS); 61 | } 62 | 63 | public function whereColumnLessThanOrEqual(): Closure 64 | { 65 | return $this->whereColumnClosure(self::LESS_THAN_OR_EQUAL); 66 | } 67 | 68 | private function whereColumnClosure(string $operator): \Closure 69 | { 70 | return function (string $first, string $second) use ($operator) { 71 | return $this->whereColumn($first, $operator, $second); 72 | }; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/DatabaseQueryBuilder/ConditionalConstraints.php: -------------------------------------------------------------------------------- 1 | when($value, fn () => $this->where($column, $value)); 17 | }; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/LaravelExtendedServiceProvider.php: -------------------------------------------------------------------------------- 1 | ['Version' => '1.0.0']); 25 | 26 | if (config(sprintf('extended.%s', Builder::class), false)) { 27 | Builder::mixin(new BuilderMixin()); 28 | } 29 | 30 | if (config(sprintf('extended.%s', Str::class), false)) { 31 | Str::mixin(new StrMixin()); 32 | Stringable::mixin(new StringableMixin()); 33 | } 34 | 35 | if ($this->app->runningInConsole()) { 36 | $this->publishing(); 37 | } 38 | } 39 | 40 | public function register(): void 41 | { 42 | $this->mergeConfigFrom(self::CONFIG_PATH, self::CONFIG_KEY); 43 | } 44 | 45 | private function publishing(): void 46 | { 47 | $this->publishes([self::CONFIG_PATH => config_path(self::CONFIG_FILE)], self::CONFIG_KEY); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Mixins/BuilderMixin.php: -------------------------------------------------------------------------------- 1 | callInClosure('between'); 19 | $before = $this->callInClosure('before'); 20 | $after = $this->callInClosure('after'); 21 | 22 | return function (string $str, string $from, string $to) use ($between, $before, $after) { 23 | return $before($str, $from) . self::squish($between($str, $from, $to)) . $after($str, $to); 24 | }; 25 | } 26 | 27 | public function replaceBetweenMatch(): Closure 28 | { 29 | $between = $this->callInClosure('between'); 30 | $before = $this->callInClosure('before'); 31 | $after = $this->callInClosure('after'); 32 | 33 | return function (string $str, string $from, string $to, string $pattern, string $replace) use ($between, $before, $after) { 34 | $target = $between($str, $from, $to); 35 | 36 | return $before($str, $from) . preg_replace($pattern, $replace, $target) . $after($str, $to); 37 | }; 38 | } 39 | 40 | public function replaceBetween(): Closure 41 | { 42 | $between = $this->callInClosure('between'); 43 | $before = $this->callInClosure('before'); 44 | $after = $this->callInClosure('after'); 45 | 46 | return function (string $str, string $from, string $to, string $search, string $replace) use ($between, $before, $after) { 47 | $target = $between($str, $from, $to); 48 | 49 | return $before($str, $from) . str_replace($search, $replace, $target) . $after($str, $to); 50 | }; 51 | } 52 | 53 | private function fromPosition(string $str, string $from): false|int 54 | { 55 | return mb_strpos($str, $from); 56 | } 57 | 58 | private function toPosition(string $str, string $to): false|int 59 | { 60 | return mb_strrpos($str, $to); 61 | } 62 | 63 | private function before(string $str, string $from): string 64 | { 65 | return mb_substr($str, 0, $this->fromPosition($str, $from)); 66 | } 67 | 68 | private function after(string $str, string $to): string 69 | { 70 | return mb_substr($str, $this->toPosition($str, $to) + mb_strlen($to)); 71 | } 72 | 73 | private function between(string $str, string $from, string $to): string 74 | { 75 | $fromPosition = $this->fromPosition($str, $from); 76 | 77 | return mb_substr($str, $fromPosition, $this->toPosition($str, $to) - $fromPosition + mb_strlen($to)); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/Mixins/StringableMixin.php: -------------------------------------------------------------------------------- 1 | value, $from, $to)); 19 | }; 20 | } 21 | 22 | public function replaceBetweenMatch(): Closure 23 | { 24 | return function (string $from, string $to, string $search, string $replace): Stringable { 25 | /** @phpstan-ignore-next-line */ 26 | return new static(Str::replaceBetweenMatch($this->value, $from, $to, $search, $replace)); 27 | }; 28 | } 29 | 30 | public function replaceBetween(): Closure 31 | { 32 | return function (string $from, string $to, string $search, string $replace): Stringable { 33 | /** @phpstan-ignore-next-line */ 34 | return new static(Str::replaceBetween($this->value, $from, $to, $search, $replace)); 35 | }; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Support/CallInClosure.php: -------------------------------------------------------------------------------- 1 | $this->$method(...$args); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Support/Enums/HasName.php: -------------------------------------------------------------------------------- 1 | connections = $connections ?: [$this->defaultConnection()]; 14 | $this->execute('beginTransaction', $this->connections); 15 | } 16 | 17 | public function commit(string ...$connections): void 18 | { 19 | $this->execute('commit', $connections); 20 | } 21 | 22 | public function commitAll(): void 23 | { 24 | $this->execute('commit', $this->connections); 25 | } 26 | 27 | public function rollBack(string ...$connections): void 28 | { 29 | $this->execute('rollBack', $connections); 30 | } 31 | 32 | public function rollBackAll(): void 33 | { 34 | $this->execute('rollBack', $this->connections); 35 | } 36 | 37 | private function defaultConnection() 38 | { 39 | return config('database.default'); 40 | } 41 | 42 | private function execute(string $method, array $connections): void 43 | { 44 | foreach ($connections ?: [$this->defaultConnection()] as $connection) { 45 | DB::connection($connection)->$method(); 46 | } 47 | } 48 | } 49 | --------------------------------------------------------------------------------