From 3f0ecc297bdcbbe0d51fad39f9090369477e215a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Jaussoin?= Date: Thu, 5 Feb 2026 17:42:33 +0100 Subject: [PATCH] Fix FLEXIAPI-433 Implement CallForwarding --- CHANGELOG.md | 1 + flexiapi/app/Account.php | 14 + flexiapi/app/CallForwarding.php | 19 + flexiapi/app/Helpers/Utils.php | 10 +- .../Account/ContactVcardController.php | 4 +- .../Account/CallForwardingController.php | 77 ++ .../Admin/Account/ContactController.php | 2 +- .../Admin/Account/TelephonyController.php | 17 + .../Api/Account/CallForwardingController.php | 35 + .../Api/Account/ContactController.php | 4 +- .../Account/CallForwardingController.php | 81 ++ .../Api/Admin/AccountController.php | 4 +- .../Controllers/Api/Admin/SpaceController.php | 12 + flexiapi/app/Rules/CallForwardingEnable.php | 26 + flexiapi/composer.lock | 1177 +++++++++-------- ...5_154352_create_call_forwardings_table.php | 31 + flexiapi/lang/fr.json | 10 +- flexiapi/public/css/form.css | 13 + flexiapi/public/scripts/utils.js | 8 + .../account/call_forwardings/edit.blade.php | 49 + .../edit_select_part.blade.php | 23 + .../admin/account/contact/index.blade.php | 2 +- .../views/admin/account/parts/tabs.blade.php | 1 + .../views/admin/account/show.blade.php | 49 +- .../admin/account/telephony/show.blade.php | 65 + .../accounts/call_forwarding.blade.php | 46 + .../call_forwarding_parameters.blade.php | 0 .../api/documentation_markdown.blade.php | 15 + flexiapi/resources/views/errors/503.blade.php | 10 +- .../resources/views/parts/errors.blade.php | 1 - flexiapi/routes/api.php | 6 + flexiapi/routes/web.php | 10 + .../Feature/ApiAccountCallForwardingTest.php | 162 +++ 33 files changed, 1388 insertions(+), 596 deletions(-) create mode 100644 flexiapi/app/CallForwarding.php create mode 100644 flexiapi/app/Http/Controllers/Admin/Account/CallForwardingController.php create mode 100644 flexiapi/app/Http/Controllers/Admin/Account/TelephonyController.php create mode 100644 flexiapi/app/Http/Controllers/Api/Account/CallForwardingController.php create mode 100644 flexiapi/app/Http/Controllers/Api/Admin/Account/CallForwardingController.php create mode 100644 flexiapi/app/Rules/CallForwardingEnable.php create mode 100644 flexiapi/database/migrations/2026_02_05_154352_create_call_forwardings_table.php create mode 100644 flexiapi/resources/views/admin/account/call_forwardings/edit.blade.php create mode 100644 flexiapi/resources/views/admin/account/call_forwardings/edit_select_part.blade.php create mode 100644 flexiapi/resources/views/admin/account/telephony/show.blade.php create mode 100644 flexiapi/resources/views/api/documentation/accounts/call_forwarding.blade.php create mode 100644 flexiapi/resources/views/api/documentation/accounts/call_forwarding_parameters.blade.php create mode 100644 flexiapi/tests/Feature/ApiAccountCallForwardingTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f5c13c..5835f6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/). - **Rockylinux 10 support** Packages are now available in the official repository - **Artisan cleanup script for statistics** Add an artisan console script to clear statistics after n days `app:clear-statistics {days} {--apply}` - **Add Voicemail features and related API endpoints** to integrate with `flexisip-voicemail` +- **Add Call Forwarding features and related API endpoints** ### Changed diff --git a/flexiapi/app/Account.php b/flexiapi/app/Account.php index 4bfca3e..fa012e5 100644 --- a/flexiapi/app/Account.php +++ b/flexiapi/app/Account.php @@ -139,6 +139,20 @@ class Account extends Authenticatable return $this->hasMany(AccountFile::class)->latest(); } + public function callForwardings() + { + return $this->hasMany(CallForwarding::class)->latest(); + } + + public function getCallForwardingsDefaultAttribute() + { + $callForwardings = $this->callForwardings->keyBy('type'); + $resolved['always'] = $callForwardings['always'] ?? new CallForwarding(['type' => 'always']); + $resolved['away'] = $callForwardings['away'] ?? new CallForwarding(['type' => 'away']); + $resolved['busy'] = $callForwardings['busy'] ?? new CallForwarding(['type' => 'busy']); + return $resolved; + } + public function voicemails() { return $this->hasMany(AccountFile::class) diff --git a/flexiapi/app/CallForwarding.php b/flexiapi/app/CallForwarding.php new file mode 100644 index 0000000..fbb88bc --- /dev/null +++ b/flexiapi/app/CallForwarding.php @@ -0,0 +1,19 @@ + 'boolean' + ]; + protected $fillable = ['enabled', 'account_id', 'type', 'forward_to', 'sip_uri']; + protected $hidden = ['account_id']; + + public function account() + { + return $this->belongsTo(Account::class); + } +} diff --git a/flexiapi/app/Helpers/Utils.php b/flexiapi/app/Helpers/Utils.php index 351cbef..6ca432f 100644 --- a/flexiapi/app/Helpers/Utils.php +++ b/flexiapi/app/Helpers/Utils.php @@ -175,21 +175,21 @@ function captchaConfigured(): bool return env('HCAPTCHA_SECRET', false) != false || env('HCAPTCHA_SITEKEY', false) != false; } -function resolveUserContacts(Request $request) +function resolveUserContacts(Account $account) { $selected = ['id', 'username', 'domain', 'activated', 'dtmf_protocol', 'display_name']; - return Account::withoutGlobalScopes()->whereIn('id', function ($query) use ($request) { + return Account::withoutGlobalScopes()->whereIn('id', function ($query) use ($account) { $query->select('contact_id') ->from('contacts') - ->where('account_id', $request->user()->id) + ->where('account_id', $account->id) ->union( DB::table('contacts_list_contact') ->select('contact_id') - ->whereIn('contacts_list_id', function ($query) use ($request) { + ->whereIn('contacts_list_id', function ($query) use ($account) { $query->select('contacts_list_id') ->from('account_contacts_list') - ->where('account_id', $request->user()->id); + ->where('account_id', $account->id); }) ); })->select($selected); diff --git a/flexiapi/app/Http/Controllers/Account/ContactVcardController.php b/flexiapi/app/Http/Controllers/Account/ContactVcardController.php index e91130b..05315b0 100644 --- a/flexiapi/app/Http/Controllers/Account/ContactVcardController.php +++ b/flexiapi/app/Http/Controllers/Account/ContactVcardController.php @@ -28,7 +28,7 @@ class ContactVcardController extends Controller public function index(Request $request) { return response( - resolveUserContacts($request)->get()->map(function ($contact) { + resolveUserContacts($request->user())->get()->map(function ($contact) { return $contact->toVcard4(); })->implode("\n") ); @@ -36,7 +36,7 @@ class ContactVcardController extends Controller public function show(Request $request, string $sip) { - return resolveUserContacts($request) + return resolveUserContacts($request->user()) ->sip($sip) ->firstOrFail() ->toVcard4(); diff --git a/flexiapi/app/Http/Controllers/Admin/Account/CallForwardingController.php b/flexiapi/app/Http/Controllers/Admin/Account/CallForwardingController.php new file mode 100644 index 0000000..ab4131c --- /dev/null +++ b/flexiapi/app/Http/Controllers/Admin/Account/CallForwardingController.php @@ -0,0 +1,77 @@ +pluck('id')->toArray(); + + $forwardTo = 'required|in:sip_uri,contact,voicemail'; + + $request->validate([ + 'always.forward_to' => $forwardTo, + 'always.sip_uri' => 'nullable|starts_with:sip:|required_if:always.forward_to,sip_uri', + 'always.contact_id' => ['required_if:always.forward_to,contact', Rule::in($contactsIds)], + + 'away.forward_to' => $forwardTo, + 'away.sip_uri' => 'nullable|starts_with:sip:|required_if:away.forward_to,sip_uri', + 'away.contact_id' => ['required_if:away.forward_to,contact', Rule::in($contactsIds)], + + 'busy.forward_to' => $forwardTo, + 'busy.sip_uri' => 'nullable|starts_with:sip:|required_if:busy.forward_to,sip_uri', + 'busy.contact_id' => ['required_if:busy.forward_to,contact', Rule::in($contactsIds)], + ]); + + $account->callForwardings()->update(['enabled' => false]); + + if (array_key_exists('enabled', $request->get('always'))) { + $alwaysForwarding = $account->callForwardings()->where('type', 'always')->first() ?? new CallForwarding; + $alwaysForwarding->enabled = true; + $alwaysForwarding->account_id = $account->id; + $alwaysForwarding->type = 'always'; + $alwaysForwarding->forward_to = $request->get('always')['forward_to']; + $alwaysForwarding->sip_uri = $request->get('always')['sip_uri']; + $alwaysForwarding->contact_id = $request->get('always')['forward_to'] == 'contact' + ? $request->get('always')['contact_id'] + : null; + $alwaysForwarding->save(); + } + + if (array_key_exists('enabled', $request->get('away'))) { + $awayForwarding = $account->callForwardings()->where('type', 'away')->first() ?? new CallForwarding; + $awayForwarding->enabled = true; + $awayForwarding->account_id = $account->id; + $awayForwarding->type = 'away'; + $awayForwarding->forward_to = $request->get('away')['forward_to']; + $awayForwarding->sip_uri = $request->get('away')['sip_uri']; + $awayForwarding->contact_id = $request->get('away')['forward_to'] == 'contact' + ? $request->get('away')['contact_id'] + : null; + $awayForwarding->save(); + } + + if (array_key_exists('enabled', $request->get('busy'))) { + $busyForwarding = $account->callForwardings()->where('type', 'busy')->first() ?? new CallForwarding; + $busyForwarding->enabled = true; + $busyForwarding->account_id = $account->id; + $busyForwarding->type = 'busy'; + $busyForwarding->forward_to = $request->get('busy')['forward_to']; + $busyForwarding->sip_uri = $request->get('busy')['sip_uri']; + $busyForwarding->contact_id = $request->get('busy')['forward_to'] == 'contact' + ? $request->get('busy')['contact_id'] + : null; + $busyForwarding->save(); + } + + return redirect()->route('admin.account.telephony.show', $account); + } +} diff --git a/flexiapi/app/Http/Controllers/Admin/Account/ContactController.php b/flexiapi/app/Http/Controllers/Admin/Account/ContactController.php index 0f07173..a698ec7 100644 --- a/flexiapi/app/Http/Controllers/Admin/Account/ContactController.php +++ b/flexiapi/app/Http/Controllers/Admin/Account/ContactController.php @@ -34,7 +34,7 @@ class ContactController extends Controller return view('admin.account.contact.index', [ 'account' => $account, - 'contacts_lists' => ContactsList::whereNotIn('id', function ($query) use ($accountId) { + 'contacts_lists' => $account->space->contactsLists()->whereNotIn('id', function ($query) use ($accountId) { $query->select('contacts_list_id') ->from('account_contacts_list') ->where('account_id', $accountId); diff --git a/flexiapi/app/Http/Controllers/Admin/Account/TelephonyController.php b/flexiapi/app/Http/Controllers/Admin/Account/TelephonyController.php new file mode 100644 index 0000000..9900fd6 --- /dev/null +++ b/flexiapi/app/Http/Controllers/Admin/Account/TelephonyController.php @@ -0,0 +1,17 @@ + Account::findOrFail($accountId) + ]); + } +} diff --git a/flexiapi/app/Http/Controllers/Api/Account/CallForwardingController.php b/flexiapi/app/Http/Controllers/Api/Account/CallForwardingController.php new file mode 100644 index 0000000..26ae10d --- /dev/null +++ b/flexiapi/app/Http/Controllers/Api/Account/CallForwardingController.php @@ -0,0 +1,35 @@ +index($request, $request->user()->id); + } + + public function store(Request $request) + { + return (new AdminCallForwardingController)->store($request, $request->user()->id); + } + + public function update(Request $request, $id) + { + return (new AdminCallForwardingController)->update($request, $request->user()->id, $id); + } + + public function show(Request $request, string $id) + { + return (new AdminCallForwardingController)->show($request, $request->user()->id, $id); + } + + public function destroy(Request $request, string $id) + { + return (new AdminCallForwardingController)->destroy($request, $request->user()->id, $id); + } +} diff --git a/flexiapi/app/Http/Controllers/Api/Account/ContactController.php b/flexiapi/app/Http/Controllers/Api/Account/ContactController.php index 343c992..fb679a8 100644 --- a/flexiapi/app/Http/Controllers/Api/Account/ContactController.php +++ b/flexiapi/app/Http/Controllers/Api/Account/ContactController.php @@ -26,11 +26,11 @@ class ContactController extends Controller { public function index(Request $request) { - return resolveUserContacts($request)->get(); + return resolveUserContacts($request->user())->get(); } public function show(Request $request, string $sip) { - return resolveUserContacts($request)->sip($sip)->firstOrFail(); + return resolveUserContacts($request->user())->sip($sip)->firstOrFail(); } } diff --git a/flexiapi/app/Http/Controllers/Api/Admin/Account/CallForwardingController.php b/flexiapi/app/Http/Controllers/Api/Admin/Account/CallForwardingController.php new file mode 100644 index 0000000..1a41b1c --- /dev/null +++ b/flexiapi/app/Http/Controllers/Api/Admin/Account/CallForwardingController.php @@ -0,0 +1,81 @@ +callForwardings; + } + + public function store(Request $request, int $accountId) + { + $account = Account::findOrFail($accountId); + $request->validate([ + 'type' => [ + 'required', + 'in:always,away,busy', + Rule::unique('call_forwardings', 'type')->where(fn($query) => $query->where('account_id', $accountId)) + ], + 'forward_to' => 'required|in:sip_uri,contact,voicemail', + 'sip_uri' => 'nullable|starts_with:sip:|required_if:forward_to,sip_uri', + 'enabled' => ['required', 'boolean', new CallForwardingEnable($request, $account)], + 'contact_id' => ['required_if:forward_to,contact', Rule::in(resolveUserContacts($account)->pluck('id')->toArray())], + ]); + + $callForwarding = new CallForwarding; + $callForwarding->account_id = $account->id; + $callForwarding->type = $request->get('type'); + $callForwarding->forward_to = $request->get('forward_to'); + $callForwarding->sip_uri = $request->get('sip_uri'); + $callForwarding->enabled = $request->get('enabled'); + $callForwarding->contact_id = $request->get('contact_id'); + $callForwarding->save(); + + return $callForwarding; + } + + public function update(Request $request, int $accountId, string $id) + { + $account = Account::findOrFail($accountId); + $callForwarding = $account->callForwardings()->where('id', $id)->firstOrFail(); + + $request->validate([ + 'type' => [ + 'required', + 'in:always,away,busy', + Rule::unique('call_forwardings', 'type') + ->where(fn($query) => $query->where('account_id', $accountId)) + ->ignore($callForwarding->id) + ], + 'forward_to' => 'required|in:sip_uri', + 'sip_uri' => 'required|starts_with:sip', + 'enabled' => ['required', 'boolean', new CallForwardingEnable($request, $account)] + ]); + + $callForwarding->forward_to = $request->get('forward_to'); + $callForwarding->sip_uri = $request->get('sip_uri'); + $callForwarding->enabled = $request->get('enabled'); + $callForwarding->save(); + + return $callForwarding; + } + + public function show(Request $request, int $accountId, string $id) + { + return Account::findOrFail($accountId)->callForwardings()->where('id', $id)->firstOrFail(); + } + + public function destroy(Request $request, int $accountId, string $id) + { + return Account::findOrFail($accountId)->callForwardings()->where('id', $id)->delete(); + } +} diff --git a/flexiapi/app/Http/Controllers/Api/Admin/AccountController.php b/flexiapi/app/Http/Controllers/Api/Admin/AccountController.php index 08cf762..a2db55d 100644 --- a/flexiapi/app/Http/Controllers/Api/Admin/AccountController.php +++ b/flexiapi/app/Http/Controllers/Api/Admin/AccountController.php @@ -67,7 +67,7 @@ class AccountController extends Controller public function search(Request $request, string $sip) { - $account = $request->space->accounts()->sip($sip)->first(); + $account = $request->space->accounts()->sip($sip)->with('callForwardings')->first(); if (!$account) abort(404, 'SIP address not found'); @@ -77,7 +77,7 @@ class AccountController extends Controller public function searchByEmail(Request $request, string $email) { - $account = $request->space->accounts()->where('email', $email)->first(); + $account = $request->space->accounts()->where('email', $email)->with('callForwardings')->first(); if (!$account) abort(404, 'Email address not found'); diff --git a/flexiapi/app/Http/Controllers/Api/Admin/SpaceController.php b/flexiapi/app/Http/Controllers/Api/Admin/SpaceController.php index ffdf321..b7fa35a 100644 --- a/flexiapi/app/Http/Controllers/Api/Admin/SpaceController.php +++ b/flexiapi/app/Http/Controllers/Api/Admin/SpaceController.php @@ -81,6 +81,18 @@ class SpaceController extends Controller return $space->refresh(); } + public function resolve(Request $request, string $sip) + { + $account = $request->space->accounts()->sip($sip)->with('callForwardings')->firstOrFail(); + $arrayAccount = $account->toArray(); + unset($arrayAccount['space']); + + return json_encode([ + 'type' => 'account', + 'payload' => $arrayAccount + ]); + } + public function show(string $domain) { return Space::where('domain', $domain)->firstOrFail(); diff --git a/flexiapi/app/Rules/CallForwardingEnable.php b/flexiapi/app/Rules/CallForwardingEnable.php new file mode 100644 index 0000000..644c967 --- /dev/null +++ b/flexiapi/app/Rules/CallForwardingEnable.php @@ -0,0 +1,26 @@ +request->get('type') == 'always' ? ['away', 'busy'] : ['always']; + + if ($this->account->callForwardings()->whereIn('type', $filter)->where('enabled', true)->exists()) { + $fail('type: always and type: always/busy cannot be enabled at the same time'); + } + } + } +} diff --git a/flexiapi/composer.lock b/flexiapi/composer.lock index b59510a..8ba2664 100644 --- a/flexiapi/composer.lock +++ b/flexiapi/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "awobaz/compoships", - "version": "2.5.1", + "version": "2.5.4", "source": { "type": "git", "url": "https://github.com/topclaudy/compoships.git", - "reference": "d8de30b57949d6021bb0312105f6d9d0920266b6" + "reference": "dcae8012a8704fc2acd8dce2d8a1b35ce292adbe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/topclaudy/compoships/zipball/d8de30b57949d6021bb0312105f6d9d0920266b6", - "reference": "d8de30b57949d6021bb0312105f6d9d0920266b6", + "url": "https://api.github.com/repos/topclaudy/compoships/zipball/dcae8012a8704fc2acd8dce2d8a1b35ce292adbe", + "reference": "dcae8012a8704fc2acd8dce2d8a1b35ce292adbe", "shasum": "" }, "require": { @@ -58,7 +58,7 @@ ], "support": { "issues": "https://github.com/topclaudy/compoships/issues", - "source": "https://github.com/topclaudy/compoships/tree/2.5.1" + "source": "https://github.com/topclaudy/compoships/tree/2.5.4" }, "funding": [ { @@ -66,20 +66,20 @@ "type": "custom" } ], - "time": "2025-10-10T14:07:12+00:00" + "time": "2025-12-23T18:33:46+00:00" }, { "name": "bacon/bacon-qr-code", - "version": "v3.0.1", + "version": "v3.0.3", "source": { "type": "git", "url": "https://github.com/Bacon/BaconQrCode.git", - "reference": "f9cc1f52b5a463062251d666761178dbdb6b544f" + "reference": "36a1cb2b81493fa5b82e50bf8068bf84d1542563" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/f9cc1f52b5a463062251d666761178dbdb6b544f", - "reference": "f9cc1f52b5a463062251d666761178dbdb6b544f", + "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/36a1cb2b81493fa5b82e50bf8068bf84d1542563", + "reference": "36a1cb2b81493fa5b82e50bf8068bf84d1542563", "shasum": "" }, "require": { @@ -89,8 +89,9 @@ }, "require-dev": { "phly/keep-a-changelog": "^2.12", - "phpunit/phpunit": "^10.5.11 || 11.0.4", + "phpunit/phpunit": "^10.5.11 || ^11.0.4", "spatie/phpunit-snapshot-assertions": "^5.1.5", + "spatie/pixelmatch-php": "^1.2.0", "squizlabs/php_codesniffer": "^3.9" }, "suggest": { @@ -118,22 +119,22 @@ "homepage": "https://github.com/Bacon/BaconQrCode", "support": { "issues": "https://github.com/Bacon/BaconQrCode/issues", - "source": "https://github.com/Bacon/BaconQrCode/tree/v3.0.1" + "source": "https://github.com/Bacon/BaconQrCode/tree/v3.0.3" }, - "time": "2024-10-01T13:55:55+00:00" + "time": "2025-11-19T17:15:36+00:00" }, { "name": "brick/math", - "version": "0.14.0", + "version": "0.14.8", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2" + "reference": "63422359a44b7f06cae63c3b429b59e8efcc0629" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2", - "reference": "113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2", + "url": "https://api.github.com/repos/brick/math/zipball/63422359a44b7f06cae63c3b429b59e8efcc0629", + "reference": "63422359a44b7f06cae63c3b429b59e8efcc0629", "shasum": "" }, "require": { @@ -172,7 +173,7 @@ ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.14.0" + "source": "https://github.com/brick/math/tree/0.14.8" }, "funding": [ { @@ -180,7 +181,7 @@ "type": "github" } ], - "time": "2025-08-29T12:40:03+00:00" + "time": "2026-02-10T14:33:43+00:00" }, { "name": "carbonphp/carbon-doctrine-types", @@ -378,16 +379,16 @@ }, { "name": "doctrine/dbal", - "version": "3.10.3", + "version": "3.10.4", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "65edaca19a752730f290ec2fb89d593cb40afb43" + "reference": "63a46cb5aa6f60991186cc98c1d1b50c09311868" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/65edaca19a752730f290ec2fb89d593cb40afb43", - "reference": "65edaca19a752730f290ec2fb89d593cb40afb43", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/63a46cb5aa6f60991186cc98c1d1b50c09311868", + "reference": "63a46cb5aa6f60991186cc98c1d1b50c09311868", "shasum": "" }, "require": { @@ -411,8 +412,8 @@ "phpunit/phpunit": "9.6.29", "slevomat/coding-standard": "8.24.0", "squizlabs/php_codesniffer": "4.0.0", - "symfony/cache": "^5.4|^6.0|^7.0", - "symfony/console": "^4.4|^5.4|^6.0|^7.0" + "symfony/cache": "^5.4|^6.0|^7.0|^8.0", + "symfony/console": "^4.4|^5.4|^6.0|^7.0|^8.0" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -472,7 +473,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.10.3" + "source": "https://github.com/doctrine/dbal/tree/3.10.4" }, "funding": [ { @@ -488,33 +489,33 @@ "type": "tidelift" } ], - "time": "2025-10-09T09:05:12+00:00" + "time": "2025-11-29T10:46:08+00:00" }, { "name": "doctrine/deprecations", - "version": "1.1.5", + "version": "1.1.6", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38" + "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", - "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", + "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "conflict": { - "phpunit/phpunit": "<=7.5 || >=13" + "phpunit/phpunit": "<=7.5 || >=14" }, "require-dev": { - "doctrine/coding-standard": "^9 || ^12 || ^13", - "phpstan/phpstan": "1.4.10 || 2.1.11", + "doctrine/coding-standard": "^9 || ^12 || ^14", + "phpstan/phpstan": "1.4.10 || 2.1.30", "phpstan/phpstan-phpunit": "^1.0 || ^2", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12.4 || ^13.0", "psr/log": "^1 || ^2 || ^3" }, "suggest": { @@ -534,22 +535,22 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.5" + "source": "https://github.com/doctrine/deprecations/tree/1.1.6" }, - "time": "2025-04-07T20:06:18+00:00" + "time": "2026-02-07T07:09:04+00:00" }, { "name": "doctrine/event-manager", - "version": "2.0.1", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/doctrine/event-manager.git", - "reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e" + "reference": "dda33921b198841ca8dbad2eaa5d4d34769d18cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/event-manager/zipball/b680156fa328f1dfd874fd48c7026c41570b9c6e", - "reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/dda33921b198841ca8dbad2eaa5d4d34769d18cf", + "reference": "dda33921b198841ca8dbad2eaa5d4d34769d18cf", "shasum": "" }, "require": { @@ -559,10 +560,10 @@ "doctrine/common": "<2.9" }, "require-dev": { - "doctrine/coding-standard": "^12", - "phpstan/phpstan": "^1.8.8", - "phpunit/phpunit": "^10.5", - "vimeo/psalm": "^5.24" + "doctrine/coding-standard": "^14", + "phpdocumentor/guides-cli": "^1.4", + "phpstan/phpstan": "^2.1.32", + "phpunit/phpunit": "^10.5.58" }, "type": "library", "autoload": { @@ -611,7 +612,7 @@ ], "support": { "issues": "https://github.com/doctrine/event-manager/issues", - "source": "https://github.com/doctrine/event-manager/tree/2.0.1" + "source": "https://github.com/doctrine/event-manager/tree/2.1.1" }, "funding": [ { @@ -627,7 +628,7 @@ "type": "tidelift" } ], - "time": "2024-05-22T20:47:39+00:00" + "time": "2026-01-29T07:11:08+00:00" }, { "name": "doctrine/inflector", @@ -1001,24 +1002,24 @@ }, { "name": "erusev/parsedown", - "version": "1.7.4", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/erusev/parsedown.git", - "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3" + "reference": "96baaad00f71ba04d76e45b4620f54d3beabd6f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/erusev/parsedown/zipball/cb17b6477dfff935958ba01325f2e8a2bfa6dab3", - "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/96baaad00f71ba04d76e45b4620f54d3beabd6f7", + "reference": "96baaad00f71ba04d76e45b4620f54d3beabd6f7", "shasum": "" }, "require": { "ext-mbstring": "*", - "php": ">=5.3.0" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "^4.8.35" + "phpunit/phpunit": "^7.5|^8.5|^9.6" }, "type": "library", "autoload": { @@ -1045,9 +1046,15 @@ ], "support": { "issues": "https://github.com/erusev/parsedown/issues", - "source": "https://github.com/erusev/parsedown/tree/1.7.x" + "source": "https://github.com/erusev/parsedown/tree/1.8.0" }, - "time": "2019-12-30T22:54:17+00:00" + "funding": [ + { + "url": "https://github.com/erusev", + "type": "github" + } + ], + "time": "2026-02-16T11:41:01+00:00" }, { "name": "evenement/evenement", @@ -1161,31 +1168,31 @@ }, { "name": "fruitcake/php-cors", - "version": "v1.3.0", + "version": "v1.4.0", "source": { "type": "git", "url": "https://github.com/fruitcake/php-cors.git", - "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b" + "reference": "38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/3d158f36e7875e2f040f37bc0573956240a5a38b", - "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b", + "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379", + "reference": "38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379", "shasum": "" }, "require": { - "php": "^7.4|^8.0", - "symfony/http-foundation": "^4.4|^5.4|^6|^7" + "php": "^8.1", + "symfony/http-foundation": "^5.4|^6.4|^7.3|^8" }, "require-dev": { - "phpstan/phpstan": "^1.4", + "phpstan/phpstan": "^2", "phpunit/phpunit": "^9", - "squizlabs/php_codesniffer": "^3.5" + "squizlabs/php_codesniffer": "^4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -1216,7 +1223,7 @@ ], "support": { "issues": "https://github.com/fruitcake/php-cors/issues", - "source": "https://github.com/fruitcake/php-cors/tree/v1.3.0" + "source": "https://github.com/fruitcake/php-cors/tree/v1.4.0" }, "funding": [ { @@ -1228,20 +1235,20 @@ "type": "github" } ], - "time": "2023-10-12T05:21:21+00:00" + "time": "2025-12-03T09:33:47+00:00" }, { "name": "giggsey/libphonenumber-for-php-lite", - "version": "9.0.18", + "version": "9.0.24", "source": { "type": "git", "url": "https://github.com/giggsey/libphonenumber-for-php-lite.git", - "reference": "e3faa62034db1ad42456a673cd568f99564a95f7" + "reference": "f3c3bd0facb1cb0d70c9c0cce609f19a74e8edc7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/giggsey/libphonenumber-for-php-lite/zipball/e3faa62034db1ad42456a673cd568f99564a95f7", - "reference": "e3faa62034db1ad42456a673cd568f99564a95f7", + "url": "https://api.github.com/repos/giggsey/libphonenumber-for-php-lite/zipball/f3c3bd0facb1cb0d70c9c0cce609f19a74e8edc7", + "reference": "f3c3bd0facb1cb0d70c9c0cce609f19a74e8edc7", "shasum": "" }, "require": { @@ -1306,28 +1313,28 @@ "issues": "https://github.com/giggsey/libphonenumber-for-php-lite/issues", "source": "https://github.com/giggsey/libphonenumber-for-php-lite" }, - "time": "2025-11-10T15:55:40+00:00" + "time": "2026-02-23T10:46:07+00:00" }, { "name": "graham-campbell/result-type", - "version": "v1.1.3", + "version": "v1.1.4", "source": { "type": "git", "url": "https://github.com/GrahamCampbell/Result-Type.git", - "reference": "3ba905c11371512af9d9bdd27d99b782216b6945" + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945", - "reference": "3ba905c11371512af9d9bdd27d99b782216b6945", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/e01f4a821471308ba86aa202fed6698b6b695e3b", + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.3" + "phpoption/phpoption": "^1.9.5" }, "require-dev": { - "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + "phpunit/phpunit": "^8.5.41 || ^9.6.22 || ^10.5.45 || ^11.5.7" }, "type": "library", "autoload": { @@ -1356,7 +1363,7 @@ ], "support": { "issues": "https://github.com/GrahamCampbell/Result-Type/issues", - "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3" + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.4" }, "funding": [ { @@ -1368,7 +1375,7 @@ "type": "tidelift" } ], - "time": "2024-07-20T21:45:45+00:00" + "time": "2025-12-27T19:43:20+00:00" }, { "name": "guzzlehttp/guzzle", @@ -1783,16 +1790,16 @@ }, { "name": "laravel/framework", - "version": "v11.46.1", + "version": "v11.48.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "5fd457f807570a962a53b403b1346efe4cc80bb8" + "reference": "5b23ab29087dbcb13077e5c049c431ec4b82f236" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/5fd457f807570a962a53b403b1346efe4cc80bb8", - "reference": "5fd457f807570a962a53b403b1346efe4cc80bb8", + "url": "https://api.github.com/repos/laravel/framework/zipball/5b23ab29087dbcb13077e5c049c431ec4b82f236", + "reference": "5b23ab29087dbcb13077e5c049c431ec4b82f236", "shasum": "" }, "require": { @@ -1994,36 +2001,36 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2025-09-30T14:51:32+00:00" + "time": "2026-01-20T15:26:20+00:00" }, { "name": "laravel/prompts", - "version": "v0.3.7", + "version": "v0.3.13", "source": { "type": "git", "url": "https://github.com/laravel/prompts.git", - "reference": "a1891d362714bc40c8d23b0b1d7090f022ea27cc" + "reference": "ed8c466571b37e977532fb2fd3c272c784d7050d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/prompts/zipball/a1891d362714bc40c8d23b0b1d7090f022ea27cc", - "reference": "a1891d362714bc40c8d23b0b1d7090f022ea27cc", + "url": "https://api.github.com/repos/laravel/prompts/zipball/ed8c466571b37e977532fb2fd3c272c784d7050d", + "reference": "ed8c466571b37e977532fb2fd3c272c784d7050d", "shasum": "" }, "require": { "composer-runtime-api": "^2.2", "ext-mbstring": "*", "php": "^8.1", - "symfony/console": "^6.2|^7.0" + "symfony/console": "^6.2|^7.0|^8.0" }, "conflict": { "illuminate/console": ">=10.17.0 <10.25.0", "laravel/framework": ">=10.17.0 <10.25.0" }, "require-dev": { - "illuminate/collections": "^10.0|^11.0|^12.0", + "illuminate/collections": "^10.0|^11.0|^12.0|^13.0", "mockery/mockery": "^1.5", - "pestphp/pest": "^2.3|^3.4", + "pestphp/pest": "^2.3|^3.4|^4.0", "phpstan/phpstan": "^1.12.28", "phpstan/phpstan-mockery": "^1.1.3" }, @@ -2051,33 +2058,33 @@ "description": "Add beautiful and user-friendly forms to your command-line applications.", "support": { "issues": "https://github.com/laravel/prompts/issues", - "source": "https://github.com/laravel/prompts/tree/v0.3.7" + "source": "https://github.com/laravel/prompts/tree/v0.3.13" }, - "time": "2025-09-19T13:47:56+00:00" + "time": "2026-02-06T12:17:10+00:00" }, { "name": "laravel/serializable-closure", - "version": "v2.0.6", + "version": "v2.0.9", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "038ce42edee619599a1debb7e81d7b3759492819" + "reference": "8f631589ab07b7b52fead814965f5a800459cb3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/038ce42edee619599a1debb7e81d7b3759492819", - "reference": "038ce42edee619599a1debb7e81d7b3759492819", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/8f631589ab07b7b52fead814965f5a800459cb3e", + "reference": "8f631589ab07b7b52fead814965f5a800459cb3e", "shasum": "" }, "require": { "php": "^8.1" }, "require-dev": { - "illuminate/support": "^10.0|^11.0|^12.0", + "illuminate/support": "^10.0|^11.0|^12.0|^13.0", "nesbot/carbon": "^2.67|^3.0", - "pestphp/pest": "^2.36|^3.0", + "pestphp/pest": "^2.36|^3.0|^4.0", "phpstan/phpstan": "^2.0", - "symfony/var-dumper": "^6.2.0|^7.0.0" + "symfony/var-dumper": "^6.2.0|^7.0.0|^8.0.0" }, "type": "library", "extra": { @@ -2114,20 +2121,20 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2025-10-09T13:42:30+00:00" + "time": "2026-02-03T06:55:34+00:00" }, { "name": "laravel/tinker", - "version": "v2.10.1", + "version": "v2.11.1", "source": { "type": "git", "url": "https://github.com/laravel/tinker.git", - "reference": "22177cc71807d38f2810c6204d8f7183d88a57d3" + "reference": "c9f80cc835649b5c1842898fb043f8cc098dd741" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/tinker/zipball/22177cc71807d38f2810c6204d8f7183d88a57d3", - "reference": "22177cc71807d38f2810c6204d8f7183d88a57d3", + "url": "https://api.github.com/repos/laravel/tinker/zipball/c9f80cc835649b5c1842898fb043f8cc098dd741", + "reference": "c9f80cc835649b5c1842898fb043f8cc098dd741", "shasum": "" }, "require": { @@ -2136,7 +2143,7 @@ "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", "php": "^7.2.5|^8.0", "psy/psysh": "^0.11.1|^0.12.0", - "symfony/var-dumper": "^4.3.4|^5.0|^6.0|^7.0" + "symfony/var-dumper": "^4.3.4|^5.0|^6.0|^7.0|^8.0" }, "require-dev": { "mockery/mockery": "~1.3.3|^1.4.2", @@ -2178,9 +2185,9 @@ ], "support": { "issues": "https://github.com/laravel/tinker/issues", - "source": "https://github.com/laravel/tinker/tree/v2.10.1" + "source": "https://github.com/laravel/tinker/tree/v2.11.1" }, - "time": "2025-01-27T14:24:01+00:00" + "time": "2026-02-06T14:12:35+00:00" }, { "name": "lcobucci/clock", @@ -2322,16 +2329,16 @@ }, { "name": "league/commonmark", - "version": "2.7.1", + "version": "2.8.0", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "10732241927d3971d28e7ea7b5712721fa2296ca" + "reference": "4efa10c1e56488e658d10adf7b7b7dcd19940bfb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/10732241927d3971d28e7ea7b5712721fa2296ca", - "reference": "10732241927d3971d28e7ea7b5712721fa2296ca", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/4efa10c1e56488e658d10adf7b7b7dcd19940bfb", + "reference": "4efa10c1e56488e658d10adf7b7b7dcd19940bfb", "shasum": "" }, "require": { @@ -2368,7 +2375,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.8-dev" + "dev-main": "2.9-dev" } }, "autoload": { @@ -2425,7 +2432,7 @@ "type": "tidelift" } ], - "time": "2025-07-20T12:47:49+00:00" + "time": "2025-11-26T21:48:24+00:00" }, { "name": "league/config", @@ -2511,16 +2518,16 @@ }, { "name": "league/flysystem", - "version": "3.30.2", + "version": "3.31.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "5966a8ba23e62bdb518dd9e0e665c2dbd4b5b277" + "reference": "1717e0b3642b0df65ecb0cc89cdd99fa840672ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/5966a8ba23e62bdb518dd9e0e665c2dbd4b5b277", - "reference": "5966a8ba23e62bdb518dd9e0e665c2dbd4b5b277", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/1717e0b3642b0df65ecb0cc89cdd99fa840672ff", + "reference": "1717e0b3642b0df65ecb0cc89cdd99fa840672ff", "shasum": "" }, "require": { @@ -2588,22 +2595,22 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/3.30.2" + "source": "https://github.com/thephpleague/flysystem/tree/3.31.0" }, - "time": "2025-11-10T17:13:11+00:00" + "time": "2026-01-23T15:38:47+00:00" }, { "name": "league/flysystem-local", - "version": "3.30.2", + "version": "3.31.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem-local.git", - "reference": "ab4f9d0d672f601b102936aa728801dd1a11968d" + "reference": "2f669db18a4c20c755c2bb7d3a7b0b2340488079" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/ab4f9d0d672f601b102936aa728801dd1a11968d", - "reference": "ab4f9d0d672f601b102936aa728801dd1a11968d", + "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/2f669db18a4c20c755c2bb7d3a7b0b2340488079", + "reference": "2f669db18a4c20c755c2bb7d3a7b0b2340488079", "shasum": "" }, "require": { @@ -2637,9 +2644,9 @@ "local" ], "support": { - "source": "https://github.com/thephpleague/flysystem-local/tree/3.30.2" + "source": "https://github.com/thephpleague/flysystem-local/tree/3.31.0" }, - "time": "2025-11-10T11:23:37+00:00" + "time": "2026-01-23T15:30:45+00:00" }, { "name": "league/mime-type-detection", @@ -2699,22 +2706,22 @@ }, { "name": "league/oauth2-client", - "version": "2.8.1", + "version": "2.9.0", "source": { "type": "git", "url": "https://github.com/thephpleague/oauth2-client.git", - "reference": "9df2924ca644736c835fc60466a3a60390d334f9" + "reference": "26e8c5da4f3d78cede7021e09b1330a0fc093d5e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/oauth2-client/zipball/9df2924ca644736c835fc60466a3a60390d334f9", - "reference": "9df2924ca644736c835fc60466a3a60390d334f9", + "url": "https://api.github.com/repos/thephpleague/oauth2-client/zipball/26e8c5da4f3d78cede7021e09b1330a0fc093d5e", + "reference": "26e8c5da4f3d78cede7021e09b1330a0fc093d5e", "shasum": "" }, "require": { "ext-json": "*", "guzzlehttp/guzzle": "^6.5.8 || ^7.4.5", - "php": "^7.1 || >=8.0.0 <8.5.0" + "php": "^7.1 || >=8.0.0 <8.6.0" }, "require-dev": { "mockery/mockery": "^1.3.5", @@ -2758,39 +2765,44 @@ ], "support": { "issues": "https://github.com/thephpleague/oauth2-client/issues", - "source": "https://github.com/thephpleague/oauth2-client/tree/2.8.1" + "source": "https://github.com/thephpleague/oauth2-client/tree/2.9.0" }, - "time": "2025-02-26T04:37:30+00:00" + "time": "2025-11-25T22:17:17+00:00" }, { "name": "league/uri", - "version": "7.5.1", + "version": "7.8.0", "source": { "type": "git", "url": "https://github.com/thephpleague/uri.git", - "reference": "81fb5145d2644324614cc532b28efd0215bda430" + "reference": "4436c6ec8d458e4244448b069cc572d088230b76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430", - "reference": "81fb5145d2644324614cc532b28efd0215bda430", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/4436c6ec8d458e4244448b069cc572d088230b76", + "reference": "4436c6ec8d458e4244448b069cc572d088230b76", "shasum": "" }, "require": { - "league/uri-interfaces": "^7.5", - "php": "^8.1" + "league/uri-interfaces": "^7.8", + "php": "^8.1", + "psr/http-factory": "^1" }, "conflict": { "league/uri-schemes": "^1.0" }, "suggest": { "ext-bcmath": "to improve IPV4 host parsing", + "ext-dom": "to convert the URI into an HTML anchor tag", "ext-fileinfo": "to create Data URI from file contennts", "ext-gmp": "to improve IPV4 host parsing", "ext-intl": "to handle IDN host with the best performance", - "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", - "league/uri-components": "Needed to easily manipulate URI objects components", + "ext-uri": "to use the PHP native URI class", + "jeremykendall/php-domain-parser": "to further parse the URI host and resolve its Public Suffix and Top Level Domain", + "league/uri-components": "to provide additional tools to manipulate URI objects components", + "league/uri-polyfill": "to backport the PHP URI extension for older versions of PHP", "php-64bit": "to improve IPV4 host parsing", + "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification", "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" }, "type": "library", @@ -2818,6 +2830,7 @@ "description": "URI manipulation library", "homepage": "https://uri.thephpleague.com", "keywords": [ + "URN", "data-uri", "file-uri", "ftp", @@ -2830,9 +2843,11 @@ "psr-7", "query-string", "querystring", + "rfc2141", "rfc3986", "rfc3987", "rfc6570", + "rfc8141", "uri", "uri-template", "url", @@ -2842,7 +2857,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri/tree/7.5.1" + "source": "https://github.com/thephpleague/uri/tree/7.8.0" }, "funding": [ { @@ -2850,26 +2865,25 @@ "type": "github" } ], - "time": "2024-12-08T08:40:02+00:00" + "time": "2026-01-14T17:24:56+00:00" }, { "name": "league/uri-interfaces", - "version": "7.5.0", + "version": "7.8.0", "source": { "type": "git", "url": "https://github.com/thephpleague/uri-interfaces.git", - "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742" + "reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", - "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/c5c5cd056110fc8afaba29fa6b72a43ced42acd4", + "reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4", "shasum": "" }, "require": { "ext-filter": "*", "php": "^8.1", - "psr/http-factory": "^1", "psr/http-message": "^1.1 || ^2.0" }, "suggest": { @@ -2877,6 +2891,7 @@ "ext-gmp": "to improve IPV4 host parsing", "ext-intl": "to handle IDN host with the best performance", "php-64bit": "to improve IPV4 host parsing", + "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification", "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" }, "type": "library", @@ -2901,7 +2916,7 @@ "homepage": "https://nyamsprod.com" } ], - "description": "Common interfaces and classes for URI representation and interaction", + "description": "Common tools for parsing and resolving RFC3987/RFC3986 URI", "homepage": "https://uri.thephpleague.com", "keywords": [ "data-uri", @@ -2926,7 +2941,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri-interfaces/tree/7.5.0" + "source": "https://github.com/thephpleague/uri-interfaces/tree/7.8.0" }, "funding": [ { @@ -2934,20 +2949,20 @@ "type": "github" } ], - "time": "2024-12-08T08:18:47+00:00" + "time": "2026-01-15T06:54:53+00:00" }, { "name": "monolog/monolog", - "version": "3.9.0", + "version": "3.10.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6" + "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/10d85740180ecba7896c87e06a166e0c95a0e3b6", - "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/b321dd6749f0bf7189444158a3ce785cc16d69b0", + "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0", "shasum": "" }, "require": { @@ -2965,7 +2980,7 @@ "graylog2/gelf-php": "^1.4.2 || ^2.0", "guzzlehttp/guzzle": "^7.4.5", "guzzlehttp/psr7": "^2.2", - "mongodb/mongodb": "^1.8", + "mongodb/mongodb": "^1.8 || ^2.0", "php-amqplib/php-amqplib": "~2.4 || ^3", "php-console/php-console": "^3.1.8", "phpstan/phpstan": "^2", @@ -3025,7 +3040,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/3.9.0" + "source": "https://github.com/Seldaek/monolog/tree/3.10.0" }, "funding": [ { @@ -3037,7 +3052,7 @@ "type": "tidelift" } ], - "time": "2025-03-24T10:02:05+00:00" + "time": "2026-01-02T08:56:05+00:00" }, { "name": "myclabs/deep-copy", @@ -3162,16 +3177,16 @@ }, { "name": "nesbot/carbon", - "version": "3.10.3", + "version": "3.11.1", "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f" + "reference": "f438fcc98f92babee98381d399c65336f3a3827f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f", - "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/f438fcc98f92babee98381d399c65336f3a3827f", + "reference": "f438fcc98f92babee98381d399c65336f3a3827f", "shasum": "" }, "require": { @@ -3179,9 +3194,9 @@ "ext-json": "*", "php": "^8.1", "psr/clock": "^1.0", - "symfony/clock": "^6.3.12 || ^7.0", + "symfony/clock": "^6.3.12 || ^7.0 || ^8.0", "symfony/polyfill-mbstring": "^1.0", - "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0" + "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0 || ^8.0" }, "provide": { "psr/clock-implementation": "1.0" @@ -3195,7 +3210,7 @@ "phpstan/extension-installer": "^1.4.3", "phpstan/phpstan": "^2.1.22", "phpunit/phpunit": "^10.5.53", - "squizlabs/php_codesniffer": "^3.13.4" + "squizlabs/php_codesniffer": "^3.13.4 || ^4.0.0" }, "bin": [ "bin/carbon" @@ -3238,14 +3253,14 @@ } ], "description": "An API extension for DateTime that supports 281 different languages.", - "homepage": "https://carbon.nesbot.com", + "homepage": "https://carbonphp.github.io/carbon/", "keywords": [ "date", "datetime", "time" ], "support": { - "docs": "https://carbon.nesbot.com/docs", + "docs": "https://carbonphp.github.io/carbon/guide/getting-started/introduction.html", "issues": "https://github.com/CarbonPHP/carbon/issues", "source": "https://github.com/CarbonPHP/carbon" }, @@ -3263,20 +3278,20 @@ "type": "tidelift" } ], - "time": "2025-09-06T13:39:36+00:00" + "time": "2026-01-29T09:26:29+00:00" }, { "name": "nette/schema", - "version": "v1.3.3", + "version": "v1.3.5", "source": { "type": "git", "url": "https://github.com/nette/schema.git", - "reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004" + "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/schema/zipball/2befc2f42d7c715fd9d95efc31b1081e5d765004", - "reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004", + "url": "https://api.github.com/repos/nette/schema/zipball/f0ab1a3cda782dbc5da270d28545236aa80c4002", + "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002", "shasum": "" }, "require": { @@ -3284,8 +3299,10 @@ "php": "8.1 - 8.5" }, "require-dev": { - "nette/tester": "^2.5.2", - "phpstan/phpstan-nette": "^2.0@stable", + "nette/phpstan-rules": "^1.0", + "nette/tester": "^2.6", + "phpstan/extension-installer": "^1.4@stable", + "phpstan/phpstan": "^2.1.39@stable", "tracy/tracy": "^2.8" }, "type": "library", @@ -3326,26 +3343,26 @@ ], "support": { "issues": "https://github.com/nette/schema/issues", - "source": "https://github.com/nette/schema/tree/v1.3.3" + "source": "https://github.com/nette/schema/tree/v1.3.5" }, - "time": "2025-10-30T22:57:59+00:00" + "time": "2026-02-23T03:47:12+00:00" }, { "name": "nette/utils", - "version": "v4.0.8", + "version": "v4.1.3", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede" + "reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/c930ca4e3cf4f17dcfb03037703679d2396d2ede", - "reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede", + "url": "https://api.github.com/repos/nette/utils/zipball/bb3ea637e3d131d72acc033cfc2746ee893349fe", + "reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe", "shasum": "" }, "require": { - "php": "8.0 - 8.5" + "php": "8.2 - 8.5" }, "conflict": { "nette/finder": "<3", @@ -3353,8 +3370,10 @@ }, "require-dev": { "jetbrains/phpstorm-attributes": "^1.2", + "nette/phpstan-rules": "^1.0", "nette/tester": "^2.5", - "phpstan/phpstan-nette": "^2.0@stable", + "phpstan/extension-installer": "^1.4@stable", + "phpstan/phpstan": "^2.1@stable", "tracy/tracy": "^2.9" }, "suggest": { @@ -3368,7 +3387,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "4.1-dev" } }, "autoload": { @@ -3415,22 +3434,22 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.0.8" + "source": "https://github.com/nette/utils/tree/v4.1.3" }, - "time": "2025-08-06T21:43:34+00:00" + "time": "2026-02-13T03:05:33+00:00" }, { "name": "nikic/php-parser", - "version": "v5.6.2", + "version": "v5.7.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "3a454ca033b9e06b63282ce19562e892747449bb" + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb", - "reference": "3a454ca033b9e06b63282ce19562e892747449bb", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", "shasum": "" }, "require": { @@ -3473,37 +3492,37 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" }, - "time": "2025-10-21T19:32:17+00:00" + "time": "2025-12-06T11:56:16+00:00" }, { "name": "nunomaduro/termwind", - "version": "v2.3.2", + "version": "v2.4.0", "source": { "type": "git", "url": "https://github.com/nunomaduro/termwind.git", - "reference": "eb61920a53057a7debd718a5b89c2178032b52c0" + "reference": "712a31b768f5daea284c2169a7d227031001b9a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/eb61920a53057a7debd718a5b89c2178032b52c0", - "reference": "eb61920a53057a7debd718a5b89c2178032b52c0", + "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/712a31b768f5daea284c2169a7d227031001b9a8", + "reference": "712a31b768f5daea284c2169a7d227031001b9a8", "shasum": "" }, "require": { "ext-mbstring": "*", "php": "^8.2", - "symfony/console": "^7.3.4" + "symfony/console": "^7.4.4 || ^8.0.4" }, "require-dev": { - "illuminate/console": "^11.46.1", - "laravel/pint": "^1.25.1", + "illuminate/console": "^11.47.0", + "laravel/pint": "^1.27.1", "mockery/mockery": "^1.6.12", - "pestphp/pest": "^2.36.0 || ^3.8.4", + "pestphp/pest": "^2.36.0 || ^3.8.4 || ^4.3.2", "phpstan/phpstan": "^1.12.32", "phpstan/phpstan-strict-rules": "^1.6.2", - "symfony/var-dumper": "^7.3.4", + "symfony/var-dumper": "^7.3.5 || ^8.0.4", "thecodingmachine/phpstan-strict-rules": "^1.0.0" }, "type": "library", @@ -3535,7 +3554,7 @@ "email": "enunomaduro@gmail.com" } ], - "description": "Its like Tailwind CSS, but for the console.", + "description": "It's like Tailwind CSS, but for the console.", "keywords": [ "cli", "console", @@ -3546,7 +3565,7 @@ ], "support": { "issues": "https://github.com/nunomaduro/termwind/issues", - "source": "https://github.com/nunomaduro/termwind/tree/v2.3.2" + "source": "https://github.com/nunomaduro/termwind/tree/v2.4.0" }, "funding": [ { @@ -3562,7 +3581,7 @@ "type": "github" } ], - "time": "2025-10-18T11:10:27+00:00" + "time": "2026-02-16T23:10:27+00:00" }, { "name": "ovh/ovh", @@ -3797,16 +3816,16 @@ }, { "name": "phpoption/phpoption", - "version": "1.9.4", + "version": "1.9.5", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d" + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d", - "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/75365b91986c2405cf5e1e012c5595cd487a98be", + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be", "shasum": "" }, "require": { @@ -3856,7 +3875,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.4" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.5" }, "funding": [ { @@ -3868,7 +3887,7 @@ "type": "tidelift" } ], - "time": "2025-08-21T11:53:16+00:00" + "time": "2025-12-27T19:41:33+00:00" }, { "name": "phpunit/php-code-coverage", @@ -4193,16 +4212,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.58", + "version": "10.5.63", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "e24fb46da450d8e6a5788670513c1af1424f16ca" + "reference": "33198268dad71e926626b618f3ec3966661e4d90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e24fb46da450d8e6a5788670513c1af1424f16ca", - "reference": "e24fb46da450d8e6a5788670513c1af1424f16ca", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/33198268dad71e926626b618f3ec3966661e4d90", + "reference": "33198268dad71e926626b618f3ec3966661e4d90", "shasum": "" }, "require": { @@ -4223,7 +4242,7 @@ "phpunit/php-timer": "^6.0.0", "sebastian/cli-parser": "^2.0.1", "sebastian/code-unit": "^2.0.0", - "sebastian/comparator": "^5.0.4", + "sebastian/comparator": "^5.0.5", "sebastian/diff": "^5.1.1", "sebastian/environment": "^6.1.0", "sebastian/exporter": "^5.1.4", @@ -4274,7 +4293,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.58" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.63" }, "funding": [ { @@ -4298,7 +4317,7 @@ "type": "tidelift" } ], - "time": "2025-09-28T12:04:46+00:00" + "time": "2026-01-27T05:48:37+00:00" }, { "name": "propaganistas/laravel-phone", @@ -4834,16 +4853,16 @@ }, { "name": "psy/psysh", - "version": "v0.12.14", + "version": "v0.12.20", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "95c29b3756a23855a30566b745d218bee690bef2" + "reference": "19678eb6b952a03b8a1d96ecee9edba518bb0373" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/95c29b3756a23855a30566b745d218bee690bef2", - "reference": "95c29b3756a23855a30566b745d218bee690bef2", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/19678eb6b952a03b8a1d96ecee9edba518bb0373", + "reference": "19678eb6b952a03b8a1d96ecee9edba518bb0373", "shasum": "" }, "require": { @@ -4851,8 +4870,8 @@ "ext-tokenizer": "*", "nikic/php-parser": "^5.0 || ^4.0", "php": "^8.0 || ^7.4", - "symfony/console": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4", - "symfony/var-dumper": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4" + "symfony/console": "^8.0 || ^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4", + "symfony/var-dumper": "^8.0 || ^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4" }, "conflict": { "symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4" @@ -4907,9 +4926,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.12.14" + "source": "https://github.com/bobthecow/psysh/tree/v0.12.20" }, - "time": "2025-10-27T17:15:31+00:00" + "time": "2026-02-11T15:05:28+00:00" }, { "name": "ralouphie/getallheaders", @@ -5033,20 +5052,20 @@ }, { "name": "ramsey/uuid", - "version": "4.9.1", + "version": "4.9.2", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "81f941f6f729b1e3ceea61d9d014f8b6c6800440" + "reference": "8429c78ca35a09f27565311b98101e2826affde0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/81f941f6f729b1e3ceea61d9d014f8b6c6800440", - "reference": "81f941f6f729b1e3ceea61d9d014f8b6c6800440", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/8429c78ca35a09f27565311b98101e2826affde0", + "reference": "8429c78ca35a09f27565311b98101e2826affde0", "shasum": "" }, "require": { - "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14", + "brick/math": "^0.8.16 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14", "php": "^8.0", "ramsey/collection": "^1.2 || ^2.0" }, @@ -5105,9 +5124,9 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "source": "https://github.com/ramsey/uuid/tree/4.9.1" + "source": "https://github.com/ramsey/uuid/tree/4.9.2" }, - "time": "2025-09-04T20:59:21+00:00" + "time": "2025-12-14T04:43:48+00:00" }, { "name": "react/cache", @@ -5183,16 +5202,16 @@ }, { "name": "react/dns", - "version": "v1.13.0", + "version": "v1.14.0", "source": { "type": "git", "url": "https://github.com/reactphp/dns.git", - "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5" + "reference": "7562c05391f42701c1fccf189c8225fece1cd7c3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/dns/zipball/eb8ae001b5a455665c89c1df97f6fb682f8fb0f5", - "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5", + "url": "https://api.github.com/repos/reactphp/dns/zipball/7562c05391f42701c1fccf189c8225fece1cd7c3", + "reference": "7562c05391f42701c1fccf189c8225fece1cd7c3", "shasum": "" }, "require": { @@ -5247,7 +5266,7 @@ ], "support": { "issues": "https://github.com/reactphp/dns/issues", - "source": "https://github.com/reactphp/dns/tree/v1.13.0" + "source": "https://github.com/reactphp/dns/tree/v1.14.0" }, "funding": [ { @@ -5255,20 +5274,20 @@ "type": "open_collective" } ], - "time": "2024-06-13T14:18:03+00:00" + "time": "2025-11-18T19:34:28+00:00" }, { "name": "react/event-loop", - "version": "v1.5.0", + "version": "v1.6.0", "source": { "type": "git", "url": "https://github.com/reactphp/event-loop.git", - "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354" + "reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/event-loop/zipball/bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", - "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", + "url": "https://api.github.com/repos/reactphp/event-loop/zipball/ba276bda6083df7e0050fd9b33f66ad7a4ac747a", + "reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a", "shasum": "" }, "require": { @@ -5319,7 +5338,7 @@ ], "support": { "issues": "https://github.com/reactphp/event-loop/issues", - "source": "https://github.com/reactphp/event-loop/tree/v1.5.0" + "source": "https://github.com/reactphp/event-loop/tree/v1.6.0" }, "funding": [ { @@ -5327,7 +5346,7 @@ "type": "open_collective" } ], - "time": "2023-11-13T13:48:05+00:00" + "time": "2025-11-17T20:46:25+00:00" }, { "name": "react/promise", @@ -5404,16 +5423,16 @@ }, { "name": "react/socket", - "version": "v1.16.0", + "version": "v1.17.0", "source": { "type": "git", "url": "https://github.com/reactphp/socket.git", - "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1" + "reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/socket/zipball/23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1", - "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1", + "url": "https://api.github.com/repos/reactphp/socket/zipball/ef5b17b81f6f60504c539313f94f2d826c5faa08", + "reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08", "shasum": "" }, "require": { @@ -5472,7 +5491,7 @@ ], "support": { "issues": "https://github.com/reactphp/socket/issues", - "source": "https://github.com/reactphp/socket/tree/v1.16.0" + "source": "https://github.com/reactphp/socket/tree/v1.17.0" }, "funding": [ { @@ -5480,7 +5499,7 @@ "type": "open_collective" } ], - "time": "2024-07-26T10:38:09+00:00" + "time": "2025-11-19T20:47:34+00:00" }, { "name": "react/stream", @@ -5562,25 +5581,30 @@ }, { "name": "respect/stringifier", - "version": "0.2.0", + "version": "1.0.0", "source": { "type": "git", "url": "https://github.com/Respect/Stringifier.git", - "reference": "e55af3c8aeaeaa2abb5fa47a58a8e9688cc23b59" + "reference": "e88515f675b373596d5dcdd9dc6103b8504c7ca5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Respect/Stringifier/zipball/e55af3c8aeaeaa2abb5fa47a58a8e9688cc23b59", - "reference": "e55af3c8aeaeaa2abb5fa47a58a8e9688cc23b59", + "url": "https://api.github.com/repos/Respect/Stringifier/zipball/e88515f675b373596d5dcdd9dc6103b8504c7ca5", + "reference": "e88515f675b373596d5dcdd9dc6103b8504c7ca5", "shasum": "" }, "require": { - "php": ">=7.1" + "php": "^8.1" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.8", "malukenho/docheader": "^0.1.7", - "phpunit/phpunit": "^6.4" + "phpstan/phpstan": "^1.10", + "phpstan/phpstan-deprecation-rules": "^1.1", + "phpstan/phpstan-phpunit": "^1.3", + "phpstan/phpstan-strict-rules": "^1.5", + "phpunit/phpunit": "^10.0", + "respect/coding-standard": "^4.0", + "squizlabs/php_codesniffer": "^3.7" }, "type": "library", "autoload": { @@ -5588,7 +5612,9 @@ "src/stringify.php" ], "psr-4": { - "Respect\\Stringifier\\": "src/" + "Respect\\Stringifier\\": "src/", + "Respect\\Stringifier\\Test\\": "tests/src/", + "Respect\\Stringifier\\Test\\Unit\\": "tests/unit" } }, "notification-url": "https://packagist.org/downloads/", @@ -5602,7 +5628,6 @@ } ], "description": "Converts any value to a string", - "homepage": "http://respect.github.io/Stringifier/", "keywords": [ "respect", "stringifier", @@ -5610,31 +5635,31 @@ ], "support": { "issues": "https://github.com/Respect/Stringifier/issues", - "source": "https://github.com/Respect/Stringifier/tree/0.2.0" + "source": "https://github.com/Respect/Stringifier/tree/1.0.0" }, - "time": "2017-12-29T19:39:25+00:00" + "time": "2023-04-12T20:15:44+00:00" }, { "name": "respect/validation", - "version": "2.4.4", + "version": "2.4.12", "source": { "type": "git", "url": "https://github.com/Respect/Validation.git", - "reference": "f13f10f19978aea33af2a102a2f58f2db1e63619" + "reference": "f05659faef60b303f194f5e8bc580c288c9699bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Respect/Validation/zipball/f13f10f19978aea33af2a102a2f58f2db1e63619", - "reference": "f13f10f19978aea33af2a102a2f58f2db1e63619", + "url": "https://api.github.com/repos/Respect/Validation/zipball/f05659faef60b303f194f5e8bc580c288c9699bf", + "reference": "f05659faef60b303f194f5e8bc580c288c9699bf", "shasum": "" }, "require": { "php": ">=8.1", - "respect/stringifier": "^0.2.0", + "respect/stringifier": "^0.2.0 || ^1.0", "symfony/polyfill-mbstring": "^1.2" }, "require-dev": { - "egulias/email-validator": "^3.0", + "egulias/email-validator": "^3.0 || ^4.0", "giggsey/libphonenumber-for-php-lite": "^8.13 || ^9.0", "malukenho/docheader": "^1.0", "mikey179/vfsstream": "^1.6", @@ -5678,9 +5703,9 @@ ], "support": { "issues": "https://github.com/Respect/Validation/issues", - "source": "https://github.com/Respect/Validation/tree/2.4.4" + "source": "https://github.com/Respect/Validation/tree/2.4.12" }, - "time": "2025-06-07T00:07:21+00:00" + "time": "2026-02-08T00:13:50+00:00" }, { "name": "rvxlab/hcaptcha", @@ -5820,16 +5845,16 @@ }, { "name": "sabre/vobject", - "version": "4.5.7", + "version": "4.5.8", "source": { "type": "git", "url": "https://github.com/sabre-io/vobject.git", - "reference": "ff22611a53782e90c97be0d0bc4a5f98a5c0a12c" + "reference": "d554eb24d64232922e1eab5896cc2f84b3b9ffb1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sabre-io/vobject/zipball/ff22611a53782e90c97be0d0bc4a5f98a5c0a12c", - "reference": "ff22611a53782e90c97be0d0bc4a5f98a5c0a12c", + "url": "https://api.github.com/repos/sabre-io/vobject/zipball/d554eb24d64232922e1eab5896cc2f84b3b9ffb1", + "reference": "d554eb24d64232922e1eab5896cc2f84b3b9ffb1", "shasum": "" }, "require": { @@ -5920,7 +5945,7 @@ "issues": "https://github.com/sabre-io/vobject/issues", "source": "https://github.com/fruux/sabre-vobject" }, - "time": "2025-04-17T09:22:48+00:00" + "time": "2026-01-12T10:45:19+00:00" }, { "name": "sabre/xml", @@ -6161,16 +6186,16 @@ }, { "name": "sebastian/comparator", - "version": "5.0.4", + "version": "5.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "e8e53097718d2b53cfb2aa859b06a41abf58c62e" + "reference": "55dfef806eb7dfeb6e7a6935601fef866f8ca48d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/e8e53097718d2b53cfb2aa859b06a41abf58c62e", - "reference": "e8e53097718d2b53cfb2aa859b06a41abf58c62e", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55dfef806eb7dfeb6e7a6935601fef866f8ca48d", + "reference": "55dfef806eb7dfeb6e7a6935601fef866f8ca48d", "shasum": "" }, "require": { @@ -6226,7 +6251,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.4" + "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.5" }, "funding": [ { @@ -6246,7 +6271,7 @@ "type": "tidelift" } ], - "time": "2025-09-07T05:25:07+00:00" + "time": "2026-01-24T09:25:16+00:00" }, { "name": "sebastian/complexity", @@ -6946,16 +6971,16 @@ }, { "name": "symfony/clock", - "version": "v7.3.0", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/clock.git", - "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24" + "reference": "9169f24776edde469914c1e7a1442a50f7a4e110" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", - "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", + "url": "https://api.github.com/repos/symfony/clock/zipball/9169f24776edde469914c1e7a1442a50f7a4e110", + "reference": "9169f24776edde469914c1e7a1442a50f7a4e110", "shasum": "" }, "require": { @@ -7000,7 +7025,7 @@ "time" ], "support": { - "source": "https://github.com/symfony/clock/tree/v7.3.0" + "source": "https://github.com/symfony/clock/tree/v7.4.0" }, "funding": [ { @@ -7011,25 +7036,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2025-11-12T15:39:26+00:00" }, { "name": "symfony/console", - "version": "v7.3.6", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a" + "reference": "41e38717ac1dd7a46b6bda7d6a82af2d98a78894" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/c28ad91448f86c5f6d9d2c70f0cf68bf135f252a", - "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a", + "url": "https://api.github.com/repos/symfony/console/zipball/41e38717ac1dd7a46b6bda7d6a82af2d98a78894", + "reference": "41e38717ac1dd7a46b6bda7d6a82af2d98a78894", "shasum": "" }, "require": { @@ -7037,7 +7066,7 @@ "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^7.2" + "symfony/string": "^7.2|^8.0" }, "conflict": { "symfony/dependency-injection": "<6.4", @@ -7051,16 +7080,16 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/lock": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/stopwatch": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/lock": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -7094,7 +7123,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.3.6" + "source": "https://github.com/symfony/console/tree/v7.4.4" }, "funding": [ { @@ -7114,20 +7143,20 @@ "type": "tidelift" } ], - "time": "2025-11-04T01:21:42+00:00" + "time": "2026-01-13T11:36:38+00:00" }, { "name": "symfony/css-selector", - "version": "v7.3.6", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "84321188c4754e64273b46b406081ad9b18e8614" + "reference": "ab862f478513e7ca2fe9ec117a6f01a8da6e1135" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/84321188c4754e64273b46b406081ad9b18e8614", - "reference": "84321188c4754e64273b46b406081ad9b18e8614", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/ab862f478513e7ca2fe9ec117a6f01a8da6e1135", + "reference": "ab862f478513e7ca2fe9ec117a6f01a8da6e1135", "shasum": "" }, "require": { @@ -7163,7 +7192,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v7.3.6" + "source": "https://github.com/symfony/css-selector/tree/v7.4.0" }, "funding": [ { @@ -7183,7 +7212,7 @@ "type": "tidelift" } ], - "time": "2025-10-29T17:24:25+00:00" + "time": "2025-10-30T13:39:42+00:00" }, { "name": "symfony/deprecation-contracts", @@ -7254,32 +7283,33 @@ }, { "name": "symfony/error-handler", - "version": "v7.3.6", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "bbe40bfab84323d99dab491b716ff142410a92a8" + "reference": "8da531f364ddfee53e36092a7eebbbd0b775f6b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/bbe40bfab84323d99dab491b716ff142410a92a8", - "reference": "bbe40bfab84323d99dab491b716ff142410a92a8", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/8da531f364ddfee53e36092a7eebbbd0b775f6b8", + "reference": "8da531f364ddfee53e36092a7eebbbd0b775f6b8", "shasum": "" }, "require": { "php": ">=8.2", "psr/log": "^1|^2|^3", - "symfony/var-dumper": "^6.4|^7.0" + "symfony/polyfill-php85": "^1.32", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "conflict": { "symfony/deprecation-contracts": "<2.5", "symfony/http-kernel": "<6.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0|^8.0", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4|^7.0|^8.0", "symfony/webpack-encore-bundle": "^1.0|^2.0" }, "bin": [ @@ -7311,7 +7341,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v7.3.6" + "source": "https://github.com/symfony/error-handler/tree/v7.4.4" }, "funding": [ { @@ -7331,20 +7361,20 @@ "type": "tidelift" } ], - "time": "2025-10-31T19:12:50+00:00" + "time": "2026-01-20T16:42:42+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v7.3.3", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191" + "reference": "dc2c0eba1af673e736bb851d747d266108aea746" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b7dc69e71de420ac04bc9ab830cf3ffebba48191", - "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/dc2c0eba1af673e736bb851d747d266108aea746", + "reference": "dc2c0eba1af673e736bb851d747d266108aea746", "shasum": "" }, "require": { @@ -7361,13 +7391,14 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/error-handler": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/framework-bundle": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^6.4|^7.0" + "symfony/stopwatch": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -7395,7 +7426,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.3" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.4.4" }, "funding": [ { @@ -7415,7 +7446,7 @@ "type": "tidelift" } ], - "time": "2025-08-13T11:49:31+00:00" + "time": "2026-01-05T11:45:34+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -7495,23 +7526,23 @@ }, { "name": "symfony/finder", - "version": "v7.3.5", + "version": "v7.4.5", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "9f696d2f1e340484b4683f7853b273abff94421f" + "reference": "ad4daa7c38668dcb031e63bc99ea9bd42196a2cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/9f696d2f1e340484b4683f7853b273abff94421f", - "reference": "9f696d2f1e340484b4683f7853b273abff94421f", + "url": "https://api.github.com/repos/symfony/finder/zipball/ad4daa7c38668dcb031e63bc99ea9bd42196a2cb", + "reference": "ad4daa7c38668dcb031e63bc99ea9bd42196a2cb", "shasum": "" }, "require": { "php": ">=8.2" }, "require-dev": { - "symfony/filesystem": "^6.4|^7.0" + "symfony/filesystem": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -7539,7 +7570,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.3.5" + "source": "https://github.com/symfony/finder/tree/v7.4.5" }, "funding": [ { @@ -7559,27 +7590,26 @@ "type": "tidelift" } ], - "time": "2025-10-15T18:45:57+00:00" + "time": "2026-01-26T15:07:59+00:00" }, { "name": "symfony/http-foundation", - "version": "v7.3.6", + "version": "v7.4.5", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "6379e490d6ecfc5c4224ff3a754b90495ecd135c" + "reference": "446d0db2b1f21575f1284b74533e425096abdfb6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6379e490d6ecfc5c4224ff3a754b90495ecd135c", - "reference": "6379e490d6ecfc5c4224ff3a754b90495ecd135c", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/446d0db2b1f21575f1284b74533e425096abdfb6", + "reference": "446d0db2b1f21575f1284b74533e425096abdfb6", "shasum": "" }, "require": { "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3.0", - "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php83": "^1.27" + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "^1.1" }, "conflict": { "doctrine/dbal": "<3.6", @@ -7588,13 +7618,13 @@ "require-dev": { "doctrine/dbal": "^3.6|^4", "predis/predis": "^1.1|^2.0", - "symfony/cache": "^6.4.12|^7.1.5", - "symfony/clock": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/mime": "^6.4|^7.0", - "symfony/rate-limiter": "^6.4|^7.0" + "symfony/cache": "^6.4.12|^7.1.5|^8.0", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", + "symfony/rate-limiter": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -7622,7 +7652,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.3.6" + "source": "https://github.com/symfony/http-foundation/tree/v7.4.5" }, "funding": [ { @@ -7642,29 +7672,29 @@ "type": "tidelift" } ], - "time": "2025-11-06T11:05:57+00:00" + "time": "2026-01-27T16:16:02+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.3.6", + "version": "v7.4.5", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "f9a34dc0196677250e3609c2fac9de9e1551a262" + "reference": "229eda477017f92bd2ce7615d06222ec0c19e82a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/f9a34dc0196677250e3609c2fac9de9e1551a262", - "reference": "f9a34dc0196677250e3609c2fac9de9e1551a262", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/229eda477017f92bd2ce7615d06222ec0c19e82a", + "reference": "229eda477017f92bd2ce7615d06222ec0c19e82a", "shasum": "" }, "require": { "php": ">=8.2", "psr/log": "^1|^2|^3", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/error-handler": "^6.4|^7.0", - "symfony/event-dispatcher": "^7.3", - "symfony/http-foundation": "^7.3", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^7.3|^8.0", + "symfony/http-foundation": "^7.4|^8.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { @@ -7674,6 +7704,7 @@ "symfony/console": "<6.4", "symfony/dependency-injection": "<6.4", "symfony/doctrine-bridge": "<6.4", + "symfony/flex": "<2.10", "symfony/form": "<6.4", "symfony/http-client": "<6.4", "symfony/http-client-contracts": "<2.5", @@ -7691,27 +7722,27 @@ }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", - "symfony/browser-kit": "^6.4|^7.0", - "symfony/clock": "^6.4|^7.0", - "symfony/config": "^6.4|^7.0", - "symfony/console": "^6.4|^7.0", - "symfony/css-selector": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/dom-crawler": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/finder": "^6.4|^7.0", + "symfony/browser-kit": "^6.4|^7.0|^8.0", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/css-selector": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/dom-crawler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", "symfony/http-client-contracts": "^2.5|^3", - "symfony/process": "^6.4|^7.0", - "symfony/property-access": "^7.1", - "symfony/routing": "^6.4|^7.0", - "symfony/serializer": "^7.1", - "symfony/stopwatch": "^6.4|^7.0", - "symfony/translation": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/property-access": "^7.1|^8.0", + "symfony/routing": "^6.4|^7.0|^8.0", + "symfony/serializer": "^7.1|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4|^7.0|^8.0", "symfony/translation-contracts": "^2.5|^3", - "symfony/uid": "^6.4|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0", - "symfony/var-exporter": "^6.4|^7.0", + "symfony/uid": "^6.4|^7.0|^8.0", + "symfony/validator": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0", + "symfony/var-exporter": "^6.4|^7.0|^8.0", "twig/twig": "^3.12" }, "type": "library", @@ -7740,7 +7771,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v7.3.6" + "source": "https://github.com/symfony/http-kernel/tree/v7.4.5" }, "funding": [ { @@ -7760,20 +7791,20 @@ "type": "tidelift" } ], - "time": "2025-11-06T20:58:12+00:00" + "time": "2026-01-28T10:33:42+00:00" }, { "name": "symfony/mailer", - "version": "v7.3.5", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "fd497c45ba9c10c37864e19466b090dcb60a50ba" + "reference": "7b750074c40c694ceb34cb926d6dffee231c5cd6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/fd497c45ba9c10c37864e19466b090dcb60a50ba", - "reference": "fd497c45ba9c10c37864e19466b090dcb60a50ba", + "url": "https://api.github.com/repos/symfony/mailer/zipball/7b750074c40c694ceb34cb926d6dffee231c5cd6", + "reference": "7b750074c40c694ceb34cb926d6dffee231c5cd6", "shasum": "" }, "require": { @@ -7781,8 +7812,8 @@ "php": ">=8.2", "psr/event-dispatcher": "^1", "psr/log": "^1|^2|^3", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/mime": "^7.2", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/mime": "^7.2|^8.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { @@ -7793,10 +7824,10 @@ "symfony/twig-bridge": "<6.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0", - "symfony/http-client": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/twig-bridge": "^6.4|^7.0" + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/twig-bridge": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -7824,7 +7855,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.3.5" + "source": "https://github.com/symfony/mailer/tree/v7.4.4" }, "funding": [ { @@ -7844,43 +7875,44 @@ "type": "tidelift" } ], - "time": "2025-10-24T14:27:20+00:00" + "time": "2026-01-08T08:25:11+00:00" }, { "name": "symfony/mime", - "version": "v7.3.4", + "version": "v7.4.5", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "b1b828f69cbaf887fa835a091869e55df91d0e35" + "reference": "b18c7e6e9eee1e19958138df10412f3c4c316148" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/b1b828f69cbaf887fa835a091869e55df91d0e35", - "reference": "b1b828f69cbaf887fa835a091869e55df91d0e35", + "url": "https://api.github.com/repos/symfony/mime/zipball/b18c7e6e9eee1e19958138df10412f3c4c316148", + "reference": "b18c7e6e9eee1e19958138df10412f3c4c316148", "shasum": "" }, "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-intl-idn": "^1.10", "symfony/polyfill-mbstring": "^1.0" }, "conflict": { "egulias/email-validator": "~3.0.0", - "phpdocumentor/reflection-docblock": "<3.2.2", - "phpdocumentor/type-resolver": "<1.4.0", + "phpdocumentor/reflection-docblock": "<5.2|>=6", + "phpdocumentor/type-resolver": "<1.5.1", "symfony/mailer": "<6.4", "symfony/serializer": "<6.4.3|>7.0,<7.0.3" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3.1|^4", "league/html-to-markdown": "^5.0", - "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/property-access": "^6.4|^7.0", - "symfony/property-info": "^6.4|^7.0", - "symfony/serializer": "^6.4.3|^7.0.3" + "phpdocumentor/reflection-docblock": "^5.2", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/property-info": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4.3|^7.0.3|^8.0" }, "type": "library", "autoload": { @@ -7912,7 +7944,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.3.4" + "source": "https://github.com/symfony/mime/tree/v7.4.5" }, "funding": [ { @@ -7932,7 +7964,7 @@ "type": "tidelift" } ], - "time": "2025-09-16T08:38:17+00:00" + "time": "2026-01-27T08:59:58+00:00" }, { "name": "symfony/polyfill-ctype", @@ -8520,6 +8552,86 @@ ], "time": "2025-07-08T02:45:35+00:00" }, + { + "name": "symfony/polyfill-php85", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php85.git", + "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", + "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php85\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php85/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-06-23T16:12:55+00:00" + }, { "name": "symfony/polyfill-uuid", "version": "v1.33.0", @@ -8605,16 +8717,16 @@ }, { "name": "symfony/process", - "version": "v7.3.4", + "version": "v7.4.5", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b" + "reference": "608476f4604102976d687c483ac63a79ba18cc97" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/f24f8f316367b30810810d4eb30c543d7003ff3b", - "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b", + "url": "https://api.github.com/repos/symfony/process/zipball/608476f4604102976d687c483ac63a79ba18cc97", + "reference": "608476f4604102976d687c483ac63a79ba18cc97", "shasum": "" }, "require": { @@ -8646,7 +8758,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.3.4" + "source": "https://github.com/symfony/process/tree/v7.4.5" }, "funding": [ { @@ -8666,20 +8778,20 @@ "type": "tidelift" } ], - "time": "2025-09-11T10:12:26+00:00" + "time": "2026-01-26T15:07:59+00:00" }, { "name": "symfony/routing", - "version": "v7.3.6", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "c97abe725f2a1a858deca629a6488c8fc20c3091" + "reference": "0798827fe2c79caeed41d70b680c2c3507d10147" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/c97abe725f2a1a858deca629a6488c8fc20c3091", - "reference": "c97abe725f2a1a858deca629a6488c8fc20c3091", + "url": "https://api.github.com/repos/symfony/routing/zipball/0798827fe2c79caeed41d70b680c2c3507d10147", + "reference": "0798827fe2c79caeed41d70b680c2c3507d10147", "shasum": "" }, "require": { @@ -8693,11 +8805,11 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/yaml": "^6.4|^7.0" + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -8731,7 +8843,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v7.3.6" + "source": "https://github.com/symfony/routing/tree/v7.4.4" }, "funding": [ { @@ -8751,7 +8863,7 @@ "type": "tidelift" } ], - "time": "2025-11-05T07:57:47+00:00" + "time": "2026-01-12T12:19:02+00:00" }, { "name": "symfony/service-contracts", @@ -8842,22 +8954,23 @@ }, { "name": "symfony/string", - "version": "v7.3.4", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "f96476035142921000338bad71e5247fbc138872" + "reference": "1c4b10461bf2ec27537b5f36105337262f5f5d6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/f96476035142921000338bad71e5247fbc138872", - "reference": "f96476035142921000338bad71e5247fbc138872", + "url": "https://api.github.com/repos/symfony/string/zipball/1c4b10461bf2ec27537b5f36105337262f5f5d6f", + "reference": "1c4b10461bf2ec27537b5f36105337262f5f5d6f", "shasum": "" }, "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-grapheme": "~1.33", "symfony/polyfill-intl-normalizer": "~1.0", "symfony/polyfill-mbstring": "~1.0" }, @@ -8865,11 +8978,11 @@ "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/emoji": "^7.1", - "symfony/http-client": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", + "symfony/emoji": "^7.1|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.4|^7.0" + "symfony/var-exporter": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -8908,7 +9021,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.3.4" + "source": "https://github.com/symfony/string/tree/v7.4.4" }, "funding": [ { @@ -8928,27 +9041,27 @@ "type": "tidelift" } ], - "time": "2025-09-11T14:36:48+00:00" + "time": "2026-01-12T10:54:30+00:00" }, { "name": "symfony/translation", - "version": "v7.3.4", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "ec25870502d0c7072d086e8ffba1420c85965174" + "reference": "bfde13711f53f549e73b06d27b35a55207528877" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/ec25870502d0c7072d086e8ffba1420c85965174", - "reference": "ec25870502d0c7072d086e8ffba1420c85965174", + "url": "https://api.github.com/repos/symfony/translation/zipball/bfde13711f53f549e73b06d27b35a55207528877", + "reference": "bfde13711f53f549e73b06d27b35a55207528877", "shasum": "" }, "require": { "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/translation-contracts": "^2.5|^3.0" + "symfony/translation-contracts": "^2.5.3|^3.3" }, "conflict": { "nikic/php-parser": "<5.0", @@ -8967,17 +9080,17 @@ "require-dev": { "nikic/php-parser": "^5.0", "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/console": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/finder": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", "symfony/http-client-contracts": "^2.5|^3.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", "symfony/polyfill-intl-icu": "^1.21", - "symfony/routing": "^6.4|^7.0", + "symfony/routing": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^6.4|^7.0" + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -9008,7 +9121,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.3.4" + "source": "https://github.com/symfony/translation/tree/v7.4.4" }, "funding": [ { @@ -9028,7 +9141,7 @@ "type": "tidelift" } ], - "time": "2025-09-07T11:39:36+00:00" + "time": "2026-01-13T10:40:19+00:00" }, { "name": "symfony/translation-contracts", @@ -9114,16 +9227,16 @@ }, { "name": "symfony/uid", - "version": "v7.3.1", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "a69f69f3159b852651a6bf45a9fdd149520525bb" + "reference": "7719ce8aba76be93dfe249192f1fbfa52c588e36" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/a69f69f3159b852651a6bf45a9fdd149520525bb", - "reference": "a69f69f3159b852651a6bf45a9fdd149520525bb", + "url": "https://api.github.com/repos/symfony/uid/zipball/7719ce8aba76be93dfe249192f1fbfa52c588e36", + "reference": "7719ce8aba76be93dfe249192f1fbfa52c588e36", "shasum": "" }, "require": { @@ -9131,7 +9244,7 @@ "symfony/polyfill-uuid": "^1.15" }, "require-dev": { - "symfony/console": "^6.4|^7.0" + "symfony/console": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -9168,7 +9281,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v7.3.1" + "source": "https://github.com/symfony/uid/tree/v7.4.4" }, "funding": [ { @@ -9179,25 +9292,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-27T19:55:54+00:00" + "time": "2026-01-03T23:30:35+00:00" }, { "name": "symfony/var-dumper", - "version": "v7.3.5", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d" + "reference": "0e4769b46a0c3c62390d124635ce59f66874b282" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/476c4ae17f43a9a36650c69879dcf5b1e6ae724d", - "reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/0e4769b46a0c3c62390d124635ce59f66874b282", + "reference": "0e4769b46a0c3c62390d124635ce59f66874b282", "shasum": "" }, "require": { @@ -9209,10 +9326,10 @@ "symfony/console": "<6.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/uid": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/uid": "^6.4|^7.0|^8.0", "twig/twig": "^3.12" }, "bin": [ @@ -9251,7 +9368,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.3.5" + "source": "https://github.com/symfony/var-dumper/tree/v7.4.4" }, "funding": [ { @@ -9271,20 +9388,20 @@ "type": "tidelift" } ], - "time": "2025-09-27T09:00:46+00:00" + "time": "2026-01-01T22:13:48+00:00" }, { "name": "theseer/tokenizer", - "version": "1.2.3", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c", "shasum": "" }, "require": { @@ -9313,7 +9430,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.3" + "source": "https://github.com/theseer/tokenizer/tree/1.3.1" }, "funding": [ { @@ -9321,27 +9438,27 @@ "type": "github" } ], - "time": "2024-03-03T12:36:25+00:00" + "time": "2025-11-17T20:03:58+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", - "version": "v2.3.0", + "version": "v2.4.0", "source": { "type": "git", "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", - "reference": "0d72ac1c00084279c1816675284073c5a337c20d" + "reference": "f0292ccf0ec75843d65027214426b6b163b48b41" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/0d72ac1c00084279c1816675284073c5a337c20d", - "reference": "0d72ac1c00084279c1816675284073c5a337c20d", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/f0292ccf0ec75843d65027214426b6b163b48b41", + "reference": "f0292ccf0ec75843d65027214426b6b163b48b41", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "php": "^7.4 || ^8.0", - "symfony/css-selector": "^5.4 || ^6.0 || ^7.0" + "symfony/css-selector": "^5.4 || ^6.0 || ^7.0 || ^8.0" }, "require-dev": { "phpstan/phpstan": "^2.0", @@ -9374,32 +9491,32 @@ "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", "support": { "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues", - "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.3.0" + "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.4.0" }, - "time": "2024-12-21T16:25:41+00:00" + "time": "2025-12-02T11:56:42+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v5.6.2", + "version": "v5.6.3", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af" + "reference": "955e7815d677a3eaa7075231212f2110983adecc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/24ac4c74f91ee2c193fa1aaa5c249cb0822809af", - "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/955e7815d677a3eaa7075231212f2110983adecc", + "reference": "955e7815d677a3eaa7075231212f2110983adecc", "shasum": "" }, "require": { "ext-pcre": "*", - "graham-campbell/result-type": "^1.1.3", + "graham-campbell/result-type": "^1.1.4", "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.3", - "symfony/polyfill-ctype": "^1.24", - "symfony/polyfill-mbstring": "^1.24", - "symfony/polyfill-php80": "^1.24" + "phpoption/phpoption": "^1.9.5", + "symfony/polyfill-ctype": "^1.26", + "symfony/polyfill-mbstring": "^1.26", + "symfony/polyfill-php80": "^1.26" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", @@ -9448,7 +9565,7 @@ ], "support": { "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.2" + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.3" }, "funding": [ { @@ -9460,7 +9577,7 @@ "type": "tidelift" } ], - "time": "2025-04-30T23:37:27+00:00" + "time": "2025-12-27T19:49:13+00:00" }, { "name": "voku/portable-ascii", @@ -10212,22 +10329,22 @@ }, { "name": "symfony/config", - "version": "v7.3.6", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "9d18eba95655a3152ae4c1d53c6cc34eb4d4a0b7" + "reference": "4275b53b8ab0cf37f48bf273dc2285c8178efdfb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/9d18eba95655a3152ae4c1d53c6cc34eb4d4a0b7", - "reference": "9d18eba95655a3152ae4c1d53c6cc34eb4d4a0b7", + "url": "https://api.github.com/repos/symfony/config/zipball/4275b53b8ab0cf37f48bf273dc2285c8178efdfb", + "reference": "4275b53b8ab0cf37f48bf273dc2285c8178efdfb", "shasum": "" }, "require": { "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/filesystem": "^7.1", + "symfony/filesystem": "^7.1|^8.0", "symfony/polyfill-ctype": "~1.8" }, "conflict": { @@ -10235,11 +10352,11 @@ "symfony/service-contracts": "<2.5" }, "require-dev": { - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/finder": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^6.4|^7.0" + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -10267,7 +10384,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v7.3.6" + "source": "https://github.com/symfony/config/tree/v7.4.4" }, "funding": [ { @@ -10287,28 +10404,28 @@ "type": "tidelift" } ], - "time": "2025-11-02T08:04:43+00:00" + "time": "2026-01-13T11:36:38+00:00" }, { "name": "symfony/dependency-injection", - "version": "v7.3.6", + "version": "v7.4.5", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "98af8bb46c56aedd9dd5a7f0414fc72bf2dcfe69" + "reference": "76a02cddca45a5254479ad68f9fa274ead0a7ef2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/98af8bb46c56aedd9dd5a7f0414fc72bf2dcfe69", - "reference": "98af8bb46c56aedd9dd5a7f0414fc72bf2dcfe69", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/76a02cddca45a5254479ad68f9fa274ead0a7ef2", + "reference": "76a02cddca45a5254479ad68f9fa274ead0a7ef2", "shasum": "" }, "require": { "php": ">=8.2", "psr/container": "^1.1|^2.0", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/service-contracts": "^3.5", - "symfony/var-exporter": "^6.4.20|^7.2.5" + "symfony/service-contracts": "^3.6", + "symfony/var-exporter": "^6.4.20|^7.2.5|^8.0" }, "conflict": { "ext-psr": "<1.1|>=2", @@ -10321,9 +10438,9 @@ "symfony/service-implementation": "1.1|2.0|3.0" }, "require-dev": { - "symfony/config": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/yaml": "^6.4|^7.0" + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -10351,7 +10468,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v7.3.6" + "source": "https://github.com/symfony/dependency-injection/tree/v7.4.5" }, "funding": [ { @@ -10371,20 +10488,20 @@ "type": "tidelift" } ], - "time": "2025-10-31T10:11:11+00:00" + "time": "2026-01-27T16:16:02+00:00" }, { "name": "symfony/filesystem", - "version": "v7.3.6", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a" + "reference": "d551b38811096d0be9c4691d406991b47c0c630a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/e9bcfd7837928ab656276fe00464092cc9e1826a", - "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/d551b38811096d0be9c4691d406991b47c0c630a", + "reference": "d551b38811096d0be9c4691d406991b47c0c630a", "shasum": "" }, "require": { @@ -10393,7 +10510,7 @@ "symfony/polyfill-mbstring": "~1.8" }, "require-dev": { - "symfony/process": "^6.4|^7.0" + "symfony/process": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -10421,7 +10538,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.3.6" + "source": "https://github.com/symfony/filesystem/tree/v7.4.0" }, "funding": [ { @@ -10441,20 +10558,20 @@ "type": "tidelift" } ], - "time": "2025-11-05T09:52:27+00:00" + "time": "2025-11-27T13:27:24+00:00" }, { "name": "symfony/var-exporter", - "version": "v7.3.4", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "0f020b544a30a7fe8ba972e53ee48a74c0bc87f4" + "reference": "03a60f169c79a28513a78c967316fbc8bf17816f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/0f020b544a30a7fe8ba972e53ee48a74c0bc87f4", - "reference": "0f020b544a30a7fe8ba972e53ee48a74c0bc87f4", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/03a60f169c79a28513a78c967316fbc8bf17816f", + "reference": "03a60f169c79a28513a78c967316fbc8bf17816f", "shasum": "" }, "require": { @@ -10462,9 +10579,9 @@ "symfony/deprecation-contracts": "^2.5|^3" }, "require-dev": { - "symfony/property-access": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -10502,7 +10619,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v7.3.4" + "source": "https://github.com/symfony/var-exporter/tree/v7.4.0" }, "funding": [ { @@ -10522,7 +10639,7 @@ "type": "tidelift" } ], - "time": "2025-09-11T10:12:26+00:00" + "time": "2025-09-11T10:15:23+00:00" } ], "aliases": [], @@ -10537,5 +10654,5 @@ "platform-overrides": { "php": "8.2" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } diff --git a/flexiapi/database/migrations/2026_02_05_154352_create_call_forwardings_table.php b/flexiapi/database/migrations/2026_02_05_154352_create_call_forwardings_table.php new file mode 100644 index 0000000..baf8c40 --- /dev/null +++ b/flexiapi/database/migrations/2026_02_05_154352_create_call_forwardings_table.php @@ -0,0 +1,31 @@ +id(); + $table->integer('account_id')->unsigned()->nullable(); + $table->foreign('account_id')->references('id') + ->on('accounts')->onDelete('cascade'); + $table->string('type'); + $table->string('forward_to'); + $table->string('sip_uri')->nullable(); + $table->boolean('enabled')->default(false); + $table->integer('contact_id')->unsigned()->nullable(); + $table->foreign('contact_id')->references('id') + ->on('accounts')->onDelete('cascade'); + $table->unique(['account_id', 'type']); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('call_forwardings'); + } +}; diff --git a/flexiapi/lang/fr.json b/flexiapi/lang/fr.json index 95848a4..7bdeb9b 100644 --- a/flexiapi/lang/fr.json +++ b/flexiapi/lang/fr.json @@ -21,6 +21,7 @@ "Admin": "Administrateur", "Administration": "Administration", "Admins": "Administrateurs", + "All the calls": "Tous les appels", "All the admins will be super admins": "Tous les administrateurs seront super-administrateurs", "Allow a custom CSS theme": "Autoriser un thème CSS personnalisé", "Allow client settings to be overwritten by the provisioning ones": "Écraser la configuration client avec celle du déploiement", @@ -30,6 +31,7 @@ "Api Keys": "Clefs d'API", "App Configuration": "Configuration de l'App", "App settings": "Paramètres d'application", + "No anwser": "Pas de réponse", "Assistant": "Assistant", "Best regards,":"Cordialement,", "Blocked": "Bloqué", @@ -38,6 +40,7 @@ "By phone": "Par téléphone", "By": "Par", "Call Recording": "Enregistrement d'appels", + "Call Forwarding": "Redirection d'appels", "Calls logs": "Journaux d'appel", "Cancel": "Annuler", "Cannot be changed once created.": "Ne peut être changé par la suite.", @@ -63,6 +66,7 @@ "Connection": "Connexion", "Contacts List": "Liste de Contacts", "Contacts Lists": "Listes de Contacts", + "Contact": "Contact", "Contacts": "Contacts", "Copyright text": "Texte droits d'auteurs", "Country code": "Code du pays", @@ -154,11 +158,13 @@ "No account yet?": "Pas encore de compte ?", "No email yet": "Pas d'email pour le moment", "No limit": "Sans limite", + "No answer": "Pas de réponse", "No phone yet": "Pas de téléphone pour le moment", "Number of minutes to expire the key after the last request.": "Nombre de minutes avant l'expiration de la clef après son dernier usage.", "Open the app": "Ouvrir l'application", "Other information": "Autres informations", "Outbound proxy": "Outbound proxy", + "Line occupied": "Ligne occupée", "Password": "Mot de passe", "Phone Countries": "Numéros Internationaux", "Phone number": "Numéro de téléphone", @@ -203,8 +209,7 @@ "Separated by commas": "Séparé par des virgules", "Settings": "Paramètres", "Show usernames only": "Afficher uniquement les noms d'utilisateur", - "SIP address":"Adresse SIP", - "Sip Adress": "Adresse SIP", + "SIP Adress": "Adresse SIP", "SIP Domain": "Domaine SIP", "Space": "Espace", "Spaces": "Espaces", @@ -212,6 +217,7 @@ "Subdomain": "Sous-domaine", "Super Admin": "Super Admin", "Super Space": "Super Espace", + "Telephony": "Téléphonie", "Thank you for registering on :space.":"Merci de vous être inscrit sur :space.", "Thanks for the validation": "Nous vous remercions pour la validation", "The :attribute should not be a phone number": "Le champ :attribute ne peut pas être un numéro de téléphone", diff --git a/flexiapi/public/css/form.css b/flexiapi/public/css/form.css index ee9713e..36c52b8 100644 --- a/flexiapi/public/css/form.css +++ b/flexiapi/public/css/form.css @@ -399,4 +399,17 @@ div.checkbox:hover > input[type="checkbox"] + label { div.checkbox > input[type="checkbox"]:checked + label { right: 0.5rem; +} + + +/* Telephony subselect */ + +div.select[data-value] ~ div.togglable { + display: none; +} + +div.select[data-value=voicemail] ~ div.togglable.voicemail, +div.select[data-value=contact] ~ div.togglable.contact, +div.select[data-value=sip_uri] ~ div.togglable.sip_uri { + display: block; } \ No newline at end of file diff --git a/flexiapi/public/scripts/utils.js b/flexiapi/public/scripts/utils.js index bd0d060..5d4f505 100644 --- a/flexiapi/public/scripts/utils.js +++ b/flexiapi/public/scripts/utils.js @@ -134,4 +134,12 @@ function copyValueTo(from, to, append) { to.value = value; } +} + +function setCheckboxValue(name, value) { + let checkbox = document.getElementsByName(name)[0]; + + if (checkbox) { + checkbox.checked = value; + } } \ No newline at end of file diff --git a/flexiapi/resources/views/admin/account/call_forwardings/edit.blade.php b/flexiapi/resources/views/admin/account/call_forwardings/edit.blade.php new file mode 100644 index 0000000..6f765a0 --- /dev/null +++ b/flexiapi/resources/views/admin/account/call_forwardings/edit.blade.php @@ -0,0 +1,49 @@ +

