├── .gitignore ├── .styleci.yml ├── .idea ├── vcs.xml ├── markdown.xml ├── laravel-idea.xml ├── .gitignore ├── phpunit.xml ├── modules.xml ├── laravel-idea-personal.xml ├── codeception.xml ├── phpspec.xml ├── laravel-metrics.iml ├── php.xml └── blade.xml ├── src ├── HasMetrics.php ├── LaravelMetricsFacade.php ├── Enums │ ├── Aggregate.php │ └── Period.php ├── Exceptions │ ├── InvalidDateFormatException.php │ ├── InvalidPeriodException.php │ ├── InvalidAggregateException.php │ └── InvalidVariationsCountException.php ├── DatesFunctions.php └── LaravelMetrics.php ├── .github └── FUNDING.yml ├── LICENSE.md ├── composer.json ├── CHANGELOG.md ├── CONTRIBUTING.md ├── README.md └── composer.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: laravel 2 | 3 | disabled: 4 | - single_class_element_per_statement 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/markdown.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/laravel-idea.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/HasMetrics.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /src/LaravelMetricsFacade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 32 | 33 | -------------------------------------------------------------------------------- /.idea/phpspec.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 11 | 12 | 14 | 15 | 17 | 18 | 20 | 21 | 23 | 24 | 26 | 27 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eliseekn/laravel-metrics", 3 | "description": "Generate easily metrics and trends data of your models for your dashboards.", 4 | "keywords": [ 5 | "laravel-package", 6 | "charts", 7 | "laravel", 8 | "dashboard" 9 | ], 10 | "homepage": "https://github.com/eliseekn/laravel-metrics", 11 | "license": "MIT", 12 | "type": "library", 13 | "authors": [ 14 | { 15 | "name": "N'Guessan Kouadio Elisée", 16 | "email": "eliseekn@gmail.com", 17 | "homepage": "https://eliseekn.netlify.app", 18 | "role": "Developer" 19 | } 20 | ], 21 | "minimum-stability": "stable", 22 | "require": { 23 | "php": "^8.1", 24 | "illuminate/database": "^10.20", 25 | "illuminate/support": "^10.20", 26 | "nesbot/carbon": "^2.69" 27 | }, 28 | "require-dev": { 29 | "laravel/pint": "^1.13", 30 | "phpunit/phpunit": "^9.6" 31 | }, 32 | "autoload": { 33 | "psr-4": { 34 | "Eliseekn\\LaravelMetrics\\": "src" 35 | } 36 | }, 37 | "autoload-dev": { 38 | "psr-4": { 39 | "Eliseekn\\LaravelMetrics\\Tests\\": "tests" 40 | } 41 | }, 42 | "scripts": { 43 | "test": "vendor/bin/phpunit" 44 | }, 45 | "config": { 46 | "sort-packages": true 47 | }, 48 | "extra": { 49 | "laravel": { 50 | "aliases": { 51 | "LaravelMetrics": "Eliseekn\\LaravelMetrics\\LaravelMetricsFacade" 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `laravel-metrics` will be documented in this file 4 | 5 | ## 2.9.3 6 | 7 | - Fix date function by database driver 8 | - Fix metrics negative variation value display 9 | 10 | ## 2.9.2 11 | 12 | - Rebase branch 2.9.0-beta-1 onto 2.x 13 | 14 | ## 2.9.2-beta-2 15 | 16 | - Add metricsWithVariations method 17 | - Fix some bugs 18 | 19 | ## 2.9.0-beta-1 20 | 21 | - Add SQLite support 22 | - Add $missingDataLabels auto discovery 23 | - Add metrics with variations option 24 | - Add trends in percents option 25 | - Fix PostgreSQL support bugs 26 | 27 | ## 2.8.0 28 | 29 | - Add PostgreSQL support 30 | 31 | ## 2.7.4 32 | 33 | - Add "from" period to set custom startDate end use the current date as endDate for between period 34 | 35 | ## 2.7.3 36 | 37 | - Fix null exception on get metrics data 38 | 39 | ## 2.7.0 40 | 41 | - Replace fillEmptyData by fillMissingData 42 | - Set fillMissingData as global method 43 | - Add groupBy methods for between period 44 | - Fix some bugs 45 | 46 | ## 2.6.1 47 | 48 | - Add Combined periods and aggregates methods 49 | 50 | ## 2.6 51 | 52 | - Add 'fillEmptyDates' method to fill data for empty dates 53 | - Fix get trends from 'between' method when using custom label 54 | 55 | ## 2.4.1 56 | 57 | - Fix undefined array key 'data' exception when trends are empty 58 | 59 | ## 2.4.0 60 | 61 | - Add HasMetrics trait for models 62 | 63 | ## 2.3.0 64 | 65 | - Add forDay and forMonth methods 66 | 67 | ## 2.1.0 68 | 69 | - Add custom label column definition 70 | - Move periods and aggregates constants to enums 71 | 72 | ## 2.0.0 73 | 74 | - Upgrade to PHP version to 8.1 75 | - Add SQLite support 76 | - Update whole code structure 77 | - Remove static method 78 | - Add eloquent query builder 79 | 80 | ## 1.0.5 - 2022-01-04 81 | 82 | - Fix parameters types 83 | 84 | ## 1.0.4 - 2022-01-04 85 | 86 | - Add demo project link 87 | 88 | ## 1.0.3 - 2021-12-30 89 | 90 | - Fix getTrends() returns data 91 | - Fix custom date range result 92 | 93 | ## 1.0.2 - 2021-12-30 94 | 95 | - Add custom date range 96 | 97 | ## 1.0.1 - 2021-09-25 98 | 99 | - Add Carbon package 100 | - Remove unnecessary files and folder 101 | 102 | ## 1.0.0 - 2021-09-25 103 | 104 | - Initial release 105 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | Please read and understand the contribution guide before creating an issue or pull request. 6 | 7 | ## Etiquette 8 | 9 | This project is open source, and as such, the maintainers give their free time to build and maintain the source code 10 | held within. They make the code freely available in the hope that it will be of use to other developers. It would be 11 | extremely unfair for them to suffer abuse or anger for their hard work. 12 | 13 | Please be considerate towards maintainers when raising issues or presenting pull requests. Let's show the 14 | world that developers are civilized and selfless people. 15 | 16 | It's the duty of the maintainer to ensure that all submissions to the project are of sufficient 17 | quality to benefit the project. Many developers have different skillsets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used. 18 | 19 | ## Viability 20 | 21 | When requesting or submitting new features, first consider whether it might be useful to others. Open 22 | source projects are used by many developers, who may have entirely different needs to your own. Think about 23 | whether or not your feature is likely to be used by other users of the project. 24 | 25 | ## Procedure 26 | 27 | Before filing an issue: 28 | 29 | - Attempt to replicate the problem, to ensure that it wasn't a coincidental incident. 30 | - Check to make sure your feature suggestion isn't already present within the project. 31 | - Check the pull requests tab to ensure that the bug doesn't have a fix in progress. 32 | - Check the pull requests tab to ensure that the feature isn't already in progress. 33 | 34 | Before submitting a pull request: 35 | 36 | - Check the codebase to ensure that your feature doesn't already exist. 37 | - Check the pull requests to ensure that another person hasn't already submitted the feature or fix. 38 | 39 | ## Requirements 40 | 41 | If the project maintainer has any additional requirements, you will find them listed here. 42 | 43 | - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](https://pear.php.net/package/PHP_CodeSniffer). 44 | 45 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests. 46 | 47 | - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. 48 | 49 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option. 50 | 51 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 52 | 53 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](https://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. 54 | 55 | **Happy coding**! 56 | -------------------------------------------------------------------------------- /.idea/laravel-metrics.iml: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /.idea/php.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | 12 | 14 | 15 | 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 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 84 | -------------------------------------------------------------------------------- /src/DatesFunctions.php: -------------------------------------------------------------------------------- 1 | year.'-'.$this->month.'-'.$this->day); 19 | } 20 | 21 | protected function getDayPeriod(): array 22 | { 23 | $day = $this->month !== Carbon::now()->month ? $this->carbon()->endOfMonth()->day : $this->day; 24 | $diff = $day - $this->carbon()->startOfMonth()->day; 25 | 26 | if ($diff < $this->count) { 27 | return [$this->carbon()->startOfMonth()->day, $day]; 28 | } 29 | 30 | return [$this->carbon()->subDays($this->count)->day, $day]; 31 | } 32 | 33 | protected function getWeekPeriod(): array 34 | { 35 | $week = $this->month !== Carbon::now()->month ? $this->carbon()->endOfMonth()->week : $this->week; 36 | $diff = $week - $this->carbon()->startOfMonth()->week; 37 | 38 | if ($diff < $this->count) { 39 | return [$this->carbon()->startOfMonth()->week, $week]; 40 | } 41 | 42 | return [$this->carbon()->subWeeks($this->count)->week, $week]; 43 | } 44 | 45 | protected function getMonthPeriod(): array 46 | { 47 | $month = $this->year !== Carbon::now()->year ? $this->carbon()->endOfYear()->month : $this->month; 48 | $diff = $month - $this->carbon()->startOfYear()->month; 49 | 50 | if ($diff < $this->count) { 51 | return [$this->carbon()->startOfYear()->month, $month]; 52 | } 53 | 54 | return [$this->carbon()->subMonths($this->count)->month, $month]; 55 | } 56 | 57 | protected function formatPeriod(string $period): string 58 | { 59 | $driver = $this->builder->getConnection()->getDriverName(); 60 | 61 | if ($driver === 'mysql') { 62 | return match ($period) { 63 | Period::TODAY->value, Period::DAY->value => "day($this->dateColumn)", 64 | Period::WEEK->value => "week($this->dateColumn)", 65 | Period::MONTH->value => "month($this->dateColumn)", 66 | default => "year($this->dateColumn)", 67 | }; 68 | } 69 | 70 | if ($driver === 'pgsql') { 71 | return match ($period) { 72 | Period::TODAY->value, Period::DAY->value => "EXTRACT(DAY FROM $this->dateColumn)", 73 | Period::WEEK->value => "EXTRACT(WEEK FROM $this->dateColumn)", 74 | Period::MONTH->value => "EXTRACT(MONTH FROM $this->dateColumn)", 75 | default => "EXTRACT(YEAR FROM $this->dateColumn)", 76 | }; 77 | } 78 | 79 | return match ($period) { 80 | Period::TODAY->value, Period::DAY->value => "strftime('%d', $this->dateColumn)", 81 | Period::WEEK->value => "strftime('%W', $this->dateColumn)", 82 | Period::MONTH->value => "strftime('%m', $this->dateColumn)", 83 | default => "strftime('%Y', $this->dateColumn)", 84 | }; 85 | } 86 | 87 | protected function formatDateColumn(): string 88 | { 89 | $driver = $this->builder->getConnection()->getDriverName(); 90 | 91 | return match ($driver) { 92 | 'mysql' => "date($this->dateColumn)", 93 | 'pgsql' => "TO_CHAR($this->dateColumn, 'YYYY-MM-DD')", 94 | default => "strftime('%Y-%m-%d', $this->dateColumn)", 95 | }; 96 | } 97 | 98 | protected function formatDate(array $data): array 99 | { 100 | return array_map(function ($datum) { 101 | if (! is_numeric($datum['label']) && ! DateTime::createFromFormat('Y-m-d', $datum['label'])) { 102 | return $datum; 103 | } 104 | 105 | if ($this->period === Period::MONTH->value) { 106 | $datum['label'] = Carbon::parse($this->year.'-'.$datum['label'])->locale(self::locale())->monthName; 107 | } elseif ($this->period === Period::DAY->value) { 108 | $datum['label'] = Carbon::parse($this->year.'-'.$this->month.'-'.$datum['label'])->locale(self::locale())->dayName; 109 | } elseif ($this->period === Period::WEEK->value) { 110 | $datum['label'] = 'Week '.$datum['label']; 111 | } elseif ($this->period === Period::YEAR->value) { 112 | $datum['label'] = intval($datum['label']); 113 | } else { 114 | $datum['label'] = Carbon::parse($datum['label'])->locale(self::locale())->isoFormat($this->dateIsoFormat); 115 | } 116 | 117 | return $datum; 118 | }, $data); 119 | } 120 | 121 | protected function checkDateFormat(array $dates): void 122 | { 123 | foreach ($dates as $date) { 124 | $d = DateTime::createFromFormat('Y-m-d', $date); 125 | 126 | if (! $d || $d->format('Y-m-d') !== $date) { 127 | throw new InvalidDateFormatException(); 128 | } 129 | } 130 | } 131 | 132 | protected function getMonthsData(): array 133 | { 134 | $result = []; 135 | 136 | $dates = collect( 137 | CarbonPeriod::between( 138 | $this->carbon()->startOfYear()->format('Y-m-d'), 139 | $this->carbon()->format('Y-m-d') 140 | )->interval('1 month')) 141 | ->map(fn ($date) => Carbon::parse($date)->locale(self::locale())->monthName)->toArray(); 142 | 143 | foreach ($dates as $date) { 144 | $result[$date] = $this->missingDataValue; 145 | } 146 | 147 | return $result; 148 | } 149 | 150 | protected function getDaysData(): array 151 | { 152 | $result = []; 153 | 154 | $dates = collect( 155 | CarbonPeriod::between( 156 | $this->carbon()->startOfWeek()->format('Y-m-d'), 157 | $this->carbon()->format('Y-m-d') 158 | )->interval('1 day')) 159 | ->map(fn ($date) => Carbon::parse($date)->locale(self::locale())->dayName)->toArray(); 160 | 161 | foreach ($dates as $date) { 162 | $result[$date] = $this->missingDataValue; 163 | } 164 | 165 | return $result; 166 | } 167 | 168 | protected function getWeeksData(): array 169 | { 170 | $result = []; 171 | 172 | $dates = collect( 173 | CarbonPeriod::between( 174 | $this->carbon()->startOfMonth()->format('Y-m-d'), 175 | $this->carbon()->format('Y-m-d') 176 | )->interval('1 week')) 177 | ->map(fn ($date) => 'Week '.Carbon::parse($date)->locale(self::locale())->week)->toArray(); 178 | 179 | foreach ($dates as $date) { 180 | $result[$date] = $this->missingDataValue; 181 | } 182 | 183 | return $result; 184 | } 185 | 186 | protected function getYearsData(): array 187 | { 188 | $result = []; 189 | 190 | $dates = collect( 191 | CarbonPeriod::between( 192 | $this->carbon()->subYears($this->count), 193 | $this->carbon() 194 | )->interval('1 year')) 195 | ->map(fn ($date) => Carbon::parse($date)->locale(self::locale())->year)->toArray(); 196 | 197 | foreach ($dates as $date) { 198 | $result[$date] = $this->missingDataValue; 199 | } 200 | 201 | return $result; 202 | } 203 | 204 | protected function getLabelsData(): array 205 | { 206 | $result = []; 207 | 208 | $labelColumn = explode('.', $this->labelColumn)[1]; 209 | 210 | $missingDataLabels = empty($this->missingDataLabels) 211 | ? DB::table($this->table)->get()->pluck($labelColumn)->toArray() 212 | : $this->missingDataLabels; 213 | 214 | foreach ($missingDataLabels as $label) { 215 | $result[$label] = $this->missingDataValue; 216 | } 217 | 218 | return $result; 219 | } 220 | 221 | protected function getCustomPeriod(): array 222 | { 223 | return collect( 224 | CarbonPeriod::between( 225 | $this->period[0], 226 | $this->period[1] 227 | )->interval('1 '.$this->groupBy)) 228 | ->map(fn ($date) => Carbon::parse($date)->format('Y-m-d'))->toArray(); 229 | } 230 | 231 | protected function getPeriod(): array 232 | { 233 | return match ($this->period) { 234 | Period::MONTH->value => $this->getMonthsData(), 235 | Period::DAY->value => $this->getDaysData(), 236 | Period::WEEK->value => $this->getWeeksData(), 237 | default => $this->getYearsData() 238 | }; 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Metrics for Laravel 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/eliseekn/laravel-metrics.svg?style=flat-square)](https://packagist.org/packages/eliseekn/laravel-metrics) 4 | [![Total Downloads](https://img.shields.io/packagist/dt/eliseekn/laravel-metrics.svg?style=flat-square)](https://packagist.org/packages/eliseekn/laravel-metrics) 5 | 6 | Generate easily metrics and trends data of your models for your dashboards. 7 | 8 | ## Requirements 9 | ```bash 10 | PHP ^8.1.x 11 | Laravel ^10.x 12 | ``` 13 | 14 | ***Note :*** For Laravel 11.x support check [3.x](https://github.com/eliseekn/laravel-metrics/tree/3.x) branch. 15 | 16 | ## Installation 17 | ```bash 18 | composer require eliseekn/laravel-metrics 19 | ``` 20 | 21 | ## Features 22 | - MySQ, PostgreSQL and SQLite support 23 | - Verbose query builder 24 | - Custom columns and table definition 25 | - Days and months translation with Carbon 26 | 27 | ## Usage 28 | 29 | ### With Eloquent Query 30 | 31 | Import the `Eliseekn\LaravelMetrics\LaravelMetrics` class in your controller and use it as follows : 32 | - Basic usage 33 | 34 | ```php 35 | // generate trends of products amount's sum for the current year 36 | LaravelMetrics::query(Product::query()) 37 | ->count() 38 | ->byMonth() 39 | ->trends(); 40 | 41 | // generate trends of orders amount's sum for the last 6 months of the current year including current month 42 | LaravelMetrics::query(Order::query()) 43 | ->sum('amount') 44 | ->byMonth(6) 45 | ->trends(); 46 | 47 | // generate total orders amount's sum 48 | LaravelMetrics::query(Order::query()) 49 | ->sum('amount') 50 | ->byYear() 51 | ->metrics(); 52 | 53 | // generate total product count for the current day 54 | LaravelMetrics::query(Product::query()) 55 | ->count() 56 | ->byDay(1) 57 | ->metrics(); 58 | ``` 59 | 60 | - Using custom query 61 | ```php 62 | LaravelMetrics::query( 63 | Post::query()->where('user_id', auth()->id()) 64 | ) 65 | ->count() 66 | ->byDay() 67 | ->trends(); 68 | ``` 69 | 70 | - Using custom date column 71 | ```php 72 | LaravelMetrics::query(Post::query()) 73 | ->count() 74 | ->byDay() 75 | ->dateColumn('published_at') 76 | ->trends(); 77 | ``` 78 | 79 | - Using date range 80 | ```php 81 | LaravelMetrics::query(Post::query())) 82 | ->count() 83 | ->between('2020-05-01', '2022-08-21') 84 | ->trends(); 85 | ``` 86 | 87 | - Using custom label column 88 | ```php 89 | LaravelMetrics::query(Order::query()) 90 | ->count() 91 | ->byMonth(12) 92 | ->labelColumn('status') 93 | ->trends(); 94 | ``` 95 | 96 | - Using custom table 97 | ```php 98 | LaravelMetrics::query( 99 | Order::query()->join('users', 'orders.id', 'users.order_id') 100 | ) 101 | ->count() 102 | ->table('users') 103 | ->labelColumn('name') 104 | ->trends(); 105 | ``` 106 | 107 | ### With Query Builder 108 | ```php 109 | LaravelMetrics::query( 110 | DB::table('orders') 111 | ) 112 | ->sum('amount') 113 | ->byMonth() 114 | ->trends(); 115 | ``` 116 | 117 | ### With traits 118 | 119 | Add `HasMetrics` trait to your models and use it as follows : 120 | 121 | ```php 122 | Order::metrics() 123 | ->sum('amount') 124 | ->byMonth() 125 | ->trends(); 126 | ``` 127 | 128 | ### Types of periods 129 | ```php 130 | LaravelMetrics::query(...) 131 | ->byDay(int $count = 0) //or 132 | ->byWeek(int $count = 0) //or 133 | ->byMonth(int $count = 0) //or 134 | ->byYear(int $count = 0) //or 135 | ->between(string $startDate, string $endDate, string $dateIsoFormat) //or 136 | ->from(string $date, string $dateIsoFormat) 137 | ``` 138 | 139 | ***Note :*** Periods are defined for the current day, week, month or year by default. However, you can define a specific value using dedicated methods. For example: 140 | 141 | ```php 142 | // generate trends of orders count for the current year 143 | LaravelMetrics::query(Order::query()) 144 | ->count() 145 | ->byMonth(12) 146 | ->forYear(now()->year) 147 | ->labelColumn('status') 148 | ->trends(); 149 | 150 | // generate total orders amount's sum for the third month only 151 | LaravelMetrics::query(Product::query()) 152 | ->sum('amount') 153 | ->byMonth(1) 154 | ->forMonth(3) 155 | ->metrics(); 156 | ``` 157 | 158 | ```php 159 | LaravelMetrics::query(...) 160 | ->forDay(int $day) 161 | ->forWeek(int $week) 162 | ->forMonth(int $month) 163 | ->forYear(int $year) 164 | ``` 165 | 166 | ### Types of aggregates 167 | ```php 168 | LaravelMetrics::query(...) 169 | ->count(string $column = 'id') //or 170 | ->average(string $column) //or 171 | ->sum(string $column) //or 172 | ->max(string $column) //or 173 | ->min(string $column) 174 | ``` 175 | 176 | ### Types of data 177 | ```php 178 | LaravelMetrics::query(...) 179 | ->trends(bool $inPercent = false) //or 180 | ->metrics() //or 181 | ->metricsWithVariations(int $previousCount, string $previousPeriod, bool $inPercent = false) 182 | ``` 183 | 184 | ***Note 1 :*** The `trends` method can generate data in percentage format when the `$inPercent` parameter is set to `true`. 185 | 186 | ***Note 2 :*** The `metricsWithVariations` method generates metrics with variations from the `$previousPeriod` period (`day`, `week`, `month`, or `year`). The `$previousCount` parameter specifies the count for the past period. Set `$inPercent` parameter to true to get variations result in percent. 187 | 188 | ### Combining periods and aggregates 189 | Combining different time periods and data aggregates can enhance your overall experience. For example : 190 | 191 | ```php 192 | LaravelMetrics::query(...) 193 | ->sumByYear() 194 | ->trends(); 195 | 196 | LaravelMetrics::query(...) 197 | ->countByMonth(count: 12) 198 | ->forYear(now()->year) 199 | ->labelColumn('status') 200 | ->trends(); 201 | 202 | LaravelMetrics::query(...) 203 | ->countBetween([Carbon::now()->subDays(10)->format('Y-m-d'), Carbon::now()->format('Y-m-d')]) 204 | ->trends(); 205 | 206 | LaravelMetrics::query(...) 207 | ->averageFrom(Carbon::now()->subDays(10)->format('Y-m-d')) 208 | ->trends(); 209 | ... 210 | ``` 211 | 212 | Possible combinations : 213 | 214 | ```php 215 | LaravelMetrics::query(...) 216 | ->countByMonth(...) //or 217 | ->countByYear(...) //or 218 | ->countByDay(...) //or 219 | ->countByWeek(...) //or 220 | ->sumByMonth(...) //or 221 | ->sumByYear(...) //or 222 | ->sumByDay(...) //or 223 | ->sumByWeek(...) //or 224 | ->averageByMonth(...) //or 225 | ->averageByYear(...) //or 226 | ->averageByDay(...) //or 227 | ->averageByWeek(...) //or 228 | ->maxByMonth(...) //or 229 | ->maxByYear(...) //or 230 | ->maxByDay(...) //or 231 | ->maxByWeek(...) //or 232 | ->minByMonth(...) //or 233 | ->minByYear(...) //or 234 | ->minByDay(...) //or 235 | ->minByWeek(...) //or 236 | ->countBetween(...) //or 237 | ->sumBetween(...) //or 238 | ->averageBetween(...) //or 239 | ->maxBetween(...) //or 240 | ->minBetween(...) //or 241 | ->countFrom(...) //or 242 | ->sumFrom(...) //or 243 | ->averageFrom(...) //or 244 | ->maxFrom(...) //or 245 | ->minFrom(...) 246 | ``` 247 | 248 | ### Fill missing data with default value 249 | You can fill missing data with default value with the global method ```fillMissingData```, especially for trends. For example : 250 | 251 | ```php 252 | LaravelMetrics::query(...) 253 | ->countBetween([Carbon::now()->subDays(10)->format('Y-m-d'), Carbon::now()->format('Y-m-d')]) 254 | ->fillMissingData() 255 | ->trends(); 256 | 257 | LaravelMetrics::query(...) 258 | ->sumByYear(count: 5) 259 | ->fillMissingData() 260 | ->trends(); 261 | ... 262 | ``` 263 | 264 | ***Note :*** The `fillMissingData` method automatically discovers all labels, ensuring that data is filled for all available labels without the need for explicit label specification. 265 | 266 | ### Group period (only when using ```between``` method) 267 | You can group period by days, months, weeks or years when using the ```between``` method (***default is day***). For example : 268 | 269 | ```php 270 | LaravelMetrics::query(...) 271 | ->countBetween([Carbon::now()->subDays(10)->format('Y-m-d'), Carbon::now()->format('Y-m-d')]) 272 | ->groupByMonth() 273 | ->fillMissingData() 274 | ->trends(); 275 | ``` 276 | 277 | ```php 278 | LaravelMetrics::query(...) 279 | ->groupByYear() //or 280 | ->groupByMonth() //or 281 | ->groupByWeek() //or 282 | ->groupByDay() 283 | ``` 284 | 285 | ### Group data (only for ```trends```) 286 | You can group data of a column with multiple values to use it in a dataset for your charts. For example : 287 | 288 | ```php 289 | Order::metrics() 290 | ->countByMonth(column: 'status') 291 | ->groupData(['pending', 'delivered', 'cancelled'], Aggregate::SUM->value) 292 | ->fillMissingData() 293 | ->trends(); 294 | ``` 295 | 296 | ***Note :*** Follow same order in the example to avoid false data. 297 | 298 | ## Translations 299 | 300 | Days and months names are automatically translated using `config(app.locale)` except 'week' period. 301 | 302 | ## Changelog 303 | 304 | Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. 305 | 306 | ## Contributing 307 | 308 | Please see [CONTRIBUTING](CONTRIBUTING.md) for details. 309 | 310 | ## Security 311 | 312 | If you discover any security related issues, please email `eliseekn@gmail.com` instead of using the issue tracker. 313 | 314 | ## Credits 315 | 316 | - [N'Guessan Kouadio Elisée](https://github.com/eliseekn) 317 | - [Chris Brown](https://github.com/drbyte) 318 | 319 | ## License 320 | 321 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 322 | 323 | ## Demo 324 | 325 | You can find a demo project [here](https://github.com/eliseekn/laravel-metrics-demo). 326 | 327 | ## Laravel Package Boilerplate 328 | 329 | This package was generated using the [Laravel Package Boilerplate](https://laravelpackageboilerplate.com). 330 | -------------------------------------------------------------------------------- /.idea/blade.xml: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /src/LaravelMetrics.php: -------------------------------------------------------------------------------- 1 | table = $this->builder->from; 67 | $this->dateColumn = $this->table.'.created_at'; 68 | $this->period = null; 69 | $this->aggregate = Aggregate::COUNT->value; 70 | $this->year = Carbon::now()->year; 71 | $this->month = Carbon::now()->month; 72 | $this->day = Carbon::now()->day; 73 | $this->week = Carbon::now()->week; 74 | $this->groupBy = Period::DAY->value; 75 | } 76 | 77 | public static function query(Builder|QueryBuilder $builder): self 78 | { 79 | return new self($builder); 80 | } 81 | 82 | public function table(string $table): self 83 | { 84 | $this->table = $table; 85 | 86 | return $this; 87 | } 88 | 89 | protected function by(string $period, int $count = 0): self 90 | { 91 | $period = strtolower($period); 92 | 93 | if (! in_array($period, Period::values())) { 94 | throw new InvalidPeriodException(); 95 | } 96 | 97 | $this->period = $period; 98 | $this->count = $count; 99 | 100 | return $this; 101 | } 102 | 103 | public function byDay(int $count = 0): self 104 | { 105 | return $this->by(Period::DAY->value, $count); 106 | } 107 | 108 | public function byWeek(int $count = 0): self 109 | { 110 | return $this->by(Period::WEEK->value, $count); 111 | } 112 | 113 | public function byMonth(int $count = 0): self 114 | { 115 | return $this->by(Period::MONTH->value, $count); 116 | } 117 | 118 | public function byYear(int $count = 0): self 119 | { 120 | return $this->by(Period::YEAR->value, $count); 121 | } 122 | 123 | public function between(string $start, string $end, string $dateIsoFormat = 'YYYY-MM-DD'): self 124 | { 125 | $this->checkDateFormat([$start, $end]); 126 | $this->period = [$start, $end]; 127 | $this->dateIsoFormat = $dateIsoFormat; 128 | 129 | return $this; 130 | } 131 | 132 | public function from(string $date, string $dateIsoFormat = 'YYYY-MM-DD'): self 133 | { 134 | return $this->between($date, Carbon::now()->format('Y-m-d'), $dateIsoFormat); 135 | } 136 | 137 | protected function groupBy(string $period): self 138 | { 139 | $this->groupBy = $period; 140 | 141 | return $this; 142 | } 143 | 144 | public function groupByYear(): self 145 | { 146 | return $this->groupBy(Period::YEAR->value); 147 | } 148 | 149 | public function groupByMonth(): self 150 | { 151 | return $this->groupBy(Period::MONTH->value); 152 | } 153 | 154 | public function groupByWeek(): self 155 | { 156 | return $this->groupBy(Period::WEEK->value); 157 | } 158 | 159 | public function groupByDay(): self 160 | { 161 | return $this->groupBy(Period::DAY->value); 162 | } 163 | 164 | public function forDay(int $day): self 165 | { 166 | $this->day = $day; 167 | 168 | return $this; 169 | } 170 | 171 | public function forWeek(int $week): self 172 | { 173 | $this->week = $week; 174 | 175 | return $this; 176 | } 177 | 178 | public function forMonth(int $month): self 179 | { 180 | $this->month = $month; 181 | 182 | return $this; 183 | } 184 | 185 | public function forYear(int $year): self 186 | { 187 | $this->year = $year; 188 | 189 | return $this; 190 | } 191 | 192 | protected function aggregate(string $aggregate, string $column): self 193 | { 194 | $aggregate = strtolower($aggregate); 195 | 196 | if (! in_array($aggregate, Aggregate::values())) { 197 | throw new InvalidAggregateException(); 198 | } 199 | 200 | $this->aggregate = $aggregate; 201 | $this->column = $this->table.'.'.$column; 202 | 203 | return $this; 204 | } 205 | 206 | public function count(string $column = 'id'): self 207 | { 208 | return $this->aggregate(Aggregate::COUNT->value, $column); 209 | } 210 | 211 | public function average(string $column): self 212 | { 213 | return $this->aggregate(Aggregate::AVERAGE->value, $column); 214 | } 215 | 216 | public function sum(string $column): self 217 | { 218 | return $this->aggregate(Aggregate::SUM->value, $column); 219 | } 220 | 221 | public function max(string $column): self 222 | { 223 | return $this->aggregate(Aggregate::MAX->value, $column); 224 | } 225 | 226 | public function min(string $column): self 227 | { 228 | return $this->aggregate(Aggregate::MIN->value, $column); 229 | } 230 | 231 | protected function countBy(string $period, string $column = 'id', int $count = 0): self 232 | { 233 | return $this 234 | ->by($period, $count) 235 | ->aggregate(Aggregate::COUNT->value, $column); 236 | } 237 | 238 | protected function averageBy(string $period, string $column = 'id', int $count = 0): self 239 | { 240 | return $this 241 | ->by($period, $count) 242 | ->aggregate(Aggregate::AVERAGE->value, $column); 243 | } 244 | 245 | protected function sumBy(string $period, string $column = 'id', int $count = 0): self 246 | { 247 | return $this 248 | ->by($period, $count) 249 | ->aggregate(Aggregate::SUM->value, $column); 250 | } 251 | 252 | protected function maxBy(string $period, string $column = 'id', int $count = 0): self 253 | { 254 | return $this 255 | ->by($period, $count) 256 | ->aggregate(Aggregate::MAX->value, $column); 257 | } 258 | 259 | protected function minBy(string $period, string $column = 'id', int $count = 0): self 260 | { 261 | return $this 262 | ->by($period, $count) 263 | ->aggregate(Aggregate::MIN->value, $column); 264 | } 265 | 266 | public function countByDay(string $column = 'id', int $count = 0): self 267 | { 268 | return $this->countBy(Period::DAY->value, $column, $count); 269 | } 270 | 271 | public function countByWeek(string $column = 'id', int $count = 0): self 272 | { 273 | return $this->countBy(Period::WEEK->value, $column, $count); 274 | } 275 | 276 | public function countByMonth(string $column = 'id', int $count = 0): self 277 | { 278 | return $this->countBy(Period::MONTH->value, $column, $count); 279 | } 280 | 281 | public function countByYear(string $column = 'id', int $count = 0): self 282 | { 283 | return $this->countBy(Period::YEAR->value, $column, $count); 284 | } 285 | 286 | public function sumByDay(string $column, int $count = 0): self 287 | { 288 | return $this->sumBy(Period::DAY->value, $column, $count); 289 | } 290 | 291 | public function sumByWeek(string $column, int $count = 0): self 292 | { 293 | return $this->sumBy(Period::WEEK->value, $column, $count); 294 | } 295 | 296 | public function sumByMonth(string $column, int $count = 0): self 297 | { 298 | return $this->sumBy(Period::MONTH->value, $column, $count); 299 | } 300 | 301 | public function sumByYear(string $column, int $count = 0): self 302 | { 303 | return $this->sumBy(Period::YEAR->value, $column, $count); 304 | } 305 | 306 | public function averageByDay(string $column, int $count = 0): self 307 | { 308 | return $this->averageBy(Period::DAY->value, $column, $count); 309 | } 310 | 311 | public function averageByWeek(string $column, int $count = 0): self 312 | { 313 | return $this->averageBy(Period::WEEK->value, $column, $count); 314 | } 315 | 316 | public function averageByMonth(string $column, int $count = 0): self 317 | { 318 | return $this->averageBy(Period::MONTH->value, $column, $count); 319 | } 320 | 321 | public function averageByYear(string $column, int $count = 0): self 322 | { 323 | return $this->averageBy(Period::YEAR->value, $column, $count); 324 | } 325 | 326 | public function maxByDay(string $column, int $count = 0): self 327 | { 328 | return $this->maxBy(Period::DAY->value, $column, $count); 329 | } 330 | 331 | public function maxByWeek(string $column, int $count = 0): self 332 | { 333 | return $this->maxBy(Period::WEEK->value, $column, $count); 334 | } 335 | 336 | public function maxByMonth(string $column, int $count = 0): self 337 | { 338 | return $this->maxBy(Period::MONTH->value, $column, $count); 339 | } 340 | 341 | public function maxByYear(string $column, int $count = 0): self 342 | { 343 | return $this->maxBy(Period::YEAR->value, $column, $count); 344 | } 345 | 346 | public function minByDay(string $column, int $count = 0): self 347 | { 348 | return $this->minBy(Period::DAY->value, $column, $count); 349 | } 350 | 351 | public function minByWeek(string $column, int $count = 0): self 352 | { 353 | return $this->minBy(Period::WEEK->value, $column, $count); 354 | } 355 | 356 | public function minByMonth(string $column, int $count = 0): self 357 | { 358 | return $this->minBy(Period::MONTH->value, $column, $count); 359 | } 360 | 361 | public function minByYear(string $column, int $count = 0): self 362 | { 363 | return $this->minBy(Period::YEAR->value, $column, $count); 364 | } 365 | 366 | public function countBetween(array $period, string $column = 'id', string $dateIsoFormat = 'YYYY-MM-DD'): self 367 | { 368 | return $this 369 | ->count($column) 370 | ->between($period[0], $period[1], $dateIsoFormat); 371 | } 372 | 373 | public function sumBetween(array $period, string $column, string $dateIsoFormat = 'YYYY-MM-DD'): self 374 | { 375 | return $this 376 | ->sum($column) 377 | ->between($period[0], $period[1], $dateIsoFormat); 378 | } 379 | 380 | public function averageBetween(array $period, string $column, string $dateIsoFormat = 'YYYY-MM-DD'): self 381 | { 382 | return $this 383 | ->average($column) 384 | ->between($period[0], $period[1], $dateIsoFormat); 385 | } 386 | 387 | public function maxBetween(array $period, string $column, string $dateIsoFormat = 'YYYY-MM-DD'): self 388 | { 389 | return $this 390 | ->max($column) 391 | ->between($period[0], $period[1], $dateIsoFormat); 392 | } 393 | 394 | public function minBetween(array $period, string $column, string $dateIsoFormat = 'YYYY-MM-DD'): self 395 | { 396 | return $this 397 | ->min($column) 398 | ->between($period[0], $period[1], $dateIsoFormat); 399 | } 400 | 401 | public function countFrom(string $date, string $column = 'id', string $dateIsoFormat = 'YYYY-MM-DD'): self 402 | { 403 | return $this 404 | ->count($column) 405 | ->from($date, $dateIsoFormat); 406 | } 407 | 408 | public function sumFrom(string $date, string $column, string $dateIsoFormat = 'YYYY-MM-DD'): self 409 | { 410 | return $this 411 | ->sum($column) 412 | ->from($date, $dateIsoFormat); 413 | } 414 | 415 | public function averageFrom(string $date, string $column, string $dateIsoFormat = 'YYYY-MM-DD'): self 416 | { 417 | return $this 418 | ->average($column) 419 | ->from($date, $dateIsoFormat); 420 | } 421 | 422 | public function maxFrom(string $date, string $column, string $dateIsoFormat = 'YYYY-MM-DD'): self 423 | { 424 | return $this 425 | ->max($column) 426 | ->from($date, $dateIsoFormat); 427 | } 428 | 429 | public function minFrom(string $date, string $column, string $dateIsoFormat = 'YYYY-MM-DD'): self 430 | { 431 | return $this 432 | ->min($column) 433 | ->from($date, $dateIsoFormat); 434 | } 435 | 436 | public function dateColumn(string $column): self 437 | { 438 | $this->dateColumn = $this->table.'.'.$column; 439 | 440 | return $this; 441 | } 442 | 443 | public function labelColumn(string $column): self 444 | { 445 | $this->labelColumn = $this->table.'.'.$column; 446 | 447 | return $this; 448 | } 449 | 450 | public function fillMissingData(int $missingDataValue = 0, array $missingDataLabels = []): self 451 | { 452 | $this->fillMissingData = true; 453 | $this->missingDataValue = $missingDataValue; 454 | $this->missingDataLabels = $missingDataLabels; 455 | 456 | return $this; 457 | } 458 | 459 | protected function metricsData(): mixed 460 | { 461 | if (is_array($this->period)) { 462 | return $this->builder 463 | ->selectRaw($this->asData()) 464 | ->whereBetween(DB::raw($this->formatDateColumn()), [$this->period[0], $this->period[1]]) 465 | ->first(); 466 | } 467 | 468 | return match ($this->period) { 469 | Period::DAY->value => $this->builder 470 | ->selectRaw($this->asData()) 471 | ->whereYear($this->dateColumn, $this->year) 472 | ->whereMonth($this->dateColumn, $this->month) 473 | ->when($this->count === 1, function (Builder|QueryBuilder $query) { 474 | return $query->where(DB::raw($this->formatPeriod(Period::TODAY->value)), $this->day); 475 | }) 476 | ->when($this->count > 1, function (Builder|QueryBuilder $query) { 477 | return $query->whereBetween(DB::raw($this->formatPeriod(Period::TODAY->value)), $this->getDayPeriod()); 478 | }) 479 | ->first(), 480 | 481 | Period::WEEK->value => $this->builder 482 | ->selectRaw($this->asData()) 483 | ->whereYear($this->dateColumn, $this->year) 484 | ->whereMonth($this->dateColumn, $this->month) 485 | ->when($this->count === 1, function (Builder|QueryBuilder $query) { 486 | return $query->where(DB::raw($this->formatPeriod(Period::WEEK->value)), $this->week); 487 | }) 488 | ->when($this->count > 1, function (Builder|QueryBuilder $query) { 489 | return $query->whereBetween(DB::raw($this->formatPeriod(Period::WEEK->value)), $this->getWeekPeriod()); 490 | }) 491 | ->first(), 492 | 493 | Period::MONTH->value => $this->builder 494 | ->selectRaw($this->asData()) 495 | ->whereYear($this->dateColumn, $this->year) 496 | ->when($this->count === 1, function (Builder|QueryBuilder $query) { 497 | return $query->where(DB::raw($this->formatPeriod(Period::MONTH->value)), $this->month); 498 | }) 499 | ->when($this->count > 1, function (Builder|QueryBuilder $query) { 500 | return $query->whereBetween(DB::raw($this->formatPeriod(Period::MONTH->value)), $this->getMonthPeriod()); 501 | }) 502 | ->first(), 503 | 504 | Period::YEAR->value => $this->builder 505 | ->selectRaw($this->asData()) 506 | ->when($this->count === 1, function (Builder|QueryBuilder $query) { 507 | return $query->where(DB::raw($this->formatPeriod(Period::YEAR->value)), $this->year); 508 | }) 509 | ->when($this->count > 1, function (Builder|QueryBuilder $query) { 510 | return $query->whereBetween(DB::raw($this->formatPeriod(Period::YEAR->value)), [ 511 | Carbon::now()->subYears($this->count)->year, $this->year, 512 | ]); 513 | }) 514 | ->first(), 515 | 516 | default => $this->builder 517 | ->selectRaw($this->asData()) 518 | ->first(), 519 | }; 520 | } 521 | 522 | protected function trendsData(): Collection 523 | { 524 | if (is_array($this->period)) { 525 | return $this->builder 526 | ->selectRaw($this->asData().', '.$this->asLabel($this->formatDateColumn(), false).$this->groupedData) 527 | ->whereBetween(DB::raw($this->formatDateColumn()), [$this->period[0], $this->period[1]]) 528 | ->groupBy('label') 529 | ->orderBy('label') 530 | ->get(); 531 | } 532 | 533 | return match ($this->period) { 534 | Period::DAY->value => $this->builder 535 | ->selectRaw($this->asData().', '.$this->asLabel(Period::DAY->value).$this->groupedData) 536 | ->whereYear($this->dateColumn, $this->year) 537 | ->whereMonth($this->dateColumn, $this->month) 538 | ->when($this->count === 1, function (Builder|QueryBuilder $query) { 539 | return $query->where(DB::raw($this->formatPeriod(Period::TODAY->value)), $this->day); 540 | }) 541 | ->when($this->count > 1, function (Builder|QueryBuilder $query) { 542 | return $query->whereBetween(DB::raw($this->formatPeriod(Period::TODAY->value)), $this->getDayPeriod()); 543 | }) 544 | ->groupBy('label') 545 | ->orderBy('label') 546 | ->get(), 547 | 548 | Period::WEEK->value => $this->builder 549 | ->selectRaw($this->asData().', '.$this->asLabel(Period::WEEK->value).$this->groupedData) 550 | ->whereYear($this->dateColumn, $this->year) 551 | ->whereMonth($this->dateColumn, $this->month) 552 | ->when($this->count === 1, function (Builder|QueryBuilder $query) { 553 | return $query->where(DB::raw($this->formatPeriod(Period::WEEK->value)), $this->week); 554 | }) 555 | ->when($this->count > 1, function (Builder|QueryBuilder $query) { 556 | return $query->whereBetween(DB::raw($this->formatPeriod(Period::WEEK->value)), $this->getWeekPeriod()); 557 | }) 558 | ->groupBy('label') 559 | ->orderBy('label') 560 | ->get(), 561 | 562 | Period::MONTH->value => $this->builder 563 | ->selectRaw($this->asData().', '.$this->asLabel(Period::MONTH->value).$this->groupedData) 564 | ->whereYear($this->dateColumn, $this->year) 565 | ->when($this->count === 1, function (Builder|QueryBuilder $query) { 566 | return $query->where(DB::raw($this->formatPeriod(Period::MONTH->value)), $this->month); 567 | }) 568 | ->when($this->count > 1, function (Builder|QueryBuilder $query) { 569 | return $query->whereBetween(DB::raw($this->formatPeriod(Period::MONTH->value)), $this->getMonthPeriod()); 570 | }) 571 | ->groupBy('label') 572 | ->orderBy('label') 573 | ->get(), 574 | 575 | Period::YEAR->value => $this->builder 576 | ->selectRaw($this->asData().', '.$this->asLabel(Period::YEAR->value).$this->groupedData) 577 | ->when($this->count === 1, function (Builder|QueryBuilder $query) { 578 | return $query->where(DB::raw($this->formatPeriod(Period::YEAR->value)), $this->year); 579 | }) 580 | ->when($this->count > 1, function (Builder|QueryBuilder $query) { 581 | return $query->whereBetween(DB::raw($this->formatPeriod(Period::YEAR->value)), [ 582 | Carbon::now()->subYears($this->count)->year, $this->year, 583 | ]); 584 | }) 585 | ->groupBy('label') 586 | ->orderBy('label') 587 | ->get(), 588 | 589 | default => $this->builder 590 | ->selectRaw($this->asData().', '.$this->asLabel().$this->groupedData) 591 | ->groupBy('label') 592 | ->orderBy('label') 593 | ->get(), 594 | }; 595 | } 596 | 597 | public function groupData(array $dataLabels, string $aggregate): self 598 | { 599 | $this->groupedDataLabels = $dataLabels; 600 | $result = []; 601 | 602 | foreach ($dataLabels as $key => $value) { 603 | $result[] = $aggregate.'('.$this->column.' = "'.$value.'")'." as data$key"; 604 | } 605 | 606 | $this->groupedData = ', '.implode(', ', $result); 607 | 608 | return $this; 609 | } 610 | 611 | protected function asData(string $name = 'data'): string 612 | { 613 | return "$this->aggregate($this->column) as $name"; 614 | } 615 | 616 | protected function asLabel(string $label = null, bool $format = true): string 617 | { 618 | if (is_null($this->labelColumn)) { 619 | $label = ! $format ? $label : $this->formatPeriod($label); 620 | } else { 621 | $label = $this->labelColumn; 622 | } 623 | 624 | return $label.' as label'; 625 | } 626 | 627 | protected function populateMissingDataForPeriod(array $data, bool $inPercent = false, string $dataLabel = 'data'): array 628 | { 629 | $dates = $this->getCustomPeriod(); 630 | $data = collect($data); 631 | $result = []; 632 | 633 | foreach ($dates as $date) { 634 | $dataForDate = $data->where('label', $date)->first(); 635 | 636 | if ($dataForDate) { 637 | $result[] = [ 638 | 'label' => $dataForDate['label'], 639 | 'data' => (int) $dataForDate[$dataLabel], 640 | ]; 641 | } else { 642 | $result[] = [ 643 | 'label' => $date, 644 | 'data' => $this->missingDataValue, 645 | ]; 646 | } 647 | } 648 | 649 | $result = $this->formatDate($result); 650 | 651 | return $this->formatTrends($result, $inPercent); 652 | } 653 | 654 | protected function populateMissingData(array $labels, array $data): array 655 | { 656 | $result = [ 657 | 'labels' => [], 658 | 'data' => [], 659 | ]; 660 | 661 | foreach ($labels as $label => $defaultValue) { 662 | $key = array_search($label, $data['labels']); 663 | $result['labels'][] = $label; 664 | 665 | if ($key !== false) { 666 | $result['data'][] = $data['data'][$key]; 667 | } else { 668 | $result['data'][] = $defaultValue; 669 | } 670 | } 671 | 672 | return $result; 673 | } 674 | 675 | /** 676 | * Generate metrics data 677 | */ 678 | public function metrics(): mixed 679 | { 680 | $metricsData = $this->metricsData(); 681 | 682 | return is_null($metricsData) ? 0 : ($metricsData->data ?? 0); 683 | } 684 | 685 | /** 686 | * Generate metrics data with variations 687 | */ 688 | public function metricsWithVariations(int $previousCount, string $previousPeriod, bool $inPercent = false): array 689 | { 690 | if (! in_array($previousPeriod, Period::values())) { 691 | throw new InvalidPeriodException(); 692 | } 693 | 694 | if ($previousCount <= 0) { 695 | throw new InvalidVariationsCountException(); 696 | } 697 | 698 | $laravelMetrics = (new self(DB::table($this->table))) 699 | ->by($previousPeriod, $previousCount) 700 | ->aggregate($this->aggregate, str_replace($this->table.'.', '', $this->column)); 701 | 702 | $variations = match ($previousPeriod) { 703 | Period::DAY->value => $laravelMetrics 704 | ->forDay(Carbon::now()->subDays($previousCount)->day) 705 | ->metrics(), 706 | 707 | Period::WEEK->value => $laravelMetrics 708 | ->forWeek(Carbon::now()->subWeeks($previousCount)->week) 709 | ->metrics(), 710 | 711 | Period::MONTH->value => $laravelMetrics 712 | ->forMonth(Carbon::now()->subMonths($previousCount)->month) 713 | ->metrics(), 714 | 715 | default => $laravelMetrics 716 | ->forYear(Carbon::now()->subYears($previousCount)->year) 717 | ->metrics(), 718 | }; 719 | 720 | $result['count'] = $this->metrics(); 721 | $result['variation'] = []; 722 | 723 | $value = $result['count'] - $variations; 724 | 725 | if ($inPercent && $variations > 0) { 726 | $value = (abs($value) / $variations) * 100 .'%'; 727 | } 728 | 729 | if ($value > 0) { 730 | $result['variation'] = [ 731 | 'type' => 'increase', 732 | 'value' => $value, 733 | ]; 734 | } elseif ($value < 0) { 735 | $result['variation'] = [ 736 | 'type' => 'decrease', 737 | 'value' => abs($value), 738 | ]; 739 | } 740 | 741 | return $result; 742 | } 743 | 744 | protected function trendsWithMergedData(bool $inPercent = false): array 745 | { 746 | $result = []; 747 | 748 | $trendsData = $this 749 | ->trendsData() 750 | ->toArray(); 751 | 752 | $trendsData = array_map(fn ($datum) => (array) $datum, $trendsData); 753 | $data = [$this->getFormattedTrendsData($trendsData, $inPercent)]; 754 | 755 | foreach ($this->groupedDataLabels as $key => $value) { 756 | $data[] = $this->getFormattedTrendsData($trendsData, $inPercent, "data$key"); 757 | } 758 | 759 | foreach ($data as $key => $value) { 760 | $result['labels'] = $value['labels']; 761 | 762 | if ($key === 0) { 763 | $result['data']['total'] = $value['data']; 764 | } else { 765 | $result['data'][$this->groupedDataLabels[$key - 1]] = $value['data']; 766 | } 767 | } 768 | 769 | return $result; 770 | } 771 | 772 | protected function getFormattedTrendsData(array $trendsData, bool $inPercent = false, string $dataLabel = 'data'): array 773 | { 774 | if (! $this->fillMissingData) { 775 | $trendsData = $this->formatDate($trendsData); 776 | 777 | return $this->formatTrends($trendsData, $inPercent, $dataLabel); 778 | } else { 779 | if (! is_null($this->labelColumn)) { 780 | $trendsData = $this->formatTrends($trendsData, $inPercent, $dataLabel); 781 | 782 | return $this->populateMissingData($this->getLabelsData(), $trendsData); 783 | } 784 | 785 | if (is_array($this->period)) { 786 | return $this->populateMissingDataForPeriod($trendsData, $inPercent, $dataLabel); 787 | } 788 | 789 | if (is_string($this->period)) { 790 | $trendsData = $this->formatDate($trendsData); 791 | 792 | return $this->populateMissingData($this->getPeriod(), $this->formatTrends($trendsData, $inPercent, $dataLabel)); 793 | } 794 | } 795 | 796 | return [ 797 | 'labels' => [], 798 | 'data' => [], 799 | ]; 800 | } 801 | 802 | /** 803 | * Generate trends data for charts 804 | */ 805 | public function trends(bool $inPercent = false): array 806 | { 807 | $trendsData = $this 808 | ->trendsData() 809 | ->toArray(); 810 | 811 | $trendsData = array_map(fn ($datum) => (array) $datum, $trendsData); 812 | 813 | if (! empty($this->groupedDataLabels)) { 814 | return $this->trendsWithMergedData($inPercent); 815 | } 816 | 817 | return $this->getFormattedTrendsData($trendsData, $inPercent); 818 | } 819 | 820 | protected function formatTrends(array $data, bool $inPercent = false, string $dataLabel = 'data'): array 821 | { 822 | $total = 0; 823 | 824 | $result = [ 825 | 'labels' => [], 826 | 'data' => [], 827 | ]; 828 | 829 | foreach ($data as $datum) { 830 | $result['labels'][] = $datum['label']; 831 | $result['data'][] = (int) $datum[$dataLabel]; 832 | $total += $datum[$dataLabel]; 833 | } 834 | 835 | if (! $inPercent) { 836 | return $result; 837 | } 838 | 839 | $percentData = []; 840 | 841 | foreach ($result['data'] as $item) { 842 | $percentData[] = round(($item / $total) * 100, 2); 843 | } 844 | 845 | $result['data'] = $percentData; 846 | 847 | return $result; 848 | } 849 | 850 | protected function locale(): string 851 | { 852 | return Config::get('app.locale'); 853 | } 854 | } 855 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "15e76d464ffb1d9f73b846a7afbbb1bf", 8 | "packages": [ 9 | { 10 | "name": "brick/math", 11 | "version": "0.11.0", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/brick/math.git", 15 | "reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/brick/math/zipball/0ad82ce168c82ba30d1c01ec86116ab52f589478", 20 | "reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "php": "^8.0" 25 | }, 26 | "require-dev": { 27 | "php-coveralls/php-coveralls": "^2.2", 28 | "phpunit/phpunit": "^9.0", 29 | "vimeo/psalm": "5.0.0" 30 | }, 31 | "type": "library", 32 | "autoload": { 33 | "psr-4": { 34 | "Brick\\Math\\": "src/" 35 | } 36 | }, 37 | "notification-url": "https://packagist.org/downloads/", 38 | "license": [ 39 | "MIT" 40 | ], 41 | "description": "Arbitrary-precision arithmetic library", 42 | "keywords": [ 43 | "Arbitrary-precision", 44 | "BigInteger", 45 | "BigRational", 46 | "arithmetic", 47 | "bigdecimal", 48 | "bignum", 49 | "brick", 50 | "math" 51 | ], 52 | "support": { 53 | "issues": "https://github.com/brick/math/issues", 54 | "source": "https://github.com/brick/math/tree/0.11.0" 55 | }, 56 | "funding": [ 57 | { 58 | "url": "https://github.com/BenMorel", 59 | "type": "github" 60 | } 61 | ], 62 | "time": "2023-01-15T23:15:59+00:00" 63 | }, 64 | { 65 | "name": "doctrine/inflector", 66 | "version": "2.0.8", 67 | "source": { 68 | "type": "git", 69 | "url": "https://github.com/doctrine/inflector.git", 70 | "reference": "f9301a5b2fb1216b2b08f02ba04dc45423db6bff" 71 | }, 72 | "dist": { 73 | "type": "zip", 74 | "url": "https://api.github.com/repos/doctrine/inflector/zipball/f9301a5b2fb1216b2b08f02ba04dc45423db6bff", 75 | "reference": "f9301a5b2fb1216b2b08f02ba04dc45423db6bff", 76 | "shasum": "" 77 | }, 78 | "require": { 79 | "php": "^7.2 || ^8.0" 80 | }, 81 | "require-dev": { 82 | "doctrine/coding-standard": "^11.0", 83 | "phpstan/phpstan": "^1.8", 84 | "phpstan/phpstan-phpunit": "^1.1", 85 | "phpstan/phpstan-strict-rules": "^1.3", 86 | "phpunit/phpunit": "^8.5 || ^9.5", 87 | "vimeo/psalm": "^4.25 || ^5.4" 88 | }, 89 | "type": "library", 90 | "autoload": { 91 | "psr-4": { 92 | "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" 93 | } 94 | }, 95 | "notification-url": "https://packagist.org/downloads/", 96 | "license": [ 97 | "MIT" 98 | ], 99 | "authors": [ 100 | { 101 | "name": "Guilherme Blanco", 102 | "email": "guilhermeblanco@gmail.com" 103 | }, 104 | { 105 | "name": "Roman Borschel", 106 | "email": "roman@code-factory.org" 107 | }, 108 | { 109 | "name": "Benjamin Eberlei", 110 | "email": "kontakt@beberlei.de" 111 | }, 112 | { 113 | "name": "Jonathan Wage", 114 | "email": "jonwage@gmail.com" 115 | }, 116 | { 117 | "name": "Johannes Schmitt", 118 | "email": "schmittjoh@gmail.com" 119 | } 120 | ], 121 | "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", 122 | "homepage": "https://www.doctrine-project.org/projects/inflector.html", 123 | "keywords": [ 124 | "inflection", 125 | "inflector", 126 | "lowercase", 127 | "manipulation", 128 | "php", 129 | "plural", 130 | "singular", 131 | "strings", 132 | "uppercase", 133 | "words" 134 | ], 135 | "support": { 136 | "issues": "https://github.com/doctrine/inflector/issues", 137 | "source": "https://github.com/doctrine/inflector/tree/2.0.8" 138 | }, 139 | "funding": [ 140 | { 141 | "url": "https://www.doctrine-project.org/sponsorship.html", 142 | "type": "custom" 143 | }, 144 | { 145 | "url": "https://www.patreon.com/phpdoctrine", 146 | "type": "patreon" 147 | }, 148 | { 149 | "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", 150 | "type": "tidelift" 151 | } 152 | ], 153 | "time": "2023-06-16T13:40:37+00:00" 154 | }, 155 | { 156 | "name": "illuminate/collections", 157 | "version": "v10.20.0", 158 | "source": { 159 | "type": "git", 160 | "url": "https://github.com/illuminate/collections.git", 161 | "reference": "f494398dbaaead9e5ff16a18002d11634e8358e6" 162 | }, 163 | "dist": { 164 | "type": "zip", 165 | "url": "https://api.github.com/repos/illuminate/collections/zipball/f494398dbaaead9e5ff16a18002d11634e8358e6", 166 | "reference": "f494398dbaaead9e5ff16a18002d11634e8358e6", 167 | "shasum": "" 168 | }, 169 | "require": { 170 | "illuminate/conditionable": "^10.0", 171 | "illuminate/contracts": "^10.0", 172 | "illuminate/macroable": "^10.0", 173 | "php": "^8.1" 174 | }, 175 | "suggest": { 176 | "symfony/var-dumper": "Required to use the dump method (^6.2)." 177 | }, 178 | "type": "library", 179 | "extra": { 180 | "branch-alias": { 181 | "dev-master": "10.x-dev" 182 | } 183 | }, 184 | "autoload": { 185 | "files": [ 186 | "helpers.php" 187 | ], 188 | "psr-4": { 189 | "Illuminate\\Support\\": "" 190 | } 191 | }, 192 | "notification-url": "https://packagist.org/downloads/", 193 | "license": [ 194 | "MIT" 195 | ], 196 | "authors": [ 197 | { 198 | "name": "Taylor Otwell", 199 | "email": "taylor@laravel.com" 200 | } 201 | ], 202 | "description": "The Illuminate Collections package.", 203 | "homepage": "https://laravel.com", 204 | "support": { 205 | "issues": "https://github.com/laravel/framework/issues", 206 | "source": "https://github.com/laravel/framework" 207 | }, 208 | "time": "2023-08-11T14:48:51+00:00" 209 | }, 210 | { 211 | "name": "illuminate/conditionable", 212 | "version": "v10.20.0", 213 | "source": { 214 | "type": "git", 215 | "url": "https://github.com/illuminate/conditionable.git", 216 | "reference": "d0958e4741fc9d6f516a552060fd1b829a85e009" 217 | }, 218 | "dist": { 219 | "type": "zip", 220 | "url": "https://api.github.com/repos/illuminate/conditionable/zipball/d0958e4741fc9d6f516a552060fd1b829a85e009", 221 | "reference": "d0958e4741fc9d6f516a552060fd1b829a85e009", 222 | "shasum": "" 223 | }, 224 | "require": { 225 | "php": "^8.0.2" 226 | }, 227 | "type": "library", 228 | "extra": { 229 | "branch-alias": { 230 | "dev-master": "10.x-dev" 231 | } 232 | }, 233 | "autoload": { 234 | "psr-4": { 235 | "Illuminate\\Support\\": "" 236 | } 237 | }, 238 | "notification-url": "https://packagist.org/downloads/", 239 | "license": [ 240 | "MIT" 241 | ], 242 | "authors": [ 243 | { 244 | "name": "Taylor Otwell", 245 | "email": "taylor@laravel.com" 246 | } 247 | ], 248 | "description": "The Illuminate Conditionable package.", 249 | "homepage": "https://laravel.com", 250 | "support": { 251 | "issues": "https://github.com/laravel/framework/issues", 252 | "source": "https://github.com/laravel/framework" 253 | }, 254 | "time": "2023-02-03T08:06:17+00:00" 255 | }, 256 | { 257 | "name": "illuminate/container", 258 | "version": "v10.20.0", 259 | "source": { 260 | "type": "git", 261 | "url": "https://github.com/illuminate/container.git", 262 | "reference": "ddc26273085fad3c471b2602ad820e0097ff7939" 263 | }, 264 | "dist": { 265 | "type": "zip", 266 | "url": "https://api.github.com/repos/illuminate/container/zipball/ddc26273085fad3c471b2602ad820e0097ff7939", 267 | "reference": "ddc26273085fad3c471b2602ad820e0097ff7939", 268 | "shasum": "" 269 | }, 270 | "require": { 271 | "illuminate/contracts": "^10.0", 272 | "php": "^8.1", 273 | "psr/container": "^1.1.1|^2.0.1" 274 | }, 275 | "provide": { 276 | "psr/container-implementation": "1.1|2.0" 277 | }, 278 | "type": "library", 279 | "extra": { 280 | "branch-alias": { 281 | "dev-master": "10.x-dev" 282 | } 283 | }, 284 | "autoload": { 285 | "psr-4": { 286 | "Illuminate\\Container\\": "" 287 | } 288 | }, 289 | "notification-url": "https://packagist.org/downloads/", 290 | "license": [ 291 | "MIT" 292 | ], 293 | "authors": [ 294 | { 295 | "name": "Taylor Otwell", 296 | "email": "taylor@laravel.com" 297 | } 298 | ], 299 | "description": "The Illuminate Container package.", 300 | "homepage": "https://laravel.com", 301 | "support": { 302 | "issues": "https://github.com/laravel/framework/issues", 303 | "source": "https://github.com/laravel/framework" 304 | }, 305 | "time": "2023-06-18T09:12:03+00:00" 306 | }, 307 | { 308 | "name": "illuminate/contracts", 309 | "version": "v10.20.0", 310 | "source": { 311 | "type": "git", 312 | "url": "https://github.com/illuminate/contracts.git", 313 | "reference": "eb1a7e72e159136a832f2c0467de5570bdc208ae" 314 | }, 315 | "dist": { 316 | "type": "zip", 317 | "url": "https://api.github.com/repos/illuminate/contracts/zipball/eb1a7e72e159136a832f2c0467de5570bdc208ae", 318 | "reference": "eb1a7e72e159136a832f2c0467de5570bdc208ae", 319 | "shasum": "" 320 | }, 321 | "require": { 322 | "php": "^8.1", 323 | "psr/container": "^1.1.1|^2.0.1", 324 | "psr/simple-cache": "^1.0|^2.0|^3.0" 325 | }, 326 | "type": "library", 327 | "extra": { 328 | "branch-alias": { 329 | "dev-master": "10.x-dev" 330 | } 331 | }, 332 | "autoload": { 333 | "psr-4": { 334 | "Illuminate\\Contracts\\": "" 335 | } 336 | }, 337 | "notification-url": "https://packagist.org/downloads/", 338 | "license": [ 339 | "MIT" 340 | ], 341 | "authors": [ 342 | { 343 | "name": "Taylor Otwell", 344 | "email": "taylor@laravel.com" 345 | } 346 | ], 347 | "description": "The Illuminate Contracts package.", 348 | "homepage": "https://laravel.com", 349 | "support": { 350 | "issues": "https://github.com/laravel/framework/issues", 351 | "source": "https://github.com/laravel/framework" 352 | }, 353 | "time": "2023-07-26T21:27:34+00:00" 354 | }, 355 | { 356 | "name": "illuminate/database", 357 | "version": "v10.20.0", 358 | "source": { 359 | "type": "git", 360 | "url": "https://github.com/illuminate/database.git", 361 | "reference": "10b3518ee8a8282f0cc16850b26d8b70f57349ad" 362 | }, 363 | "dist": { 364 | "type": "zip", 365 | "url": "https://api.github.com/repos/illuminate/database/zipball/10b3518ee8a8282f0cc16850b26d8b70f57349ad", 366 | "reference": "10b3518ee8a8282f0cc16850b26d8b70f57349ad", 367 | "shasum": "" 368 | }, 369 | "require": { 370 | "brick/math": "^0.9.3|^0.10.2|^0.11", 371 | "ext-pdo": "*", 372 | "illuminate/collections": "^10.0", 373 | "illuminate/container": "^10.0", 374 | "illuminate/contracts": "^10.0", 375 | "illuminate/macroable": "^10.0", 376 | "illuminate/support": "^10.0", 377 | "php": "^8.1" 378 | }, 379 | "suggest": { 380 | "doctrine/dbal": "Required to rename columns and drop SQLite columns (^3.5.1).", 381 | "ext-filter": "Required to use the Postgres database driver.", 382 | "fakerphp/faker": "Required to use the eloquent factory builder (^1.21).", 383 | "illuminate/console": "Required to use the database commands (^10.0).", 384 | "illuminate/events": "Required to use the observers with Eloquent (^10.0).", 385 | "illuminate/filesystem": "Required to use the migrations (^10.0).", 386 | "illuminate/pagination": "Required to paginate the result set (^10.0).", 387 | "symfony/finder": "Required to use Eloquent model factories (^6.2)." 388 | }, 389 | "type": "library", 390 | "extra": { 391 | "branch-alias": { 392 | "dev-master": "10.x-dev" 393 | } 394 | }, 395 | "autoload": { 396 | "psr-4": { 397 | "Illuminate\\Database\\": "" 398 | } 399 | }, 400 | "notification-url": "https://packagist.org/downloads/", 401 | "license": [ 402 | "MIT" 403 | ], 404 | "authors": [ 405 | { 406 | "name": "Taylor Otwell", 407 | "email": "taylor@laravel.com" 408 | } 409 | ], 410 | "description": "The Illuminate Database package.", 411 | "homepage": "https://laravel.com", 412 | "keywords": [ 413 | "database", 414 | "laravel", 415 | "orm", 416 | "sql" 417 | ], 418 | "support": { 419 | "issues": "https://github.com/laravel/framework/issues", 420 | "source": "https://github.com/laravel/framework" 421 | }, 422 | "time": "2023-08-21T21:08:22+00:00" 423 | }, 424 | { 425 | "name": "illuminate/macroable", 426 | "version": "v10.20.0", 427 | "source": { 428 | "type": "git", 429 | "url": "https://github.com/illuminate/macroable.git", 430 | "reference": "dff667a46ac37b634dcf68909d9d41e94dc97c27" 431 | }, 432 | "dist": { 433 | "type": "zip", 434 | "url": "https://api.github.com/repos/illuminate/macroable/zipball/dff667a46ac37b634dcf68909d9d41e94dc97c27", 435 | "reference": "dff667a46ac37b634dcf68909d9d41e94dc97c27", 436 | "shasum": "" 437 | }, 438 | "require": { 439 | "php": "^8.1" 440 | }, 441 | "type": "library", 442 | "extra": { 443 | "branch-alias": { 444 | "dev-master": "10.x-dev" 445 | } 446 | }, 447 | "autoload": { 448 | "psr-4": { 449 | "Illuminate\\Support\\": "" 450 | } 451 | }, 452 | "notification-url": "https://packagist.org/downloads/", 453 | "license": [ 454 | "MIT" 455 | ], 456 | "authors": [ 457 | { 458 | "name": "Taylor Otwell", 459 | "email": "taylor@laravel.com" 460 | } 461 | ], 462 | "description": "The Illuminate Macroable package.", 463 | "homepage": "https://laravel.com", 464 | "support": { 465 | "issues": "https://github.com/laravel/framework/issues", 466 | "source": "https://github.com/laravel/framework" 467 | }, 468 | "time": "2023-06-05T12:46:42+00:00" 469 | }, 470 | { 471 | "name": "illuminate/support", 472 | "version": "v10.20.0", 473 | "source": { 474 | "type": "git", 475 | "url": "https://github.com/illuminate/support.git", 476 | "reference": "38d3e064b7b9420d2173f23a31a435bde221b56d" 477 | }, 478 | "dist": { 479 | "type": "zip", 480 | "url": "https://api.github.com/repos/illuminate/support/zipball/38d3e064b7b9420d2173f23a31a435bde221b56d", 481 | "reference": "38d3e064b7b9420d2173f23a31a435bde221b56d", 482 | "shasum": "" 483 | }, 484 | "require": { 485 | "doctrine/inflector": "^2.0", 486 | "ext-ctype": "*", 487 | "ext-filter": "*", 488 | "ext-mbstring": "*", 489 | "illuminate/collections": "^10.0", 490 | "illuminate/conditionable": "^10.0", 491 | "illuminate/contracts": "^10.0", 492 | "illuminate/macroable": "^10.0", 493 | "nesbot/carbon": "^2.67", 494 | "php": "^8.1", 495 | "voku/portable-ascii": "^2.0" 496 | }, 497 | "conflict": { 498 | "tightenco/collect": "<5.5.33" 499 | }, 500 | "suggest": { 501 | "illuminate/filesystem": "Required to use the composer class (^10.0).", 502 | "league/commonmark": "Required to use Str::markdown() and Stringable::markdown() (^2.0.2).", 503 | "ramsey/uuid": "Required to use Str::uuid() (^4.7).", 504 | "symfony/process": "Required to use the composer class (^6.2).", 505 | "symfony/uid": "Required to use Str::ulid() (^6.2).", 506 | "symfony/var-dumper": "Required to use the dd function (^6.2).", 507 | "vlucas/phpdotenv": "Required to use the Env class and env helper (^5.4.1)." 508 | }, 509 | "type": "library", 510 | "extra": { 511 | "branch-alias": { 512 | "dev-master": "10.x-dev" 513 | } 514 | }, 515 | "autoload": { 516 | "files": [ 517 | "helpers.php" 518 | ], 519 | "psr-4": { 520 | "Illuminate\\Support\\": "" 521 | } 522 | }, 523 | "notification-url": "https://packagist.org/downloads/", 524 | "license": [ 525 | "MIT" 526 | ], 527 | "authors": [ 528 | { 529 | "name": "Taylor Otwell", 530 | "email": "taylor@laravel.com" 531 | } 532 | ], 533 | "description": "The Illuminate Support package.", 534 | "homepage": "https://laravel.com", 535 | "support": { 536 | "issues": "https://github.com/laravel/framework/issues", 537 | "source": "https://github.com/laravel/framework" 538 | }, 539 | "time": "2023-08-21T13:45:59+00:00" 540 | }, 541 | { 542 | "name": "nesbot/carbon", 543 | "version": "2.69.0", 544 | "source": { 545 | "type": "git", 546 | "url": "https://github.com/briannesbitt/Carbon.git", 547 | "reference": "4308217830e4ca445583a37d1bf4aff4153fa81c" 548 | }, 549 | "dist": { 550 | "type": "zip", 551 | "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/4308217830e4ca445583a37d1bf4aff4153fa81c", 552 | "reference": "4308217830e4ca445583a37d1bf4aff4153fa81c", 553 | "shasum": "" 554 | }, 555 | "require": { 556 | "ext-json": "*", 557 | "php": "^7.1.8 || ^8.0", 558 | "psr/clock": "^1.0", 559 | "symfony/polyfill-mbstring": "^1.0", 560 | "symfony/polyfill-php80": "^1.16", 561 | "symfony/translation": "^3.4 || ^4.0 || ^5.0 || ^6.0" 562 | }, 563 | "provide": { 564 | "psr/clock-implementation": "1.0" 565 | }, 566 | "require-dev": { 567 | "doctrine/dbal": "^2.0 || ^3.1.4", 568 | "doctrine/orm": "^2.7", 569 | "friendsofphp/php-cs-fixer": "^3.0", 570 | "kylekatarnls/multi-tester": "^2.0", 571 | "ondrejmirtes/better-reflection": "*", 572 | "phpmd/phpmd": "^2.9", 573 | "phpstan/extension-installer": "^1.0", 574 | "phpstan/phpstan": "^0.12.99 || ^1.7.14", 575 | "phpunit/php-file-iterator": "^2.0.5 || ^3.0.6", 576 | "phpunit/phpunit": "^7.5.20 || ^8.5.26 || ^9.5.20", 577 | "squizlabs/php_codesniffer": "^3.4" 578 | }, 579 | "bin": [ 580 | "bin/carbon" 581 | ], 582 | "type": "library", 583 | "extra": { 584 | "branch-alias": { 585 | "dev-3.x": "3.x-dev", 586 | "dev-master": "2.x-dev" 587 | }, 588 | "laravel": { 589 | "providers": [ 590 | "Carbon\\Laravel\\ServiceProvider" 591 | ] 592 | }, 593 | "phpstan": { 594 | "includes": [ 595 | "extension.neon" 596 | ] 597 | } 598 | }, 599 | "autoload": { 600 | "psr-4": { 601 | "Carbon\\": "src/Carbon/" 602 | } 603 | }, 604 | "notification-url": "https://packagist.org/downloads/", 605 | "license": [ 606 | "MIT" 607 | ], 608 | "authors": [ 609 | { 610 | "name": "Brian Nesbitt", 611 | "email": "brian@nesbot.com", 612 | "homepage": "https://markido.com" 613 | }, 614 | { 615 | "name": "kylekatarnls", 616 | "homepage": "https://github.com/kylekatarnls" 617 | } 618 | ], 619 | "description": "An API extension for DateTime that supports 281 different languages.", 620 | "homepage": "https://carbon.nesbot.com", 621 | "keywords": [ 622 | "date", 623 | "datetime", 624 | "time" 625 | ], 626 | "support": { 627 | "docs": "https://carbon.nesbot.com/docs", 628 | "issues": "https://github.com/briannesbitt/Carbon/issues", 629 | "source": "https://github.com/briannesbitt/Carbon" 630 | }, 631 | "funding": [ 632 | { 633 | "url": "https://github.com/sponsors/kylekatarnls", 634 | "type": "github" 635 | }, 636 | { 637 | "url": "https://opencollective.com/Carbon#sponsor", 638 | "type": "opencollective" 639 | }, 640 | { 641 | "url": "https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme", 642 | "type": "tidelift" 643 | } 644 | ], 645 | "time": "2023-08-03T09:00:52+00:00" 646 | }, 647 | { 648 | "name": "psr/clock", 649 | "version": "1.0.0", 650 | "source": { 651 | "type": "git", 652 | "url": "https://github.com/php-fig/clock.git", 653 | "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" 654 | }, 655 | "dist": { 656 | "type": "zip", 657 | "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", 658 | "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", 659 | "shasum": "" 660 | }, 661 | "require": { 662 | "php": "^7.0 || ^8.0" 663 | }, 664 | "type": "library", 665 | "autoload": { 666 | "psr-4": { 667 | "Psr\\Clock\\": "src/" 668 | } 669 | }, 670 | "notification-url": "https://packagist.org/downloads/", 671 | "license": [ 672 | "MIT" 673 | ], 674 | "authors": [ 675 | { 676 | "name": "PHP-FIG", 677 | "homepage": "https://www.php-fig.org/" 678 | } 679 | ], 680 | "description": "Common interface for reading the clock.", 681 | "homepage": "https://github.com/php-fig/clock", 682 | "keywords": [ 683 | "clock", 684 | "now", 685 | "psr", 686 | "psr-20", 687 | "time" 688 | ], 689 | "support": { 690 | "issues": "https://github.com/php-fig/clock/issues", 691 | "source": "https://github.com/php-fig/clock/tree/1.0.0" 692 | }, 693 | "time": "2022-11-25T14:36:26+00:00" 694 | }, 695 | { 696 | "name": "psr/container", 697 | "version": "2.0.2", 698 | "source": { 699 | "type": "git", 700 | "url": "https://github.com/php-fig/container.git", 701 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" 702 | }, 703 | "dist": { 704 | "type": "zip", 705 | "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", 706 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", 707 | "shasum": "" 708 | }, 709 | "require": { 710 | "php": ">=7.4.0" 711 | }, 712 | "type": "library", 713 | "extra": { 714 | "branch-alias": { 715 | "dev-master": "2.0.x-dev" 716 | } 717 | }, 718 | "autoload": { 719 | "psr-4": { 720 | "Psr\\Container\\": "src/" 721 | } 722 | }, 723 | "notification-url": "https://packagist.org/downloads/", 724 | "license": [ 725 | "MIT" 726 | ], 727 | "authors": [ 728 | { 729 | "name": "PHP-FIG", 730 | "homepage": "https://www.php-fig.org/" 731 | } 732 | ], 733 | "description": "Common Container Interface (PHP FIG PSR-11)", 734 | "homepage": "https://github.com/php-fig/container", 735 | "keywords": [ 736 | "PSR-11", 737 | "container", 738 | "container-interface", 739 | "container-interop", 740 | "psr" 741 | ], 742 | "support": { 743 | "issues": "https://github.com/php-fig/container/issues", 744 | "source": "https://github.com/php-fig/container/tree/2.0.2" 745 | }, 746 | "time": "2021-11-05T16:47:00+00:00" 747 | }, 748 | { 749 | "name": "psr/simple-cache", 750 | "version": "3.0.0", 751 | "source": { 752 | "type": "git", 753 | "url": "https://github.com/php-fig/simple-cache.git", 754 | "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" 755 | }, 756 | "dist": { 757 | "type": "zip", 758 | "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", 759 | "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", 760 | "shasum": "" 761 | }, 762 | "require": { 763 | "php": ">=8.0.0" 764 | }, 765 | "type": "library", 766 | "extra": { 767 | "branch-alias": { 768 | "dev-master": "3.0.x-dev" 769 | } 770 | }, 771 | "autoload": { 772 | "psr-4": { 773 | "Psr\\SimpleCache\\": "src/" 774 | } 775 | }, 776 | "notification-url": "https://packagist.org/downloads/", 777 | "license": [ 778 | "MIT" 779 | ], 780 | "authors": [ 781 | { 782 | "name": "PHP-FIG", 783 | "homepage": "https://www.php-fig.org/" 784 | } 785 | ], 786 | "description": "Common interfaces for simple caching", 787 | "keywords": [ 788 | "cache", 789 | "caching", 790 | "psr", 791 | "psr-16", 792 | "simple-cache" 793 | ], 794 | "support": { 795 | "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" 796 | }, 797 | "time": "2021-10-29T13:26:27+00:00" 798 | }, 799 | { 800 | "name": "symfony/deprecation-contracts", 801 | "version": "v3.3.0", 802 | "source": { 803 | "type": "git", 804 | "url": "https://github.com/symfony/deprecation-contracts.git", 805 | "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" 806 | }, 807 | "dist": { 808 | "type": "zip", 809 | "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", 810 | "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", 811 | "shasum": "" 812 | }, 813 | "require": { 814 | "php": ">=8.1" 815 | }, 816 | "type": "library", 817 | "extra": { 818 | "branch-alias": { 819 | "dev-main": "3.4-dev" 820 | }, 821 | "thanks": { 822 | "name": "symfony/contracts", 823 | "url": "https://github.com/symfony/contracts" 824 | } 825 | }, 826 | "autoload": { 827 | "files": [ 828 | "function.php" 829 | ] 830 | }, 831 | "notification-url": "https://packagist.org/downloads/", 832 | "license": [ 833 | "MIT" 834 | ], 835 | "authors": [ 836 | { 837 | "name": "Nicolas Grekas", 838 | "email": "p@tchwork.com" 839 | }, 840 | { 841 | "name": "Symfony Community", 842 | "homepage": "https://symfony.com/contributors" 843 | } 844 | ], 845 | "description": "A generic function and convention to trigger deprecation notices", 846 | "homepage": "https://symfony.com", 847 | "support": { 848 | "source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0" 849 | }, 850 | "funding": [ 851 | { 852 | "url": "https://symfony.com/sponsor", 853 | "type": "custom" 854 | }, 855 | { 856 | "url": "https://github.com/fabpot", 857 | "type": "github" 858 | }, 859 | { 860 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 861 | "type": "tidelift" 862 | } 863 | ], 864 | "time": "2023-05-23T14:45:45+00:00" 865 | }, 866 | { 867 | "name": "symfony/polyfill-mbstring", 868 | "version": "v1.27.0", 869 | "source": { 870 | "type": "git", 871 | "url": "https://github.com/symfony/polyfill-mbstring.git", 872 | "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" 873 | }, 874 | "dist": { 875 | "type": "zip", 876 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", 877 | "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", 878 | "shasum": "" 879 | }, 880 | "require": { 881 | "php": ">=7.1" 882 | }, 883 | "provide": { 884 | "ext-mbstring": "*" 885 | }, 886 | "suggest": { 887 | "ext-mbstring": "For best performance" 888 | }, 889 | "type": "library", 890 | "extra": { 891 | "branch-alias": { 892 | "dev-main": "1.27-dev" 893 | }, 894 | "thanks": { 895 | "name": "symfony/polyfill", 896 | "url": "https://github.com/symfony/polyfill" 897 | } 898 | }, 899 | "autoload": { 900 | "files": [ 901 | "bootstrap.php" 902 | ], 903 | "psr-4": { 904 | "Symfony\\Polyfill\\Mbstring\\": "" 905 | } 906 | }, 907 | "notification-url": "https://packagist.org/downloads/", 908 | "license": [ 909 | "MIT" 910 | ], 911 | "authors": [ 912 | { 913 | "name": "Nicolas Grekas", 914 | "email": "p@tchwork.com" 915 | }, 916 | { 917 | "name": "Symfony Community", 918 | "homepage": "https://symfony.com/contributors" 919 | } 920 | ], 921 | "description": "Symfony polyfill for the Mbstring extension", 922 | "homepage": "https://symfony.com", 923 | "keywords": [ 924 | "compatibility", 925 | "mbstring", 926 | "polyfill", 927 | "portable", 928 | "shim" 929 | ], 930 | "support": { 931 | "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" 932 | }, 933 | "funding": [ 934 | { 935 | "url": "https://symfony.com/sponsor", 936 | "type": "custom" 937 | }, 938 | { 939 | "url": "https://github.com/fabpot", 940 | "type": "github" 941 | }, 942 | { 943 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 944 | "type": "tidelift" 945 | } 946 | ], 947 | "time": "2022-11-03T14:55:06+00:00" 948 | }, 949 | { 950 | "name": "symfony/polyfill-php80", 951 | "version": "v1.27.0", 952 | "source": { 953 | "type": "git", 954 | "url": "https://github.com/symfony/polyfill-php80.git", 955 | "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" 956 | }, 957 | "dist": { 958 | "type": "zip", 959 | "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", 960 | "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", 961 | "shasum": "" 962 | }, 963 | "require": { 964 | "php": ">=7.1" 965 | }, 966 | "type": "library", 967 | "extra": { 968 | "branch-alias": { 969 | "dev-main": "1.27-dev" 970 | }, 971 | "thanks": { 972 | "name": "symfony/polyfill", 973 | "url": "https://github.com/symfony/polyfill" 974 | } 975 | }, 976 | "autoload": { 977 | "files": [ 978 | "bootstrap.php" 979 | ], 980 | "psr-4": { 981 | "Symfony\\Polyfill\\Php80\\": "" 982 | }, 983 | "classmap": [ 984 | "Resources/stubs" 985 | ] 986 | }, 987 | "notification-url": "https://packagist.org/downloads/", 988 | "license": [ 989 | "MIT" 990 | ], 991 | "authors": [ 992 | { 993 | "name": "Ion Bazan", 994 | "email": "ion.bazan@gmail.com" 995 | }, 996 | { 997 | "name": "Nicolas Grekas", 998 | "email": "p@tchwork.com" 999 | }, 1000 | { 1001 | "name": "Symfony Community", 1002 | "homepage": "https://symfony.com/contributors" 1003 | } 1004 | ], 1005 | "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", 1006 | "homepage": "https://symfony.com", 1007 | "keywords": [ 1008 | "compatibility", 1009 | "polyfill", 1010 | "portable", 1011 | "shim" 1012 | ], 1013 | "support": { 1014 | "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" 1015 | }, 1016 | "funding": [ 1017 | { 1018 | "url": "https://symfony.com/sponsor", 1019 | "type": "custom" 1020 | }, 1021 | { 1022 | "url": "https://github.com/fabpot", 1023 | "type": "github" 1024 | }, 1025 | { 1026 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1027 | "type": "tidelift" 1028 | } 1029 | ], 1030 | "time": "2022-11-03T14:55:06+00:00" 1031 | }, 1032 | { 1033 | "name": "symfony/translation", 1034 | "version": "v6.3.3", 1035 | "source": { 1036 | "type": "git", 1037 | "url": "https://github.com/symfony/translation.git", 1038 | "reference": "3ed078c54bc98bbe4414e1e9b2d5e85ed5a5c8bd" 1039 | }, 1040 | "dist": { 1041 | "type": "zip", 1042 | "url": "https://api.github.com/repos/symfony/translation/zipball/3ed078c54bc98bbe4414e1e9b2d5e85ed5a5c8bd", 1043 | "reference": "3ed078c54bc98bbe4414e1e9b2d5e85ed5a5c8bd", 1044 | "shasum": "" 1045 | }, 1046 | "require": { 1047 | "php": ">=8.1", 1048 | "symfony/deprecation-contracts": "^2.5|^3", 1049 | "symfony/polyfill-mbstring": "~1.0", 1050 | "symfony/translation-contracts": "^2.5|^3.0" 1051 | }, 1052 | "conflict": { 1053 | "symfony/config": "<5.4", 1054 | "symfony/console": "<5.4", 1055 | "symfony/dependency-injection": "<5.4", 1056 | "symfony/http-client-contracts": "<2.5", 1057 | "symfony/http-kernel": "<5.4", 1058 | "symfony/service-contracts": "<2.5", 1059 | "symfony/twig-bundle": "<5.4", 1060 | "symfony/yaml": "<5.4" 1061 | }, 1062 | "provide": { 1063 | "symfony/translation-implementation": "2.3|3.0" 1064 | }, 1065 | "require-dev": { 1066 | "nikic/php-parser": "^4.13", 1067 | "psr/log": "^1|^2|^3", 1068 | "symfony/config": "^5.4|^6.0", 1069 | "symfony/console": "^5.4|^6.0", 1070 | "symfony/dependency-injection": "^5.4|^6.0", 1071 | "symfony/finder": "^5.4|^6.0", 1072 | "symfony/http-client-contracts": "^2.5|^3.0", 1073 | "symfony/http-kernel": "^5.4|^6.0", 1074 | "symfony/intl": "^5.4|^6.0", 1075 | "symfony/polyfill-intl-icu": "^1.21", 1076 | "symfony/routing": "^5.4|^6.0", 1077 | "symfony/service-contracts": "^2.5|^3", 1078 | "symfony/yaml": "^5.4|^6.0" 1079 | }, 1080 | "type": "library", 1081 | "autoload": { 1082 | "files": [ 1083 | "Resources/functions.php" 1084 | ], 1085 | "psr-4": { 1086 | "Symfony\\Component\\Translation\\": "" 1087 | }, 1088 | "exclude-from-classmap": [ 1089 | "/Tests/" 1090 | ] 1091 | }, 1092 | "notification-url": "https://packagist.org/downloads/", 1093 | "license": [ 1094 | "MIT" 1095 | ], 1096 | "authors": [ 1097 | { 1098 | "name": "Fabien Potencier", 1099 | "email": "fabien@symfony.com" 1100 | }, 1101 | { 1102 | "name": "Symfony Community", 1103 | "homepage": "https://symfony.com/contributors" 1104 | } 1105 | ], 1106 | "description": "Provides tools to internationalize your application", 1107 | "homepage": "https://symfony.com", 1108 | "support": { 1109 | "source": "https://github.com/symfony/translation/tree/v6.3.3" 1110 | }, 1111 | "funding": [ 1112 | { 1113 | "url": "https://symfony.com/sponsor", 1114 | "type": "custom" 1115 | }, 1116 | { 1117 | "url": "https://github.com/fabpot", 1118 | "type": "github" 1119 | }, 1120 | { 1121 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1122 | "type": "tidelift" 1123 | } 1124 | ], 1125 | "time": "2023-07-31T07:08:24+00:00" 1126 | }, 1127 | { 1128 | "name": "symfony/translation-contracts", 1129 | "version": "v3.3.0", 1130 | "source": { 1131 | "type": "git", 1132 | "url": "https://github.com/symfony/translation-contracts.git", 1133 | "reference": "02c24deb352fb0d79db5486c0c79905a85e37e86" 1134 | }, 1135 | "dist": { 1136 | "type": "zip", 1137 | "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/02c24deb352fb0d79db5486c0c79905a85e37e86", 1138 | "reference": "02c24deb352fb0d79db5486c0c79905a85e37e86", 1139 | "shasum": "" 1140 | }, 1141 | "require": { 1142 | "php": ">=8.1" 1143 | }, 1144 | "type": "library", 1145 | "extra": { 1146 | "branch-alias": { 1147 | "dev-main": "3.4-dev" 1148 | }, 1149 | "thanks": { 1150 | "name": "symfony/contracts", 1151 | "url": "https://github.com/symfony/contracts" 1152 | } 1153 | }, 1154 | "autoload": { 1155 | "psr-4": { 1156 | "Symfony\\Contracts\\Translation\\": "" 1157 | }, 1158 | "exclude-from-classmap": [ 1159 | "/Test/" 1160 | ] 1161 | }, 1162 | "notification-url": "https://packagist.org/downloads/", 1163 | "license": [ 1164 | "MIT" 1165 | ], 1166 | "authors": [ 1167 | { 1168 | "name": "Nicolas Grekas", 1169 | "email": "p@tchwork.com" 1170 | }, 1171 | { 1172 | "name": "Symfony Community", 1173 | "homepage": "https://symfony.com/contributors" 1174 | } 1175 | ], 1176 | "description": "Generic abstractions related to translation", 1177 | "homepage": "https://symfony.com", 1178 | "keywords": [ 1179 | "abstractions", 1180 | "contracts", 1181 | "decoupling", 1182 | "interfaces", 1183 | "interoperability", 1184 | "standards" 1185 | ], 1186 | "support": { 1187 | "source": "https://github.com/symfony/translation-contracts/tree/v3.3.0" 1188 | }, 1189 | "funding": [ 1190 | { 1191 | "url": "https://symfony.com/sponsor", 1192 | "type": "custom" 1193 | }, 1194 | { 1195 | "url": "https://github.com/fabpot", 1196 | "type": "github" 1197 | }, 1198 | { 1199 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1200 | "type": "tidelift" 1201 | } 1202 | ], 1203 | "time": "2023-05-30T17:17:10+00:00" 1204 | }, 1205 | { 1206 | "name": "voku/portable-ascii", 1207 | "version": "2.0.1", 1208 | "source": { 1209 | "type": "git", 1210 | "url": "https://github.com/voku/portable-ascii.git", 1211 | "reference": "b56450eed252f6801410d810c8e1727224ae0743" 1212 | }, 1213 | "dist": { 1214 | "type": "zip", 1215 | "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b56450eed252f6801410d810c8e1727224ae0743", 1216 | "reference": "b56450eed252f6801410d810c8e1727224ae0743", 1217 | "shasum": "" 1218 | }, 1219 | "require": { 1220 | "php": ">=7.0.0" 1221 | }, 1222 | "require-dev": { 1223 | "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" 1224 | }, 1225 | "suggest": { 1226 | "ext-intl": "Use Intl for transliterator_transliterate() support" 1227 | }, 1228 | "type": "library", 1229 | "autoload": { 1230 | "psr-4": { 1231 | "voku\\": "src/voku/" 1232 | } 1233 | }, 1234 | "notification-url": "https://packagist.org/downloads/", 1235 | "license": [ 1236 | "MIT" 1237 | ], 1238 | "authors": [ 1239 | { 1240 | "name": "Lars Moelleken", 1241 | "homepage": "http://www.moelleken.org/" 1242 | } 1243 | ], 1244 | "description": "Portable ASCII library - performance optimized (ascii) string functions for php.", 1245 | "homepage": "https://github.com/voku/portable-ascii", 1246 | "keywords": [ 1247 | "ascii", 1248 | "clean", 1249 | "php" 1250 | ], 1251 | "support": { 1252 | "issues": "https://github.com/voku/portable-ascii/issues", 1253 | "source": "https://github.com/voku/portable-ascii/tree/2.0.1" 1254 | }, 1255 | "funding": [ 1256 | { 1257 | "url": "https://www.paypal.me/moelleken", 1258 | "type": "custom" 1259 | }, 1260 | { 1261 | "url": "https://github.com/voku", 1262 | "type": "github" 1263 | }, 1264 | { 1265 | "url": "https://opencollective.com/portable-ascii", 1266 | "type": "open_collective" 1267 | }, 1268 | { 1269 | "url": "https://www.patreon.com/voku", 1270 | "type": "patreon" 1271 | }, 1272 | { 1273 | "url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii", 1274 | "type": "tidelift" 1275 | } 1276 | ], 1277 | "time": "2022-03-08T17:03:00+00:00" 1278 | } 1279 | ], 1280 | "packages-dev": [ 1281 | { 1282 | "name": "doctrine/instantiator", 1283 | "version": "2.0.0", 1284 | "source": { 1285 | "type": "git", 1286 | "url": "https://github.com/doctrine/instantiator.git", 1287 | "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" 1288 | }, 1289 | "dist": { 1290 | "type": "zip", 1291 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", 1292 | "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", 1293 | "shasum": "" 1294 | }, 1295 | "require": { 1296 | "php": "^8.1" 1297 | }, 1298 | "require-dev": { 1299 | "doctrine/coding-standard": "^11", 1300 | "ext-pdo": "*", 1301 | "ext-phar": "*", 1302 | "phpbench/phpbench": "^1.2", 1303 | "phpstan/phpstan": "^1.9.4", 1304 | "phpstan/phpstan-phpunit": "^1.3", 1305 | "phpunit/phpunit": "^9.5.27", 1306 | "vimeo/psalm": "^5.4" 1307 | }, 1308 | "type": "library", 1309 | "autoload": { 1310 | "psr-4": { 1311 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" 1312 | } 1313 | }, 1314 | "notification-url": "https://packagist.org/downloads/", 1315 | "license": [ 1316 | "MIT" 1317 | ], 1318 | "authors": [ 1319 | { 1320 | "name": "Marco Pivetta", 1321 | "email": "ocramius@gmail.com", 1322 | "homepage": "https://ocramius.github.io/" 1323 | } 1324 | ], 1325 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 1326 | "homepage": "https://www.doctrine-project.org/projects/instantiator.html", 1327 | "keywords": [ 1328 | "constructor", 1329 | "instantiate" 1330 | ], 1331 | "support": { 1332 | "issues": "https://github.com/doctrine/instantiator/issues", 1333 | "source": "https://github.com/doctrine/instantiator/tree/2.0.0" 1334 | }, 1335 | "funding": [ 1336 | { 1337 | "url": "https://www.doctrine-project.org/sponsorship.html", 1338 | "type": "custom" 1339 | }, 1340 | { 1341 | "url": "https://www.patreon.com/phpdoctrine", 1342 | "type": "patreon" 1343 | }, 1344 | { 1345 | "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", 1346 | "type": "tidelift" 1347 | } 1348 | ], 1349 | "time": "2022-12-30T00:23:10+00:00" 1350 | }, 1351 | { 1352 | "name": "laravel/pint", 1353 | "version": "v1.13.5", 1354 | "source": { 1355 | "type": "git", 1356 | "url": "https://github.com/laravel/pint.git", 1357 | "reference": "df105cf8ce7a8f0b8a9425ff45cd281a5448e423" 1358 | }, 1359 | "dist": { 1360 | "type": "zip", 1361 | "url": "https://api.github.com/repos/laravel/pint/zipball/df105cf8ce7a8f0b8a9425ff45cd281a5448e423", 1362 | "reference": "df105cf8ce7a8f0b8a9425ff45cd281a5448e423", 1363 | "shasum": "" 1364 | }, 1365 | "require": { 1366 | "ext-json": "*", 1367 | "ext-mbstring": "*", 1368 | "ext-tokenizer": "*", 1369 | "ext-xml": "*", 1370 | "php": "^8.1.0" 1371 | }, 1372 | "require-dev": { 1373 | "friendsofphp/php-cs-fixer": "^3.34.1", 1374 | "illuminate/view": "^10.26.2", 1375 | "laravel-zero/framework": "^10.1.2", 1376 | "mockery/mockery": "^1.6.6", 1377 | "nunomaduro/larastan": "^2.6.4", 1378 | "nunomaduro/termwind": "^1.15.1", 1379 | "pestphp/pest": "^2.20.0" 1380 | }, 1381 | "bin": [ 1382 | "builds/pint" 1383 | ], 1384 | "type": "project", 1385 | "autoload": { 1386 | "psr-4": { 1387 | "App\\": "app/", 1388 | "Database\\Seeders\\": "database/seeders/", 1389 | "Database\\Factories\\": "database/factories/" 1390 | } 1391 | }, 1392 | "notification-url": "https://packagist.org/downloads/", 1393 | "license": [ 1394 | "MIT" 1395 | ], 1396 | "authors": [ 1397 | { 1398 | "name": "Nuno Maduro", 1399 | "email": "enunomaduro@gmail.com" 1400 | } 1401 | ], 1402 | "description": "An opinionated code formatter for PHP.", 1403 | "homepage": "https://laravel.com", 1404 | "keywords": [ 1405 | "format", 1406 | "formatter", 1407 | "lint", 1408 | "linter", 1409 | "php" 1410 | ], 1411 | "support": { 1412 | "issues": "https://github.com/laravel/pint/issues", 1413 | "source": "https://github.com/laravel/pint" 1414 | }, 1415 | "time": "2023-10-26T09:26:10+00:00" 1416 | }, 1417 | { 1418 | "name": "myclabs/deep-copy", 1419 | "version": "1.11.1", 1420 | "source": { 1421 | "type": "git", 1422 | "url": "https://github.com/myclabs/DeepCopy.git", 1423 | "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" 1424 | }, 1425 | "dist": { 1426 | "type": "zip", 1427 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", 1428 | "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", 1429 | "shasum": "" 1430 | }, 1431 | "require": { 1432 | "php": "^7.1 || ^8.0" 1433 | }, 1434 | "conflict": { 1435 | "doctrine/collections": "<1.6.8", 1436 | "doctrine/common": "<2.13.3 || >=3,<3.2.2" 1437 | }, 1438 | "require-dev": { 1439 | "doctrine/collections": "^1.6.8", 1440 | "doctrine/common": "^2.13.3 || ^3.2.2", 1441 | "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" 1442 | }, 1443 | "type": "library", 1444 | "autoload": { 1445 | "files": [ 1446 | "src/DeepCopy/deep_copy.php" 1447 | ], 1448 | "psr-4": { 1449 | "DeepCopy\\": "src/DeepCopy/" 1450 | } 1451 | }, 1452 | "notification-url": "https://packagist.org/downloads/", 1453 | "license": [ 1454 | "MIT" 1455 | ], 1456 | "description": "Create deep copies (clones) of your objects", 1457 | "keywords": [ 1458 | "clone", 1459 | "copy", 1460 | "duplicate", 1461 | "object", 1462 | "object graph" 1463 | ], 1464 | "support": { 1465 | "issues": "https://github.com/myclabs/DeepCopy/issues", 1466 | "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" 1467 | }, 1468 | "funding": [ 1469 | { 1470 | "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", 1471 | "type": "tidelift" 1472 | } 1473 | ], 1474 | "time": "2023-03-08T13:26:56+00:00" 1475 | }, 1476 | { 1477 | "name": "nikic/php-parser", 1478 | "version": "v4.17.1", 1479 | "source": { 1480 | "type": "git", 1481 | "url": "https://github.com/nikic/PHP-Parser.git", 1482 | "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" 1483 | }, 1484 | "dist": { 1485 | "type": "zip", 1486 | "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", 1487 | "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", 1488 | "shasum": "" 1489 | }, 1490 | "require": { 1491 | "ext-tokenizer": "*", 1492 | "php": ">=7.0" 1493 | }, 1494 | "require-dev": { 1495 | "ircmaxell/php-yacc": "^0.0.7", 1496 | "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" 1497 | }, 1498 | "bin": [ 1499 | "bin/php-parse" 1500 | ], 1501 | "type": "library", 1502 | "extra": { 1503 | "branch-alias": { 1504 | "dev-master": "4.9-dev" 1505 | } 1506 | }, 1507 | "autoload": { 1508 | "psr-4": { 1509 | "PhpParser\\": "lib/PhpParser" 1510 | } 1511 | }, 1512 | "notification-url": "https://packagist.org/downloads/", 1513 | "license": [ 1514 | "BSD-3-Clause" 1515 | ], 1516 | "authors": [ 1517 | { 1518 | "name": "Nikita Popov" 1519 | } 1520 | ], 1521 | "description": "A PHP parser written in PHP", 1522 | "keywords": [ 1523 | "parser", 1524 | "php" 1525 | ], 1526 | "support": { 1527 | "issues": "https://github.com/nikic/PHP-Parser/issues", 1528 | "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1" 1529 | }, 1530 | "time": "2023-08-13T19:53:39+00:00" 1531 | }, 1532 | { 1533 | "name": "phar-io/manifest", 1534 | "version": "2.0.3", 1535 | "source": { 1536 | "type": "git", 1537 | "url": "https://github.com/phar-io/manifest.git", 1538 | "reference": "97803eca37d319dfa7826cc2437fc020857acb53" 1539 | }, 1540 | "dist": { 1541 | "type": "zip", 1542 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", 1543 | "reference": "97803eca37d319dfa7826cc2437fc020857acb53", 1544 | "shasum": "" 1545 | }, 1546 | "require": { 1547 | "ext-dom": "*", 1548 | "ext-phar": "*", 1549 | "ext-xmlwriter": "*", 1550 | "phar-io/version": "^3.0.1", 1551 | "php": "^7.2 || ^8.0" 1552 | }, 1553 | "type": "library", 1554 | "extra": { 1555 | "branch-alias": { 1556 | "dev-master": "2.0.x-dev" 1557 | } 1558 | }, 1559 | "autoload": { 1560 | "classmap": [ 1561 | "src/" 1562 | ] 1563 | }, 1564 | "notification-url": "https://packagist.org/downloads/", 1565 | "license": [ 1566 | "BSD-3-Clause" 1567 | ], 1568 | "authors": [ 1569 | { 1570 | "name": "Arne Blankerts", 1571 | "email": "arne@blankerts.de", 1572 | "role": "Developer" 1573 | }, 1574 | { 1575 | "name": "Sebastian Heuer", 1576 | "email": "sebastian@phpeople.de", 1577 | "role": "Developer" 1578 | }, 1579 | { 1580 | "name": "Sebastian Bergmann", 1581 | "email": "sebastian@phpunit.de", 1582 | "role": "Developer" 1583 | } 1584 | ], 1585 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", 1586 | "support": { 1587 | "issues": "https://github.com/phar-io/manifest/issues", 1588 | "source": "https://github.com/phar-io/manifest/tree/2.0.3" 1589 | }, 1590 | "time": "2021-07-20T11:28:43+00:00" 1591 | }, 1592 | { 1593 | "name": "phar-io/version", 1594 | "version": "3.2.1", 1595 | "source": { 1596 | "type": "git", 1597 | "url": "https://github.com/phar-io/version.git", 1598 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" 1599 | }, 1600 | "dist": { 1601 | "type": "zip", 1602 | "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", 1603 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", 1604 | "shasum": "" 1605 | }, 1606 | "require": { 1607 | "php": "^7.2 || ^8.0" 1608 | }, 1609 | "type": "library", 1610 | "autoload": { 1611 | "classmap": [ 1612 | "src/" 1613 | ] 1614 | }, 1615 | "notification-url": "https://packagist.org/downloads/", 1616 | "license": [ 1617 | "BSD-3-Clause" 1618 | ], 1619 | "authors": [ 1620 | { 1621 | "name": "Arne Blankerts", 1622 | "email": "arne@blankerts.de", 1623 | "role": "Developer" 1624 | }, 1625 | { 1626 | "name": "Sebastian Heuer", 1627 | "email": "sebastian@phpeople.de", 1628 | "role": "Developer" 1629 | }, 1630 | { 1631 | "name": "Sebastian Bergmann", 1632 | "email": "sebastian@phpunit.de", 1633 | "role": "Developer" 1634 | } 1635 | ], 1636 | "description": "Library for handling version information and constraints", 1637 | "support": { 1638 | "issues": "https://github.com/phar-io/version/issues", 1639 | "source": "https://github.com/phar-io/version/tree/3.2.1" 1640 | }, 1641 | "time": "2022-02-21T01:04:05+00:00" 1642 | }, 1643 | { 1644 | "name": "phpunit/php-code-coverage", 1645 | "version": "9.2.27", 1646 | "source": { 1647 | "type": "git", 1648 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 1649 | "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1" 1650 | }, 1651 | "dist": { 1652 | "type": "zip", 1653 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/b0a88255cb70d52653d80c890bd7f38740ea50d1", 1654 | "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1", 1655 | "shasum": "" 1656 | }, 1657 | "require": { 1658 | "ext-dom": "*", 1659 | "ext-libxml": "*", 1660 | "ext-xmlwriter": "*", 1661 | "nikic/php-parser": "^4.15", 1662 | "php": ">=7.3", 1663 | "phpunit/php-file-iterator": "^3.0.3", 1664 | "phpunit/php-text-template": "^2.0.2", 1665 | "sebastian/code-unit-reverse-lookup": "^2.0.2", 1666 | "sebastian/complexity": "^2.0", 1667 | "sebastian/environment": "^5.1.2", 1668 | "sebastian/lines-of-code": "^1.0.3", 1669 | "sebastian/version": "^3.0.1", 1670 | "theseer/tokenizer": "^1.2.0" 1671 | }, 1672 | "require-dev": { 1673 | "phpunit/phpunit": "^9.3" 1674 | }, 1675 | "suggest": { 1676 | "ext-pcov": "PHP extension that provides line coverage", 1677 | "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" 1678 | }, 1679 | "type": "library", 1680 | "extra": { 1681 | "branch-alias": { 1682 | "dev-master": "9.2-dev" 1683 | } 1684 | }, 1685 | "autoload": { 1686 | "classmap": [ 1687 | "src/" 1688 | ] 1689 | }, 1690 | "notification-url": "https://packagist.org/downloads/", 1691 | "license": [ 1692 | "BSD-3-Clause" 1693 | ], 1694 | "authors": [ 1695 | { 1696 | "name": "Sebastian Bergmann", 1697 | "email": "sebastian@phpunit.de", 1698 | "role": "lead" 1699 | } 1700 | ], 1701 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 1702 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 1703 | "keywords": [ 1704 | "coverage", 1705 | "testing", 1706 | "xunit" 1707 | ], 1708 | "support": { 1709 | "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", 1710 | "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", 1711 | "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.27" 1712 | }, 1713 | "funding": [ 1714 | { 1715 | "url": "https://github.com/sebastianbergmann", 1716 | "type": "github" 1717 | } 1718 | ], 1719 | "time": "2023-07-26T13:44:30+00:00" 1720 | }, 1721 | { 1722 | "name": "phpunit/php-file-iterator", 1723 | "version": "3.0.6", 1724 | "source": { 1725 | "type": "git", 1726 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 1727 | "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" 1728 | }, 1729 | "dist": { 1730 | "type": "zip", 1731 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", 1732 | "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", 1733 | "shasum": "" 1734 | }, 1735 | "require": { 1736 | "php": ">=7.3" 1737 | }, 1738 | "require-dev": { 1739 | "phpunit/phpunit": "^9.3" 1740 | }, 1741 | "type": "library", 1742 | "extra": { 1743 | "branch-alias": { 1744 | "dev-master": "3.0-dev" 1745 | } 1746 | }, 1747 | "autoload": { 1748 | "classmap": [ 1749 | "src/" 1750 | ] 1751 | }, 1752 | "notification-url": "https://packagist.org/downloads/", 1753 | "license": [ 1754 | "BSD-3-Clause" 1755 | ], 1756 | "authors": [ 1757 | { 1758 | "name": "Sebastian Bergmann", 1759 | "email": "sebastian@phpunit.de", 1760 | "role": "lead" 1761 | } 1762 | ], 1763 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 1764 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 1765 | "keywords": [ 1766 | "filesystem", 1767 | "iterator" 1768 | ], 1769 | "support": { 1770 | "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", 1771 | "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" 1772 | }, 1773 | "funding": [ 1774 | { 1775 | "url": "https://github.com/sebastianbergmann", 1776 | "type": "github" 1777 | } 1778 | ], 1779 | "time": "2021-12-02T12:48:52+00:00" 1780 | }, 1781 | { 1782 | "name": "phpunit/php-invoker", 1783 | "version": "3.1.1", 1784 | "source": { 1785 | "type": "git", 1786 | "url": "https://github.com/sebastianbergmann/php-invoker.git", 1787 | "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" 1788 | }, 1789 | "dist": { 1790 | "type": "zip", 1791 | "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", 1792 | "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", 1793 | "shasum": "" 1794 | }, 1795 | "require": { 1796 | "php": ">=7.3" 1797 | }, 1798 | "require-dev": { 1799 | "ext-pcntl": "*", 1800 | "phpunit/phpunit": "^9.3" 1801 | }, 1802 | "suggest": { 1803 | "ext-pcntl": "*" 1804 | }, 1805 | "type": "library", 1806 | "extra": { 1807 | "branch-alias": { 1808 | "dev-master": "3.1-dev" 1809 | } 1810 | }, 1811 | "autoload": { 1812 | "classmap": [ 1813 | "src/" 1814 | ] 1815 | }, 1816 | "notification-url": "https://packagist.org/downloads/", 1817 | "license": [ 1818 | "BSD-3-Clause" 1819 | ], 1820 | "authors": [ 1821 | { 1822 | "name": "Sebastian Bergmann", 1823 | "email": "sebastian@phpunit.de", 1824 | "role": "lead" 1825 | } 1826 | ], 1827 | "description": "Invoke callables with a timeout", 1828 | "homepage": "https://github.com/sebastianbergmann/php-invoker/", 1829 | "keywords": [ 1830 | "process" 1831 | ], 1832 | "support": { 1833 | "issues": "https://github.com/sebastianbergmann/php-invoker/issues", 1834 | "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" 1835 | }, 1836 | "funding": [ 1837 | { 1838 | "url": "https://github.com/sebastianbergmann", 1839 | "type": "github" 1840 | } 1841 | ], 1842 | "time": "2020-09-28T05:58:55+00:00" 1843 | }, 1844 | { 1845 | "name": "phpunit/php-text-template", 1846 | "version": "2.0.4", 1847 | "source": { 1848 | "type": "git", 1849 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 1850 | "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" 1851 | }, 1852 | "dist": { 1853 | "type": "zip", 1854 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", 1855 | "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", 1856 | "shasum": "" 1857 | }, 1858 | "require": { 1859 | "php": ">=7.3" 1860 | }, 1861 | "require-dev": { 1862 | "phpunit/phpunit": "^9.3" 1863 | }, 1864 | "type": "library", 1865 | "extra": { 1866 | "branch-alias": { 1867 | "dev-master": "2.0-dev" 1868 | } 1869 | }, 1870 | "autoload": { 1871 | "classmap": [ 1872 | "src/" 1873 | ] 1874 | }, 1875 | "notification-url": "https://packagist.org/downloads/", 1876 | "license": [ 1877 | "BSD-3-Clause" 1878 | ], 1879 | "authors": [ 1880 | { 1881 | "name": "Sebastian Bergmann", 1882 | "email": "sebastian@phpunit.de", 1883 | "role": "lead" 1884 | } 1885 | ], 1886 | "description": "Simple template engine.", 1887 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 1888 | "keywords": [ 1889 | "template" 1890 | ], 1891 | "support": { 1892 | "issues": "https://github.com/sebastianbergmann/php-text-template/issues", 1893 | "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" 1894 | }, 1895 | "funding": [ 1896 | { 1897 | "url": "https://github.com/sebastianbergmann", 1898 | "type": "github" 1899 | } 1900 | ], 1901 | "time": "2020-10-26T05:33:50+00:00" 1902 | }, 1903 | { 1904 | "name": "phpunit/php-timer", 1905 | "version": "5.0.3", 1906 | "source": { 1907 | "type": "git", 1908 | "url": "https://github.com/sebastianbergmann/php-timer.git", 1909 | "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" 1910 | }, 1911 | "dist": { 1912 | "type": "zip", 1913 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", 1914 | "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", 1915 | "shasum": "" 1916 | }, 1917 | "require": { 1918 | "php": ">=7.3" 1919 | }, 1920 | "require-dev": { 1921 | "phpunit/phpunit": "^9.3" 1922 | }, 1923 | "type": "library", 1924 | "extra": { 1925 | "branch-alias": { 1926 | "dev-master": "5.0-dev" 1927 | } 1928 | }, 1929 | "autoload": { 1930 | "classmap": [ 1931 | "src/" 1932 | ] 1933 | }, 1934 | "notification-url": "https://packagist.org/downloads/", 1935 | "license": [ 1936 | "BSD-3-Clause" 1937 | ], 1938 | "authors": [ 1939 | { 1940 | "name": "Sebastian Bergmann", 1941 | "email": "sebastian@phpunit.de", 1942 | "role": "lead" 1943 | } 1944 | ], 1945 | "description": "Utility class for timing", 1946 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 1947 | "keywords": [ 1948 | "timer" 1949 | ], 1950 | "support": { 1951 | "issues": "https://github.com/sebastianbergmann/php-timer/issues", 1952 | "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" 1953 | }, 1954 | "funding": [ 1955 | { 1956 | "url": "https://github.com/sebastianbergmann", 1957 | "type": "github" 1958 | } 1959 | ], 1960 | "time": "2020-10-26T13:16:10+00:00" 1961 | }, 1962 | { 1963 | "name": "phpunit/phpunit", 1964 | "version": "9.6.11", 1965 | "source": { 1966 | "type": "git", 1967 | "url": "https://github.com/sebastianbergmann/phpunit.git", 1968 | "reference": "810500e92855eba8a7a5319ae913be2da6f957b0" 1969 | }, 1970 | "dist": { 1971 | "type": "zip", 1972 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/810500e92855eba8a7a5319ae913be2da6f957b0", 1973 | "reference": "810500e92855eba8a7a5319ae913be2da6f957b0", 1974 | "shasum": "" 1975 | }, 1976 | "require": { 1977 | "doctrine/instantiator": "^1.3.1 || ^2", 1978 | "ext-dom": "*", 1979 | "ext-json": "*", 1980 | "ext-libxml": "*", 1981 | "ext-mbstring": "*", 1982 | "ext-xml": "*", 1983 | "ext-xmlwriter": "*", 1984 | "myclabs/deep-copy": "^1.10.1", 1985 | "phar-io/manifest": "^2.0.3", 1986 | "phar-io/version": "^3.0.2", 1987 | "php": ">=7.3", 1988 | "phpunit/php-code-coverage": "^9.2.13", 1989 | "phpunit/php-file-iterator": "^3.0.5", 1990 | "phpunit/php-invoker": "^3.1.1", 1991 | "phpunit/php-text-template": "^2.0.3", 1992 | "phpunit/php-timer": "^5.0.2", 1993 | "sebastian/cli-parser": "^1.0.1", 1994 | "sebastian/code-unit": "^1.0.6", 1995 | "sebastian/comparator": "^4.0.8", 1996 | "sebastian/diff": "^4.0.3", 1997 | "sebastian/environment": "^5.1.3", 1998 | "sebastian/exporter": "^4.0.5", 1999 | "sebastian/global-state": "^5.0.1", 2000 | "sebastian/object-enumerator": "^4.0.3", 2001 | "sebastian/resource-operations": "^3.0.3", 2002 | "sebastian/type": "^3.2", 2003 | "sebastian/version": "^3.0.2" 2004 | }, 2005 | "suggest": { 2006 | "ext-soap": "To be able to generate mocks based on WSDL files", 2007 | "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" 2008 | }, 2009 | "bin": [ 2010 | "phpunit" 2011 | ], 2012 | "type": "library", 2013 | "extra": { 2014 | "branch-alias": { 2015 | "dev-master": "9.6-dev" 2016 | } 2017 | }, 2018 | "autoload": { 2019 | "files": [ 2020 | "src/Framework/Assert/Functions.php" 2021 | ], 2022 | "classmap": [ 2023 | "src/" 2024 | ] 2025 | }, 2026 | "notification-url": "https://packagist.org/downloads/", 2027 | "license": [ 2028 | "BSD-3-Clause" 2029 | ], 2030 | "authors": [ 2031 | { 2032 | "name": "Sebastian Bergmann", 2033 | "email": "sebastian@phpunit.de", 2034 | "role": "lead" 2035 | } 2036 | ], 2037 | "description": "The PHP Unit Testing framework.", 2038 | "homepage": "https://phpunit.de/", 2039 | "keywords": [ 2040 | "phpunit", 2041 | "testing", 2042 | "xunit" 2043 | ], 2044 | "support": { 2045 | "issues": "https://github.com/sebastianbergmann/phpunit/issues", 2046 | "security": "https://github.com/sebastianbergmann/phpunit/security/policy", 2047 | "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.11" 2048 | }, 2049 | "funding": [ 2050 | { 2051 | "url": "https://phpunit.de/sponsors.html", 2052 | "type": "custom" 2053 | }, 2054 | { 2055 | "url": "https://github.com/sebastianbergmann", 2056 | "type": "github" 2057 | }, 2058 | { 2059 | "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", 2060 | "type": "tidelift" 2061 | } 2062 | ], 2063 | "time": "2023-08-19T07:10:56+00:00" 2064 | }, 2065 | { 2066 | "name": "sebastian/cli-parser", 2067 | "version": "1.0.1", 2068 | "source": { 2069 | "type": "git", 2070 | "url": "https://github.com/sebastianbergmann/cli-parser.git", 2071 | "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" 2072 | }, 2073 | "dist": { 2074 | "type": "zip", 2075 | "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", 2076 | "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", 2077 | "shasum": "" 2078 | }, 2079 | "require": { 2080 | "php": ">=7.3" 2081 | }, 2082 | "require-dev": { 2083 | "phpunit/phpunit": "^9.3" 2084 | }, 2085 | "type": "library", 2086 | "extra": { 2087 | "branch-alias": { 2088 | "dev-master": "1.0-dev" 2089 | } 2090 | }, 2091 | "autoload": { 2092 | "classmap": [ 2093 | "src/" 2094 | ] 2095 | }, 2096 | "notification-url": "https://packagist.org/downloads/", 2097 | "license": [ 2098 | "BSD-3-Clause" 2099 | ], 2100 | "authors": [ 2101 | { 2102 | "name": "Sebastian Bergmann", 2103 | "email": "sebastian@phpunit.de", 2104 | "role": "lead" 2105 | } 2106 | ], 2107 | "description": "Library for parsing CLI options", 2108 | "homepage": "https://github.com/sebastianbergmann/cli-parser", 2109 | "support": { 2110 | "issues": "https://github.com/sebastianbergmann/cli-parser/issues", 2111 | "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" 2112 | }, 2113 | "funding": [ 2114 | { 2115 | "url": "https://github.com/sebastianbergmann", 2116 | "type": "github" 2117 | } 2118 | ], 2119 | "time": "2020-09-28T06:08:49+00:00" 2120 | }, 2121 | { 2122 | "name": "sebastian/code-unit", 2123 | "version": "1.0.8", 2124 | "source": { 2125 | "type": "git", 2126 | "url": "https://github.com/sebastianbergmann/code-unit.git", 2127 | "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" 2128 | }, 2129 | "dist": { 2130 | "type": "zip", 2131 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", 2132 | "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", 2133 | "shasum": "" 2134 | }, 2135 | "require": { 2136 | "php": ">=7.3" 2137 | }, 2138 | "require-dev": { 2139 | "phpunit/phpunit": "^9.3" 2140 | }, 2141 | "type": "library", 2142 | "extra": { 2143 | "branch-alias": { 2144 | "dev-master": "1.0-dev" 2145 | } 2146 | }, 2147 | "autoload": { 2148 | "classmap": [ 2149 | "src/" 2150 | ] 2151 | }, 2152 | "notification-url": "https://packagist.org/downloads/", 2153 | "license": [ 2154 | "BSD-3-Clause" 2155 | ], 2156 | "authors": [ 2157 | { 2158 | "name": "Sebastian Bergmann", 2159 | "email": "sebastian@phpunit.de", 2160 | "role": "lead" 2161 | } 2162 | ], 2163 | "description": "Collection of value objects that represent the PHP code units", 2164 | "homepage": "https://github.com/sebastianbergmann/code-unit", 2165 | "support": { 2166 | "issues": "https://github.com/sebastianbergmann/code-unit/issues", 2167 | "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" 2168 | }, 2169 | "funding": [ 2170 | { 2171 | "url": "https://github.com/sebastianbergmann", 2172 | "type": "github" 2173 | } 2174 | ], 2175 | "time": "2020-10-26T13:08:54+00:00" 2176 | }, 2177 | { 2178 | "name": "sebastian/code-unit-reverse-lookup", 2179 | "version": "2.0.3", 2180 | "source": { 2181 | "type": "git", 2182 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", 2183 | "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" 2184 | }, 2185 | "dist": { 2186 | "type": "zip", 2187 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", 2188 | "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", 2189 | "shasum": "" 2190 | }, 2191 | "require": { 2192 | "php": ">=7.3" 2193 | }, 2194 | "require-dev": { 2195 | "phpunit/phpunit": "^9.3" 2196 | }, 2197 | "type": "library", 2198 | "extra": { 2199 | "branch-alias": { 2200 | "dev-master": "2.0-dev" 2201 | } 2202 | }, 2203 | "autoload": { 2204 | "classmap": [ 2205 | "src/" 2206 | ] 2207 | }, 2208 | "notification-url": "https://packagist.org/downloads/", 2209 | "license": [ 2210 | "BSD-3-Clause" 2211 | ], 2212 | "authors": [ 2213 | { 2214 | "name": "Sebastian Bergmann", 2215 | "email": "sebastian@phpunit.de" 2216 | } 2217 | ], 2218 | "description": "Looks up which function or method a line of code belongs to", 2219 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", 2220 | "support": { 2221 | "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", 2222 | "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" 2223 | }, 2224 | "funding": [ 2225 | { 2226 | "url": "https://github.com/sebastianbergmann", 2227 | "type": "github" 2228 | } 2229 | ], 2230 | "time": "2020-09-28T05:30:19+00:00" 2231 | }, 2232 | { 2233 | "name": "sebastian/comparator", 2234 | "version": "4.0.8", 2235 | "source": { 2236 | "type": "git", 2237 | "url": "https://github.com/sebastianbergmann/comparator.git", 2238 | "reference": "fa0f136dd2334583309d32b62544682ee972b51a" 2239 | }, 2240 | "dist": { 2241 | "type": "zip", 2242 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", 2243 | "reference": "fa0f136dd2334583309d32b62544682ee972b51a", 2244 | "shasum": "" 2245 | }, 2246 | "require": { 2247 | "php": ">=7.3", 2248 | "sebastian/diff": "^4.0", 2249 | "sebastian/exporter": "^4.0" 2250 | }, 2251 | "require-dev": { 2252 | "phpunit/phpunit": "^9.3" 2253 | }, 2254 | "type": "library", 2255 | "extra": { 2256 | "branch-alias": { 2257 | "dev-master": "4.0-dev" 2258 | } 2259 | }, 2260 | "autoload": { 2261 | "classmap": [ 2262 | "src/" 2263 | ] 2264 | }, 2265 | "notification-url": "https://packagist.org/downloads/", 2266 | "license": [ 2267 | "BSD-3-Clause" 2268 | ], 2269 | "authors": [ 2270 | { 2271 | "name": "Sebastian Bergmann", 2272 | "email": "sebastian@phpunit.de" 2273 | }, 2274 | { 2275 | "name": "Jeff Welch", 2276 | "email": "whatthejeff@gmail.com" 2277 | }, 2278 | { 2279 | "name": "Volker Dusch", 2280 | "email": "github@wallbash.com" 2281 | }, 2282 | { 2283 | "name": "Bernhard Schussek", 2284 | "email": "bschussek@2bepublished.at" 2285 | } 2286 | ], 2287 | "description": "Provides the functionality to compare PHP values for equality", 2288 | "homepage": "https://github.com/sebastianbergmann/comparator", 2289 | "keywords": [ 2290 | "comparator", 2291 | "compare", 2292 | "equality" 2293 | ], 2294 | "support": { 2295 | "issues": "https://github.com/sebastianbergmann/comparator/issues", 2296 | "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" 2297 | }, 2298 | "funding": [ 2299 | { 2300 | "url": "https://github.com/sebastianbergmann", 2301 | "type": "github" 2302 | } 2303 | ], 2304 | "time": "2022-09-14T12:41:17+00:00" 2305 | }, 2306 | { 2307 | "name": "sebastian/complexity", 2308 | "version": "2.0.2", 2309 | "source": { 2310 | "type": "git", 2311 | "url": "https://github.com/sebastianbergmann/complexity.git", 2312 | "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" 2313 | }, 2314 | "dist": { 2315 | "type": "zip", 2316 | "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", 2317 | "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", 2318 | "shasum": "" 2319 | }, 2320 | "require": { 2321 | "nikic/php-parser": "^4.7", 2322 | "php": ">=7.3" 2323 | }, 2324 | "require-dev": { 2325 | "phpunit/phpunit": "^9.3" 2326 | }, 2327 | "type": "library", 2328 | "extra": { 2329 | "branch-alias": { 2330 | "dev-master": "2.0-dev" 2331 | } 2332 | }, 2333 | "autoload": { 2334 | "classmap": [ 2335 | "src/" 2336 | ] 2337 | }, 2338 | "notification-url": "https://packagist.org/downloads/", 2339 | "license": [ 2340 | "BSD-3-Clause" 2341 | ], 2342 | "authors": [ 2343 | { 2344 | "name": "Sebastian Bergmann", 2345 | "email": "sebastian@phpunit.de", 2346 | "role": "lead" 2347 | } 2348 | ], 2349 | "description": "Library for calculating the complexity of PHP code units", 2350 | "homepage": "https://github.com/sebastianbergmann/complexity", 2351 | "support": { 2352 | "issues": "https://github.com/sebastianbergmann/complexity/issues", 2353 | "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" 2354 | }, 2355 | "funding": [ 2356 | { 2357 | "url": "https://github.com/sebastianbergmann", 2358 | "type": "github" 2359 | } 2360 | ], 2361 | "time": "2020-10-26T15:52:27+00:00" 2362 | }, 2363 | { 2364 | "name": "sebastian/diff", 2365 | "version": "4.0.5", 2366 | "source": { 2367 | "type": "git", 2368 | "url": "https://github.com/sebastianbergmann/diff.git", 2369 | "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" 2370 | }, 2371 | "dist": { 2372 | "type": "zip", 2373 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", 2374 | "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", 2375 | "shasum": "" 2376 | }, 2377 | "require": { 2378 | "php": ">=7.3" 2379 | }, 2380 | "require-dev": { 2381 | "phpunit/phpunit": "^9.3", 2382 | "symfony/process": "^4.2 || ^5" 2383 | }, 2384 | "type": "library", 2385 | "extra": { 2386 | "branch-alias": { 2387 | "dev-master": "4.0-dev" 2388 | } 2389 | }, 2390 | "autoload": { 2391 | "classmap": [ 2392 | "src/" 2393 | ] 2394 | }, 2395 | "notification-url": "https://packagist.org/downloads/", 2396 | "license": [ 2397 | "BSD-3-Clause" 2398 | ], 2399 | "authors": [ 2400 | { 2401 | "name": "Sebastian Bergmann", 2402 | "email": "sebastian@phpunit.de" 2403 | }, 2404 | { 2405 | "name": "Kore Nordmann", 2406 | "email": "mail@kore-nordmann.de" 2407 | } 2408 | ], 2409 | "description": "Diff implementation", 2410 | "homepage": "https://github.com/sebastianbergmann/diff", 2411 | "keywords": [ 2412 | "diff", 2413 | "udiff", 2414 | "unidiff", 2415 | "unified diff" 2416 | ], 2417 | "support": { 2418 | "issues": "https://github.com/sebastianbergmann/diff/issues", 2419 | "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" 2420 | }, 2421 | "funding": [ 2422 | { 2423 | "url": "https://github.com/sebastianbergmann", 2424 | "type": "github" 2425 | } 2426 | ], 2427 | "time": "2023-05-07T05:35:17+00:00" 2428 | }, 2429 | { 2430 | "name": "sebastian/environment", 2431 | "version": "5.1.5", 2432 | "source": { 2433 | "type": "git", 2434 | "url": "https://github.com/sebastianbergmann/environment.git", 2435 | "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" 2436 | }, 2437 | "dist": { 2438 | "type": "zip", 2439 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", 2440 | "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", 2441 | "shasum": "" 2442 | }, 2443 | "require": { 2444 | "php": ">=7.3" 2445 | }, 2446 | "require-dev": { 2447 | "phpunit/phpunit": "^9.3" 2448 | }, 2449 | "suggest": { 2450 | "ext-posix": "*" 2451 | }, 2452 | "type": "library", 2453 | "extra": { 2454 | "branch-alias": { 2455 | "dev-master": "5.1-dev" 2456 | } 2457 | }, 2458 | "autoload": { 2459 | "classmap": [ 2460 | "src/" 2461 | ] 2462 | }, 2463 | "notification-url": "https://packagist.org/downloads/", 2464 | "license": [ 2465 | "BSD-3-Clause" 2466 | ], 2467 | "authors": [ 2468 | { 2469 | "name": "Sebastian Bergmann", 2470 | "email": "sebastian@phpunit.de" 2471 | } 2472 | ], 2473 | "description": "Provides functionality to handle HHVM/PHP environments", 2474 | "homepage": "http://www.github.com/sebastianbergmann/environment", 2475 | "keywords": [ 2476 | "Xdebug", 2477 | "environment", 2478 | "hhvm" 2479 | ], 2480 | "support": { 2481 | "issues": "https://github.com/sebastianbergmann/environment/issues", 2482 | "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" 2483 | }, 2484 | "funding": [ 2485 | { 2486 | "url": "https://github.com/sebastianbergmann", 2487 | "type": "github" 2488 | } 2489 | ], 2490 | "time": "2023-02-03T06:03:51+00:00" 2491 | }, 2492 | { 2493 | "name": "sebastian/exporter", 2494 | "version": "4.0.5", 2495 | "source": { 2496 | "type": "git", 2497 | "url": "https://github.com/sebastianbergmann/exporter.git", 2498 | "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" 2499 | }, 2500 | "dist": { 2501 | "type": "zip", 2502 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", 2503 | "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", 2504 | "shasum": "" 2505 | }, 2506 | "require": { 2507 | "php": ">=7.3", 2508 | "sebastian/recursion-context": "^4.0" 2509 | }, 2510 | "require-dev": { 2511 | "ext-mbstring": "*", 2512 | "phpunit/phpunit": "^9.3" 2513 | }, 2514 | "type": "library", 2515 | "extra": { 2516 | "branch-alias": { 2517 | "dev-master": "4.0-dev" 2518 | } 2519 | }, 2520 | "autoload": { 2521 | "classmap": [ 2522 | "src/" 2523 | ] 2524 | }, 2525 | "notification-url": "https://packagist.org/downloads/", 2526 | "license": [ 2527 | "BSD-3-Clause" 2528 | ], 2529 | "authors": [ 2530 | { 2531 | "name": "Sebastian Bergmann", 2532 | "email": "sebastian@phpunit.de" 2533 | }, 2534 | { 2535 | "name": "Jeff Welch", 2536 | "email": "whatthejeff@gmail.com" 2537 | }, 2538 | { 2539 | "name": "Volker Dusch", 2540 | "email": "github@wallbash.com" 2541 | }, 2542 | { 2543 | "name": "Adam Harvey", 2544 | "email": "aharvey@php.net" 2545 | }, 2546 | { 2547 | "name": "Bernhard Schussek", 2548 | "email": "bschussek@gmail.com" 2549 | } 2550 | ], 2551 | "description": "Provides the functionality to export PHP variables for visualization", 2552 | "homepage": "https://www.github.com/sebastianbergmann/exporter", 2553 | "keywords": [ 2554 | "export", 2555 | "exporter" 2556 | ], 2557 | "support": { 2558 | "issues": "https://github.com/sebastianbergmann/exporter/issues", 2559 | "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" 2560 | }, 2561 | "funding": [ 2562 | { 2563 | "url": "https://github.com/sebastianbergmann", 2564 | "type": "github" 2565 | } 2566 | ], 2567 | "time": "2022-09-14T06:03:37+00:00" 2568 | }, 2569 | { 2570 | "name": "sebastian/global-state", 2571 | "version": "5.0.6", 2572 | "source": { 2573 | "type": "git", 2574 | "url": "https://github.com/sebastianbergmann/global-state.git", 2575 | "reference": "bde739e7565280bda77be70044ac1047bc007e34" 2576 | }, 2577 | "dist": { 2578 | "type": "zip", 2579 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", 2580 | "reference": "bde739e7565280bda77be70044ac1047bc007e34", 2581 | "shasum": "" 2582 | }, 2583 | "require": { 2584 | "php": ">=7.3", 2585 | "sebastian/object-reflector": "^2.0", 2586 | "sebastian/recursion-context": "^4.0" 2587 | }, 2588 | "require-dev": { 2589 | "ext-dom": "*", 2590 | "phpunit/phpunit": "^9.3" 2591 | }, 2592 | "suggest": { 2593 | "ext-uopz": "*" 2594 | }, 2595 | "type": "library", 2596 | "extra": { 2597 | "branch-alias": { 2598 | "dev-master": "5.0-dev" 2599 | } 2600 | }, 2601 | "autoload": { 2602 | "classmap": [ 2603 | "src/" 2604 | ] 2605 | }, 2606 | "notification-url": "https://packagist.org/downloads/", 2607 | "license": [ 2608 | "BSD-3-Clause" 2609 | ], 2610 | "authors": [ 2611 | { 2612 | "name": "Sebastian Bergmann", 2613 | "email": "sebastian@phpunit.de" 2614 | } 2615 | ], 2616 | "description": "Snapshotting of global state", 2617 | "homepage": "http://www.github.com/sebastianbergmann/global-state", 2618 | "keywords": [ 2619 | "global state" 2620 | ], 2621 | "support": { 2622 | "issues": "https://github.com/sebastianbergmann/global-state/issues", 2623 | "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" 2624 | }, 2625 | "funding": [ 2626 | { 2627 | "url": "https://github.com/sebastianbergmann", 2628 | "type": "github" 2629 | } 2630 | ], 2631 | "time": "2023-08-02T09:26:13+00:00" 2632 | }, 2633 | { 2634 | "name": "sebastian/lines-of-code", 2635 | "version": "1.0.3", 2636 | "source": { 2637 | "type": "git", 2638 | "url": "https://github.com/sebastianbergmann/lines-of-code.git", 2639 | "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" 2640 | }, 2641 | "dist": { 2642 | "type": "zip", 2643 | "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", 2644 | "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", 2645 | "shasum": "" 2646 | }, 2647 | "require": { 2648 | "nikic/php-parser": "^4.6", 2649 | "php": ">=7.3" 2650 | }, 2651 | "require-dev": { 2652 | "phpunit/phpunit": "^9.3" 2653 | }, 2654 | "type": "library", 2655 | "extra": { 2656 | "branch-alias": { 2657 | "dev-master": "1.0-dev" 2658 | } 2659 | }, 2660 | "autoload": { 2661 | "classmap": [ 2662 | "src/" 2663 | ] 2664 | }, 2665 | "notification-url": "https://packagist.org/downloads/", 2666 | "license": [ 2667 | "BSD-3-Clause" 2668 | ], 2669 | "authors": [ 2670 | { 2671 | "name": "Sebastian Bergmann", 2672 | "email": "sebastian@phpunit.de", 2673 | "role": "lead" 2674 | } 2675 | ], 2676 | "description": "Library for counting the lines of code in PHP source code", 2677 | "homepage": "https://github.com/sebastianbergmann/lines-of-code", 2678 | "support": { 2679 | "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", 2680 | "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" 2681 | }, 2682 | "funding": [ 2683 | { 2684 | "url": "https://github.com/sebastianbergmann", 2685 | "type": "github" 2686 | } 2687 | ], 2688 | "time": "2020-11-28T06:42:11+00:00" 2689 | }, 2690 | { 2691 | "name": "sebastian/object-enumerator", 2692 | "version": "4.0.4", 2693 | "source": { 2694 | "type": "git", 2695 | "url": "https://github.com/sebastianbergmann/object-enumerator.git", 2696 | "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" 2697 | }, 2698 | "dist": { 2699 | "type": "zip", 2700 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", 2701 | "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", 2702 | "shasum": "" 2703 | }, 2704 | "require": { 2705 | "php": ">=7.3", 2706 | "sebastian/object-reflector": "^2.0", 2707 | "sebastian/recursion-context": "^4.0" 2708 | }, 2709 | "require-dev": { 2710 | "phpunit/phpunit": "^9.3" 2711 | }, 2712 | "type": "library", 2713 | "extra": { 2714 | "branch-alias": { 2715 | "dev-master": "4.0-dev" 2716 | } 2717 | }, 2718 | "autoload": { 2719 | "classmap": [ 2720 | "src/" 2721 | ] 2722 | }, 2723 | "notification-url": "https://packagist.org/downloads/", 2724 | "license": [ 2725 | "BSD-3-Clause" 2726 | ], 2727 | "authors": [ 2728 | { 2729 | "name": "Sebastian Bergmann", 2730 | "email": "sebastian@phpunit.de" 2731 | } 2732 | ], 2733 | "description": "Traverses array structures and object graphs to enumerate all referenced objects", 2734 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/", 2735 | "support": { 2736 | "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", 2737 | "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" 2738 | }, 2739 | "funding": [ 2740 | { 2741 | "url": "https://github.com/sebastianbergmann", 2742 | "type": "github" 2743 | } 2744 | ], 2745 | "time": "2020-10-26T13:12:34+00:00" 2746 | }, 2747 | { 2748 | "name": "sebastian/object-reflector", 2749 | "version": "2.0.4", 2750 | "source": { 2751 | "type": "git", 2752 | "url": "https://github.com/sebastianbergmann/object-reflector.git", 2753 | "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" 2754 | }, 2755 | "dist": { 2756 | "type": "zip", 2757 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", 2758 | "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", 2759 | "shasum": "" 2760 | }, 2761 | "require": { 2762 | "php": ">=7.3" 2763 | }, 2764 | "require-dev": { 2765 | "phpunit/phpunit": "^9.3" 2766 | }, 2767 | "type": "library", 2768 | "extra": { 2769 | "branch-alias": { 2770 | "dev-master": "2.0-dev" 2771 | } 2772 | }, 2773 | "autoload": { 2774 | "classmap": [ 2775 | "src/" 2776 | ] 2777 | }, 2778 | "notification-url": "https://packagist.org/downloads/", 2779 | "license": [ 2780 | "BSD-3-Clause" 2781 | ], 2782 | "authors": [ 2783 | { 2784 | "name": "Sebastian Bergmann", 2785 | "email": "sebastian@phpunit.de" 2786 | } 2787 | ], 2788 | "description": "Allows reflection of object attributes, including inherited and non-public ones", 2789 | "homepage": "https://github.com/sebastianbergmann/object-reflector/", 2790 | "support": { 2791 | "issues": "https://github.com/sebastianbergmann/object-reflector/issues", 2792 | "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" 2793 | }, 2794 | "funding": [ 2795 | { 2796 | "url": "https://github.com/sebastianbergmann", 2797 | "type": "github" 2798 | } 2799 | ], 2800 | "time": "2020-10-26T13:14:26+00:00" 2801 | }, 2802 | { 2803 | "name": "sebastian/recursion-context", 2804 | "version": "4.0.5", 2805 | "source": { 2806 | "type": "git", 2807 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 2808 | "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" 2809 | }, 2810 | "dist": { 2811 | "type": "zip", 2812 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", 2813 | "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", 2814 | "shasum": "" 2815 | }, 2816 | "require": { 2817 | "php": ">=7.3" 2818 | }, 2819 | "require-dev": { 2820 | "phpunit/phpunit": "^9.3" 2821 | }, 2822 | "type": "library", 2823 | "extra": { 2824 | "branch-alias": { 2825 | "dev-master": "4.0-dev" 2826 | } 2827 | }, 2828 | "autoload": { 2829 | "classmap": [ 2830 | "src/" 2831 | ] 2832 | }, 2833 | "notification-url": "https://packagist.org/downloads/", 2834 | "license": [ 2835 | "BSD-3-Clause" 2836 | ], 2837 | "authors": [ 2838 | { 2839 | "name": "Sebastian Bergmann", 2840 | "email": "sebastian@phpunit.de" 2841 | }, 2842 | { 2843 | "name": "Jeff Welch", 2844 | "email": "whatthejeff@gmail.com" 2845 | }, 2846 | { 2847 | "name": "Adam Harvey", 2848 | "email": "aharvey@php.net" 2849 | } 2850 | ], 2851 | "description": "Provides functionality to recursively process PHP variables", 2852 | "homepage": "https://github.com/sebastianbergmann/recursion-context", 2853 | "support": { 2854 | "issues": "https://github.com/sebastianbergmann/recursion-context/issues", 2855 | "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" 2856 | }, 2857 | "funding": [ 2858 | { 2859 | "url": "https://github.com/sebastianbergmann", 2860 | "type": "github" 2861 | } 2862 | ], 2863 | "time": "2023-02-03T06:07:39+00:00" 2864 | }, 2865 | { 2866 | "name": "sebastian/resource-operations", 2867 | "version": "3.0.3", 2868 | "source": { 2869 | "type": "git", 2870 | "url": "https://github.com/sebastianbergmann/resource-operations.git", 2871 | "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" 2872 | }, 2873 | "dist": { 2874 | "type": "zip", 2875 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", 2876 | "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", 2877 | "shasum": "" 2878 | }, 2879 | "require": { 2880 | "php": ">=7.3" 2881 | }, 2882 | "require-dev": { 2883 | "phpunit/phpunit": "^9.0" 2884 | }, 2885 | "type": "library", 2886 | "extra": { 2887 | "branch-alias": { 2888 | "dev-master": "3.0-dev" 2889 | } 2890 | }, 2891 | "autoload": { 2892 | "classmap": [ 2893 | "src/" 2894 | ] 2895 | }, 2896 | "notification-url": "https://packagist.org/downloads/", 2897 | "license": [ 2898 | "BSD-3-Clause" 2899 | ], 2900 | "authors": [ 2901 | { 2902 | "name": "Sebastian Bergmann", 2903 | "email": "sebastian@phpunit.de" 2904 | } 2905 | ], 2906 | "description": "Provides a list of PHP built-in functions that operate on resources", 2907 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations", 2908 | "support": { 2909 | "issues": "https://github.com/sebastianbergmann/resource-operations/issues", 2910 | "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" 2911 | }, 2912 | "funding": [ 2913 | { 2914 | "url": "https://github.com/sebastianbergmann", 2915 | "type": "github" 2916 | } 2917 | ], 2918 | "time": "2020-09-28T06:45:17+00:00" 2919 | }, 2920 | { 2921 | "name": "sebastian/type", 2922 | "version": "3.2.1", 2923 | "source": { 2924 | "type": "git", 2925 | "url": "https://github.com/sebastianbergmann/type.git", 2926 | "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" 2927 | }, 2928 | "dist": { 2929 | "type": "zip", 2930 | "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", 2931 | "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", 2932 | "shasum": "" 2933 | }, 2934 | "require": { 2935 | "php": ">=7.3" 2936 | }, 2937 | "require-dev": { 2938 | "phpunit/phpunit": "^9.5" 2939 | }, 2940 | "type": "library", 2941 | "extra": { 2942 | "branch-alias": { 2943 | "dev-master": "3.2-dev" 2944 | } 2945 | }, 2946 | "autoload": { 2947 | "classmap": [ 2948 | "src/" 2949 | ] 2950 | }, 2951 | "notification-url": "https://packagist.org/downloads/", 2952 | "license": [ 2953 | "BSD-3-Clause" 2954 | ], 2955 | "authors": [ 2956 | { 2957 | "name": "Sebastian Bergmann", 2958 | "email": "sebastian@phpunit.de", 2959 | "role": "lead" 2960 | } 2961 | ], 2962 | "description": "Collection of value objects that represent the types of the PHP type system", 2963 | "homepage": "https://github.com/sebastianbergmann/type", 2964 | "support": { 2965 | "issues": "https://github.com/sebastianbergmann/type/issues", 2966 | "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" 2967 | }, 2968 | "funding": [ 2969 | { 2970 | "url": "https://github.com/sebastianbergmann", 2971 | "type": "github" 2972 | } 2973 | ], 2974 | "time": "2023-02-03T06:13:03+00:00" 2975 | }, 2976 | { 2977 | "name": "sebastian/version", 2978 | "version": "3.0.2", 2979 | "source": { 2980 | "type": "git", 2981 | "url": "https://github.com/sebastianbergmann/version.git", 2982 | "reference": "c6c1022351a901512170118436c764e473f6de8c" 2983 | }, 2984 | "dist": { 2985 | "type": "zip", 2986 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", 2987 | "reference": "c6c1022351a901512170118436c764e473f6de8c", 2988 | "shasum": "" 2989 | }, 2990 | "require": { 2991 | "php": ">=7.3" 2992 | }, 2993 | "type": "library", 2994 | "extra": { 2995 | "branch-alias": { 2996 | "dev-master": "3.0-dev" 2997 | } 2998 | }, 2999 | "autoload": { 3000 | "classmap": [ 3001 | "src/" 3002 | ] 3003 | }, 3004 | "notification-url": "https://packagist.org/downloads/", 3005 | "license": [ 3006 | "BSD-3-Clause" 3007 | ], 3008 | "authors": [ 3009 | { 3010 | "name": "Sebastian Bergmann", 3011 | "email": "sebastian@phpunit.de", 3012 | "role": "lead" 3013 | } 3014 | ], 3015 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 3016 | "homepage": "https://github.com/sebastianbergmann/version", 3017 | "support": { 3018 | "issues": "https://github.com/sebastianbergmann/version/issues", 3019 | "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" 3020 | }, 3021 | "funding": [ 3022 | { 3023 | "url": "https://github.com/sebastianbergmann", 3024 | "type": "github" 3025 | } 3026 | ], 3027 | "time": "2020-09-28T06:39:44+00:00" 3028 | }, 3029 | { 3030 | "name": "theseer/tokenizer", 3031 | "version": "1.2.1", 3032 | "source": { 3033 | "type": "git", 3034 | "url": "https://github.com/theseer/tokenizer.git", 3035 | "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" 3036 | }, 3037 | "dist": { 3038 | "type": "zip", 3039 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", 3040 | "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", 3041 | "shasum": "" 3042 | }, 3043 | "require": { 3044 | "ext-dom": "*", 3045 | "ext-tokenizer": "*", 3046 | "ext-xmlwriter": "*", 3047 | "php": "^7.2 || ^8.0" 3048 | }, 3049 | "type": "library", 3050 | "autoload": { 3051 | "classmap": [ 3052 | "src/" 3053 | ] 3054 | }, 3055 | "notification-url": "https://packagist.org/downloads/", 3056 | "license": [ 3057 | "BSD-3-Clause" 3058 | ], 3059 | "authors": [ 3060 | { 3061 | "name": "Arne Blankerts", 3062 | "email": "arne@blankerts.de", 3063 | "role": "Developer" 3064 | } 3065 | ], 3066 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", 3067 | "support": { 3068 | "issues": "https://github.com/theseer/tokenizer/issues", 3069 | "source": "https://github.com/theseer/tokenizer/tree/1.2.1" 3070 | }, 3071 | "funding": [ 3072 | { 3073 | "url": "https://github.com/theseer", 3074 | "type": "github" 3075 | } 3076 | ], 3077 | "time": "2021-07-28T10:34:58+00:00" 3078 | } 3079 | ], 3080 | "aliases": [], 3081 | "minimum-stability": "stable", 3082 | "stability-flags": [], 3083 | "prefer-stable": false, 3084 | "prefer-lowest": false, 3085 | "platform": { 3086 | "php": "^8.1" 3087 | }, 3088 | "platform-dev": [], 3089 | "plugin-api-version": "2.3.0" 3090 | } 3091 | --------------------------------------------------------------------------------