From: Vincent Vanwaelscappel Date: Thu, 11 Aug 2022 11:02:12 +0000 (+0200) Subject: wait #5390 @4 X-Git-Url: http://git.cubedesigners.com/?a=commitdiff_plain;h=c732eebde2d01fbdf8135ad69bb3dfd0695fdc5d;p=fluidbook-toolbox.git wait #5390 @4 --- diff --git a/app/Jobs/DownloadBase.php b/app/Jobs/DownloadBase.php index 6b3d18669..4c8b5519d 100644 --- a/app/Jobs/DownloadBase.php +++ b/app/Jobs/DownloadBase.php @@ -4,10 +4,14 @@ namespace App\Jobs; use App\Mail\DeferredDownload; use App\Models\User; +use App\Services\ScormCloud; use Cubist\Backpack\Magic\Models\CubistMagicAbstractModel; use Cubist\Util\Files\Files; use Cubist\Util\Str; +use Cubist\Util\Zip; +use GrahamCampbell\Markdown\Facades\Markdown; use Illuminate\Support\Facades\Mail; +use JoliCode\Slack\ClientFactory; class DownloadBase extends Base { @@ -26,6 +30,8 @@ class DownloadBase extends Base */ protected $action; + protected $_subject; + /** * @param $entry CubistMagicAbstractModel * @param $action string @@ -38,33 +44,95 @@ class DownloadBase extends Base $this->action = $action; } - public function sendNotification($subject, $body) + public function sendNotification($subject, $text, $actions = []) { - if ($this->user->slack) { - $this->sendSlack($subject, $body); + if ($this->getUser()->slack) { + $this->sendSlack($subject, $text, $actions); } else { - $this->sendEmail($subject, $body); + $this->sendEmail($subject, $text, $actions); } } - public function sendSlack($subject, $body) + public function sendSlack($subject, $text, $actions = []) { - $client = JoliCode\Slack\ClientFactory::create(env()); + $client = ClientFactory::create(env('SLACK_BOT_TOKEN')); + $blocks = [ + [ + 'type' => 'section', + 'text' => [ + 'type' => 'mrkdwn', + 'text' => '*' . $subject . '*', + ] + ] + ]; + if ($text) { + $blocks[] = [ + 'type' => 'section', + 'text' => [ + 'type' => 'mrkdwn', + 'text' => $text, + ] + ]; + } + if (count($actions) > 0) { + $a = [ + 'type' => 'actions', + 'block_id' => 'actions', + 'elements' => [], + ]; + $text = ''; + $i = 0; + foreach ($actions as $label => $url) { + $a['elements'][] = [ + 'type' => 'button', + 'text' => [ + 'type' => 'plain_text', + 'text' => $label + ], + 'url' => $url, + ]; + $i++; + $text .= '> ' . $label . ' : ' . $url . "\n"; + } + $blocks[] = [ + 'type' => 'section', + 'text' => [ + 'type' => 'mrkdwn', + 'text' => $text, + ] + ]; + $blocks[] = $a; + } + + $client->chatPostMessage([ + 'username' => 'Fluidbook Toolbox', + 'channel' => $this->getUser()->slack, + 'blocks' => json_encode($blocks), + 'text' => $subject, + 'unfurl_links' => false, + ]); } - public function sendEmail($subject, $body) + public function sendEmail($subject, $text, $actions = []) { + $body = ''; + foreach ($actions as $label => $url) { + $body .= $label . ' : ' . $url . '
'; + } + if ($text) { + $body .= '
' . $text; + } $mail = new DeferredDownload(); $mail->to($this->user->email); $mail->subject($subject); - $mail->html($body); + $mail->html(Markdown::convert($body)->getContent()); Mail::send($mail); } protected function _fname($title = null, $extension = 'zip') { if (null === $title) { - $title = $this->entry->title; + $title = $this->_title(); } return Str::slugCase($this->type . '-' . date('Ymdhis') . '-' . md5(rand(10000, 100000000)) . '-' . Str::slug($title)) . '.' . $extension; } @@ -79,4 +147,61 @@ class DownloadBase extends Base { return url('storage/' . $this->type . '/download/' . $fname); } + + protected function _title() + { + return $this->entry->title; + } + + protected function _id() + { + return $this->entry->id; + } + + public function handle() + { + try { + $url = $this->_compileandpackage(); + $subject = __($this->_subject, ['title' => $this->_title(), 'nb' => $this->_id()]); + $text = ''; + $actions = ['Télécharger' => $url]; + + try { + if ($this->action === 'scormcloud') { + $scormURL = ScormCloud::send($url, 'toolbox_' . $this->type . '_' . $this->_id()); + $actions[__('Tester sur SCORM Cloud')] = $scormURL; + } + } catch (\Exception $e) { + $text = __('Une erreur s\'est produite lors de l\'envoi sur SCORM Cloud (App ID :appid) : :error', ['error' => $e->getMessage(), 'appid' => env('SCORM_CLOUD_APP_ID')]); + } + } catch (\Exception $e) { + $subject = __('Erreur lors de la compilation du :type :nb', ['nb' => $this->_id(), 'type' => $this->type]); + $text = __('Détails de l\'erreur :message', ['message' => $e->getMessage() . ' at line ' . $e->getLine() . ' of ' . $e->getFile()]); + $actions = []; + } + + $this->sendNotification($subject, $text, $actions); + } + + protected function _compileandpackage() + { + + $compilepath = $this->_compile(); + $fname = $this->_fname(); + $dest = Files::mkdir(storage_path('app/public/' . $this->type . '/download/')) . $fname; + + Zip::archive($compilepath, $dest); + if (!file_exists($dest)) { + throw new \Exception('An error occured while compiling the collection'); + } + + return $this->_url($fname); + } + + protected function _compile() + { + $compilepath = $this->entry->getFinalPath(); + $this->entry->compile($compilepath); + return $compilepath; + } } diff --git a/app/Jobs/ElearningMediaDownload.php b/app/Jobs/ElearningMediaDownload.php index 1368b7d11..dea8bb12f 100644 --- a/app/Jobs/ElearningMediaDownload.php +++ b/app/Jobs/ElearningMediaDownload.php @@ -8,47 +8,7 @@ use Cubist\Util\Zip; class ElearningMediaDownload extends DownloadBase { - protected $type = 'elearningmedia'; - - public function handle() - { - try { - $compilepath = $this->entry->getFinalPath(); - $this->entry->compile($compilepath); - - $fname = $this->_fname(); - $dest = Files::mkdir(storage_path('app/public/elearningmedia/download/')) . $fname; - - Zip::archive($compilepath, $dest); - if (!file_exists($dest)) { - throw new \Exception('An error occured while compiling the collection'); - } - - $url = $this->_url($fname); - - $subject = __('Media ":title" (#:nb) prêt au téléchargement', ['title' => $this->entry->title, 'nb' => $this->entry->id]); - $body = __('Le fichier est disponible à l\'adresse suivante : :url', ['url' => $url]); - - try { - if ($this->action === 'scormcloud') { - $scormURL = ScormCloud::send($url, 'toolbox_' . $this->type . '_' . $this->entry->id, true); - $body .= "

"; - $body .= __('Le media peut être testé sur SCORM Cloud : :url', ['url' => $scormURL]); - } - } catch (\Exception $e) { - $body .= "

"; - $body .= __('Une erreur s\'est produite lors de l\'envoi sur SCORM Cloud (App ID :appid) : :error', ['error' => $e->getMessage(), 'appid' => env('SCORM_CLOUD_APP_ID')]); - } - - - } catch (\Exception $e) { - $subject = __('Erreur lors de la compilation du media :nb', ['nb' => $this->entry->id]); - $body = __('Détails de l\'erreur :message', ['message' => $e->getMessage() . ' at line ' . $e->getLine() . ' of ' . $e->getFile()]); - } - - $this->sendNotification($subject, $body); - } - - + // __('Media ":title" (#:nb) prêt au téléchargement') + protected $_subject = 'Media ":title" (#:nb) prêt au téléchargement'; } diff --git a/app/Jobs/ElearningPackageDownload.php b/app/Jobs/ElearningPackageDownload.php index 4d57c26c7..d4fbb5845 100644 --- a/app/Jobs/ElearningPackageDownload.php +++ b/app/Jobs/ElearningPackageDownload.php @@ -8,47 +8,7 @@ use Cubist\Util\Zip; class ElearningPackageDownload extends DownloadBase { - protected $type = 'elearningpackage'; - - public function handle() - { - try { - $compilepath = $this->entry->getFinalPath(); - $this->entry->compile($compilepath, $this->user); - - $fname = $this->_fname(); - $dest = Files::mkdir(storage_path('app/public/elearningpackage/download/')) . $fname; - - Zip::archive($compilepath, $dest); - if (!file_exists($dest)) { - throw new \Exception('An error occured while compiling the collection'); - } - - $url = $this->_url($fname); - - $subject = __('Package ":title" (#:nb) prêt au téléchargement', ['title' => $this->entry->title, 'nb' => $this->entry->id]); - $body = __('Le fichier est disponible à l\'adresse suivante : :url', ['url' => $url]); - - try { - if ($this->action === 'scormcloud') { - $scormURL = ScormCloud::send($url, 'toolbox_' . $this->type . '_' . $this->entry->id); - $body .= "

"; - $body .= __('Le package peut être testé sur SCORM Cloud : :url', ['url' => $scormURL]); - } - } catch (\Exception $e) { - $body .= "

"; - $body .= __('Une erreur s\'est produite lors de l\'envoi sur SCORM Cloud (App ID :appid) : :error', ['error' => $e->getMessage(), 'appid' => env('SCORM_CLOUD_APP_ID')]); - } - - - } catch (\Exception $e) { - $subject = __('Erreur lors de la compilation du package :nb', ['nb' => $this->entry->id]); - $body = __('Détails de l\'erreur :message', ['message' => $e->getMessage() . ' at line ' . $e->getLine() . ' of ' . $e->getFile()]); - } - - $this->sendNotification($subject, $body); - } - - + // __('Package ":title" (#:nb) prêt au téléchargement') + protected $_subject = 'Package ":title" (#:nb) prêt au téléchargement'; } diff --git a/app/Jobs/FluidbookCollectionDownload.php b/app/Jobs/FluidbookCollectionDownload.php index 7316ef457..2cbb0cccd 100644 --- a/app/Jobs/FluidbookCollectionDownload.php +++ b/app/Jobs/FluidbookCollectionDownload.php @@ -12,50 +12,16 @@ use Cubist\Util\Zip; class FluidbookCollectionDownload extends DownloadBase { - protected $type = 'collection'; + protected $type = 'fluidbookcollection'; - /** - * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response - * @throws \Exception - */ - public function handle() - { - try { - $compilepath = protected_path('collection/final/' . $this->entry->id); - $this->compile($compilepath); - - $fname = $this->_fname(); - $dest = $this->_dest($fname); - - Zip::archive($compilepath, $dest); - if (!file_exists($dest)) { - throw new \Exception('An error occured while compiling the collection'); - } - - $url = $this->_url($fname); - - $subject = __('Collection ":title" (#:nb) prête au téléchargement', ['title' => $this->entry->title, 'nb' => $this->entry->id]); - $body = __('Le fichier est disponible à l\'adresse suivante : :url', ['url' => $url]); - - try { - if ($this->action === 'scormcloud') { - $scormURL = $this->sendToSCORMCloud($url); - $body .= "

"; - $body .= __('La collection peut être testée sur SCORM Cloud : :url', ['url' => $scormURL]); - } - } catch (\Exception $e) { - $body .= "

"; - $body .= __('Une erreur s\'est produite lors de l\'envoi sur SCORM Cloud (App ID :appid) : :error', ['error' => $e->getMessage(), 'appid' => env('SCORM_CLOUD_APP_ID')]); - } - - - } catch (\Exception $e) { - $subject = __('Erreur lors de la compilation de la collection :nb', ['nb' => $this->entry->id]); - $body = __('Détails de l\'erreur :message', ['message' => $e->getMessage() . ' at line ' . $e->getLine() . ' of ' . $e->getFile()]); - } - - $this->sendNotification($subject, $body); + // __('Collection ":title" (#:nb) prête au téléchargement') + protected $_subject = 'Collection ":title" (#:nb) prête au téléchargement'; + protected function _compile() + { + $compilepath = protected_path('collection/final/' . $this->entry->id); + $this->compile($compilepath); + return $compilepath; } /** @@ -67,13 +33,11 @@ class FluidbookCollectionDownload extends DownloadBase $path = Files::emptyDir($path); PHP::neverStop(); - if ($data->type === 'scorm_multilang') { $res = $this->compileSCORMMultilang($data, $path); } elseif ($data->type === 'export') { $res = $this->compileExport($data, $path); } - return $res; } @@ -253,9 +217,4 @@ window.location='./' + locale + '/index.html'; } } } - - public function sendToSCORMCloud($url) - { - return ScormCloud::send($url, 'toolbox_collection_' . $this->entry->getKey()); - } } diff --git a/app/Jobs/QuizDownload.php b/app/Jobs/QuizDownload.php index 0de98681e..8489f1c2d 100644 --- a/app/Jobs/QuizDownload.php +++ b/app/Jobs/QuizDownload.php @@ -10,45 +10,6 @@ class QuizDownload extends DownloadBase { protected $type = 'quiz'; - - public function handle() - { - try { - $compilepath = $this->entry->getFinalPath(); - $this->entry->compile($compilepath, $this->user); - - $fname = $this->_fname(); - $dest = Files::mkdir(storage_path('app/public/quiz/download/')) . $fname; - - Zip::archive($compilepath, $dest); - if (!file_exists($dest)) { - throw new \Exception('An error occured while compiling the quiz'); - } - - $url = $this->_url($fname); - - $subject = __('Quiz ":title" (#:nb) prêt au téléchargement', ['title' => $this->entry->title, 'nb' => $this->entry->id]); - $body = __('Le fichier est disponible à l\'adresse suivante : :url', ['url' => $url]); - - try { - if ($this->action === 'scormcloud') { - $scormURL = ScormCloud::send($url, 'toolbox_' . $this->type . '_' . $this->entry->id, true); - $body .= "

"; - $body .= __('Le package peut être testé sur SCORM Cloud : :url', ['url' => $scormURL]); - } - } catch (\Exception $e) { - $body .= "

"; - $body .= __('Une erreur s\'est produite lors de l\'envoi sur SCORM Cloud (App ID :appid) : :error', ['error' => $e->getMessage(), 'appid' => env('SCORM_CLOUD_APP_ID')]); - } - - - } catch (\Exception $e) { - $subject = __('Erreur lors de la compilation du quiz :nb', ['nb' => $this->entry->id]); - $body = __('Détails de l\'erreur :message', ['message' => $e->getMessage() . ' at line ' . $e->getLine() . ' of ' . $e->getFile()]); - } - - $this->sendNotification($subject, $body); - } - - + // __('Quiz ":title" (#:nb) prêt au téléchargement') + protected $_subject = 'Quiz ":title" (#:nb) prêt au téléchargement'; } diff --git a/app/Models/FluidbookCollection.php b/app/Models/FluidbookCollection.php index f7a4bb430..0fd5641da 100644 --- a/app/Models/FluidbookCollection.php +++ b/app/Models/FluidbookCollection.php @@ -38,5 +38,9 @@ class FluidbookCollection extends ToolboxModel $this->addField('override_settings', BunchOfFieldsMultiple::class, __('Redéfinir les paramètres lors de l\'export'), ['bunch' => Fluidbook_Setting::class]); } + public function getFinalPath() + { + return protected_path('fluidbookcollection/final/' . $this->id); + } } diff --git a/composer.json b/composer.json index 1d3abf0f1..0c8b1c75d 100644 --- a/composer.json +++ b/composer.json @@ -36,10 +36,12 @@ "fluidbook/tools": "dev-master", "league/csv": "^9.8", "mxl/laravel-job": "^1.3", + "nyholm/psr7": "^1.5", "php-ffmpeg/php-ffmpeg": "^0.18.0", "phpoffice/phpspreadsheet": "^1.22", + "jolicode/slack-php-api": "^v4.5", "rustici-software/scormcloud-api-v2-client-php": "^2.0", - "jolicode/slack-php-api": "^v4.5" + "symfony/http-client": "^v6.0" }, "require-dev": { "facade/ignition": "^2.17", diff --git a/composer.lock b/composer.lock index 75deced59..541ad55ee 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "bfe1b5fa780d2071379160da507262f0", + "content-hash": "bfa94f9e80d61a885ec49fbe1e6ae225", "packages": [ { "name": "ahmadshah/lucy", @@ -1168,46 +1168,6 @@ ], "time": "2020-09-08T20:04:29+00:00" }, - { - "name": "chartisan/php", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/Chartisan/PHP.git", - "reference": "85d2352077800e9bcb411aec1ff7e4d23eef93a1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Chartisan/PHP/zipball/85d2352077800e9bcb411aec1ff7e4d23eef93a1", - "reference": "85d2352077800e9bcb411aec1ff7e4d23eef93a1", - "shasum": "" - }, - "require": { - "php": ">=7.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Chartisan\\PHP\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Èrik Campobadal Forés", - "email": "soc@erik.cat" - } - ], - "description": "Chartisan's PHP backend", - "support": { - "issues": "https://github.com/Chartisan/PHP/issues", - "source": "https://github.com/Chartisan/PHP/tree/1.2.1" - }, - "time": "2020-11-05T13:13:58+00:00" - }, { "name": "chrisjean/php-ico", "version": "1.0.4", @@ -6448,6 +6408,83 @@ "abandoned": "blade-ui-kit/blade-icons", "time": "2020-11-05T20:40:53+00:00" }, + { + "name": "nyholm/psr7", + "version": "1.5.1", + "source": { + "type": "git", + "url": "https://github.com/Nyholm/psr7.git", + "reference": "f734364e38a876a23be4d906a2a089e1315be18a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Nyholm/psr7/zipball/f734364e38a876a23be4d906a2a089e1315be18a", + "reference": "f734364e38a876a23be4d906a2a089e1315be18a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "php-http/message-factory": "^1.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "http-interop/http-factory-tests": "^0.9", + "php-http/psr7-integration-tests": "^1.0", + "phpunit/phpunit": "^7.5 || 8.5 || 9.4", + "symfony/error-handler": "^4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "Nyholm\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com" + }, + { + "name": "Martijn van der Ven", + "email": "martijn@vanderven.se" + } + ], + "description": "A fast PHP7 implementation of PSR-7", + "homepage": "https://tnyholm.se", + "keywords": [ + "psr-17", + "psr-7" + ], + "support": { + "issues": "https://github.com/Nyholm/psr7/issues", + "source": "https://github.com/Nyholm/psr7/tree/1.5.1" + }, + "funding": [ + { + "url": "https://github.com/Zegnat", + "type": "github" + }, + { + "url": "https://github.com/nyholm", + "type": "github" + } + ], + "time": "2022-06-22T07:13:36+00:00" + }, { "name": "opis/closure", "version": "3.6.3", @@ -9792,6 +9829,171 @@ ], "time": "2022-07-29T07:37:50+00:00" }, + { + "name": "symfony/http-client", + "version": "v6.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client.git", + "reference": "1ef59920a9cedf223e8564ae8ad7608cbe799b4d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client/zipball/1ef59920a9cedf223e8564ae8ad7608cbe799b4d", + "reference": "1ef59920a9cedf223e8564ae8ad7608cbe799b4d", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/log": "^1|^2|^3", + "symfony/http-client-contracts": "^3", + "symfony/service-contracts": "^1.0|^2|^3" + }, + "provide": { + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/http-client-implementation": "1.0", + "symfony/http-client-implementation": "3.0" + }, + "require-dev": { + "amphp/amp": "^2.5", + "amphp/http-client": "^4.2.1", + "amphp/http-tunnel": "^1.0", + "amphp/socket": "^1.1", + "guzzlehttp/promises": "^1.4", + "nyholm/psr7": "^1.0", + "php-http/httplug": "^1.0|^2.0", + "psr/http-client": "^1.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/http-kernel": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0", + "symfony/stopwatch": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "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": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-client/tree/v6.1.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-28T13:40:41+00:00" + }, + { + "name": "symfony/http-client-contracts", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "fd038f08c623ab5d22b26e9ba35afe8c79071800" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/fd038f08c623ab5d22b26e9ba35afe8c79071800", + "reference": "fd038f08c623ab5d22b26e9ba35afe8c79071800", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "suggest": { + "symfony/http-client-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "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": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v3.1.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-04-22T07:30:54+00:00" + }, { "name": "symfony/http-foundation", "version": "v5.4.11",