+ {{ __('Call Forwarding') }} +

+ +
+ @csrf + @method('put') + @php($callForwardings = $account->callForwardingsDefault) + +
+

{{ __('All the calls') }}

+ +
+ enabled) checked @endif name="always[enabled]" + onchange="if (this.checked) { setCheckboxValue('away[enabled]', false); setCheckboxValue('busy[enabled]', false); }"> + +
+ + @include('admin.account.call_forwardings.edit_select_part', ['callForwarding' => $callForwardings, 'type' => 'always']) +
+ +
+

{{ __('No answer') }}

+ +
+ enabled) checked @endif name="away[enabled]" + onchange="if (this.checked) { setCheckboxValue('always[enabled]', false); }"> + +
+ + @include('admin.account.call_forwardings.edit_select_part', ['callForwarding' => $callForwardings, 'type' => 'away']) +
+ +
+

{{ __('Line occupied') }}

+ +
+ enabled) checked @endif name="busy[enabled]" + onchange="if (this.checked) { setCheckboxValue('always[enabled]', false); }"> + +
+ + @include('admin.account.call_forwardings.edit_select_part', ['callForwarding' => $callForwardings, 'type' => 'busy']) +
+ +
+ +
+
\ No newline at end of file diff --git a/flexiapi/resources/views/admin/account/call_forwardings/edit_select_part.blade.php b/flexiapi/resources/views/admin/account/call_forwardings/edit_select_part.blade.php new file mode 100644 index 0000000..356520c --- /dev/null +++ b/flexiapi/resources/views/admin/account/call_forwardings/edit_select_part.blade.php @@ -0,0 +1,23 @@ +
+ + +
+
+ + + @include('parts.errors', ['name' => $type . '.sip_uri']) +
+
+
+ + + @include('parts.errors', ['name' => $type . '.contact']) +
\ No newline at end of file diff --git a/flexiapi/resources/views/admin/account/contact/index.blade.php b/flexiapi/resources/views/admin/account/contact/index.blade.php index 0fde1d3..643fe9a 100644 --- a/flexiapi/resources/views/admin/account/contact/index.blade.php +++ b/flexiapi/resources/views/admin/account/contact/index.blade.php @@ -49,7 +49,7 @@ @foreach ($account->contactsLists as $contactsList) - {{ $contactsList->title }} + {{ $contactsList->title }} {{ $contactsList->contacts_count }} {{ __('Contacts') }} diff --git a/flexiapi/resources/views/admin/account/parts/tabs.blade.php b/flexiapi/resources/views/admin/account/parts/tabs.blade.php index ffff7e6..76b4d04 100644 --- a/flexiapi/resources/views/admin/account/parts/tabs.blade.php +++ b/flexiapi/resources/views/admin/account/parts/tabs.blade.php @@ -1,6 +1,7 @@ @include('parts.tabs', [ 'items' => [ route('admin.account.show', $account) => __('Information'), + route('admin.account.telephony.show', $account) => __('Telephony'), route('admin.account.contact.index', $account) => __('Contacts'), route('admin.account.statistics.show_call_logs', $account) => __('Calls logs'), route('admin.account.statistics.show', $account) => __('Statistics'), diff --git a/flexiapi/resources/views/admin/account/show.blade.php b/flexiapi/resources/views/admin/account/show.blade.php index 027e4ef..d03a4f9 100644 --- a/flexiapi/resources/views/admin/account/show.blade.php +++ b/flexiapi/resources/views/admin/account/show.blade.php @@ -179,7 +179,7 @@ @endif -
+

{{ __('Devices') }}

@@ -211,53 +211,6 @@
-
-

- {{ __('Voicemails') }} -

- - - - - - - - - @if ($account->uploadedVoicemails->isEmpty()) - - - - @endif - @foreach ($account->uploadedVoicemails as $voicemail) - - - - - @endforeach - -
{{ __('Created') }}
{{ __('Empty') }}
- {{ $voicemail->created_at }} - @if ($voicemail->url) - - - - @endif - @if ($voicemail->sip_from) -
- {{ $voicemail->sip_from }} - @endif -
- @if ($voicemail->url) - - - - - @endif -
-
-
diff --git a/flexiapi/resources/views/admin/account/telephony/show.blade.php b/flexiapi/resources/views/admin/account/telephony/show.blade.php new file mode 100644 index 0000000..adbcefc --- /dev/null +++ b/flexiapi/resources/views/admin/account/telephony/show.blade.php @@ -0,0 +1,65 @@ +@extends('layouts.main') + +@section('breadcrumb') + @include('admin.parts.breadcrumb.accounts.show', ['account' => $account]) +@endsection + +@section('content') +
+

{{ $account->identifier }}

+
+ @include('admin.account.parts.tabs') + +
+
+

+ {{ __('Voicemails') }} +

+ + + + + + + + + @if ($account->uploadedVoicemails->isEmpty()) + + + + @endif + @foreach ($account->uploadedVoicemails as $voicemail) + + + + + @endforeach + +
{{ __('Created') }}
{{ __('Empty') }}
+ {{ $voicemail->created_at }} + @if ($voicemail->url) + + + + @endif + @if ($voicemail->sip_from) +
+ {{ $voicemail->sip_from }} + @endif +
+ @if ($voicemail->url) + + + + + @endif +
+
+ +
+ @include('admin.account.call_forwardings.edit', ['account' => $account]) +
+
+@endsection \ No newline at end of file diff --git a/flexiapi/resources/views/api/documentation/accounts/call_forwarding.blade.php b/flexiapi/resources/views/api/documentation/accounts/call_forwarding.blade.php new file mode 100644 index 0000000..450ea3c --- /dev/null +++ b/flexiapi/resources/views/api/documentation/accounts/call_forwarding.blade.php @@ -0,0 +1,46 @@ +## Account Call Forwardings + +### `GET /accounts/{id/me}/call_forwardings` +User +Admin + +Return the user Call Forwardings. + +### `GET /accounts/{id/me}/call_forwardings/{call_forwarding_id}` +User +Admin + +Return a Call Forwarding configuration. + +### `POST /accounts/{id/me}/call_forwardings` +User +Admin + +Create a new Call Forwarding configuration. + +JSON parameters: + +* `type` **required**, must be `always`, `away` or `busy`, one of each declaration maximum per account +* `forward_to` **required**, must be `sip_uri`, `voicemail` or `contact` +* `sip_uri` **required if `forward_to` is set to `sip_uri`**, must be a SIP URI, must be set when `forward_to` set to `sip_uri` +* `contact_id` **required if `forward_to` is set to `contact`**, must be a valid `contact_id` of the contact +* `enabled` **required**, boolean. If `type: always` is enabled `away` and `busy` must be disabled. If `type: away or busy` are enabled `always` must be disabled. + +### `PUT /accounts/{id/me}/call_forwardings/{call_forwarding_id}` +User +Admin + +Create a new Call Forwarding configuration. + +JSON parameters: + +* `forward_to` **required**, must be `sip_uri`, `voicemail` or `contact` +* `sip_uri` **required if `forward_to` is set to `sip_uri`**, must be a SIP URI, must be set when `forward_to` set to `sip_uri` +* `contact_id` **required if `forward_to` is set to `contact`**, must be a valid `contact_id` of the contact +* `enabled` **required**, boolean. If `type: always` is enabled `away` and `busy` must be disabled. If `type: away or busy` are enabled `always` must be disabled. + +### `DELETE /accounts/{id/me}/call_forwardings/{call_forwarding_id}` +User +Admin + +Remove a Call Forwarding configuration. diff --git a/flexiapi/resources/views/api/documentation/accounts/call_forwarding_parameters.blade.php b/flexiapi/resources/views/api/documentation/accounts/call_forwarding_parameters.blade.php new file mode 100644 index 0000000..e69de29 diff --git a/flexiapi/resources/views/api/documentation_markdown.blade.php b/flexiapi/resources/views/api/documentation_markdown.blade.php index 0373ae1..44a9790 100644 --- a/flexiapi/resources/views/api/documentation_markdown.blade.php +++ b/flexiapi/resources/views/api/documentation_markdown.blade.php @@ -9,6 +9,19 @@ Returns `pong` +## SIP URI Resolving + +### `GET /resolve/{sip}` +Admin + +Resolve a specific `SIP URI` in the space. +All the resolved object can be reached using direct API endpoints. This endpoint is only there as a shortcut and should be used sparingly. + +Will return a JSON message with: + +* `type` resolved API object `type`, can be `acccount` +* `payload` that contains the resolved object + @include('api.documentation.spaces') @include('api.documentation.spaces.carddav') @@ -25,6 +38,8 @@ Returns `pong` @include('api.documentation.accounts.contacts_lists') +@include('api.documentation.accounts.call_forwarding') + @include('api.documentation.accounts.contacts') @include('api.documentation.accounts.dictionary') diff --git a/flexiapi/resources/views/errors/503.blade.php b/flexiapi/resources/views/errors/503.blade.php index 3d72dbc..5f3aa44 100644 --- a/flexiapi/resources/views/errors/503.blade.php +++ b/flexiapi/resources/views/errors/503.blade.php @@ -1,5 +1,11 @@ @extends('errors::minimal') -@section('title', __('Service Unavailable')) @section('code', '503') -@section('message', $exception->getMessage()) + +@if (app()->isDownForMaintenance()) + @section('title', __('We will be back soon!')) + @section('message', 'Sorry for the inconvenience but we are performing some maintenance at the moment.') +@else + @section('title', __('Service Unavailable')) + @section('message', $exception->getMessage()) +@endif diff --git a/flexiapi/resources/views/parts/errors.blade.php b/flexiapi/resources/views/parts/errors.blade.php index bd4e35b..bd74b7c 100644 --- a/flexiapi/resources/views/parts/errors.blade.php +++ b/flexiapi/resources/views/parts/errors.blade.php @@ -1,4 +1,3 @@ - @if (isset($errors) && isset($name) && count($errors->get($name)) > 0) @foreach ($errors->get($name) as $error) diff --git a/flexiapi/routes/api.php b/flexiapi/routes/api.php index a6e3e72..1ae8be0 100644 --- a/flexiapi/routes/api.php +++ b/flexiapi/routes/api.php @@ -20,6 +20,7 @@ use App\Http\Controllers\Api\Account\AccountController; use App\Http\Controllers\Api\Account\ApiKeyController; use App\Http\Controllers\Api\Account\AuthTokenController; +use App\Http\Controllers\Api\Account\CallForwardingController; use App\Http\Controllers\Api\Account\ContactController; use App\Http\Controllers\Api\Account\CreationRequestToken; use App\Http\Controllers\Api\Account\CreationTokenController; @@ -33,6 +34,7 @@ use App\Http\Controllers\Api\Account\RecoveryTokenController; use App\Http\Controllers\Api\Account\VcardsStorageController; use App\Http\Controllers\Api\Account\VoicemailController; use App\Http\Controllers\Api\Admin\Account\ActionController; +use App\Http\Controllers\Api\Admin\Account\CallForwardingController as AdminCallForwardingController; use App\Http\Controllers\Api\Admin\Account\CardDavCredentialsController; use App\Http\Controllers\Api\Admin\Account\ContactController as AdminContactController; use App\Http\Controllers\Api\Admin\Account\CreationTokenController as AdminCreationTokenController; @@ -111,6 +113,7 @@ Route::group(['middleware' => ['auth.jwt', 'auth.digest_or_key', 'auth.check_blo Route::apiResource('vcards-storage', VcardsStorageController::class); Route::apiResource('voicemails', VoicemailController::class, ['only' => ['index', 'show', 'store', 'destroy']]); + Route::apiResource('call_forwardings', CallForwardingController::class); }); Route::group(['middleware' => ['auth.admin']], function () { @@ -134,6 +137,8 @@ Route::group(['middleware' => ['auth.jwt', 'auth.digest_or_key', 'auth.check_blo Route::post('phone_countries/{code}/deactivate', [AdminPhoneCountryController::class, 'deactivate']); }); + Route::get('resolve/{sip}', [SpaceController::class, 'resolve']); + // Account creation token Route::post('account_creation_tokens', [AdminCreationTokenController::class, 'create']); @@ -181,6 +186,7 @@ Route::group(['middleware' => ['auth.jwt', 'auth.digest_or_key', 'auth.check_blo Route::apiResource('account_types', TypeController::class); Route::apiResource('accounts/{id}/vcards-storage', AdminVcardsStorageController::class); Route::apiResource('accounts/{id}/voicemails', AdminVoicemailController::class, ['only' => ['index', 'show', 'store', 'destroy']]); + Route::apiResource('accounts/{id}/call_forwardings', AdminCallForwardingController::class); Route::apiResource('contacts_lists', ContactsListController::class); Route::prefix('contacts_lists')->controller(ContactsListController::class)->group(function () { diff --git a/flexiapi/routes/web.php b/flexiapi/routes/web.php index a2af9ad..92db0bd 100644 --- a/flexiapi/routes/web.php +++ b/flexiapi/routes/web.php @@ -36,6 +36,7 @@ use App\Http\Controllers\Account\VcardsStorageController; use App\Http\Controllers\Admin\Account\AccountTypeController; use App\Http\Controllers\Admin\Account\ActionController; use App\Http\Controllers\Admin\Account\ActivityController; +use App\Http\Controllers\Admin\Account\CallForwardingController; use App\Http\Controllers\Admin\Account\CardDavCredentialsController; use App\Http\Controllers\Admin\Account\ContactController; use App\Http\Controllers\Admin\Account\DeviceController as AdminAccountDeviceController; @@ -43,6 +44,7 @@ use App\Http\Controllers\Admin\Account\DictionaryController; use App\Http\Controllers\Admin\Account\FileController as AdminFileController; use App\Http\Controllers\Admin\Account\ImportController; use App\Http\Controllers\Admin\Account\StatisticsController as AdminAccountStatisticsController; +use App\Http\Controllers\Admin\Account\TelephonyController; use App\Http\Controllers\Admin\Account\TypeController; use App\Http\Controllers\Admin\AccountController as AdminAccountController; use App\Http\Controllers\Admin\ApiKeyController as AdminApiKeyController; @@ -312,6 +314,14 @@ Route::middleware(['feature.web_panel_enabled'])->group(function () { Route::delete('/', 'destroy')->name('destroy'); }); + Route::name('telephony.')->prefix('{account}/telephony')->controller(TelephonyController::class)->group(function () { + Route::get('/', 'show')->name('show'); + }); + + Route::name('call_forwardings.')->prefix('{account}/call_forwardings')->controller(CallForwardingController::class)->group(function () { + Route::put('/', 'update')->name('update'); + }); + Route::name('device.')->prefix('{account}/devices')->controller(AdminAccountDeviceController::class)->group(function () { Route::get('{device_id}/delete', 'delete')->name('delete'); Route::delete('/', 'destroy')->name('destroy'); diff --git a/flexiapi/tests/Feature/ApiAccountCallForwardingTest.php b/flexiapi/tests/Feature/ApiAccountCallForwardingTest.php new file mode 100644 index 0000000..fa30e3c --- /dev/null +++ b/flexiapi/tests/Feature/ApiAccountCallForwardingTest.php @@ -0,0 +1,162 @@ +. +*/ + +namespace Tests\Feature; + +use App\Account; +use Tests\TestCase; +use function PHPUnit\Framework\assertJson; + +class ApiAccountCallForwardingTest extends TestCase +{ + protected $route = '/api/accounts/me/call_forwardings'; + protected $method = 'POST'; + + public function testResolving() + { + $account = Account::factory()->create(); + $account->generateUserApiKey(); + + $uri = 'sip:uri'; + $this->keyAuthenticated($account) + ->json($this->method, $this->route, [ + 'type' => 'always', + 'forward_to' => 'sip_uri', + 'sip_uri' => $uri, + 'enabled' => true + ]) + ->assertStatus(201); + + $admin = Account::factory()->admin()->create(); + $admin->generateUserApiKey(); + + $this->keyAuthenticated($admin) + ->get('/api/resolve/' . $account->identifier) + ->assertStatus(200) + ->assertJsonFragment(['type' => 'account']); + } + + public function testCrud() + { + $account = Account::factory()->create(); + $account->generateUserApiKey(); + $admin = Account::factory()->admin()->create(); + $admin->generateUserApiKey(); + + $uri = 'sip:uri'; + + // Contacts + + $contactAccount = Account::factory()->create(); + + $this->keyAuthenticated($account) + ->json($this->method, $this->route, [ + 'type' => 'always', + 'forward_to' => 'contact', + 'enabled' => true + ]) + ->assertJsonValidationErrors(['contact_id']); + + $this->keyAuthenticated($account) + ->json($this->method, $this->route, [ + 'type' => 'always', + 'forward_to' => 'contact', + 'contact_id' => $contactAccount->id, + 'enabled' => true + ]) + ->assertJsonValidationErrors(['contact_id']); + + $this->keyAuthenticated($admin) + ->json($this->method, '/api/accounts/' . $account->id . '/contacts/' . $contactAccount->id) + ->assertStatus(200); + + $response = $this->keyAuthenticated($account) + ->json($this->method, $this->route, [ + 'type' => 'always', + 'forward_to' => 'contact', + 'contact_id' => $contactAccount->id, + 'enabled' => true + ]) + ->assertStatus(201); + + // SIP URI + + $this->keyAuthenticated($account) + ->json($this->method, $this->route, [ + 'type' => 'always', + 'forward_to' => 'sip_uri', + 'sip_uri' => null, + 'enabled' => true + ]) + ->assertJsonValidationErrors(['type']); + + $this->keyAuthenticated($account) + ->json('DELETE', $this->route . '/' . $response['id']) + ->assertStatus(200); + + $this->keyAuthenticated($account) + ->json($this->method, $this->route, [ + 'type' => 'always', + 'forward_to' => 'sip_uri', + 'sip_uri' => null, + 'enabled' => true + ]) + ->assertJsonValidationErrors(['sip_uri']); + + $response = $this->keyAuthenticated($account) + ->json($this->method, $this->route, [ + 'type' => 'always', + 'forward_to' => 'sip_uri', + 'sip_uri' => $uri, + 'enabled' => true + ]) + ->assertStatus(201); + + $this->keyAuthenticated($account) + ->json($this->method, $this->route, [ + 'type' => 'away', + 'forward_to' => 'sip_uri', + 'sip_uri' => $uri, + 'enabled' => true + ]) + ->assertJsonValidationErrors(['enabled']); + + + $this->keyAuthenticated($account) + ->json('PUT', $this->route . '/' . $response->json()['id'], [ + 'type' => 'always', + 'forward_to' => 'sip_uri', + 'sip_uri' => $uri, + 'enabled' => false + ]) + ->assertStatus(200); + + $this->keyAuthenticated($account) + ->json($this->method, $this->route, [ + 'type' => 'away', + 'forward_to' => 'sip_uri', + 'sip_uri' => $uri, + 'enabled' => true + ]) + ->assertStatus(201); + + $this->assertCount(2, $this->keyAuthenticated($account) + ->json('GET', $this->route)->json()); + } +}