diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 078ac62c4..6123b91c0 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -42,7 +42,7 @@ ->setRiskyAllowed(true) ->setFinder( (new PhpCsFixer\Finder()) - ->in([__DIR__.'/src', __DIR__.'/examples', __DIR__.'/fixtures']) + ->in([__DIR__.'/demo', __DIR__.'/examples', __DIR__.'/fixtures', __DIR__.'/src']) ->append([__FILE__]) ->notPath('#/Fixtures/#') ) diff --git a/demo/.env b/demo/.env new file mode 100644 index 000000000..52c6ea228 --- /dev/null +++ b/demo/.env @@ -0,0 +1,23 @@ +# In all environments, the following files are loaded if they exist, +# the latter taking precedence over the former: +# +# * .env contains default values for the environment variables needed by the app +# * .env.local uncommitted file with local overrides +# * .env.$APP_ENV committed environment-specific defaults +# * .env.$APP_ENV.local uncommitted environment-specific overrides +# +# Real environment variables win over .env files. +# +# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES. +# https://symfony.com/doc/current/configuration/secrets.html +# +# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2). +# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration + +###> symfony/framework-bundle ### +APP_ENV=dev +APP_SECRET=ccb9dca72dce53c683eaaf775bfdb253 +###< symfony/framework-bundle ### + +CHROMADB_HOST=chromadb +OPENAI_API_KEY=sk-... diff --git a/demo/.env.test b/demo/.env.test new file mode 100644 index 000000000..7da36bf4a --- /dev/null +++ b/demo/.env.test @@ -0,0 +1,7 @@ +# define your env variables for the test env here +KERNEL_CLASS='App\Kernel' +APP_SECRET='$ecretf0rt3st' +SYMFONY_DEPRECATIONS_HELPER=999999 +PANTHER_APP_ENV=panther +PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots +OPENAI_API_KEY=sk-proj-testing1234 diff --git a/demo/.github/PULL_REQUEST_TEMPLATE.md b/demo/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..fcb87228a --- /dev/null +++ b/demo/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,8 @@ +Please do not submit any Pull Requests here. They will be closed. +--- + +Please submit your PR here instead: +https://github.com/symfony/ai + +This repository is what we call a "subtree split": a read-only subset of that main repository. +We're looking forward to your PR there! diff --git a/demo/.github/workflows/close-pull-request.yml b/demo/.github/workflows/close-pull-request.yml new file mode 100644 index 000000000..207153fd5 --- /dev/null +++ b/demo/.github/workflows/close-pull-request.yml @@ -0,0 +1,20 @@ +name: Close Pull Request + +on: + pull_request_target: + types: [opened] + +jobs: + run: + runs-on: ubuntu-latest + steps: + - uses: superbrothers/close-pull-request@v3 + with: + comment: | + Thanks for your Pull Request! We love contributions. + + However, you should instead open your PR on the main repository: + https://github.com/symfony/ai + + This repository is what we call a "subtree split": a read-only subset of that main repository. + We're looking forward to your PR there! diff --git a/demo/.gitignore b/demo/.gitignore new file mode 100644 index 000000000..a94a1b6c1 --- /dev/null +++ b/demo/.gitignore @@ -0,0 +1,30 @@ +###> symfony/framework-bundle ### +/.env.local +/.env.local.php +/.env.*.local +/config/secrets/dev/dev.decrypt.private.php +/config/secrets/prod/prod.decrypt.private.php +/public/bundles/ +/var/ +/vendor/ +###< symfony/framework-bundle ### +###> symfony/asset-mapper ### +/public/assets/ +/assets/vendor/ +###< symfony/asset-mapper ### + +###> php-cs-fixer/shim ### +/.php-cs-fixer.php +/.php-cs-fixer.cache +###< php-cs-fixer/shim ### + +###> phpstan/phpstan ### +phpstan.neon +###< phpstan/phpstan ### + +###> phpunit/phpunit ### +.phpunit.cache +###< phpunit/phpunit ### + +chromadb +coverage diff --git a/demo/LICENSE b/demo/LICENSE new file mode 100644 index 000000000..bc38d714e --- /dev/null +++ b/demo/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2025-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/demo/README.md b/demo/README.md new file mode 100644 index 000000000..ff3ebdcfe --- /dev/null +++ b/demo/README.md @@ -0,0 +1,92 @@ +# Symfony AI - Demo Application + +Symfony application demoing Symfony AI components. + +## Examples + +![demo.png](demo.png) + +## Requirements + +What you need to run this demo: + +* Internet Connection +* Terminal & Browser +* [Git](https://git-scm.com/) & [GitHub Account](https://github.com) +* [Docker](https://www.docker.com/) with [Docker Compose Plugin](https://docs.docker.com/compose/) +* Your Favorite IDE or Editor +* An [OpenAI API Key](https://platform.openai.com/docs/api-reference/create-and-export-an-api-key) + +## Technology + +This small demo sits on top of following technologies: + +* [PHP >= 8.4](https://www.php.net/releases/8.4/en.php) +* [Symfony 7.3 incl. Twig, Asset Mapper & UX](https://symfony.com/) +* [Bootstrap 5](https://getbootstrap.com/docs/5.0/getting-started/introduction/) +* [OpenAI's GPT & Embeddings](https://platform.openai.com/docs/overview) +* [ChromaDB Vector Store](https://www.trychroma.com/) +* [FrankenPHP](https://frankenphp.dev/) + +## Setup + +The setup is split into three parts, the Symfony application, the OpenAI configuration, and initializing the Chroma DB. + +### 1. Symfony App + +Checkout the repository, start the docker environment and install dependencies: + +```shell +git clone git@github.com:symfony/ai-demo.git +cd ai-demo +docker compose up -d +docker compose run composer install +``` + +Now you should be able to open https://localhost/ in your browser, +and the chatbot UI should be available for you to start chatting. + +> [!NOTE] +> You might have to bypass the security warning of your browser with regard to self-signed certificates. + +### 2. OpenAI Configuration + +For using GPT and embedding models from OpenAI, you need to configure an OpenAI API key as environment variable. +This requires you to have an OpenAI account, create a valid API key and set it as `OPENAI_API_KEY` in `.env.local` file. + +```shell +echo "OPENAI_API_KEY='sk-...'" > .env.local +``` + +Verify the success of this step by running the following command: + +```shell +docker compose exec app bin/console debug:dotenv +``` + +You should be able to see the `OPENAI_API_KEY` in the list of environment variables. + +### 3. Chroma DB Initialization + +The [Chroma DB](https://www.trychroma.com/) is a vector store that is used to store embeddings of the chatbot's context. + +To initialize the Chroma DB, you need to run the following command: + +```shell +docker compose exec app bin/console app:blog:embed -vv +``` + +Now you should be able to run the test command and get some results: + +```shell +docker compose exec app bin/console app:blog:query +``` + +**Don't forget to set up the project in your favorite IDE or editor.** + +## Functionality + +* The chatbot application is a simple and small Symfony 7.3 application. +* The UI is coupled to a [Twig LiveComponent](https://symfony.com/bundles/ux-live-component/current/index.html), that integrates different `Chat` implementations on top of the user's session. +* You can reset the chat context by hitting the `Reset` button in the top right corner. +* You find three different usage scenarios in the upper navbar. diff --git a/demo/assets/app.js b/demo/assets/app.js new file mode 100644 index 000000000..f3e7dc105 --- /dev/null +++ b/demo/assets/app.js @@ -0,0 +1,8 @@ +import './bootstrap.js'; +import 'bootstrap/dist/css/bootstrap.min.css'; +import './styles/app.css'; +import './styles/audio.css'; +import './styles/blog.css'; +import './styles/youtube.css'; +import './styles/video.css'; +import './styles/wikipedia.css'; diff --git a/demo/assets/bootstrap.js b/demo/assets/bootstrap.js new file mode 100644 index 000000000..d4e50c919 --- /dev/null +++ b/demo/assets/bootstrap.js @@ -0,0 +1,5 @@ +import { startStimulusApp } from '@symfony/stimulus-bundle'; + +const app = startStimulusApp(); +// register any custom, 3rd party controllers here +// app.register('some_controller_name', SomeImportedController); diff --git a/demo/assets/controllers.json b/demo/assets/controllers.json new file mode 100644 index 000000000..6dd960d42 --- /dev/null +++ b/demo/assets/controllers.json @@ -0,0 +1,30 @@ +{ + "controllers": { + "@symfony/ux-live-component": { + "live": { + "enabled": true, + "fetch": "eager", + "autoimport": { + "@symfony/ux-live-component/dist/live.min.css": true + } + } + }, + "@symfony/ux-turbo": { + "turbo-core": { + "enabled": true, + "fetch": "eager" + }, + "mercure-turbo-stream": { + "enabled": false, + "fetch": "eager" + } + }, + "@symfony/ux-typed": { + "typed": { + "enabled": true, + "fetch": "eager" + } + } + }, + "entrypoints": [] +} diff --git a/demo/assets/controllers/audio_controller.js b/demo/assets/controllers/audio_controller.js new file mode 100644 index 000000000..d251b1721 --- /dev/null +++ b/demo/assets/controllers/audio_controller.js @@ -0,0 +1,83 @@ +import { Controller } from '@hotwired/stimulus'; +import { getComponent } from '@symfony/ux-live-component'; + +export default class extends Controller { + async initialize() { + this.component = await getComponent(this.element); + this.scrollToBottom(); + + const resetButton = document.getElementById('chat-reset'); + resetButton.addEventListener('click', (event) => { + this.component.action('reset'); + }); + + const startButton = document.getElementById('micro-start'); + const stopButton = document.getElementById('micro-stop'); + const botThinkingButton = document.getElementById('bot-thinking'); + + startButton.addEventListener('click', (event) => { + event.preventDefault(); + startButton.classList.add('d-none'); + stopButton.classList.remove('d-none'); + this.startRecording(); + }); + stopButton.addEventListener('click', (event) => { + event.preventDefault(); + stopButton.classList.add('d-none'); + botThinkingButton.classList.remove('d-none'); + this.mediaRecorder.stop(); + }); + + this.component.on('loading.state:started', (e,r) => { + if (r.actions.includes('reset')) { + return; + } + document.getElementById('welcome')?.remove(); + document.getElementById('loading-message').removeAttribute('class'); + this.scrollToBottom(); + }); + + this.component.on('loading.state:finished', () => { + document.getElementById('loading-message').setAttribute('class', 'd-none'); + botThinkingButton.classList.add('d-none'); + startButton.classList.remove('d-none'); + }); + + this.component.on('render:finished', () => { + this.scrollToBottom(); + }); + }; + + async startRecording() { + const stream = await navigator.mediaDevices.getUserMedia({audio: true}); + this.mediaRecorder = new MediaRecorder(stream); + let audioChunks = []; + + this.mediaRecorder.ondataavailable = (event) => { + audioChunks.push(event.data); + }; + + this.mediaRecorder.onstop = async () => { + const audioBlob = new Blob(audioChunks, {type: 'audio/wav'}); + this.mediaRecorder.stream.getAudioTracks().forEach(track => track.stop()); + + const base64String = await this.blobToBase64(audioBlob); + this.component.action('submit', { audio: base64String }); + }; + + this.mediaRecorder.start(); + } + + scrollToBottom() { + const chatBody = document.getElementById('chat-body'); + chatBody.scrollTop = chatBody.scrollHeight; + } + + blobToBase64(blob) { + return new Promise((resolve) => { + const reader = new FileReader(); + reader.readAsDataURL(blob); + reader.onloadend = () => resolve(reader.result.split(',')[1]); + }); + } +} diff --git a/demo/assets/controllers/chat_controller.js b/demo/assets/controllers/chat_controller.js new file mode 100644 index 000000000..d7cc4b87b --- /dev/null +++ b/demo/assets/controllers/chat_controller.js @@ -0,0 +1,59 @@ +import { Controller } from '@hotwired/stimulus'; +import { getComponent } from '@symfony/ux-live-component'; + +export default class extends Controller { + async initialize() { + this.component = await getComponent(this.element); + this.scrollToBottom(); + + const input = document.getElementById('chat-message'); + input.addEventListener('keypress', (event) => { + if (event.key === 'Enter') { + this.submitMessage(); + } + }); + input.focus(); + + const resetButton = document.getElementById('chat-reset'); + resetButton.addEventListener('click', (event) => { + this.component.action('reset'); + }); + + const submitButton = document.getElementById('chat-submit'); + submitButton.addEventListener('click', (event) => { + this.submitMessage(); + }); + + this.component.on('loading.state:started', (e,r) => { + if (r.actions.includes('reset')) { + return; + } + document.getElementById('welcome')?.remove(); + document.getElementById('loading-message').removeAttribute('class'); + this.scrollToBottom(); + }); + + this.component.on('loading.state:finished', () => { + document.getElementById('loading-message').setAttribute('class', 'd-none'); + }); + + this.component.on('render:finished', () => { + this.scrollToBottom(); + }); + }; + + submitMessage() { + const input = document.getElementById('chat-message'); + const message = input.value; + document + .getElementById('loading-message') + .getElementsByClassName('user-message')[0].innerHTML = message; + this.component.action('submit', { message }); + input.value = ''; + } + + scrollToBottom() { + const chatBody = document.getElementById('chat-body'); + chatBody.scrollTop = chatBody.scrollHeight; + } +} diff --git a/demo/assets/controllers/video_controller.js b/demo/assets/controllers/video_controller.js new file mode 100644 index 000000000..d7b8e446a --- /dev/null +++ b/demo/assets/controllers/video_controller.js @@ -0,0 +1,67 @@ +import {Controller} from '@hotwired/stimulus'; +import {getComponent} from '@symfony/ux-live-component'; + +/** + * Heavily inspired by https://github.com/ngxson/smolvlm-realtime-webcam + */ +export default class extends Controller { + async initialize() { + this.component = await getComponent(this.element); + + this.video = document.getElementById('videoFeed'); + this.canvas = document.getElementById('canvas'); + + const input = document.getElementById('chat-message'); + input.addEventListener('keypress', (event) => { + if (event.key === 'Enter') { + this.submitMessage(); + } + }); + input.focus(); + + const submitButton = document.getElementById('chat-submit'); + submitButton.addEventListener('click', (event) => { + this.submitMessage(); + }); + + await this.initCamera(); + }; + + async initCamera() { + try { + this.stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: false }); + this.video.srcObject = this.stream; + console.log('Camera access granted. Ready to start.'); + } catch (err) { + console.error('Error accessing camera:', err); + alert(`Error accessing camera: ${err.name}. Make sure you've granted permission and are on HTTPS or localhost.`); + } + } + + submitMessage() { + const input = document.getElementById('chat-message'); + const instruction = input.value; + const image = this.captureImage(); + + if (null === image) { + console.warn('No image captured. Cannot submit message.'); + return; + } + + this.component.action('submit', { instruction, image }); + input.value = ''; + } + + captureImage() { + if (!this.stream || !this.video.videoWidth) { + console.warn('Video stream not ready for capture.'); + return null; + } + + this.canvas.width = this.video.videoWidth; + this.canvas.height = this.video.videoHeight; + const context = this.canvas.getContext('2d'); + context.drawImage(this.video, 0, 0, this.canvas.width, this.canvas.height); + return this.canvas.toDataURL('image/jpeg', 0.8); + } +} diff --git a/demo/assets/controllers/wikipedia_controller.js b/demo/assets/controllers/wikipedia_controller.js new file mode 100644 index 000000000..d7cc4b87b --- /dev/null +++ b/demo/assets/controllers/wikipedia_controller.js @@ -0,0 +1,59 @@ +import { Controller } from '@hotwired/stimulus'; +import { getComponent } from '@symfony/ux-live-component'; + +export default class extends Controller { + async initialize() { + this.component = await getComponent(this.element); + this.scrollToBottom(); + + const input = document.getElementById('chat-message'); + input.addEventListener('keypress', (event) => { + if (event.key === 'Enter') { + this.submitMessage(); + } + }); + input.focus(); + + const resetButton = document.getElementById('chat-reset'); + resetButton.addEventListener('click', (event) => { + this.component.action('reset'); + }); + + const submitButton = document.getElementById('chat-submit'); + submitButton.addEventListener('click', (event) => { + this.submitMessage(); + }); + + this.component.on('loading.state:started', (e,r) => { + if (r.actions.includes('reset')) { + return; + } + document.getElementById('welcome')?.remove(); + document.getElementById('loading-message').removeAttribute('class'); + this.scrollToBottom(); + }); + + this.component.on('loading.state:finished', () => { + document.getElementById('loading-message').setAttribute('class', 'd-none'); + }); + + this.component.on('render:finished', () => { + this.scrollToBottom(); + }); + }; + + submitMessage() { + const input = document.getElementById('chat-message'); + const message = input.value; + document + .getElementById('loading-message') + .getElementsByClassName('user-message')[0].innerHTML = message; + this.component.action('submit', { message }); + input.value = ''; + } + + scrollToBottom() { + const chatBody = document.getElementById('chat-body'); + chatBody.scrollTop = chatBody.scrollHeight; + } +} diff --git a/demo/assets/controllers/youtube_controller.js b/demo/assets/controllers/youtube_controller.js new file mode 100644 index 000000000..5765367ec --- /dev/null +++ b/demo/assets/controllers/youtube_controller.js @@ -0,0 +1,95 @@ +import { Controller } from '@hotwired/stimulus'; +import { getComponent } from '@symfony/ux-live-component'; + +export default class extends Controller { + async initialize() { + this.component = await getComponent(this.element); + this.scrollToBottom(); + + const input = document.getElementById('chat-message'); + input.addEventListener('keypress', (event) => { + if (event.key === 'Enter') { + this.submitMessage(); + } + }); + input.focus(); + + const resetButton = document.getElementById('chat-reset'); + resetButton.addEventListener('click', (event) => { + this.component.action('reset'); + }); + + if (document.getElementById('welcome')) { + this.initStartButton(); + } + + const submitButton = document.getElementById('chat-submit'); + submitButton.addEventListener('click', (event) => { + this.submitMessage(); + }); + + this.component.on('loading.state:started', (e,r) => { + if (r.actions.includes('reset') || r.actions.includes('start')) { + return; + } + document.getElementById('welcome')?.remove(); + document.getElementById('loading-message').removeAttribute('class'); + this.scrollToBottom(); + }); + + this.component.on('loading.state:finished', () => { + document.getElementById('loading-message').setAttribute('class', 'd-none'); + }); + + this.component.on('render:finished', () => { + this.scrollToBottom(); + if (document.getElementById('welcome')) { + this.initStartButton(); + } + }); + }; + + initStartButton() { + const input = document.getElementById('youtube-id'); + input.disabled = false; + input.value = ''; + input.focus(); + const startButton = document.getElementById('chat-start'); + startButton.disabled = false; + startButton.addEventListener('click', (event) => { + this.start(); + }); + document.getElementById('chat-message').disabled = true; + document.getElementById('chat-submit').disabled = true; + } + + start() { + const input = document.getElementById('youtube-id'); + input.disabled = true; + const videoId = input.value; + const button = document.getElementById('chat-start'); + button.disabled = true; + button.innerHTML = 'Loading...'; + document + .getElementById('loading-message') + .getElementsByClassName('user-message')[0].innerHTML = 'Starting chat for video ID: ' + videoId; + this.component.action('start', { videoId }); + document.getElementById('chat-message').disabled = false; + document.getElementById('chat-submit').disabled = false; + } + + submitMessage() { + const input = document.getElementById('chat-message'); + const message = input.value; + document + .getElementById('loading-message') + .getElementsByClassName('user-message')[0].innerHTML = message; + this.component.action('submit', { message }); + input.value = ''; + } + + scrollToBottom() { + const chatBody = document.getElementById('chat-body'); + chatBody.scrollTop = chatBody.scrollHeight; + } +} diff --git a/demo/assets/icons/bi/youtube.svg b/demo/assets/icons/bi/youtube.svg new file mode 100644 index 000000000..6a25be026 --- /dev/null +++ b/demo/assets/icons/bi/youtube.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/assets/icons/fluent/bot-24-filled.svg b/demo/assets/icons/fluent/bot-24-filled.svg new file mode 100644 index 000000000..5e27ff9c0 --- /dev/null +++ b/demo/assets/icons/fluent/bot-24-filled.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/assets/icons/iconoir/microphone-mute-solid.svg b/demo/assets/icons/iconoir/microphone-mute-solid.svg new file mode 100644 index 000000000..3d6f673c3 --- /dev/null +++ b/demo/assets/icons/iconoir/microphone-mute-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/assets/icons/iconoir/microphone-solid.svg b/demo/assets/icons/iconoir/microphone-solid.svg new file mode 100644 index 000000000..32c72a87c --- /dev/null +++ b/demo/assets/icons/iconoir/microphone-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/assets/icons/iconoir/timer-solid.svg b/demo/assets/icons/iconoir/timer-solid.svg new file mode 100644 index 000000000..7a7950076 --- /dev/null +++ b/demo/assets/icons/iconoir/timer-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/assets/icons/material-symbols/cancel.svg b/demo/assets/icons/material-symbols/cancel.svg new file mode 100644 index 000000000..7a69e8e34 --- /dev/null +++ b/demo/assets/icons/material-symbols/cancel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/assets/icons/mdi/github.svg b/demo/assets/icons/mdi/github.svg new file mode 100644 index 000000000..ae68105b7 --- /dev/null +++ b/demo/assets/icons/mdi/github.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/assets/icons/mdi/symfony.svg b/demo/assets/icons/mdi/symfony.svg new file mode 100644 index 000000000..5ed86808f --- /dev/null +++ b/demo/assets/icons/mdi/symfony.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/assets/icons/mdi/wikipedia.svg b/demo/assets/icons/mdi/wikipedia.svg new file mode 100644 index 000000000..4b79068e1 --- /dev/null +++ b/demo/assets/icons/mdi/wikipedia.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/assets/icons/mingcute/send-fill.svg b/demo/assets/icons/mingcute/send-fill.svg new file mode 100644 index 000000000..d1229e823 --- /dev/null +++ b/demo/assets/icons/mingcute/send-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/assets/icons/solar/code-linear.svg b/demo/assets/icons/solar/code-linear.svg new file mode 100644 index 000000000..96a0d8ece --- /dev/null +++ b/demo/assets/icons/solar/code-linear.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/assets/icons/solar/user-bold.svg b/demo/assets/icons/solar/user-bold.svg new file mode 100644 index 000000000..48e20b78b --- /dev/null +++ b/demo/assets/icons/solar/user-bold.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/assets/icons/symfony.svg b/demo/assets/icons/symfony.svg new file mode 100644 index 000000000..93fb329cc --- /dev/null +++ b/demo/assets/icons/symfony.svg @@ -0,0 +1 @@ + diff --git a/demo/assets/icons/tabler/video-filled.svg b/demo/assets/icons/tabler/video-filled.svg new file mode 100644 index 000000000..c16aab2ae --- /dev/null +++ b/demo/assets/icons/tabler/video-filled.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/demo/assets/styles/app.css b/demo/assets/styles/app.css new file mode 100644 index 000000000..f6151b1d8 --- /dev/null +++ b/demo/assets/styles/app.css @@ -0,0 +1,65 @@ +body { + min-height: 100vh; + + footer, footer a { + color: #6c757d; + } +} + +.index { + .card-img-top { + text-align: center; + } +} + +.chat { + .card { + border: 1px solid #bcbcbc; + background-color: rgba(250, 250, 250, 0.9); + } + + .card-header { + background: #efefef; + + svg { + margin-top: -2px; + } + } + + .card-body { + height: 700px; + + .user-message { + border-radius: 10px 10px 0 10px; + color: #292929; + } + + .bot-message { + border-radius: 10px 10px 10px 0; + color: #292929; + + &.loading { + color: rgba(41, 41, 41, 0.5); + } + + p { + margin-bottom: 0; + } + } + + .avatar { + width: 50px; + height: 50px; + border: 2px solid white; + } + } + + .card-footer { + background: #efefef; + + input:focus { + outline: none !important; + box-shadow: none !important; + } + } +} diff --git a/demo/assets/styles/audio.css b/demo/assets/styles/audio.css new file mode 100644 index 000000000..f1584dfab --- /dev/null +++ b/demo/assets/styles/audio.css @@ -0,0 +1,73 @@ +.audio { + body&, .card-img-top { + background: #df662f; + background: linear-gradient(0deg, #df662f 0%, #a80a1d 100%); + } + + .card-img-top { + color: #ffffff; + } + + &.chat { + .user-message { + background: #df662f; + color: #ffffff; + + #loading-message & { + color: rgba(255, 255, 255, 0.7); + } + } + + .bot-message { + color: #ffffff; + background: #215d9a; + + &.loading { + color: rgba(255, 255, 255, 0.5); + } + + a { + color: #c8d8ef; + + &:hover { + color: #ffffff; + } + } + + code { + color: #ffb1ca; + } + } + + .avatar { + &.bot { + outline: 1px solid #c0dbf4; + background: #c0dbf4; + } + + &.user { + outline: 1px solid #f3b396; + background: #f3b396; + } + } + + #welcome h4 { + color: #2c5282; + } + + #chat-reset, #chat-submit { + &:hover { + background: #a80a1d; + border-color: #a80a1d; + } + } + } + + footer { + color: #ffffff; + + a { + color: #ffffff; + } + } +} diff --git a/demo/assets/styles/blog.css b/demo/assets/styles/blog.css new file mode 100644 index 000000000..7750ecc9d --- /dev/null +++ b/demo/assets/styles/blog.css @@ -0,0 +1,61 @@ +.blog { + body&, .card-img-top { + background: #2c5282; + background: linear-gradient(0deg, #2c5282 0%, #3c366b 100%); + } + + .card-img-top { + color: #ffffff; + } + + &.chat { + .user-message { + background: #d5054e; + color: #ffffff; + } + + .bot-message { + color: #ffffff; + background: #3182ce; + + &.loading { + color: rgba(255, 255, 255, 0.5); + } + + a { + color: #c8d8ef; + + &:hover { + color: #ffffff; + } + } + + code { + color: #ffb1ca; + } + } + + .avatar { + &.bot { + outline: 1px solid #b8d8fb; + background: #b8d8fb; + } + + &.user { + outline: 1px solid #ffb1ca; + background: #ffb1ca; + } + } + + #welcome h4 { + color: #2c5282; + } + + #chat-reset, #chat-submit { + &:hover { + background: #d5054e; + border-color: #d5054e; + } + } + } +} diff --git a/demo/assets/styles/video.css b/demo/assets/styles/video.css new file mode 100644 index 000000000..98c3c78ac --- /dev/null +++ b/demo/assets/styles/video.css @@ -0,0 +1,27 @@ +.video { + body&, .card-img-top { + background: #26931e; + background: linear-gradient(0deg, #186361 0%, #26931e 100%); + } + + .card-img-top { + color: #ffffff; + } + + &.chat { + #chat-submit { + &:hover { + background: #186361; + border-color: #186361; + } + } + } + + footer { + color: #ffffff; + + a { + color: #ffffff; + } + } +} diff --git a/demo/assets/styles/wikipedia.css b/demo/assets/styles/wikipedia.css new file mode 100644 index 000000000..a1eec154f --- /dev/null +++ b/demo/assets/styles/wikipedia.css @@ -0,0 +1,31 @@ +.wikipedia { + body&, .card-img-top { + background: url('/wiki.png') no-repeat right 50px bottom 50px fixed, linear-gradient(0deg, rgb(246, 246, 246) 0%, rgb(197, 197, 197) 100%); + } + + &.chat { + .card-body { + background-image: linear-gradient(135deg, #f2f2f2 16.67%, #ebebeb 16.67%, #ebebeb 50%, #f2f2f2 50%, #f2f2f2 66.67%, #ebebeb 66.67%, #ebebeb 100%); + background-size: 21.21px 21.21px; + } + + .user-message { + background: #ffffff; + } + + .bot-message { + background: #ffffff; + + a { + color: #3e2926; + } + } + + .avatar { + &.bot, &.user { + outline: 1px solid #eaeaea; + background: #eaeaea; + } + } + } +} diff --git a/demo/assets/styles/youtube.css b/demo/assets/styles/youtube.css new file mode 100644 index 000000000..85967ea1f --- /dev/null +++ b/demo/assets/styles/youtube.css @@ -0,0 +1,49 @@ +.youtube { + body&, .card-img-top { + background: rgb(34,34,34); + background: linear-gradient(0deg, rgb(0, 0, 0) 0%, rgb(71, 71, 71) 100%); + } + + .card-img-top { + color: #ff0000; + } + + &.chat { + .user-message { + background: #3e2926; + color: #fafafa; + } + + .bot-message { + color: #ffffff; + background: #df3535; + + &.loading { + color: rgba(255, 255, 255, 0.5); + } + } + + .avatar { + &.bot { + outline: 1px solid #ffcccc; + background: #ffcccc; + } + + &.user { + outline: 1px solid #9e8282; + background: #9e8282; + } + } + + #welcome h4 { + color: #ff0000; + } + + #chat-reset, #chat-submit { + &:hover { + background: #ff0000; + border-color: #ff0000; + } + } + } +} diff --git a/demo/bin/console b/demo/bin/console new file mode 100755 index 000000000..d8d530e2c --- /dev/null +++ b/demo/bin/console @@ -0,0 +1,21 @@ +#!/usr/bin/env php +=8.4", + "ext-ctype": "*", + "ext-iconv": "*", + "codewithkyrian/chromadb-php": "^0.4.0", + "league/commonmark": "^2.7", + "runtime/frankenphp-symfony": "^0.2.0", + "symfony/ai-bundle": "@dev", + "symfony/asset": "7.3.*", + "symfony/asset-mapper": "7.3.*", + "symfony/clock": "7.3.*", + "symfony/console": "7.3.*", + "symfony/css-selector": "7.3.*", + "symfony/dom-crawler": "7.3.*", + "symfony/dotenv": "7.3.*", + "symfony/flex": "^2.5", + "symfony/framework-bundle": "7.3.*", + "symfony/http-client": "7.3.*", + "symfony/monolog-bundle": "^3.10", + "symfony/runtime": "7.3.*", + "symfony/twig-bundle": "7.3.*", + "symfony/uid": "7.3.*", + "symfony/ux-icons": "^2.25", + "symfony/ux-live-component": "^2.25", + "symfony/ux-turbo": "^2.25", + "symfony/ux-typed": "^2.25", + "symfony/yaml": "7.3.*", + "twig/extra-bundle": "^3.21", + "twig/markdown-extra": "^3.21", + "twig/twig": "^3.21" + }, + "replace": { + "symfony/polyfill-ctype": "*", + "symfony/polyfill-iconv": "*", + "symfony/polyfill-mbstring": "*", + "symfony/polyfill-php72": "*", + "symfony/polyfill-php73": "*", + "symfony/polyfill-php74": "*", + "symfony/polyfill-php80": "*", + "symfony/polyfill-php81": "*", + "symfony/polyfill-php82": "*", + "symfony/polyfill-php83": "*", + "symfony/polyfill-php84": "*" + }, + "conflict": { + "symfony/symfony": "*" + }, + "require-dev": { + "nyholm/nsa": "^1.3", + "php-cs-fixer/shim": "^3.75", + "phpstan/phpstan": "^2.1", + "phpunit/phpunit": "^11.5", + "symfony/browser-kit": "7.3.*", + "symfony/debug-bundle": "7.3.*", + "symfony/stopwatch": "7.3.*", + "symfony/web-profiler-bundle": "7.3.*" + }, + "config": { + "allow-plugins": { + "php-http/discovery": true, + "symfony/flex": true, + "symfony/runtime": true + }, + "platform": { + "php": "8.4.7" + }, + "sort-packages": true + }, + "extra": { + "symfony": { + "allow-contrib": false, + "require": "7.3.*" + } + }, + "autoload": { + "psr-4": { + "App\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "App\\Tests\\": "tests/" + } + }, + "scripts": { + "post-install-cmd": [ + "@auto-scripts" + ], + "post-update-cmd": [ + "@auto-scripts" + ], + "auto-scripts": { + "cache:clear": "symfony-cmd", + "assets:install %PUBLIC_DIR%": "symfony-cmd", + "importmap:install": "symfony-cmd" + }, + "pipeline": [ + "composer validate --strict", + "php -l src/**/*.php tests/**/*.php", + "bin/console lint:twig templates", + "bin/console lint:yaml config", + "bin/console lint:container", + "PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix", + "phpstan analyse", + "XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-html=coverage" + ] + }, + "repositories": [ + { "type": "path", "url": "../src/agent" }, + { "type": "path", "url": "../src/ai-bundle" }, + { "type": "path", "url": "../src/platform" }, + { "type": "path", "url": "../src/store" } + ] +} diff --git a/demo/composer.lock b/demo/composer.lock new file mode 100644 index 000000000..c11bbca49 --- /dev/null +++ b/demo/composer.lock @@ -0,0 +1,8667 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "afb427389b43f337697f38a12fb4c765", + "packages": [ + { + "name": "codewithkyrian/chromadb-php", + "version": "0.4.0", + "source": { + "type": "git", + "url": "https://github.com/CodeWithKyrian/chromadb-php.git", + "reference": "53bb269c6e76ae9976b0750eed3731d1fdcb9ea5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CodeWithKyrian/chromadb-php/zipball/53bb269c6e76ae9976b0750eed3731d1fdcb9ea5", + "reference": "53bb269c6e76ae9976b0750eed3731d1fdcb9ea5", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^7.0", + "php": "^8.1" + }, + "require-dev": { + "mockery/mockery": "^1.6", + "pestphp/pest": "^2.19", + "symfony/var-dumper": "^6.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Codewithkyrian\\ChromaDB\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kyrian Obikwelu", + "email": "kyrianobikwelu@gmail.com" + } + ], + "description": "A PHP client for the Chroma Open Source Embedding Database", + "keywords": [ + "chroma", + "chromadb", + "database", + "embedding", + "open-source", + "php", + "search", + "semantic", + "vectors" + ], + "support": { + "issues": "https://github.com/CodeWithKyrian/chromadb-php/issues", + "source": "https://github.com/CodeWithKyrian/chromadb-php/tree/0.4.0" + }, + "time": "2025-03-09T16:58:50+00:00" + }, + { + "name": "composer/semver", + "version": "3.4.3", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.4.3" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-09-19T14:15:21+00:00" + }, + { + "name": "dflydev/dot-access-data", + "version": "v3.0.3", + "source": { + "type": "git", + "url": "https://github.com/dflydev/dflydev-dot-access-data.git", + "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/a23a2bf4f31d3518f3ecb38660c95715dfead60f", + "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.42", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.3", + "scrutinizer/ocular": "1.6.0", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Dflydev\\DotAccessData\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dragonfly Development Inc.", + "email": "info@dflydev.com", + "homepage": "http://dflydev.com" + }, + { + "name": "Beau Simensen", + "email": "beau@dflydev.com", + "homepage": "http://beausimensen.com" + }, + { + "name": "Carlos Frutos", + "email": "carlos@kiwing.it", + "homepage": "https://github.com/cfrutos" + }, + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com" + } + ], + "description": "Given a deep data structure, access data by dot notation.", + "homepage": "https://github.com/dflydev/dflydev-dot-access-data", + "keywords": [ + "access", + "data", + "dot", + "notation" + ], + "support": { + "issues": "https://github.com/dflydev/dflydev-dot-access-data/issues", + "source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.3" + }, + "time": "2024-07-08T12:26:09+00:00" + }, + { + "name": "doctrine/deprecations", + "version": "1.1.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", + "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "phpunit/phpunit": "<=7.5 || >=13" + }, + "require-dev": { + "doctrine/coding-standard": "^9 || ^12 || ^13", + "phpstan/phpstan": "1.4.10 || 2.1.11", + "phpstan/phpstan-phpunit": "^1.0 || ^2", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12", + "psr/log": "^1 || ^2 || ^3" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/1.1.5" + }, + "time": "2025-04-07T20:06:18+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.9.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", + "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5.3 || ^2.0.3", + "guzzlehttp/psr7": "^2.7.0", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "guzzle/client-integration-tests": "3.0.2", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.9.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2025-03-27T13:37:11+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c", + "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.2.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2025-03-27T13:27:01+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.7.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16", + "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.7.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2025-03-27T12:30:47+00:00" + }, + { + "name": "league/commonmark", + "version": "2.7.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/commonmark.git", + "reference": "6fbb36d44824ed4091adbcf4c7d4a3923cdb3405" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/6fbb36d44824ed4091adbcf4c7d4a3923cdb3405", + "reference": "6fbb36d44824ed4091adbcf4c7d4a3923cdb3405", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "league/config": "^1.1.1", + "php": "^7.4 || ^8.0", + "psr/event-dispatcher": "^1.0", + "symfony/deprecation-contracts": "^2.1 || ^3.0", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "cebe/markdown": "^1.0", + "commonmark/cmark": "0.31.1", + "commonmark/commonmark.js": "0.31.1", + "composer/package-versions-deprecated": "^1.8", + "embed/embed": "^4.4", + "erusev/parsedown": "^1.0", + "ext-json": "*", + "github/gfm": "0.29.0", + "michelf/php-markdown": "^1.4 || ^2.0", + "nyholm/psr7": "^1.5", + "phpstan/phpstan": "^1.8.2", + "phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0", + "scrutinizer/ocular": "^1.8.1", + "symfony/finder": "^5.3 | ^6.0 | ^7.0", + "symfony/process": "^5.4 | ^6.0 | ^7.0", + "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0", + "unleashedtech/php-coding-standard": "^3.1.1", + "vimeo/psalm": "^4.24.0 || ^5.0.0" + }, + "suggest": { + "symfony/yaml": "v2.3+ required if using the Front Matter extension" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "League\\CommonMark\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and GitHub-Flavored Markdown (GFM)", + "homepage": "https://commonmark.thephpleague.com", + "keywords": [ + "commonmark", + "flavored", + "gfm", + "github", + "github-flavored", + "markdown", + "md", + "parser" + ], + "support": { + "docs": "https://commonmark.thephpleague.com/", + "forum": "https://github.com/thephpleague/commonmark/discussions", + "issues": "https://github.com/thephpleague/commonmark/issues", + "rss": "https://github.com/thephpleague/commonmark/releases.atom", + "source": "https://github.com/thephpleague/commonmark" + }, + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/commonmark", + "type": "tidelift" + } + ], + "time": "2025-05-05T12:20:28+00:00" + }, + { + "name": "league/config", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/config.git", + "reference": "754b3604fb2984c71f4af4a9cbe7b57f346ec1f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/config/zipball/754b3604fb2984c71f4af4a9cbe7b57f346ec1f3", + "reference": "754b3604fb2984c71f4af4a9cbe7b57f346ec1f3", + "shasum": "" + }, + "require": { + "dflydev/dot-access-data": "^3.0.1", + "nette/schema": "^1.2", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.8.2", + "phpunit/phpunit": "^9.5.5", + "scrutinizer/ocular": "^1.8.1", + "unleashedtech/php-coding-standard": "^3.1", + "vimeo/psalm": "^4.7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Config\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Define configuration arrays with strict schemas and access values with dot notation", + "homepage": "https://config.thephpleague.com", + "keywords": [ + "array", + "config", + "configuration", + "dot", + "dot-access", + "nested", + "schema" + ], + "support": { + "docs": "https://config.thephpleague.com/", + "issues": "https://github.com/thephpleague/config/issues", + "rss": "https://github.com/thephpleague/config/releases.atom", + "source": "https://github.com/thephpleague/config" + }, + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + } + ], + "time": "2022-12-11T20:36:23+00:00" + }, + { + "name": "masterminds/html5", + "version": "2.9.0", + "source": { + "type": "git", + "url": "https://github.com/Masterminds/html5-php.git", + "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", + "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Masterminds\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matt Butcher", + "email": "technosophos@gmail.com" + }, + { + "name": "Matt Farina", + "email": "matt@mattfarina.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" + } + ], + "description": "An HTML5 parser and serializer.", + "homepage": "http://masterminds.github.io/html5-php", + "keywords": [ + "HTML5", + "dom", + "html", + "parser", + "querypath", + "serializer", + "xml" + ], + "support": { + "issues": "https://github.com/Masterminds/html5-php/issues", + "source": "https://github.com/Masterminds/html5-php/tree/2.9.0" + }, + "time": "2024-03-31T07:05:07+00:00" + }, + { + "name": "monolog/monolog", + "version": "3.9.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/10d85740180ecba7896c87e06a166e0c95a0e3b6", + "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/log": "^2.0 || ^3.0" + }, + "provide": { + "psr/log-implementation": "3.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^3.0", + "doctrine/couchdb": "~1.0@dev", + "elasticsearch/elasticsearch": "^7 || ^8", + "ext-json": "*", + "graylog2/gelf-php": "^1.4.2 || ^2.0", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/psr7": "^2.2", + "mongodb/mongodb": "^1.8", + "php-amqplib/php-amqplib": "~2.4 || ^3", + "php-console/php-console": "^3.1.8", + "phpstan/phpstan": "^2", + "phpstan/phpstan-deprecation-rules": "^2", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "^10.5.17 || ^11.0.7", + "predis/predis": "^1.1 || ^2", + "rollbar/rollbar": "^4.0", + "ruflin/elastica": "^7 || ^8", + "symfony/mailer": "^5.4 || ^6", + "symfony/mime": "^5.4 || ^6" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-openssl": "Required to send log messages using SSL", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "https://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/3.9.0" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2025-03-24T10:02:05+00:00" + }, + { + "name": "nette/schema", + "version": "v1.3.2", + "source": { + "type": "git", + "url": "https://github.com/nette/schema.git", + "reference": "da801d52f0354f70a638673c4a0f04e16529431d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/schema/zipball/da801d52f0354f70a638673c4a0f04e16529431d", + "reference": "da801d52f0354f70a638673c4a0f04e16529431d", + "shasum": "" + }, + "require": { + "nette/utils": "^4.0", + "php": "8.1 - 8.4" + }, + "require-dev": { + "nette/tester": "^2.5.2", + "phpstan/phpstan-nette": "^1.0", + "tracy/tracy": "^2.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "📐 Nette Schema: validating data structures against a given Schema.", + "homepage": "https://nette.org", + "keywords": [ + "config", + "nette" + ], + "support": { + "issues": "https://github.com/nette/schema/issues", + "source": "https://github.com/nette/schema/tree/v1.3.2" + }, + "time": "2024-10-06T23:10:23+00:00" + }, + { + "name": "nette/utils", + "version": "v4.0.7", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/e67c4061eb40b9c113b218214e42cb5a0dda28f2", + "reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2", + "shasum": "" + }, + "require": { + "php": "8.0 - 8.4" + }, + "conflict": { + "nette/finder": "<3", + "nette/schema": "<1.2.2" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "dev-master", + "nette/tester": "^2.5", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.9" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "support": { + "issues": "https://github.com/nette/utils/issues", + "source": "https://github.com/nette/utils/tree/v4.0.7" + }, + "time": "2025-06-03T04:55:08+00:00" + }, + { + "name": "oskarstark/enum-helper", + "version": "1.6.1", + "source": { + "type": "git", + "url": "https://github.com/OskarStark/enum-helper.git", + "reference": "adccc8c099db61cb26497a1e1987fc95ebda02a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/OskarStark/enum-helper/zipball/adccc8c099db61cb26497a1e1987fc95ebda02a9", + "reference": "adccc8c099db61cb26497a1e1987fc95ebda02a9", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "conflict": { + "phpunit/phpunit": "<10" + }, + "require-dev": { + "ergebnis/php-cs-fixer-config": "^5.16", + "phpstan/phpstan": "^1.11.8", + "phpunit/phpunit": "^10.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "OskarStark\\Enum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Oskar Stark", + "email": "oskarstark@googlemail.com" + } + ], + "description": "This library provides helpers for several enum operations", + "keywords": [ + "enum" + ], + "support": { + "issues": "https://github.com/OskarStark/enum-helper/issues", + "source": "https://github.com/OskarStark/enum-helper/tree/1.6.1" + }, + "time": "2025-03-26T16:14:22+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "5.6.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "92dde6a5919e34835c506ac8c523ef095a95ed62" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/92dde6a5919e34835c506ac8c523ef095a95ed62", + "reference": "92dde6a5919e34835c506ac8c523ef095a95ed62", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.1", + "ext-filter": "*", + "php": "^7.4 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.7", + "phpstan/phpdoc-parser": "^1.7|^2.0", + "webmozart/assert": "^1.9.1" + }, + "require-dev": { + "mockery/mockery": "~1.3.5 || ~1.6.0", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-webmozart-assert": "^1.2", + "phpunit/phpunit": "^9.5", + "psalm/phar": "^5.26" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.2" + }, + "time": "2025-04-13T19:20:35+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.10.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a", + "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.0", + "php": "^7.3 || ^8.0", + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^1.18|^2.0" + }, + "require-dev": { + "ext-tokenizer": "*", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.13.9", + "vimeo/psalm": "^4.25" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0" + }, + "time": "2024-11-09T15:12:26+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "9b30d6fd026b2c132b3985ce6b23bec09ab3aa68" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/9b30d6fd026b2c132b3985ce6b23bec09ab3aa68", + "reference": "9b30d6fd026b2c132b3985ce6b23bec09ab3aa68", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^5.3.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.1.0" + }, + "time": "2025-02-19T13:28:12+00:00" + }, + { + "name": "psr/cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/3.0.0" + }, + "time": "2021-02-03T23:26:27+00:00" + }, + { + "name": "psr/clock", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], + "support": { + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" + }, + "time": "2022-11-25T14:36:26+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "time": "2024-04-15T12:06:14+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, + { + "name": "psr/log", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.2" + }, + "time": "2024-09-11T13:17:53+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "runtime/frankenphp-symfony", + "version": "0.2.0", + "source": { + "type": "git", + "url": "https://github.com/php-runtime/frankenphp-symfony.git", + "reference": "56822c3631d9522a3136a4c33082d006bdfe4bad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-runtime/frankenphp-symfony/zipball/56822c3631d9522a3136a4c33082d006bdfe4bad", + "reference": "56822c3631d9522a3136a4c33082d006bdfe4bad", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0", + "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0", + "symfony/runtime": "^5.4 || ^6.0 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Runtime\\FrankenPhpSymfony\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "kevin@dunglas.dev" + } + ], + "description": "FrankenPHP runtime for Symfony", + "support": { + "issues": "https://github.com/php-runtime/frankenphp-symfony/issues", + "source": "https://github.com/php-runtime/frankenphp-symfony/tree/0.2.0" + }, + "funding": [ + { + "url": "https://github.com/nyholm", + "type": "github" + } + ], + "time": "2023-12-12T12:06:11+00:00" + }, + { + "name": "symfony/ai-agent", + "version": "dev-integrate-demo", + "dist": { + "type": "path", + "url": "../src/agent", + "reference": "291833affae32075b3c79790a1a9c5b197fd9b95" + }, + "require": { + "ext-fileinfo": "*", + "php": ">=8.2", + "phpdocumentor/reflection-docblock": "^5.4", + "phpstan/phpdoc-parser": "^2.1", + "psr/log": "^3.0", + "symfony/ai-platform": "@dev", + "symfony/clock": "^6.4 || ^7.1", + "symfony/http-client": "^6.4 || ^7.1", + "symfony/property-access": "^6.4 || ^7.1", + "symfony/property-info": "^6.4 || ^7.1", + "symfony/serializer": "^6.4 || ^7.1", + "symfony/type-info": "^7.2.3" + }, + "require-dev": { + "phpstan/phpstan": "^2.0", + "phpunit/phpunit": "^11.5.13", + "symfony/ai-store": "@dev", + "symfony/css-selector": "^6.4 || ^7.1", + "symfony/dom-crawler": "^6.4 || ^7.1", + "symfony/event-dispatcher": "^6.4 || ^7.1" + }, + "suggest": { + "symfony/ai-store": "For using Similarity Search with a vector store.", + "symfony/css-selector": "For using the YouTube transcription tool.", + "symfony/dom-crawler": "For using the YouTube transcription tool." + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/ai", + "url": "https://github.com/symfony/ai" + } + }, + "autoload": { + "psr-4": { + "Symfony\\AI\\Agent\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Symfony\\AI\\Agent\\Tests\\": "tests/", + "Symfony\\AI\\Fixtures\\": "../../fixtures" + } + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christopher Hertel", + "email": "mail@christopher-hertel.de" + }, + { + "name": "Oskar Stark", + "email": "oskarstark@googlemail.com" + } + ], + "description": "PHP library for building agentic applications.", + "keywords": [ + "agent", + "ai", + "llm" + ], + "transport-options": { + "relative": true + } + }, + { + "name": "symfony/ai-bundle", + "version": "dev-integrate-demo", + "dist": { + "type": "path", + "url": "../src/ai-bundle", + "reference": "b86468029dddc20ded4eda60e1250e3aed68034d" + }, + "require": { + "php": ">=8.2", + "symfony/ai-agent": "@dev", + "symfony/ai-platform": "@dev", + "symfony/ai-store": "@dev", + "symfony/config": "^6.4 || ^7.0", + "symfony/dependency-injection": "^6.4 || ^7.0", + "symfony/framework-bundle": "^6.4 || ^7.0", + "symfony/string": "^6.4 || ^7.0" + }, + "require-dev": { + "phpstan/phpstan": "^2.1", + "phpunit/phpunit": "^11.5" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\AI\\AIBundle\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Symfony\\AI\\AIBundle\\Tests\\": "tests/" + } + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christopher Hertel", + "email": "mail@christopher-hertel.de" + }, + { + "name": "Oskar Stark", + "email": "oskarstark@googlemail.com" + } + ], + "description": "Integration bundle for Symfony AI components", + "transport-options": { + "relative": true + } + }, + { + "name": "symfony/ai-platform", + "version": "dev-integrate-demo", + "dist": { + "type": "path", + "url": "../src/platform", + "reference": "9fe0bfa258e784fc869062f53868ffc836f5106d" + }, + "require": { + "ext-fileinfo": "*", + "oskarstark/enum-helper": "^1.5", + "php": ">=8.2", + "phpdocumentor/reflection-docblock": "^5.4", + "phpstan/phpdoc-parser": "^2.1", + "psr/log": "^3.0", + "symfony/clock": "^6.4 || ^7.1", + "symfony/http-client": "^6.4 || ^7.1", + "symfony/property-access": "^6.4 || ^7.1", + "symfony/property-info": "^6.4 || ^7.1", + "symfony/serializer": "^6.4 || ^7.1", + "symfony/type-info": "^7.2.3", + "webmozart/assert": "^1.11" + }, + "require-dev": { + "async-aws/bedrock-runtime": "^0.1.0", + "codewithkyrian/transformers": "^0.5.3", + "phpstan/phpstan": "^2.1.17", + "phpstan/phpstan-symfony": "^2.0.6", + "phpstan/phpstan-webmozart-assert": "^2.0.0", + "phpunit/phpunit": "^11.5", + "symfony/ai-agent": "@dev", + "symfony/console": "^6.4 || ^7.1", + "symfony/dotenv": "^6.4 || ^7.1", + "symfony/event-dispatcher": "^6.4 || ^7.1", + "symfony/finder": "^6.4 || ^7.1", + "symfony/process": "^6.4 || ^7.1", + "symfony/var-dumper": "^6.4 || ^7.1" + }, + "suggest": { + "async-aws/bedrock-runtime": "For using the Bedrock platform.", + "codewithkyrian/transformers": "For using the TransformersPHP with FFI to run models in PHP." + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/ai", + "url": "https://github.com/symfony/ai" + } + }, + "autoload": { + "psr-4": { + "Symfony\\AI\\Platform\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Symfony\\AI\\Platform\\Tests\\": "tests/", + "Symfony\\AI\\Fixtures\\": "../../fixtures" + } + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christopher Hertel", + "email": "mail@christopher-hertel.de" + }, + { + "name": "Oskar Stark", + "email": "oskarstark@googlemail.com" + } + ], + "description": "PHP library for interacting with AI platform provider.", + "keywords": [ + "ai", + "huggingface", + "inference", + "transformers" + ], + "transport-options": { + "relative": true + } + }, + { + "name": "symfony/ai-store", + "version": "dev-integrate-demo", + "dist": { + "type": "path", + "url": "../src/store", + "reference": "8c2f8bb841d392d3981d76c8485193abb9dc00b9" + }, + "require": { + "ext-fileinfo": "*", + "php": ">=8.2", + "psr/log": "^3.0", + "symfony/ai-platform": "@dev", + "symfony/clock": "^6.4 || ^7.1", + "symfony/http-client": "^6.4 || ^7.1", + "symfony/uid": "^6.4 || ^7.1", + "webmozart/assert": "^1.11" + }, + "conflict": { + "mongodb/mongodb": "<1.21" + }, + "require-dev": { + "codewithkyrian/chromadb-php": "^0.2.1 || ^0.3 || ^0.4", + "mongodb/mongodb": "^1.21", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-webmozart-assert": "^2.0", + "phpunit/phpunit": "^11.5", + "probots-io/pinecone-php": "^1.0" + }, + "suggest": { + "codewithkyrian/chromadb-php": "For using the ChromaDB as retrieval vector store.", + "mongodb/mongodb": "For using MongoDB Atlas as retrieval vector store.", + "probots-io/pinecone-php": "For using the Pinecone as retrieval vector store." + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/ai", + "url": "https://github.com/symfony/ai" + } + }, + "autoload": { + "psr-4": { + "Symfony\\AI\\Store\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Symfony\\AI\\Store\\Tests\\": "tests/" + } + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christopher Hertel", + "email": "mail@christopher-hertel.de" + }, + { + "name": "Oskar Stark", + "email": "oskarstark@googlemail.com" + } + ], + "description": "PHP library for abstracting interaction with data stores in AI applications.", + "keywords": [ + "ai", + "chromadb", + "mongodb", + "pinecone" + ], + "transport-options": { + "relative": true + } + }, + { + "name": "symfony/asset", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/asset.git", + "reference": "56c4d9f759247c4e07d8549e3baf7493cb9c3e4b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/asset/zipball/56c4d9f759247c4e07d8549e3baf7493cb9c3e4b", + "reference": "56c4d9f759247c4e07d8549e3baf7493cb9c3e4b", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "conflict": { + "symfony/http-foundation": "<6.4" + }, + "require-dev": { + "symfony/http-client": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Asset\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Manages URL generation and versioning of web assets such as CSS stylesheets, JavaScript files and image files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/asset/tree/v7.3.0" + }, + "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": "2025-03-05T10:15:41+00:00" + }, + { + "name": "symfony/asset-mapper", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/asset-mapper.git", + "reference": "6516f38868b75c4902ea72a9fa44967628375ae7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/asset-mapper/zipball/6516f38868b75c4902ea72a9fa44967628375ae7", + "reference": "6516f38868b75c4902ea72a9fa44967628375ae7", + "shasum": "" + }, + "require": { + "composer/semver": "^3.0", + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/filesystem": "^7.1", + "symfony/http-client": "^6.4|^7.0" + }, + "conflict": { + "symfony/framework-bundle": "<6.4" + }, + "require-dev": { + "symfony/asset": "^6.4|^7.0", + "symfony/browser-kit": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/event-dispatcher-contracts": "^3.0", + "symfony/finder": "^6.4|^7.0", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/web-link": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\AssetMapper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Maps directories of assets & makes them available in a public directory with versioned filenames.", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/asset-mapper/tree/v7.3.0" + }, + "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": "2025-05-24T14:05:12+00:00" + }, + { + "name": "symfony/cache", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache.git", + "reference": "c4b217b578c11ec764867aa0c73e602c602965de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache/zipball/c4b217b578c11ec764867aa0c73e602c602965de", + "reference": "c4b217b578c11ec764867aa0c73e602c602965de", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/cache": "^2.0|^3.0", + "psr/log": "^1.1|^2|^3", + "symfony/cache-contracts": "^3.6", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/var-exporter": "^6.4|^7.0" + }, + "conflict": { + "doctrine/dbal": "<3.6", + "symfony/dependency-injection": "<6.4", + "symfony/http-kernel": "<6.4", + "symfony/var-dumper": "<6.4" + }, + "provide": { + "psr/cache-implementation": "2.0|3.0", + "psr/simple-cache-implementation": "1.0|2.0|3.0", + "symfony/cache-implementation": "1.1|2.0|3.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/dbal": "^3.6|^4", + "predis/predis": "^1.1|^2.0", + "psr/simple-cache": "^1.0|^2.0|^3.0", + "symfony/clock": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/filesystem": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Cache\\": "" + }, + "classmap": [ + "Traits/ValueWrapper.php" + ], + "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 extended PSR-6, PSR-16 (and tags) implementations", + "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], + "support": { + "source": "https://github.com/symfony/cache/tree/v7.3.0" + }, + "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": "2025-05-06T19:00:13+00:00" + }, + { + "name": "symfony/cache-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/5d68a57d66910405e5c0b63d6f0af941e66fc868", + "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/cache": "^3.0" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Cache\\": "" + } + }, + "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 caching", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/cache-contracts/tree/v3.6.0" + }, + "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": "2025-03-13T15:25:07+00:00" + }, + { + "name": "symfony/clock", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/clock.git", + "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/clock/zipball/b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", + "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/clock": "^1.0", + "symfony/polyfill-php83": "^1.28" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/now.php" + ], + "psr-4": { + "Symfony\\Component\\Clock\\": "" + }, + "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": "Decouples applications from the system clock", + "homepage": "https://symfony.com", + "keywords": [ + "clock", + "psr20", + "time" + ], + "support": { + "source": "https://github.com/symfony/clock/tree/v7.3.0" + }, + "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": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/config", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "ba62ae565f1327c2f6366726312ed828c85853bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/ba62ae565f1327c2f6366726312ed828c85853bc", + "reference": "ba62ae565f1327c2f6366726312ed828c85853bc", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/filesystem": "^7.1", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/finder": "<6.4", + "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/service-contracts": "^2.5|^3", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "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.0" + }, + "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": "2025-05-15T09:04:05+00:00" + }, + { + "name": "symfony/console", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "66c1440edf6f339fd82ed6c7caa76cb006211b44" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/66c1440edf6f339fd82ed6c7caa76cb006211b44", + "reference": "66c1440edf6f339fd82ed6c7caa76cb006211b44", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^7.2" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/lock": "<6.4", + "symfony/process": "<6.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "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" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v7.3.0" + }, + "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": "2025-05-24T10:34:04+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/601a5ce9aaad7bf10797e3663faefce9e26c24e2", + "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts CSS selectors to XPath expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v7.3.0" + }, + "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": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/dependency-injection", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "f64a8f3fa7d4ad5e85de1b128a0e03faed02b732" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/f64a8f3fa7d4ad5e85de1b128a0e03faed02b732", + "reference": "f64a8f3fa7d4ad5e85de1b128a0e03faed02b732", + "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" + }, + "conflict": { + "ext-psr": "<1.1|>=2", + "symfony/config": "<6.4", + "symfony/finder": "<6.4", + "symfony/yaml": "<6.4" + }, + "provide": { + "psr/container-implementation": "1.1|2.0", + "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" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DependencyInjection\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "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.0" + }, + "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": "2025-05-19T13:28:56+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "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": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" + }, + "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": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/dom-crawler", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "0fabbc3d6a9c473b716a93fc8e7a537adb396166" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/0fabbc3d6a9c473b716a93fc8e7a537adb396166", + "reference": "0fabbc3d6a9c473b716a93fc8e7a537adb396166", + "shasum": "" + }, + "require": { + "masterminds/html5": "^2.6", + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "symfony/css-selector": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases DOM navigation for HTML and XML documents", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dom-crawler/tree/v7.3.0" + }, + "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": "2025-03-05T10:15:41+00:00" + }, + { + "name": "symfony/dotenv", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/dotenv.git", + "reference": "28347a897771d0c28e99b75166dd2689099f3045" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/28347a897771d0c28e99b75166dd2689099f3045", + "reference": "28347a897771d0c28e99b75166dd2689099f3045", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "conflict": { + "symfony/console": "<6.4", + "symfony/process": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Dotenv\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Registers environment variables from a .env file", + "homepage": "https://symfony.com", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "source": "https://github.com/symfony/dotenv/tree/v7.3.0" + }, + "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": "2024-11-27T11:18:42+00:00" + }, + { + "name": "symfony/error-handler", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/error-handler.git", + "reference": "cf68d225bc43629de4ff54778029aee6dc191b83" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/cf68d225bc43629de4ff54778029aee6dc191b83", + "reference": "cf68d225bc43629de4ff54778029aee6dc191b83", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/var-dumper": "^6.4|^7.0" + }, + "conflict": { + "symfony/deprecation-contracts": "<2.5", + "symfony/http-kernel": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/webpack-encore-bundle": "^1.0|^2.0" + }, + "bin": [ + "Resources/bin/patch-type-declarations" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "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.0" + }, + "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": "2025-05-29T07:19:49+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "497f73ac996a598c92409b44ac43b6690c4f666d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/497f73ac996a598c92409b44ac43b6690c4f666d", + "reference": "497f73ac996a598c92409b44ac43b6690c4f666d", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/event-dispatcher-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/service-contracts": "<2.5" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" + }, + "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/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "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.0" + }, + "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": "2025-04-22T09:11:45+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/event-dispatcher": "^1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "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 dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0" + }, + "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": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb", + "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8" + }, + "require-dev": { + "symfony/process": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v7.3.0" + }, + "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": "2024-10-25T15:15:23+00:00" + }, + { + "name": "symfony/finder", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/ec2344cf77a48253bbca6939aa3d2477773ea63d", + "reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/filesystem": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v7.3.0" + }, + "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": "2024-12-30T19:00:26+00:00" + }, + { + "name": "symfony/flex", + "version": "v2.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/flex.git", + "reference": "4ae50d368415a06820739e54d38a4a29d6df9155" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/flex/zipball/4ae50d368415a06820739e54d38a4a29d6df9155", + "reference": "4ae50d368415a06820739e54d38a4a29d6df9155", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.1", + "php": ">=8.0" + }, + "conflict": { + "composer/semver": "<1.7.2" + }, + "require-dev": { + "composer/composer": "^2.1", + "symfony/dotenv": "^5.4|^6.0", + "symfony/filesystem": "^5.4|^6.0", + "symfony/phpunit-bridge": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Symfony\\Flex\\Flex" + }, + "autoload": { + "psr-4": { + "Symfony\\Flex\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien.potencier@gmail.com" + } + ], + "description": "Composer plugin for Symfony", + "support": { + "issues": "https://github.com/symfony/flex/issues", + "source": "https://github.com/symfony/flex/tree/v2.7.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": "2025-05-28T14:22:54+00:00" + }, + { + "name": "symfony/framework-bundle", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/framework-bundle.git", + "reference": "030646f55fe18501a43edab22a8ad250d8ec42a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/030646f55fe18501a43edab22a8ad250d8ec42a6", + "reference": "030646f55fe18501a43edab22a8ad250d8ec42a6", + "shasum": "" + }, + "require": { + "composer-runtime-api": ">=2.1", + "ext-xml": "*", + "php": ">=8.2", + "symfony/cache": "^6.4|^7.0", + "symfony/config": "^7.3", + "symfony/dependency-injection": "^7.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/error-handler": "^7.3", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/filesystem": "^7.1", + "symfony/finder": "^6.4|^7.0", + "symfony/http-foundation": "^7.3", + "symfony/http-kernel": "^7.2", + "symfony/polyfill-mbstring": "~1.0", + "symfony/routing": "^6.4|^7.0" + }, + "conflict": { + "doctrine/persistence": "<1.3", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/asset": "<6.4", + "symfony/asset-mapper": "<6.4", + "symfony/clock": "<6.4", + "symfony/console": "<6.4", + "symfony/dom-crawler": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/form": "<6.4", + "symfony/http-client": "<6.4", + "symfony/json-streamer": ">=7.4", + "symfony/lock": "<6.4", + "symfony/mailer": "<6.4", + "symfony/messenger": "<6.4", + "symfony/mime": "<6.4", + "symfony/object-mapper": ">=7.4", + "symfony/property-access": "<6.4", + "symfony/property-info": "<6.4", + "symfony/runtime": "<6.4.13|>=7.0,<7.1.6", + "symfony/scheduler": "<6.4.4|>=7.0.0,<7.0.4", + "symfony/security-core": "<6.4", + "symfony/security-csrf": "<7.2", + "symfony/serializer": "<7.2.5", + "symfony/stopwatch": "<6.4", + "symfony/translation": "<7.3", + "symfony/twig-bridge": "<6.4", + "symfony/twig-bundle": "<6.4", + "symfony/validator": "<6.4", + "symfony/web-profiler-bundle": "<6.4", + "symfony/webhook": "<7.2", + "symfony/workflow": "<7.3.0-beta2" + }, + "require-dev": { + "doctrine/persistence": "^1.3|^2|^3", + "dragonmantank/cron-expression": "^3.1", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "seld/jsonlint": "^1.10", + "symfony/asset": "^6.4|^7.0", + "symfony/asset-mapper": "^6.4|^7.0", + "symfony/browser-kit": "^6.4|^7.0", + "symfony/clock": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/css-selector": "^6.4|^7.0", + "symfony/dom-crawler": "^6.4|^7.0", + "symfony/dotenv": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/form": "^6.4|^7.0", + "symfony/html-sanitizer": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/json-streamer": "7.3.*", + "symfony/lock": "^6.4|^7.0", + "symfony/mailer": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/notifier": "^6.4|^7.0", + "symfony/object-mapper": "^v7.3.0-beta2", + "symfony/polyfill-intl-icu": "~1.0", + "symfony/process": "^6.4|^7.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/rate-limiter": "^6.4|^7.0", + "symfony/scheduler": "^6.4.4|^7.0.4", + "symfony/security-bundle": "^6.4|^7.0", + "symfony/semaphore": "^6.4|^7.0", + "symfony/serializer": "^7.2.5", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/string": "^6.4|^7.0", + "symfony/translation": "^7.3", + "symfony/twig-bundle": "^6.4|^7.0", + "symfony/type-info": "^7.1", + "symfony/uid": "^6.4|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/web-link": "^6.4|^7.0", + "symfony/webhook": "^7.2", + "symfony/workflow": "^7.3", + "symfony/yaml": "^6.4|^7.0", + "twig/twig": "^3.12" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\FrameworkBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/framework-bundle/tree/v7.3.0" + }, + "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": "2025-05-28T06:56:42+00:00" + }, + { + "name": "symfony/http-client", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client.git", + "reference": "57e4fb86314015a695a750ace358d07a7e37b8a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client/zipball/57e4fb86314015a695a750ace358d07a7e37b8a9", + "reference": "57e4fb86314015a695a750ace358d07a7e37b8a9", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-client-contracts": "~3.4.4|^3.5.2", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "amphp/amp": "<2.5", + "php-http/discovery": "<1.15", + "symfony/http-foundation": "<6.4" + }, + "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/http-client": "^4.2.1|^5.0", + "amphp/http-tunnel": "^1.0|^2.0", + "amphp/socket": "^1.1", + "guzzlehttp/promises": "^1.4|^2.0", + "nyholm/psr7": "^1.0", + "php-http/httplug": "^1.0|^2.0", + "psr/http-client": "^1.0", + "symfony/amphp-http-client-meta": "^1.0|^2.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/rate-limiter": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.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", + "keywords": [ + "http" + ], + "support": { + "source": "https://github.com/symfony/http-client/tree/v7.3.0" + }, + "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": "2025-05-02T08:23:16+00:00" + }, + { + "name": "symfony/http-client-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "75d7043853a42837e68111812f4d964b01e5101c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/75d7043853a42837e68111812f4d964b01e5101c", + "reference": "75d7043853a42837e68111812f4d964b01e5101c", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "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.6.0" + }, + "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": "2025-04-29T11:18:49+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "4236baf01609667d53b20371486228231eb135fd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/4236baf01609667d53b20371486228231eb135fd", + "reference": "4236baf01609667d53b20371486228231eb135fd", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php83": "^1.27" + }, + "conflict": { + "doctrine/dbal": "<3.6", + "symfony/cache": "<6.4.12|>=7.0,<7.1.5" + }, + "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" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "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.0" + }, + "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": "2025-05-12T14:48:23+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "ac7b8e163e8c83dce3abcc055a502d4486051a9f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/ac7b8e163e8c83dce3abcc055a502d4486051a9f", + "reference": "ac7b8e163e8c83dce3abcc055a502d4486051a9f", + "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/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/browser-kit": "<6.4", + "symfony/cache": "<6.4", + "symfony/config": "<6.4", + "symfony/console": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/doctrine-bridge": "<6.4", + "symfony/form": "<6.4", + "symfony/http-client": "<6.4", + "symfony/http-client-contracts": "<2.5", + "symfony/mailer": "<6.4", + "symfony/messenger": "<6.4", + "symfony/translation": "<6.4", + "symfony/translation-contracts": "<2.5", + "symfony/twig-bridge": "<6.4", + "symfony/validator": "<6.4", + "symfony/var-dumper": "<6.4", + "twig/twig": "<3.12" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "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/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/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", + "twig/twig": "^3.12" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "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.0" + }, + "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": "2025-05-29T07:47:32+00:00" + }, + { + "name": "symfony/monolog-bridge", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bridge.git", + "reference": "1b188c8abbbef25b111da878797514b7a8d33990" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/1b188c8abbbef25b111da878797514b7a8d33990", + "reference": "1b188c8abbbef25b111da878797514b7a8d33990", + "shasum": "" + }, + "require": { + "monolog/monolog": "^3", + "php": ">=8.2", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/console": "<6.4", + "symfony/http-foundation": "<6.4", + "symfony/security-core": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/mailer": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/security-core": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "symfony-bridge", + "autoload": { + "psr-4": { + "Symfony\\Bridge\\Monolog\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides integration for Monolog with various Symfony components", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/monolog-bridge/tree/v7.3.0" + }, + "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": "2025-03-21T12:17:46+00:00" + }, + { + "name": "symfony/monolog-bundle", + "version": "v3.10.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bundle.git", + "reference": "414f951743f4aa1fd0f5bf6a0e9c16af3fe7f181" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/414f951743f4aa1fd0f5bf6a0e9c16af3fe7f181", + "reference": "414f951743f4aa1fd0f5bf6a0e9c16af3fe7f181", + "shasum": "" + }, + "require": { + "monolog/monolog": "^1.25.1 || ^2.0 || ^3.0", + "php": ">=7.2.5", + "symfony/config": "^5.4 || ^6.0 || ^7.0", + "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0", + "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0", + "symfony/monolog-bridge": "^5.4 || ^6.0 || ^7.0" + }, + "require-dev": { + "symfony/console": "^5.4 || ^6.0 || ^7.0", + "symfony/phpunit-bridge": "^6.3 || ^7.0", + "symfony/yaml": "^5.4 || ^6.0 || ^7.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bundle\\MonologBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony MonologBundle", + "homepage": "https://symfony.com", + "keywords": [ + "log", + "logging" + ], + "support": { + "issues": "https://github.com/symfony/monolog-bundle/issues", + "source": "https://github.com/symfony/monolog-bundle/tree/v3.10.0" + }, + "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": "2023-11-06T17:08:13+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "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 for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0" + }, + "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": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "3833d7255cc303546435cb650316bff708a1c75c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "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 for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0" + }, + "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": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-uuid", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-uuid.git", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-uuid": "*" + }, + "suggest": { + "ext-uuid": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Uuid\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for uuid functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "uuid" + ], + "support": { + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.32.0" + }, + "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": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/property-access", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-access.git", + "reference": "3bcf43665d6aff90547b005348e1e351f4e2174b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-access/zipball/3bcf43665d6aff90547b005348e1e351f4e2174b", + "reference": "3bcf43665d6aff90547b005348e1e351f4e2174b", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/property-info": "^6.4|^7.0" + }, + "require-dev": { + "symfony/cache": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyAccess\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides functions to read and write from/to an object or array using a simple string notation", + "homepage": "https://symfony.com", + "keywords": [ + "access", + "array", + "extraction", + "index", + "injection", + "object", + "property", + "property-path", + "reflection" + ], + "support": { + "source": "https://github.com/symfony/property-access/tree/v7.3.0" + }, + "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": "2025-05-10T11:59:09+00:00" + }, + { + "name": "symfony/property-info", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-info.git", + "reference": "200d230d8553610ada73ac557501dc4609aad31f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-info/zipball/200d230d8553610ada73ac557501dc4609aad31f", + "reference": "200d230d8553610ada73ac557501dc4609aad31f", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/string": "^6.4|^7.0", + "symfony/type-info": "~7.1.9|^7.2.2" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "<5.2", + "phpdocumentor/type-resolver": "<1.5.1", + "symfony/cache": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/serializer": "<6.4" + }, + "require-dev": { + "phpdocumentor/reflection-docblock": "^5.2", + "phpstan/phpdoc-parser": "^1.0|^2.0", + "symfony/cache": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyInfo\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "dunglas@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Extracts information about PHP class' properties using metadata of popular sources", + "homepage": "https://symfony.com", + "keywords": [ + "doctrine", + "phpdoc", + "property", + "symfony", + "type", + "validator" + ], + "support": { + "source": "https://github.com/symfony/property-info/tree/v7.3.0" + }, + "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": "2025-04-04T13:12:05+00:00" + }, + { + "name": "symfony/routing", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "8e213820c5fea844ecea29203d2a308019007c15" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/8e213820c5fea844ecea29203d2a308019007c15", + "reference": "8e213820c5fea844ecea29203d2a308019007c15", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/config": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/yaml": "<6.4" + }, + "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" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Maps an HTTP request to a set of configuration variables", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "support": { + "source": "https://github.com/symfony/routing/tree/v7.3.0" + }, + "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": "2025-05-24T20:43:28+00:00" + }, + { + "name": "symfony/runtime", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/runtime.git", + "reference": "fda552ee63dce9f3365f9c397efe7a80c8abac0a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/runtime/zipball/fda552ee63dce9f3365f9c397efe7a80c8abac0a", + "reference": "fda552ee63dce9f3365f9c397efe7a80c8abac0a", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0|^2.0", + "php": ">=8.2" + }, + "conflict": { + "symfony/dotenv": "<6.4" + }, + "require-dev": { + "composer/composer": "^2.6", + "symfony/console": "^6.4|^7.0", + "symfony/dotenv": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Symfony\\Component\\Runtime\\Internal\\ComposerPlugin" + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Runtime\\": "", + "Symfony\\Runtime\\Symfony\\Component\\": "Internal/" + }, + "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": "Enables decoupling PHP applications from global state", + "homepage": "https://symfony.com", + "keywords": [ + "runtime" + ], + "support": { + "source": "https://github.com/symfony/runtime/tree/v7.3.0" + }, + "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": "2025-04-06T16:01:50+00:00" + }, + { + "name": "symfony/serializer", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/serializer.git", + "reference": "2d86f81b1c506d7e1578789f93280dab4b8411bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/serializer/zipball/2d86f81b1c506d7e1578789f93280dab4b8411bb", + "reference": "2d86f81b1c506d7e1578789f93280dab4b8411bb", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/dependency-injection": "<6.4", + "symfony/property-access": "<6.4", + "symfony/property-info": "<6.4", + "symfony/uid": "<6.4", + "symfony/validator": "<6.4", + "symfony/yaml": "<6.4" + }, + "require-dev": { + "phpdocumentor/reflection-docblock": "^3.2|^4.0|^5.0", + "phpstan/phpdoc-parser": "^1.0|^2.0", + "seld/jsonlint": "^1.10", + "symfony/cache": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/dependency-injection": "^7.2", + "symfony/error-handler": "^6.4|^7.0", + "symfony/filesystem": "^6.4|^7.0", + "symfony/form": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/property-access": "^6.4|^7.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3", + "symfony/type-info": "^7.1", + "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/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Serializer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/serializer/tree/v7.3.0" + }, + "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": "2025-05-12T14:48:23+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "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 writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" + }, + "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": "2025-04-25T09:37:31+00:00" + }, + { + "name": "symfony/stimulus-bundle", + "version": "v2.26.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/stimulus-bundle.git", + "reference": "82c174ebe564e6ecc1412974b6380b86d450675f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stimulus-bundle/zipball/82c174ebe564e6ecc1412974b6380b86d450675f", + "reference": "82c174ebe564e6ecc1412974b6380b86d450675f", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/deprecation-contracts": "^2.0|^3.0", + "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "twig/twig": "^2.15.3|^3.8" + }, + "require-dev": { + "symfony/asset-mapper": "^6.3|^7.0", + "symfony/framework-bundle": "^5.4|^6.0|^7.0", + "symfony/phpunit-bridge": "^5.4|^6.0|^7.0", + "symfony/twig-bundle": "^5.4|^6.0|^7.0", + "zenstruck/browser": "^1.4" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\UX\\StimulusBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Integration with your Symfony app & Stimulus!", + "keywords": [ + "symfony-ux" + ], + "support": { + "source": "https://github.com/symfony/stimulus-bundle/tree/v2.26.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": "2025-06-05T17:25:17+00:00" + }, + { + "name": "symfony/string", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/f3570b8c61ca887a9e2938e85cb6458515d2b125", + "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/emoji": "^7.1", + "symfony/error-handler": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "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 an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v7.3.0" + }, + "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": "2025-04-20T20:19:01+00:00" + }, + { + "name": "symfony/translation-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/df210c7a2573f1913b2d17cc95f90f53a73d8f7d", + "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + }, + "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 translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/translation-contracts/tree/v3.6.0" + }, + "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": "2024-09-27T08:32:26+00:00" + }, + { + "name": "symfony/twig-bridge", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/twig-bridge.git", + "reference": "082eb15d8a4f9afee0acc4709fbe3aaf26d48891" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/082eb15d8a4f9afee0acc4709fbe3aaf26d48891", + "reference": "082eb15d8a4f9afee0acc4709fbe3aaf26d48891", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/translation-contracts": "^2.5|^3", + "twig/twig": "^3.21" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/console": "<6.4", + "symfony/form": "<6.4", + "symfony/http-foundation": "<6.4", + "symfony/http-kernel": "<6.4", + "symfony/mime": "<6.4", + "symfony/serializer": "<6.4", + "symfony/translation": "<6.4", + "symfony/workflow": "<6.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3|^4", + "league/html-to-markdown": "^5.0", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/asset": "^6.4|^7.0", + "symfony/asset-mapper": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/emoji": "^7.1", + "symfony/expression-language": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/form": "^6.4.20|^7.2.5", + "symfony/html-sanitizer": "^6.4|^7.0", + "symfony/http-foundation": "^7.3", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/polyfill-intl-icu": "~1.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/routing": "^6.4|^7.0", + "symfony/security-acl": "^2.8|^3.0", + "symfony/security-core": "^6.4|^7.0", + "symfony/security-csrf": "^6.4|^7.0", + "symfony/security-http": "^6.4|^7.0", + "symfony/serializer": "^6.4.3|^7.0.3", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/translation": "^6.4|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/web-link": "^6.4|^7.0", + "symfony/workflow": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0", + "twig/cssinliner-extra": "^3", + "twig/inky-extra": "^3", + "twig/markdown-extra": "^3" + }, + "type": "symfony-bridge", + "autoload": { + "psr-4": { + "Symfony\\Bridge\\Twig\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides integration for Twig with various Symfony components", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/twig-bridge/tree/v7.3.0" + }, + "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": "2025-05-19T13:28:56+00:00" + }, + { + "name": "symfony/twig-bundle", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/twig-bundle.git", + "reference": "0ace7d92b92437a5ad59fad457af7dc2475db89b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/0ace7d92b92437a5ad59fad457af7dc2475db89b", + "reference": "0ace7d92b92437a5ad59fad457af7dc2475db89b", + "shasum": "" + }, + "require": { + "composer-runtime-api": ">=2.1", + "php": ">=8.2", + "symfony/config": "^7.3", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/twig-bridge": "^7.3", + "twig/twig": "^3.12" + }, + "conflict": { + "symfony/framework-bundle": "<6.4", + "symfony/translation": "<6.4" + }, + "require-dev": { + "symfony/asset": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/form": "^6.4|^7.0", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/routing": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/translation": "^6.4|^7.0", + "symfony/web-link": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\TwigBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration of Twig into the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/twig-bundle/tree/v7.3.0" + }, + "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": "2025-05-14T11:51:37+00:00" + }, + { + "name": "symfony/type-info", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/type-info.git", + "reference": "bc9af22e25796d98078f69c0749ab3a9d3454786" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/type-info/zipball/bc9af22e25796d98078f69c0749ab3a9d3454786", + "reference": "bc9af22e25796d98078f69c0749ab3a9d3454786", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "phpstan/phpdoc-parser": "<1.30" + }, + "require-dev": { + "phpstan/phpdoc-parser": "^1.30|^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\TypeInfo\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mathias Arlaud", + "email": "mathias.arlaud@gmail.com" + }, + { + "name": "Baptiste LEDUC", + "email": "baptiste.leduc@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Extracts PHP types information.", + "homepage": "https://symfony.com", + "keywords": [ + "PHPStan", + "phpdoc", + "symfony", + "type" + ], + "support": { + "source": "https://github.com/symfony/type-info/tree/v7.3.0" + }, + "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": "2025-03-30T12:17:06+00:00" + }, + { + "name": "symfony/uid", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/uid.git", + "reference": "7beeb2b885cd584cd01e126c5777206ae4c3c6a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/uid/zipball/7beeb2b885cd584cd01e126c5777206ae4c3c6a3", + "reference": "7beeb2b885cd584cd01e126c5777206ae4c3c6a3", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-uuid": "^1.15" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Uid\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to generate and represent UIDs", + "homepage": "https://symfony.com", + "keywords": [ + "UID", + "ulid", + "uuid" + ], + "support": { + "source": "https://github.com/symfony/uid/tree/v7.3.0" + }, + "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": "2025-05-24T14:28:13+00:00" + }, + { + "name": "symfony/ux-icons", + "version": "v2.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/ux-icons.git", + "reference": "e5c1e5b5093ae26dba45d0f3390a1e21f305c47a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/ux-icons/zipball/e5c1e5b5093ae26dba45d0f3390a1e21f305c47a", + "reference": "e5c1e5b5093ae26dba45d0f3390a1e21f305c47a", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/twig-bundle": "^6.4|^7.0" + }, + "conflict": { + "symfony/flex": "<1.13", + "symfony/ux-twig-component": "<2.21" + }, + "require-dev": { + "psr/log": "^2|^3", + "symfony/asset-mapper": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/http-client": "6.4|^7.0", + "symfony/phpunit-bridge": "^6.3|^7.0", + "symfony/ux-twig-component": "^2.14", + "zenstruck/console-test": "^1.5" + }, + "type": "symfony-bundle", + "extra": { + "thanks": { + "url": "https://github.com/symfony/ux", + "name": "symfony/ux" + } + }, + "autoload": { + "psr-4": { + "Symfony\\UX\\Icons\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kevin Bond", + "email": "kevinbond@gmail.com" + }, + { + "name": "Simon André", + "email": "smn.andre@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Renders local and remote SVG icons in your Twig templates.", + "homepage": "https://symfony.com", + "keywords": [ + "icons", + "svg", + "symfony-ux", + "twig" + ], + "support": { + "source": "https://github.com/symfony/ux-icons/tree/v2.26.0" + }, + "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": "2025-05-30T02:07:34+00:00" + }, + { + "name": "symfony/ux-live-component", + "version": "v2.26.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/ux-live-component.git", + "reference": "92b300bb90d87f14aeae47b0f5c9e058b15f5c2f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/ux-live-component/zipball/92b300bb90d87f14aeae47b0f5c9e058b15f5c2f", + "reference": "92b300bb90d87f14aeae47b0f5c9e058b15f5c2f", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/property-access": "^5.4.5|^6.0|^7.0", + "symfony/property-info": "^5.4|^6.0|^7.0", + "symfony/stimulus-bundle": "^2.9", + "symfony/ux-twig-component": "^2.25.1", + "twig/twig": "^3.10.3" + }, + "conflict": { + "symfony/config": "<5.4.0", + "symfony/property-info": "~7.0.0", + "symfony/type-info": "<7.2" + }, + "require-dev": { + "doctrine/annotations": "^1.0", + "doctrine/collections": "^1.6.8|^2.0", + "doctrine/doctrine-bundle": "^2.4.3", + "doctrine/orm": "^2.9.4", + "doctrine/persistence": "^2.5.2|^3.0", + "phpdocumentor/reflection-docblock": "5.x-dev", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/form": "^5.4|^6.0|^7.0", + "symfony/framework-bundle": "^5.4|^6.0|^7.0", + "symfony/options-resolver": "^5.4|^6.0|^7.0", + "symfony/phpunit-bridge": "^6.1|^7.0", + "symfony/security-bundle": "^5.4|^6.0|^7.0", + "symfony/serializer": "^5.4|^6.0|^7.0", + "symfony/twig-bundle": "^5.4|^6.0|^7.0", + "symfony/uid": "^5.4|^6.0|^7.0", + "symfony/validator": "^5.4|^6.0|^7.0", + "zenstruck/browser": "^1.2.0", + "zenstruck/foundry": "^2.0" + }, + "type": "symfony-bundle", + "extra": { + "thanks": { + "url": "https://github.com/symfony/ux", + "name": "symfony/ux" + } + }, + "autoload": { + "psr-4": { + "Symfony\\UX\\LiveComponent\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Live components for Symfony", + "homepage": "https://symfony.com", + "keywords": [ + "components", + "symfony-ux", + "twig" + ], + "support": { + "source": "https://github.com/symfony/ux-live-component/tree/v2.26.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": "2025-06-06T19:57:53+00:00" + }, + { + "name": "symfony/ux-turbo", + "version": "v2.26.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/ux-turbo.git", + "reference": "3754ac2b41220127e58c62f7599eaf7834b69a55" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/ux-turbo/zipball/3754ac2b41220127e58c62f7599eaf7834b69a55", + "reference": "3754ac2b41220127e58c62f7599eaf7834b69a55", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/stimulus-bundle": "^2.9.1" + }, + "conflict": { + "symfony/flex": "<1.13" + }, + "require-dev": { + "dbrekelmans/bdi": "dev-main", + "doctrine/doctrine-bundle": "^2.4.3", + "doctrine/orm": "^2.8 | 3.0", + "php-webdriver/webdriver": "^1.15", + "phpstan/phpstan": "^2.1.17", + "symfony/asset-mapper": "^6.4|^7.0", + "symfony/debug-bundle": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/form": "^5.4|^6.0|^7.0", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/mercure-bundle": "^0.3.7", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/panther": "^2.2", + "symfony/phpunit-bridge": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|6.3.*|^7.0", + "symfony/property-access": "^5.4|^6.0|^7.0", + "symfony/security-core": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/twig-bundle": "^6.4|^7.0", + "symfony/ux-twig-component": "^2.21", + "symfony/web-profiler-bundle": "^5.4|^6.0|^7.0" + }, + "type": "symfony-bundle", + "extra": { + "thanks": { + "url": "https://github.com/symfony/ux", + "name": "symfony/ux" + } + }, + "autoload": { + "psr-4": { + "Symfony\\UX\\Turbo\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "kevin@dunglas.fr" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Hotwire Turbo integration for Symfony", + "homepage": "https://symfony.com", + "keywords": [ + "hotwire", + "javascript", + "mercure", + "symfony-ux", + "turbo", + "turbo-stream" + ], + "support": { + "source": "https://github.com/symfony/ux-turbo/tree/v2.26.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": "2025-06-05T17:25:17+00:00" + }, + { + "name": "symfony/ux-twig-component", + "version": "v2.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/ux-twig-component.git", + "reference": "825e653b34fb48ed2198913c603d80f7632fe9c1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/ux-twig-component/zipball/825e653b34fb48ed2198913c603d80f7632fe9c1", + "reference": "825e653b34fb48ed2198913c603d80f7632fe9c1", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/deprecation-contracts": "^2.2|^3.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/property-access": "^5.4|^6.0|^7.0", + "twig/twig": "^3.10.3" + }, + "conflict": { + "symfony/config": "<5.4.0" + }, + "require-dev": { + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/css-selector": "^5.4|^6.0|^7.0", + "symfony/dom-crawler": "^5.4|^6.0|^7.0", + "symfony/framework-bundle": "^5.4|^6.0|^7.0", + "symfony/phpunit-bridge": "^6.0|^7.0", + "symfony/stimulus-bundle": "^2.9.1", + "symfony/twig-bundle": "^5.4|^6.0|^7.0", + "symfony/webpack-encore-bundle": "^1.15" + }, + "type": "symfony-bundle", + "extra": { + "thanks": { + "url": "https://github.com/symfony/ux", + "name": "symfony/ux" + } + }, + "autoload": { + "psr-4": { + "Symfony\\UX\\TwigComponent\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Twig components for Symfony", + "homepage": "https://symfony.com", + "keywords": [ + "components", + "symfony-ux", + "twig" + ], + "support": { + "source": "https://github.com/symfony/ux-twig-component/tree/v2.26.0" + }, + "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": "2025-05-26T06:21:54+00:00" + }, + { + "name": "symfony/ux-typed", + "version": "v2.26.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/ux-typed.git", + "reference": "df0f3bec5c4e6016f2a777420a545a5bb50495ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/ux-typed/zipball/df0f3bec5c4e6016f2a777420a545a5bb50495ca", + "reference": "df0f3bec5c4e6016f2a777420a545a5bb50495ca", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/flex": "<1.13" + }, + "type": "symfony-bundle", + "extra": { + "thanks": { + "url": "https://github.com/symfony/ux", + "name": "symfony/ux" + } + }, + "autoload": { + "psr-4": { + "Symfony\\UX\\Typed\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "email": "contact@spomky-labs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Typed integration for Symfony", + "homepage": "https://symfony.com", + "keywords": [ + "symfony-ux" + ], + "support": { + "source": "https://github.com/symfony/ux-typed/tree/v2.26.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": "2025-06-05T20:47:06+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "548f6760c54197b1084e1e5c71f6d9d523f2f78e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/548f6760c54197b1084e1e5c71f6d9d523f2f78e", + "reference": "548f6760c54197b1084e1e5c71f6d9d523f2f78e", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "ext-iconv": "*", + "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", + "twig/twig": "^3.12" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "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 mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v7.3.0" + }, + "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": "2025-04-27T18:39:23+00:00" + }, + { + "name": "symfony/var-exporter", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "c9a1168891b5aaadfd6332ef44393330b3498c4c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/c9a1168891b5aaadfd6332ef44393330b3498c4c", + "reference": "c9a1168891b5aaadfd6332ef44393330b3498c4c", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "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" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "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": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "lazy-loading", + "proxy", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v7.3.0" + }, + "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": "2025-05-15T09:04:05+00:00" + }, + { + "name": "symfony/yaml", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "cea40a48279d58dc3efee8112634cb90141156c2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/cea40a48279d58dc3efee8112634cb90141156c2", + "reference": "cea40a48279d58dc3efee8112634cb90141156c2", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0" + }, + "bin": [ + "Resources/bin/yaml-lint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v7.3.0" + }, + "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": "2025-04-04T10:10:33+00:00" + }, + { + "name": "twig/extra-bundle", + "version": "v3.21.0", + "source": { + "type": "git", + "url": "https://github.com/twigphp/twig-extra-bundle.git", + "reference": "62d1cf47a1aa009cbd07b21045b97d3d5cb79896" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/62d1cf47a1aa009cbd07b21045b97d3d5cb79896", + "reference": "62d1cf47a1aa009cbd07b21045b97d3d5cb79896", + "shasum": "" + }, + "require": { + "php": ">=8.1.0", + "symfony/framework-bundle": "^5.4|^6.4|^7.0", + "symfony/twig-bundle": "^5.4|^6.4|^7.0", + "twig/twig": "^3.2|^4.0" + }, + "require-dev": { + "league/commonmark": "^1.0|^2.0", + "symfony/phpunit-bridge": "^6.4|^7.0", + "twig/cache-extra": "^3.0", + "twig/cssinliner-extra": "^3.0", + "twig/html-extra": "^3.0", + "twig/inky-extra": "^3.0", + "twig/intl-extra": "^3.0", + "twig/markdown-extra": "^3.0", + "twig/string-extra": "^3.0" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Twig\\Extra\\TwigExtraBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + } + ], + "description": "A Symfony bundle for extra Twig extensions", + "homepage": "https://twig.symfony.com", + "keywords": [ + "bundle", + "extra", + "twig" + ], + "support": { + "source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.21.0" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2025-02-19T14:29:33+00:00" + }, + { + "name": "twig/markdown-extra", + "version": "v3.21.0", + "source": { + "type": "git", + "url": "https://github.com/twigphp/markdown-extra.git", + "reference": "f4616e1dd375209dacf6026f846e6b537d036ce4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/markdown-extra/zipball/f4616e1dd375209dacf6026f846e6b537d036ce4", + "reference": "f4616e1dd375209dacf6026f846e6b537d036ce4", + "shasum": "" + }, + "require": { + "php": ">=8.1.0", + "symfony/deprecation-contracts": "^2.5|^3", + "twig/twig": "^3.13|^4.0" + }, + "require-dev": { + "erusev/parsedown": "dev-master as 1.x-dev", + "league/commonmark": "^1.0|^2.0", + "league/html-to-markdown": "^4.8|^5.0", + "michelf/php-markdown": "^1.8|^2.0", + "symfony/phpunit-bridge": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Twig\\Extra\\Markdown\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + } + ], + "description": "A Twig extension for Markdown", + "homepage": "https://twig.symfony.com", + "keywords": [ + "html", + "markdown", + "twig" + ], + "support": { + "source": "https://github.com/twigphp/markdown-extra/tree/v3.21.0" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2025-01-31T20:45:36+00:00" + }, + { + "name": "twig/twig", + "version": "v3.21.1", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig.git", + "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/285123877d4dd97dd7c11842ac5fb7e86e60d81d", + "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d", + "shasum": "" + }, + "require": { + "php": ">=8.1.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.3" + }, + "require-dev": { + "phpstan/phpstan": "^2.0", + "psr/container": "^1.0|^2.0", + "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "src/Resources/core.php", + "src/Resources/debug.php", + "src/Resources/escaper.php", + "src/Resources/string_loader.php" + ], + "psr-4": { + "Twig\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Twig Team", + "role": "Contributors" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "https://twig.symfony.com", + "keywords": [ + "templating" + ], + "support": { + "issues": "https://github.com/twigphp/Twig/issues", + "source": "https://github.com/twigphp/Twig/tree/v3.21.1" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2025-05-03T07:21:55+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": "^7.2 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.11.0" + }, + "time": "2022-06-03T18:03:27+00:00" + } + ], + "packages-dev": [ + { + "name": "myclabs/deep-copy", + "version": "1.13.1", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/1720ddd719e16cf0db4eb1c6eca108031636d46c", + "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.1" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-04-29T12:36:36+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.5.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9", + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0" + }, + "time": "2025-05-31T08:24:38+00:00" + }, + { + "name": "nyholm/nsa", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/Nyholm/NSA.git", + "reference": "c264c17ed2aa8251c64ad289442ed53f64cdb283" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Nyholm/NSA/zipball/c264c17ed2aa8251c64ad289442ed53f64cdb283", + "reference": "c264c17ed2aa8251c64ad289442ed53f64cdb283", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "webmozart/assert": "^1.1.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Nyholm\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com" + } + ], + "description": "See everything and do whatever you want. No privacy rule will stop us. Used in tests, debugging and fixtures to access properties and methods.", + "homepage": "https://tnyholm.se", + "keywords": [ + "Fixture", + "debug", + "reflection", + "test" + ], + "support": { + "issues": "https://github.com/Nyholm/NSA/issues", + "source": "https://github.com/Nyholm/NSA/tree/1.3.0" + }, + "funding": [ + { + "url": "https://github.com/nyholm", + "type": "github" + } + ], + "time": "2021-07-15T18:25:37+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "php-cs-fixer/shim", + "version": "v3.75.0", + "source": { + "type": "git", + "url": "https://github.com/PHP-CS-Fixer/shim.git", + "reference": "eea219a577085bd13ff0cb644a422c20798316c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/eea219a577085bd13ff0cb644a422c20798316c7", + "reference": "eea219a577085bd13ff0cb644a422c20798316c7", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "replace": { + "friendsofphp/php-cs-fixer": "self.version" + }, + "suggest": { + "ext-dom": "For handling output formats in XML", + "ext-mbstring": "For handling non-UTF8 characters." + }, + "bin": [ + "php-cs-fixer", + "php-cs-fixer.phar" + ], + "type": "application", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Dariusz Rumiński", + "email": "dariusz.ruminski@gmail.com" + } + ], + "description": "A tool to automatically fix PHP code style", + "support": { + "issues": "https://github.com/PHP-CS-Fixer/shim/issues", + "source": "https://github.com/PHP-CS-Fixer/shim/tree/v3.75.0" + }, + "time": "2025-03-31T18:45:02+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "2.1.17", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "89b5ef665716fa2a52ecd2633f21007a6a349053" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/89b5ef665716fa2a52ecd2633f21007a6a349053", + "reference": "89b5ef665716fa2a52ecd2633f21007a6a349053", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2025-05-21T20:55:28+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "11.0.10", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "1a800a7446add2d79cc6b3c01c45381810367d76" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1a800a7446add2d79cc6b3c01c45381810367d76", + "reference": "1a800a7446add2d79cc6b3c01c45381810367d76", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.4.0", + "php": ">=8.2", + "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-text-template": "^4.0.1", + "sebastian/code-unit-reverse-lookup": "^4.0.1", + "sebastian/complexity": "^4.0.1", + "sebastian/environment": "^7.2.0", + "sebastian/lines-of-code": "^3.0.1", + "sebastian/version": "^5.0.2", + "theseer/tokenizer": "^1.2.3" + }, + "require-dev": { + "phpunit/phpunit": "^11.5.2" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/show" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage", + "type": "tidelift" + } + ], + "time": "2025-06-18T08:56:18+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "5.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/118cfaaa8bc5aef3287bf315b6060b1174754af6", + "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-08-27T05:02:59+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "5.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^11.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:07:44+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:08:43+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "7.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:09:35+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "11.5.24", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "6b07ab1047155cf38f82dd691787a277782271dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6b07ab1047155cf38f82dd691787a277782271dd", + "reference": "6b07ab1047155cf38f82dd691787a277782271dd", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.1", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=8.2", + "phpunit/php-code-coverage": "^11.0.10", + "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-invoker": "^5.0.1", + "phpunit/php-text-template": "^4.0.1", + "phpunit/php-timer": "^7.0.1", + "sebastian/cli-parser": "^3.0.2", + "sebastian/code-unit": "^3.0.3", + "sebastian/comparator": "^6.3.1", + "sebastian/diff": "^6.0.2", + "sebastian/environment": "^7.2.1", + "sebastian/exporter": "^6.3.0", + "sebastian/global-state": "^7.0.2", + "sebastian/object-enumerator": "^6.0.1", + "sebastian/type": "^5.1.2", + "sebastian/version": "^5.0.2", + "staabm/side-effects-detector": "^1.0.5" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.5-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.24" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2025-06-20T11:31:02+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:41:36+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "security": "https://github.com/sebastianbergmann/code-unit/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-03-19T07:56:08+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:45:54+00:00" + }, + { + "name": "sebastian/comparator", + "version": "6.3.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/24b8fbc2c8e201bb1308e7b05148d6ab393b6959", + "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/diff": "^6.0", + "sebastian/exporter": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.4" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-03-07T06:57:01+00:00" + }, + { + "name": "sebastian/complexity", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:49:50+00:00" + }, + { + "name": "sebastian/diff", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:53:05+00:00" + }, + { + "name": "sebastian/environment", + "version": "7.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/a5c75038693ad2e8d4b6c15ba2403532647830c4", + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "https://github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/7.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/environment", + "type": "tidelift" + } + ], + "time": "2025-05-21T11:55:47+00:00" + }, + { + "name": "sebastian/exporter", + "version": "6.3.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/3473f61172093b2da7de1fb5782e1f24cc036dc3", + "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-12-05T09:17:50+00:00" + }, + { + "name": "sebastian/global-state", + "version": "7.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:57:36+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:58:38+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "6.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:00:13+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:01:32+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "694d156164372abbd149a4b85ccda2e4670c0e16" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/694d156164372abbd149a4b85ccda2e4670c0e16", + "reference": "694d156164372abbd149a4b85ccda2e4670c0e16", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:10:34+00:00" + }, + { + "name": "sebastian/type", + "version": "5.1.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/a8a7e30534b0eb0c77cd9d07e82de1a114389f5e", + "reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/5.1.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-03-18T13:35:50+00:00" + }, + { + "name": "sebastian/version", + "version": "5.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/5.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-10-09T05:16:32+00:00" + }, + { + "name": "staabm/side-effects-detector", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + }, + "funding": [ + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2024-10-20T05:08:20+00:00" + }, + { + "name": "symfony/browser-kit", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/browser-kit.git", + "reference": "5384291845e74fd7d54f3d925c4a86ce12336593" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/5384291845e74fd7d54f3d925c4a86ce12336593", + "reference": "5384291845e74fd7d54f3d925c4a86ce12336593", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/dom-crawler": "^6.4|^7.0" + }, + "require-dev": { + "symfony/css-selector": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\BrowserKit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/browser-kit/tree/v7.3.0" + }, + "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": "2025-03-05T10:15:41+00:00" + }, + { + "name": "symfony/debug-bundle", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug-bundle.git", + "reference": "781acc90f31f5fe18915f9276890864ebbbe3da8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/781acc90f31f5fe18915f9276890864ebbbe3da8", + "reference": "781acc90f31f5fe18915f9276890864ebbbe3da8", + "shasum": "" + }, + "require": { + "composer-runtime-api": ">=2.1", + "ext-xml": "*", + "php": ">=8.2", + "symfony/config": "^7.3", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/twig-bridge": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "require-dev": { + "symfony/web-profiler-bundle": "^6.4|^7.0" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\DebugBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration of the Symfony VarDumper component and the ServerLogCommand from MonologBridge into the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/debug-bundle/tree/v7.3.0" + }, + "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": "2025-05-04T13:21:13+00:00" + }, + { + "name": "symfony/stopwatch", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd", + "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/service-contracts": "^2.5|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a way to profile code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/stopwatch/tree/v7.3.0" + }, + "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": "2025-02-24T10:49:57+00:00" + }, + { + "name": "symfony/web-profiler-bundle", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/web-profiler-bundle.git", + "reference": "a22b7e4a744820a56f1bafa830f2c72a2ba0913c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/a22b7e4a744820a56f1bafa830f2c72a2ba0913c", + "reference": "a22b7e4a744820a56f1bafa830f2c72a2ba0913c", + "shasum": "" + }, + "require": { + "composer-runtime-api": ">=2.1", + "php": ">=8.2", + "symfony/config": "^7.3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/routing": "^6.4|^7.0", + "symfony/twig-bundle": "^6.4|^7.0", + "twig/twig": "^3.12" + }, + "conflict": { + "symfony/form": "<6.4", + "symfony/mailer": "<6.4", + "symfony/messenger": "<6.4", + "symfony/serializer": "<7.2", + "symfony/workflow": "<7.3" + }, + "require-dev": { + "symfony/browser-kit": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/css-selector": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\WebProfilerBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a development tool that gives detailed information about the execution of any request", + "homepage": "https://symfony.com", + "keywords": [ + "dev" + ], + "support": { + "source": "https://github.com/symfony/web-profiler-bundle/tree/v7.3.0" + }, + "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": "2025-05-02T05:30:54+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "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" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:36:25+00:00" + } + ], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": { + "symfony/ai-bundle": 20 + }, + "prefer-stable": true, + "prefer-lowest": false, + "platform": { + "php": ">=8.4", + "ext-ctype": "*", + "ext-iconv": "*" + }, + "platform-dev": {}, + "platform-overrides": { + "php": "8.4.7" + }, + "plugin-api-version": "2.6.0" +} diff --git a/demo/config/bundles.php b/demo/config/bundles.php new file mode 100644 index 000000000..1b4577690 --- /dev/null +++ b/demo/config/bundles.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], + Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], + Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true], + Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], + Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], + Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true], + Symfony\UX\TwigComponent\TwigComponentBundle::class => ['all' => true], + Symfony\UX\LiveComponent\LiveComponentBundle::class => ['all' => true], + Symfony\UX\StimulusBundle\StimulusBundle::class => ['all' => true], + Symfony\UX\Turbo\TurboBundle::class => ['all' => true], + Symfony\UX\Icons\UXIconsBundle::class => ['all' => true], + Symfony\UX\Typed\TypedBundle::class => ['all' => true], + Symfony\AI\AIBundle\AIBundle::class => ['all' => true], +]; diff --git a/demo/config/packages/ai.yaml b/demo/config/packages/ai.yaml new file mode 100644 index 000000000..845f8840e --- /dev/null +++ b/demo/config/packages/ai.yaml @@ -0,0 +1,65 @@ +ai: + platform: + openai: + api_key: '%env(OPENAI_API_KEY)%' + agent: + blog: + # platform: 'symfony_ai.platform.anthropic' + model: + name: 'GPT' + version: 'gpt-4o-mini' + tools: + - 'Symfony\AI\Agent\Toolbox\Tool\SimilaritySearch' + - service: 'clock' + name: 'clock' + description: 'Provides the current date and time.' + method: 'now' + youtube: + model: + name: 'GPT' + version: 'gpt-4o-mini' + tools: false + wikipedia: + model: + name: 'GPT' + version: 'gpt-4o-mini' + options: + temperature: 0.5 + system_prompt: 'Please answer the users question based on Wikipedia and provide a link to the article.' + include_tools: true + tools: + - 'Symfony\AI\Agent\Toolbox\Tool\Wikipedia' + audio: + model: + name: 'GPT' + version: 'gpt-4o-mini' + system_prompt: 'You are a friendly chatbot that likes to have a conversation with users and asks them some questions.' + tools: + # Agent in agent 🤯 + - service: 'symfony_ai.agent.blog' + name: 'symfony_blog' + description: 'Can answer questions based on the Symfony blog.' + is_agent: true + store: + chroma_db: + symfonycon: + collection: 'symfony_blog' + indexer: + default: + model: + name: 'Embeddings' + version: 'text-embedding-ada-002' + +services: + _defaults: + autowire: true + autoconfigure: true + + # Symfony\AI\Agent\Toolbox\Tool\Clock: ~ + # Symfony\AI\Agent\Toolbox\Tool\OpenMeteo: ~ + # Symfony\AI\Agent\Toolbox\Tool\SerpApi: + # $apiKey: '%env(SERP_API_KEY)%' + Symfony\AI\Agent\Toolbox\Tool\Wikipedia: ~ + Symfony\AI\Agent\Toolbox\Tool\SimilaritySearch: + $model: '@symfony_ai.indexer.default.model' + diff --git a/demo/config/packages/asset_mapper.yaml b/demo/config/packages/asset_mapper.yaml new file mode 100644 index 000000000..f7653e97f --- /dev/null +++ b/demo/config/packages/asset_mapper.yaml @@ -0,0 +1,11 @@ +framework: + asset_mapper: + # The paths to make available to the asset mapper. + paths: + - assets/ + missing_import_mode: strict + +when@prod: + framework: + asset_mapper: + missing_import_mode: warn diff --git a/demo/config/packages/cache.yaml b/demo/config/packages/cache.yaml new file mode 100644 index 000000000..6899b7200 --- /dev/null +++ b/demo/config/packages/cache.yaml @@ -0,0 +1,19 @@ +framework: + cache: + # Unique name of your app: used to compute stable namespaces for cache keys. + #prefix_seed: your_vendor_name/app_name + + # The "app" cache stores to the filesystem by default. + # The data in this cache should persist between deploys. + # Other options include: + + # Redis + #app: cache.adapter.redis + #default_redis_provider: redis://localhost + + # APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues) + #app: cache.adapter.apcu + + # Namespaced pools use the above "app" backend by default + #pools: + #my.dedicated.cache: null diff --git a/demo/config/packages/chromadb.yaml b/demo/config/packages/chromadb.yaml new file mode 100644 index 000000000..7a10c43b4 --- /dev/null +++ b/demo/config/packages/chromadb.yaml @@ -0,0 +1,8 @@ +services: + Codewithkyrian\ChromaDB\Factory: + calls: + - withHost: ['%env(CHROMADB_HOST)%'] + + Codewithkyrian\ChromaDB\Client: + factory: ['@Codewithkyrian\ChromaDB\Factory', 'connect'] + lazy: true diff --git a/demo/config/packages/debug.yaml b/demo/config/packages/debug.yaml new file mode 100644 index 000000000..ad874afdd --- /dev/null +++ b/demo/config/packages/debug.yaml @@ -0,0 +1,5 @@ +when@dev: + debug: + # Forwards VarDumper Data clones to a centralized server allowing to inspect dumps on CLI or in your browser. + # See the "server:dump" command to start a new server. + dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%" diff --git a/demo/config/packages/framework.yaml b/demo/config/packages/framework.yaml new file mode 100644 index 000000000..877eb25d1 --- /dev/null +++ b/demo/config/packages/framework.yaml @@ -0,0 +1,16 @@ +# see https://symfony.com/doc/current/reference/configuration/framework.html +framework: + secret: '%env(APP_SECRET)%' + #csrf_protection: true + + # Note that the session will be started ONLY if you read or write from it. + session: true + + #esi: true + #fragments: true + +when@test: + framework: + test: true + session: + storage_factory_id: session.storage.factory.mock_file diff --git a/demo/config/packages/monolog.yaml b/demo/config/packages/monolog.yaml new file mode 100644 index 000000000..9db7d8a7f --- /dev/null +++ b/demo/config/packages/monolog.yaml @@ -0,0 +1,62 @@ +monolog: + channels: + - deprecation # Deprecations are logged in the dedicated "deprecation" channel when it exists + +when@dev: + monolog: + handlers: + main: + type: stream + path: "%kernel.logs_dir%/%kernel.environment%.log" + level: debug + channels: ["!event"] + # uncomment to get logging in your browser + # you may have to allow bigger header sizes in your Web server configuration + #firephp: + # type: firephp + # level: info + #chromephp: + # type: chromephp + # level: info + console: + type: console + process_psr_3_messages: false + channels: ["!event", "!doctrine", "!console"] + +when@test: + monolog: + handlers: + main: + type: fingers_crossed + action_level: error + handler: nested + excluded_http_codes: [404, 405] + channels: ["!event"] + nested: + type: stream + path: "%kernel.logs_dir%/%kernel.environment%.log" + level: debug + +when@prod: + monolog: + handlers: + main: + type: fingers_crossed + action_level: error + handler: nested + excluded_http_codes: [404, 405] + buffer_size: 50 # How many messages should be saved? Prevent memory leaks + nested: + type: stream + path: php://stderr + level: debug + formatter: monolog.formatter.json + console: + type: console + process_psr_3_messages: false + channels: ["!event", "!doctrine"] + deprecation: + type: stream + channels: [deprecation] + path: php://stderr + formatter: monolog.formatter.json diff --git a/demo/config/packages/property_info.yaml b/demo/config/packages/property_info.yaml new file mode 100644 index 000000000..dd31b9da2 --- /dev/null +++ b/demo/config/packages/property_info.yaml @@ -0,0 +1,3 @@ +framework: + property_info: + with_constructor_extractor: true diff --git a/demo/config/packages/routing.yaml b/demo/config/packages/routing.yaml new file mode 100644 index 000000000..8166181c6 --- /dev/null +++ b/demo/config/packages/routing.yaml @@ -0,0 +1,10 @@ +framework: + router: + # Configure how to generate URLs in non-HTTP contexts, such as CLI commands. + # See https://symfony.com/doc/current/routing.html#generating-urls-in-commands + #default_uri: http://localhost + +when@prod: + framework: + router: + strict_requirements: null diff --git a/demo/config/packages/twig.yaml b/demo/config/packages/twig.yaml new file mode 100644 index 000000000..3f795d921 --- /dev/null +++ b/demo/config/packages/twig.yaml @@ -0,0 +1,6 @@ +twig: + file_name_pattern: '*.twig' + +when@test: + twig: + strict_variables: true diff --git a/demo/config/packages/twig_component.yaml b/demo/config/packages/twig_component.yaml new file mode 100644 index 000000000..fd17ac693 --- /dev/null +++ b/demo/config/packages/twig_component.yaml @@ -0,0 +1,5 @@ +twig_component: + anonymous_template_directory: 'components/' + defaults: + # Namespace & directory for components + App\Twig\Components\: 'components/' diff --git a/demo/config/packages/web_profiler.yaml b/demo/config/packages/web_profiler.yaml new file mode 100644 index 000000000..9bd60954f --- /dev/null +++ b/demo/config/packages/web_profiler.yaml @@ -0,0 +1,19 @@ +when@dev: + web_profiler: + toolbar: + enabled: true + ajax_replace: true + intercept_redirects: false + + framework: + profiler: + only_exceptions: false + collect_serializer_data: true + +when@test: + web_profiler: + toolbar: false + intercept_redirects: false + + framework: + profiler: { collect: false } diff --git a/demo/config/preload.php b/demo/config/preload.php new file mode 100644 index 000000000..1abd55975 --- /dev/null +++ b/demo/config/preload.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (file_exists(dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php')) { + require dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php'; +} diff --git a/demo/config/routes.yaml b/demo/config/routes.yaml new file mode 100644 index 000000000..8cd723c53 --- /dev/null +++ b/demo/config/routes.yaml @@ -0,0 +1,40 @@ +index: + path: '/' + controller: 'Symfony\Bundle\FrameworkBundle\Controller\TemplateController' + defaults: + template: 'index.html.twig' + +blog: + path: '/blog' + controller: 'Symfony\Bundle\FrameworkBundle\Controller\TemplateController' + defaults: + template: 'chat.html.twig' + context: { chat: 'blog' } + +audio: + path: '/audio' + controller: 'Symfony\Bundle\FrameworkBundle\Controller\TemplateController' + defaults: + template: 'chat.html.twig' + context: { chat: 'audio' } + +youtube: + path: '/youtube' + controller: 'Symfony\Bundle\FrameworkBundle\Controller\TemplateController' + defaults: + template: 'chat.html.twig' + context: { chat: 'youtube' } + +video: + path: '/video' + controller: 'Symfony\Bundle\FrameworkBundle\Controller\TemplateController' + defaults: + template: 'chat.html.twig' + context: { chat: 'video' } + +wikipedia: + path: '/wikipedia' + controller: 'Symfony\Bundle\FrameworkBundle\Controller\TemplateController' + defaults: + template: 'chat.html.twig' + context: { chat: 'wikipedia' } diff --git a/demo/config/routes/framework.yaml b/demo/config/routes/framework.yaml new file mode 100644 index 000000000..0fc74bbac --- /dev/null +++ b/demo/config/routes/framework.yaml @@ -0,0 +1,4 @@ +when@dev: + _errors: + resource: '@FrameworkBundle/Resources/config/routing/errors.xml' + prefix: /_error diff --git a/demo/config/routes/ux_live_component.yaml b/demo/config/routes/ux_live_component.yaml new file mode 100644 index 000000000..e56523abf --- /dev/null +++ b/demo/config/routes/ux_live_component.yaml @@ -0,0 +1,5 @@ +live_component: + resource: '@LiveComponentBundle/config/routes.php' + prefix: '/_components' + # adjust prefix to add localization to your components + #prefix: '/{_locale}/_components' diff --git a/demo/config/routes/web_profiler.yaml b/demo/config/routes/web_profiler.yaml new file mode 100644 index 000000000..8d85319fd --- /dev/null +++ b/demo/config/routes/web_profiler.yaml @@ -0,0 +1,8 @@ +when@dev: + web_profiler_wdt: + resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml' + prefix: /_wdt + + web_profiler_profiler: + resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml' + prefix: /_profiler diff --git a/demo/config/secrets/dev/dev.OPENAI_API_KEY.66949e.php b/demo/config/secrets/dev/dev.OPENAI_API_KEY.66949e.php new file mode 100644 index 000000000..5bcf003c5 --- /dev/null +++ b/demo/config/secrets/dev/dev.OPENAI_API_KEY.66949e.php @@ -0,0 +1,12 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return "\x07\x7B\x97\x1E\xD7\x80g\x3F\xE9\x8F\xB6\xFF\x24~\x912\xFF\xD7\x2A\x5B\x1F\xDFS\xCBc\x29\xBD\xA2\xAB\x11\xBC\x0F-E\x7B\xB5\x7C\xD3\xCD\xCC\xF1E\x9B\x140-8\x3A\x84\xB6\xD8\x40\x21\x40x2\x10VNY\x5E\xE6\x9C\xF3\x13\xF1RZ\x14\xF6\xD8\xAC\x9E\x12\xD6\x20\x0C\x1F\x9E\x00\x9B\x3F\xDCv\x06T\x17\x2F\x2C4\x29\xD5\x1E\x0B\xE24\xE3z\xF6\x04\x0Ek\x03\x24"; diff --git a/demo/config/secrets/dev/dev.encrypt.public.php b/demo/config/secrets/dev/dev.encrypt.public.php new file mode 100644 index 000000000..3f615eb2e --- /dev/null +++ b/demo/config/secrets/dev/dev.encrypt.public.php @@ -0,0 +1,12 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return "\x60\xB0\x2B\x00\xA2W\x1F\x1E\x0B\x18\xBBT\x5D\x04\xD1S\x1C\x05\x03\x91\xFF\xBA\x5Cnj\x13\xCD\x11\x2C\xEBqD"; diff --git a/demo/config/secrets/dev/dev.list.php b/demo/config/secrets/dev/dev.list.php new file mode 100644 index 000000000..a329bf97f --- /dev/null +++ b/demo/config/secrets/dev/dev.list.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'OPENAI_API_KEY' => null, +]; diff --git a/demo/config/services.yaml b/demo/config/services.yaml new file mode 100644 index 000000000..ceb2c1789 --- /dev/null +++ b/demo/config/services.yaml @@ -0,0 +1,20 @@ +# This file is the entry point to configure your own services. +# Files in the packages/ subdirectory configure your dependencies. + +# Put parameters here that don't need to change on each machine where the app is deployed +# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration + +services: + # default configuration for services in *this* file + _defaults: + autowire: true # Automatically injects dependencies in your services. + autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. + + # makes classes in src/ available to be used as services + # this creates a service per class whose id is the fully-qualified class name + App\: + resource: '../src/' + exclude: + - '../src/DependencyInjection/' + - '../src/Entity/' + - '../src/Kernel.php' diff --git a/demo/demo.png b/demo/demo.png new file mode 100644 index 000000000..8007e323c Binary files /dev/null and b/demo/demo.png differ diff --git a/demo/importmap.php b/demo/importmap.php new file mode 100644 index 000000000..e2a1bbfb4 --- /dev/null +++ b/demo/importmap.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'app' => [ + 'path' => './assets/app.js', + 'entrypoint' => true, + ], + '@symfony/ux-live-component' => [ + 'path' => './vendor/symfony/ux-live-component/assets/dist/live_controller.js', + ], + '@symfony/stimulus-bundle' => [ + 'path' => './vendor/symfony/stimulus-bundle/assets/dist/loader.js', + ], + 'bootstrap' => [ + 'version' => '5.3.3', + ], + '@popperjs/core' => [ + 'version' => '2.11.8', + ], + 'bootstrap/dist/css/bootstrap.min.css' => [ + 'version' => '5.3.3', + 'type' => 'css', + ], + '@hotwired/stimulus' => [ + 'version' => '3.2.2', + ], + '@hotwired/turbo' => [ + 'version' => '8.0.4', + ], + 'typed.js' => [ + 'version' => '2.1.0', + ], +]; diff --git a/demo/phpstan.dist.neon b/demo/phpstan.dist.neon new file mode 100644 index 000000000..e9bd41c3f --- /dev/null +++ b/demo/phpstan.dist.neon @@ -0,0 +1,8 @@ +parameters: + level: 8 + paths: + - bin/ + - config/ + - public/ + - src/ + - tests/ diff --git a/demo/phpunit.xml b/demo/phpunit.xml new file mode 100644 index 000000000..0eab86518 --- /dev/null +++ b/demo/phpunit.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + tests + + + + + + src + + + diff --git a/demo/public/favicon.ico b/demo/public/favicon.ico new file mode 100644 index 000000000..8382adc6b Binary files /dev/null and b/demo/public/favicon.ico differ diff --git a/demo/public/index.php b/demo/public/index.php new file mode 100644 index 000000000..570ee3cb1 --- /dev/null +++ b/demo/public/index.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use App\Kernel; + +require_once dirname(__DIR__).'/vendor/autoload_runtime.php'; + +return function (array $context) { + return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']); +}; diff --git a/demo/public/wiki.png b/demo/public/wiki.png new file mode 100644 index 000000000..ebaec1519 Binary files /dev/null and b/demo/public/wiki.png differ diff --git a/demo/src/Audio/Chat.php b/demo/src/Audio/Chat.php new file mode 100644 index 000000000..6e0eebb39 --- /dev/null +++ b/demo/src/Audio/Chat.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\Audio; + +use Symfony\AI\Agent\AgentInterface; +use Symfony\AI\Platform\Bridge\OpenAI\Whisper; +use Symfony\AI\Platform\Message\Content\Audio; +use Symfony\AI\Platform\Message\Message; +use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Platform\PlatformInterface; +use Symfony\AI\Platform\Response\AsyncResponse; +use Symfony\AI\Platform\Response\TextResponse; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\HttpFoundation\RequestStack; + +final class Chat +{ + private const SESSION_KEY = 'audio-chat'; + + public function __construct( + private readonly PlatformInterface $platform, + private readonly RequestStack $requestStack, + #[Autowire(service: 'symfony_ai.agent.audio')] + private readonly AgentInterface $agent, + ) { + } + + public function say(string $base64audio): void + { + // Convert base64 to temporary binary file + $path = tempnam(sys_get_temp_dir(), 'audio-').'.wav'; + file_put_contents($path, base64_decode($base64audio)); + + $response = $this->platform->request(new Whisper(), Audio::fromFile($path)); + \assert($response instanceof AsyncResponse); + $response = $response->unwrap(); + \assert($response instanceof TextResponse); + + $this->submitMessage($response->getContent()); + } + + public function loadMessages(): MessageBag + { + return $this->requestStack->getSession()->get(self::SESSION_KEY, new MessageBag()); + } + + public function submitMessage(string $message): void + { + $messages = $this->loadMessages(); + + $messages->add(Message::ofUser($message)); + $response = $this->agent->call($messages); + + \assert($response instanceof TextResponse); + + $messages->add(Message::ofAssistant($response->getContent())); + + $this->saveMessages($messages); + } + + public function reset(): void + { + $this->requestStack->getSession()->remove(self::SESSION_KEY); + } + + private function saveMessages(MessageBag $messages): void + { + $this->requestStack->getSession()->set(self::SESSION_KEY, $messages); + } +} diff --git a/demo/src/Audio/TwigComponent.php b/demo/src/Audio/TwigComponent.php new file mode 100644 index 000000000..dbb33a1be --- /dev/null +++ b/demo/src/Audio/TwigComponent.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\Audio; + +use Symfony\AI\Platform\Message\MessageInterface; +use Symfony\UX\LiveComponent\Attribute\AsLiveComponent; +use Symfony\UX\LiveComponent\Attribute\LiveAction; +use Symfony\UX\LiveComponent\Attribute\LiveArg; +use Symfony\UX\LiveComponent\DefaultActionTrait; + +#[AsLiveComponent('audio')] +final class TwigComponent +{ + use DefaultActionTrait; + + public function __construct( + private readonly Chat $chat, + ) { + } + + /** + * @return MessageInterface[] + */ + public function getMessages(): array + { + return $this->chat->loadMessages()->withoutSystemMessage()->getMessages(); + } + + #[LiveAction] + public function submit(#[LiveArg] string $audio): void + { + $this->chat->say($audio); + } + + #[LiveAction] + public function reset(): void + { + $this->chat->reset(); + } +} diff --git a/demo/src/Blog/Chat.php b/demo/src/Blog/Chat.php new file mode 100644 index 000000000..174bacb69 --- /dev/null +++ b/demo/src/Blog/Chat.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\Blog; + +use Symfony\AI\Agent\AgentInterface; +use Symfony\AI\Platform\Message\Message; +use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Platform\Response\TextResponse; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\HttpFoundation\RequestStack; + +final class Chat +{ + private const SESSION_KEY = 'blog-chat'; + + public function __construct( + private readonly RequestStack $requestStack, + #[Autowire(service: 'symfony_ai.agent.blog')] + private readonly AgentInterface $agent, + ) { + } + + public function loadMessages(): MessageBag + { + $messages = new MessageBag( + Message::forSystem(<<requestStack->getSession()->get(self::SESSION_KEY, $messages); + } + + public function submitMessage(string $message): void + { + $messages = $this->loadMessages(); + + $messages->add(Message::ofUser($message)); + $response = $this->agent->call($messages); + + \assert($response instanceof TextResponse); + + $messages->add(Message::ofAssistant($response->getContent())); + + $this->saveMessages($messages); + } + + public function reset(): void + { + $this->requestStack->getSession()->remove(self::SESSION_KEY); + } + + private function saveMessages(MessageBag $messages): void + { + $this->requestStack->getSession()->set(self::SESSION_KEY, $messages); + } +} diff --git a/demo/src/Blog/Command/EmbedCommand.php b/demo/src/Blog/Command/EmbedCommand.php new file mode 100644 index 000000000..370a25f34 --- /dev/null +++ b/demo/src/Blog/Command/EmbedCommand.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\Blog\Command; + +use App\Blog\Embedder; +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; + +#[AsCommand('app:blog:embed', description: 'Create embeddings for Symfony blog and push to ChromaDB.')] +final class EmbedCommand extends Command +{ + public function __construct( + private readonly Embedder $embedder, + ) { + parent::__construct(); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + $io->title('Loading RSS of Symfony blog as embeddings into ChromaDB'); + + $this->embedder->embedBlog(); + + $io->success('Symfony Blog Successfully Embedded!'); + + return Command::SUCCESS; + } +} diff --git a/demo/src/Blog/Command/QueryCommand.php b/demo/src/Blog/Command/QueryCommand.php new file mode 100644 index 000000000..cb7272a20 --- /dev/null +++ b/demo/src/Blog/Command/QueryCommand.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\Blog\Command; + +use Codewithkyrian\ChromaDB\Client; +use Symfony\AI\Platform\Bridge\OpenAI\Embeddings; +use Symfony\AI\Platform\PlatformInterface; +use Symfony\AI\Platform\Response\AsyncResponse; +use Symfony\AI\Platform\Response\VectorResponse; +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; + +#[AsCommand('app:blog:query', description: 'Test command for querying the blog collection in Chroma DB.')] +final class QueryCommand extends Command +{ + public function __construct( + private readonly Client $chromaClient, + private readonly PlatformInterface $platform, + ) { + parent::__construct(); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + $io->title('Testing Chroma DB Connection'); + + $io->comment('Connecting to Chroma DB ...'); + $collection = $this->chromaClient->getOrCreateCollection('symfony_blog'); + $io->table(['Key', 'Value'], [ + ['ChromaDB Version', $this->chromaClient->version()], + ['Collection Name', $collection->name], + ['Collection ID', $collection->id], + ['Total Documents', $collection->count()], + ]); + + $search = $io->ask('What do you want to know about?', 'New Symfony Features'); + $io->comment(\sprintf('Converting "%s" to vector & searching in Chroma DB ...', $search)); + $io->comment('Results are limited to 4 most similar documents.'); + + $platformResponse = $this->platform->request(new Embeddings(), $search); + \assert($platformResponse instanceof AsyncResponse); + $platformResponse = $platformResponse->unwrap(); + \assert($platformResponse instanceof VectorResponse); + $queryResponse = $collection->query( + queryEmbeddings: [$platformResponse->getContent()[0]->getData()], + nResults: 4, + ); + + if (1 === \count($queryResponse->ids, \COUNT_RECURSIVE)) { + $io->error('No results found!'); + + return Command::FAILURE; + } + + foreach ($queryResponse->ids[0] as $i => $id) { + /* @phpstan-ignore-next-line */ + $io->section($queryResponse->metadatas[0][$i]['title']); + /* @phpstan-ignore-next-line */ + $io->block($queryResponse->metadatas[0][$i]['description']); + } + + $io->success('Chroma DB Connection & Similarity Search Test Successful!'); + + return Command::SUCCESS; + } +} diff --git a/demo/src/Blog/Embedder.php b/demo/src/Blog/Embedder.php new file mode 100644 index 000000000..3491f564e --- /dev/null +++ b/demo/src/Blog/Embedder.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\Blog; + +use Symfony\AI\Store\Document\Metadata; +use Symfony\AI\Store\Document\TextDocument; +use Symfony\AI\Store\Indexer; + +final readonly class Embedder +{ + public function __construct( + private FeedLoader $loader, + private Indexer $indexer, + ) { + } + + public function embedBlog(): void + { + $documents = []; + foreach ($this->loader->load() as $post) { + $documents[] = new TextDocument($post->id, $post->toString(), new Metadata($post->toArray())); + } + + $this->indexer->index($documents); + } +} diff --git a/demo/src/Blog/FeedLoader.php b/demo/src/Blog/FeedLoader.php new file mode 100644 index 000000000..b82d95a46 --- /dev/null +++ b/demo/src/Blog/FeedLoader.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\Blog; + +use Symfony\Component\DomCrawler\Crawler; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +class FeedLoader +{ + public function __construct( + private HttpClientInterface $httpClient, + ) { + } + + /** + * @return Post[] + */ + public function load(): array + { + $response = $this->httpClient->request('GET', 'https://feeds.feedburner.com/symfony/blog'); + + $posts = []; + $crawler = new Crawler($response->getContent()); + $crawler->filter('item')->each(function (Crawler $node) use (&$posts) { + $title = $node->filter('title')->text(); + $posts[] = new Post( + Uuid::v5(Uuid::fromString('6ba7b810-9dad-11d1-80b4-00c04fd430c8'), $title), + $title, + $node->filter('link')->text(), + $node->filter('description')->text(), + (new Crawler($node->filter('content\:encoded')->text()))->text(), + $node->filter('dc\:creator')->text(), + new \DateTimeImmutable($node->filter('pubDate')->text()), + ); + }); + + return $posts; + } +} diff --git a/demo/src/Blog/Post.php b/demo/src/Blog/Post.php new file mode 100644 index 000000000..13f9819b3 --- /dev/null +++ b/demo/src/Blog/Post.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\Blog; + +use Symfony\Component\Uid\Uuid; + +final readonly class Post +{ + public function __construct( + public Uuid $id, + public string $title, + public string $link, + public string $description, + public string $content, + public string $author, + public \DateTimeImmutable $date, + ) { + } + + public function toString(): string + { + return <<title} + From: {$this->author} on {$this->date->format('Y-m-d')} + Description: {$this->description} + {$this->content} + TEXT; + } + + /** + * @return array{ + * id: string, + * title: string, + * link: string, + * description: string, + * content: string, + * author: string, + * date: string, + * } + */ + public function toArray(): array + { + return [ + 'id' => $this->id->toRfc4122(), + 'title' => $this->title, + 'link' => $this->link, + 'description' => $this->description, + 'content' => $this->content, + 'author' => $this->author, + 'date' => $this->date->format('Y-m-d'), + ]; + } +} diff --git a/demo/src/Blog/TwigComponent.php b/demo/src/Blog/TwigComponent.php new file mode 100644 index 000000000..5b7c3371d --- /dev/null +++ b/demo/src/Blog/TwigComponent.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\Blog; + +use Symfony\AI\Platform\Message\MessageInterface; +use Symfony\UX\LiveComponent\Attribute\AsLiveComponent; +use Symfony\UX\LiveComponent\Attribute\LiveAction; +use Symfony\UX\LiveComponent\Attribute\LiveArg; +use Symfony\UX\LiveComponent\DefaultActionTrait; + +#[AsLiveComponent('blog')] +final class TwigComponent +{ + use DefaultActionTrait; + + public function __construct( + private readonly Chat $chat, + ) { + } + + /** + * @return MessageInterface[] + */ + public function getMessages(): array + { + return $this->chat->loadMessages()->withoutSystemMessage()->getMessages(); + } + + #[LiveAction] + public function submit(#[LiveArg] string $message): void + { + $this->chat->submitMessage($message); + } + + #[LiveAction] + public function reset(): void + { + $this->chat->reset(); + } +} diff --git a/demo/src/Kernel.php b/demo/src/Kernel.php new file mode 100644 index 000000000..07997857d --- /dev/null +++ b/demo/src/Kernel.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App; + +use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; +use Symfony\Component\HttpKernel\Kernel as BaseKernel; + +class Kernel extends BaseKernel +{ + use MicroKernelTrait; +} diff --git a/demo/src/Video/TwigComponent.php b/demo/src/Video/TwigComponent.php new file mode 100644 index 000000000..9ba1a18db --- /dev/null +++ b/demo/src/Video/TwigComponent.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\Video; + +use Symfony\AI\Platform\Bridge\OpenAI\GPT; +use Symfony\AI\Platform\Message\Content\Image; +use Symfony\AI\Platform\Message\Message; +use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Platform\PlatformInterface; +use Symfony\AI\Platform\Response\AsyncResponse; +use Symfony\AI\Platform\Response\TextResponse; +use Symfony\UX\LiveComponent\Attribute\AsLiveComponent; +use Symfony\UX\LiveComponent\Attribute\LiveAction; +use Symfony\UX\LiveComponent\Attribute\LiveArg; +use Symfony\UX\LiveComponent\Attribute\LiveProp; +use Symfony\UX\LiveComponent\DefaultActionTrait; + +#[AsLiveComponent('video')] +final class TwigComponent +{ + use DefaultActionTrait; + + #[LiveProp] + public string $caption = 'Please define an instruction and hit submit.'; + + public function __construct( + private readonly PlatformInterface $platform, + ) { + } + + #[LiveAction] + public function submit(#[LiveArg] string $instruction, #[LiveArg] string $image): void + { + $messageBag = new MessageBag( + Message::forSystem(<<platform->request(new GPT(GPT::GPT_4O_MINI), $messageBag, [ + 'max_tokens' => 100, + ]); + + \assert($response instanceof AsyncResponse); + $response = $response->unwrap(); + \assert($response instanceof TextResponse); + + $this->caption = $response->getContent(); + } +} diff --git a/demo/src/Wikipedia/Chat.php b/demo/src/Wikipedia/Chat.php new file mode 100644 index 000000000..af44f38e9 --- /dev/null +++ b/demo/src/Wikipedia/Chat.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\Wikipedia; + +use Symfony\AI\Agent\AgentInterface; +use Symfony\AI\Platform\Message\Message; +use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Platform\Response\TextResponse; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\HttpFoundation\RequestStack; + +final class Chat +{ + private const SESSION_KEY = 'wikipedia-chat'; + + public function __construct( + private readonly RequestStack $requestStack, + #[Autowire(service: 'symfony_ai.agent.wikipedia')] + private readonly AgentInterface $chain, + ) { + } + + public function loadMessages(): MessageBag + { + return $this->requestStack->getSession()->get(self::SESSION_KEY, new MessageBag()); + } + + public function submitMessage(string $message): void + { + $messages = $this->loadMessages(); + + $messages->add(Message::ofUser($message)); + $response = $this->chain->call($messages); + + \assert($response instanceof TextResponse); + + $messages->add(Message::ofAssistant($response->getContent())); + + $this->saveMessages($messages); + } + + public function reset(): void + { + $this->requestStack->getSession()->remove(self::SESSION_KEY); + } + + private function saveMessages(MessageBag $messages): void + { + $this->requestStack->getSession()->set(self::SESSION_KEY, $messages); + } +} diff --git a/demo/src/Wikipedia/TwigComponent.php b/demo/src/Wikipedia/TwigComponent.php new file mode 100644 index 000000000..d0f4897e9 --- /dev/null +++ b/demo/src/Wikipedia/TwigComponent.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\Wikipedia; + +use Symfony\AI\Platform\Message\MessageInterface; +use Symfony\UX\LiveComponent\Attribute\AsLiveComponent; +use Symfony\UX\LiveComponent\Attribute\LiveAction; +use Symfony\UX\LiveComponent\Attribute\LiveArg; +use Symfony\UX\LiveComponent\DefaultActionTrait; + +#[AsLiveComponent('wikipedia')] +final class TwigComponent +{ + use DefaultActionTrait; + + public function __construct( + private readonly Chat $wikipedia, + ) { + } + + /** + * @return MessageInterface[] + */ + public function getMessages(): array + { + return $this->wikipedia->loadMessages()->withoutSystemMessage()->getMessages(); + } + + #[LiveAction] + public function submit(#[LiveArg] string $message): void + { + $this->wikipedia->submitMessage($message); + } + + #[LiveAction] + public function reset(): void + { + $this->wikipedia->reset(); + } +} diff --git a/demo/src/YouTube/Chat.php b/demo/src/YouTube/Chat.php new file mode 100644 index 000000000..8959ad995 --- /dev/null +++ b/demo/src/YouTube/Chat.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\YouTube; + +use Symfony\AI\Agent\AgentInterface; +use Symfony\AI\Platform\Message\Message; +use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Platform\Response\TextResponse; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\HttpFoundation\RequestStack; + +final class Chat +{ + private const SESSION_KEY = 'youtube-chat'; + + public function __construct( + private readonly RequestStack $requestStack, + #[Autowire(service: 'symfony_ai.agent.youtube')] + private readonly AgentInterface $agent, + private readonly TranscriptFetcher $transcriptFetcher, + ) { + } + + public function loadMessages(): MessageBag + { + return $this->requestStack->getSession()->get(self::SESSION_KEY, new MessageBag()); + } + + public function start(string $videoId): void + { + $transcript = $this->transcriptFetcher->fetchTranscript($videoId); + $system = <<reset(); + $this->saveMessages($messages); + } + + public function submitMessage(string $message): void + { + $messages = $this->loadMessages(); + + $messages->add(Message::ofUser($message)); + $response = $this->agent->call($messages); + + \assert($response instanceof TextResponse); + + $messages->add(Message::ofAssistant($response->getContent())); + + $this->saveMessages($messages); + } + + public function reset(): void + { + $this->requestStack->getSession()->remove(self::SESSION_KEY); + } + + private function saveMessages(MessageBag $messages): void + { + $this->requestStack->getSession()->set(self::SESSION_KEY, $messages); + } +} diff --git a/demo/src/YouTube/TranscriptFetcher.php b/demo/src/YouTube/TranscriptFetcher.php new file mode 100644 index 000000000..568ee01d6 --- /dev/null +++ b/demo/src/YouTube/TranscriptFetcher.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\YouTube; + +use Symfony\Component\DomCrawler\Crawler; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +final class TranscriptFetcher +{ + public function __construct( + private readonly HttpClientInterface $client, + ) { + } + + public function fetchTranscript(string $videoId): string + { + // Fetch the HTML content of the YouTube video page + $htmlResponse = $this->client->request('GET', 'https://youtube.com/watch?v='.$videoId); + $html = $htmlResponse->getContent(); + + // Use DomCrawler to parse the HTML + $crawler = new Crawler($html); + + // Extract the script containing the ytInitialPlayerResponse + $scriptContent = $crawler->filter('script')->reduce(function (Crawler $node) { + return str_contains($node->text(), 'var ytInitialPlayerResponse = {'); + })->text(); + + // Extract and parse the JSON data from the script + $start = strpos($scriptContent, 'var ytInitialPlayerResponse = ') + \strlen('var ytInitialPlayerResponse = '); + $dataString = substr($scriptContent, $start); + $dataString = substr($dataString, 0, strrpos($dataString, ';') ?: null); + $data = json_decode(trim($dataString), true); + + // Extract the URL for the captions + if (!isset($data['captions']['playerCaptionsTracklistRenderer']['captionTracks'][0]['baseUrl'])) { + throw new \Exception('Captions are not available for this video.'); + } + $captionsUrl = $data['captions']['playerCaptionsTracklistRenderer']['captionTracks'][0]['baseUrl']; + + // Fetch and parse the captions XML + $xmlResponse = $this->client->request('GET', $captionsUrl); + $xmlContent = $xmlResponse->getContent(); + $xmlCrawler = new Crawler($xmlContent); + + // Collect all text elements from the captions + $transcript = $xmlCrawler->filter('text')->each(function (Crawler $node) { + return $node->text().' TranscriptFetcher.php'; + }); + + // Combine all the text elements into one string + return implode(\PHP_EOL, $transcript); + } +} diff --git a/demo/src/YouTube/TwigComponent.php b/demo/src/YouTube/TwigComponent.php new file mode 100644 index 000000000..6675abd21 --- /dev/null +++ b/demo/src/YouTube/TwigComponent.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\YouTube; + +use Psr\Log\LoggerInterface; +use Symfony\AI\Platform\Message\MessageInterface; +use Symfony\UX\LiveComponent\Attribute\AsLiveComponent; +use Symfony\UX\LiveComponent\Attribute\LiveAction; +use Symfony\UX\LiveComponent\Attribute\LiveArg; +use Symfony\UX\LiveComponent\DefaultActionTrait; + +use function Symfony\Component\String\u; + +#[AsLiveComponent('youtube')] +final class TwigComponent +{ + use DefaultActionTrait; + + public function __construct( + private readonly Chat $youTube, + private readonly LoggerInterface $logger, + ) { + } + + #[LiveAction] + public function start(#[LiveArg] string $videoId): void + { + if (str_contains($videoId, 'youtube.com')) { + $videoId = $this->getVideoIdFromUrl($videoId); + } + + try { + $this->youTube->start($videoId); + } catch (\Exception $e) { + $this->logger->error('Unable to start YouTube chat.', ['exception' => $e]); + $this->youTube->reset(); + } + } + + /** + * @return MessageInterface[] + */ + public function getMessages(): array + { + return $this->youTube->loadMessages()->withoutSystemMessage()->getMessages(); + } + + #[LiveAction] + public function submit(#[LiveArg] string $message): void + { + $this->youTube->submitMessage($message); + } + + #[LiveAction] + public function reset(): void + { + $this->youTube->reset(); + } + + private function getVideoIdFromUrl(string $url): string + { + $query = parse_url($url, \PHP_URL_QUERY); + + if (!$query) { + throw new \InvalidArgumentException('Unable to parse YouTube URL.'); + } + + return u($query)->after('v=')->before('&')->toString(); + } +} diff --git a/demo/symfony.lock b/demo/symfony.lock new file mode 100644 index 000000000..4255e4cfe --- /dev/null +++ b/demo/symfony.lock @@ -0,0 +1,256 @@ +{ + "doctrine/deprecations": { + "version": "1.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "1.0", + "ref": "87424683adc81d7dc305eefec1fced883084aab9" + } + }, + "php-cs-fixer/shim": { + "version": "3.55", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "3.0", + "ref": "16422bf8eac6c3be42afe07d37e2abc89d2bdf6b" + }, + "files": [ + ".php-cs-fixer.dist.php" + ] + }, + "php-llm/llm-chain-bundle": { + "version": "dev-main" + }, + "phpstan/phpstan": { + "version": "1.10", + "recipe": { + "repo": "github.com/symfony/recipes-contrib", + "branch": "main", + "version": "1.0", + "ref": "5e490cc197fb6bb1ae22e5abbc531ddc633b6767" + }, + "files": [ + "phpstan.dist.neon" + ] + }, + "phpunit/phpunit": { + "version": "11.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "9.6", + "ref": "7364a21d87e658eb363c5020c072ecfdc12e2326" + }, + "files": [ + ".env.test", + "phpunit.xml.dist", + "tests/bootstrap.php" + ] + }, + "symfony/ai-bundle": { + "version": "dev-integrate-demo" + }, + "symfony/asset-mapper": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "6.4", + "ref": "5ad1308aa756d58f999ffbe1540d1189f5d7d14a" + }, + "files": [ + "assets/app.js", + "assets/styles/app.css", + "config/packages/asset_mapper.yaml", + "importmap.php" + ] + }, + "symfony/console": { + "version": "7.0", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "5.3", + "ref": "1781ff40d8a17d87cf53f8d4cf0c8346ed2bb461" + }, + "files": [ + "bin/console" + ] + }, + "symfony/debug-bundle": { + "version": "7.0", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "5.3", + "ref": "5aa8aa48234c8eb6dbdd7b3cd5d791485d2cec4b" + }, + "files": [ + "config/packages/debug.yaml" + ] + }, + "symfony/flex": { + "version": "2.4", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "1.0", + "ref": "146251ae39e06a95be0fe3d13c807bcf3938b172" + }, + "files": [ + ".env" + ] + }, + "symfony/framework-bundle": { + "version": "7.0", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "7.0", + "ref": "6356c19b9ae08e7763e4ba2d9ae63043efc75db5" + }, + "files": [ + "config/packages/cache.yaml", + "config/packages/framework.yaml", + "config/preload.php", + "config/routes/framework.yaml", + "config/services.yaml", + "public/index.php", + "src/Controller/.gitignore", + "src/Kernel.php" + ] + }, + "symfony/monolog-bundle": { + "version": "3.10", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "3.7", + "ref": "aff23899c4440dd995907613c1dd709b6f59503f" + }, + "files": [ + "config/packages/monolog.yaml" + ] + }, + "symfony/property-info": { + "version": "7.3", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "7.3", + "ref": "dae70df71978ae9226ae915ffd5fad817f5ca1f7" + }, + "files": [ + "config/packages/property_info.yaml" + ] + }, + "symfony/routing": { + "version": "7.0", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "7.0", + "ref": "21b72649d5622d8f7da329ffb5afb232a023619d" + }, + "files": [ + "config/packages/routing.yaml", + "config/routes.yaml" + ] + }, + "symfony/stimulus-bundle": { + "version": "2.17", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "2.13", + "ref": "6acd9ff4f7fd5626d2962109bd4ebab351d43c43" + }, + "files": [ + "assets/bootstrap.js", + "assets/controllers.json", + "assets/controllers/chat_controller.js" + ] + }, + "symfony/twig-bundle": { + "version": "7.0", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "6.4", + "ref": "cab5fd2a13a45c266d45a7d9337e28dee6272877" + }, + "files": [ + "config/packages/twig.yaml", + "templates/base.html.twig" + ] + }, + "symfony/uid": { + "version": "7.0", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "7.0", + "ref": "0df5844274d871b37fc3816c57a768ffc60a43a5" + } + }, + "symfony/ux-icons": { + "version": "2.17", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "2.17", + "ref": "803a3bbd5893f9584969ab8670290cdfb6a0a5b5" + }, + "files": [ + "assets/icons/symfony.svg" + ] + }, + "symfony/ux-live-component": { + "version": "2.17", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "2.6", + "ref": "73e69baf18f47740d6f58688c5464b10cdacae06" + }, + "files": [ + "config/routes/ux_live_component.yaml" + ] + }, + "symfony/ux-turbo": { + "version": "v2.17.0" + }, + "symfony/ux-twig-component": { + "version": "2.17", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "2.13", + "ref": "67814b5f9794798b885cec9d3f48631424449a01" + }, + "files": [ + "config/packages/twig_component.yaml" + ] + }, + "symfony/ux-typed": { + "version": "v2.22.0" + }, + "symfony/web-profiler-bundle": { + "version": "7.0", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "6.1", + "ref": "e42b3f0177df239add25373083a564e5ead4e13a" + }, + "files": [ + "config/packages/web_profiler.yaml", + "config/routes/web_profiler.yaml" + ] + }, + "twig/extra-bundle": { + "version": "v3.9.3" + } +} diff --git a/demo/templates/_message.html.twig b/demo/templates/_message.html.twig new file mode 100644 index 000000000..141dd2f8c --- /dev/null +++ b/demo/templates/_message.html.twig @@ -0,0 +1,53 @@ +{% if message.role.value == 'assistant' %} + {{ _self.bot(message.content, latest: latest) }} +{% else %} + {{ _self.user(message.content) }} +{% endif %} + +{% macro bot(content, loading = false, latest = false) %} +
+
+ {{ ux_icon('fluent:bot-24-filled', { height: '45px', width: '45px' }) }} +
+
+ {% if loading %} +
+ + {{ content }} +
+ {% else %} +
+ {% if latest and app.request.xmlHttpRequest %} + + {% else %} + {{ content|markdown_to_html }} + {% endif %} +
+ {% endif %} +
+
+{% endmacro %} + +{% macro user(content, loading = false) %} +
+
+ {% for item in content %} +
+ {% if loading %} + {{ item.text }} + {% else %} + {{ item.text }} + {% endif %} +
+ {% endfor %} +
+
+ {{ ux_icon('solar:user-bold', { width: '45px', height: '45px' }) }} +
+
+{% endmacro %} diff --git a/demo/templates/base.html.twig b/demo/templates/base.html.twig new file mode 100644 index 000000000..c7286096c --- /dev/null +++ b/demo/templates/base.html.twig @@ -0,0 +1,57 @@ + + + + + {% block title %}Symfony AI Demo{% endblock %} + + + + {% block stylesheets %} + {% endblock %} + + {% block javascripts %} + {% block importmap %}{{ importmap('app') }}{% endblock %} + {% endblock %} + + + +
+ {% block content %}{% endblock %} +
+ Demo application for Symfony AI + • + Feel free to propose more examples on GitHub +
+
+ + diff --git a/demo/templates/chat.html.twig b/demo/templates/chat.html.twig new file mode 100644 index 000000000..a3270e69d --- /dev/null +++ b/demo/templates/chat.html.twig @@ -0,0 +1,9 @@ +{% extends 'base.html.twig' %} + +{% block body_class 'chat ' ~ chat %} + +{% block content %} +
+ {{ component(chat) }} +
+{% endblock %} diff --git a/demo/templates/components/audio.html.twig b/demo/templates/components/audio.html.twig new file mode 100644 index 000000000..303b59b34 --- /dev/null +++ b/demo/templates/components/audio.html.twig @@ -0,0 +1,38 @@ +{% import "_message.html.twig" as message %} + +
+
+ {{ ux_icon('iconoir:microphone-solid', { height: '32px', width: '32px' }) }} + Conversational Bot + +
+
+ {% for message in this.messages %} + {% include '_message.html.twig' with { message, latest: loop.last } %} + {% else %} +
+ {{ ux_icon('iconoir:microphone-solid', { height: '200px', width: '200px' }) }} +

Audio Bot

+ Please hit the button below to start talking and again to stop +
+ {% endfor %} +
+ {{ message.user([{text:'Converting your speech to text ...'}], true) }} + {{ message.bot('The Bot is looking for an answer ...', true) }} +
+
+ +
diff --git a/demo/templates/components/blog.html.twig b/demo/templates/components/blog.html.twig new file mode 100644 index 000000000..868e5105f --- /dev/null +++ b/demo/templates/components/blog.html.twig @@ -0,0 +1,30 @@ +{% import "_message.html.twig" as message %} + +
+
+ {{ ux_icon('mdi:symfony', { height: '32px', width: '32px' }) }} + Symfony Blog Bot + +
+
+ {% for message in this.messages %} + {% include '_message.html.twig' with { message, latest: loop.last } %} + {% else %} +
+ {{ ux_icon('mdi:symfony', { height: '200px', width: '200px' }) }} +

Retrieval Augmented Generation based on the Symfony blog

+ Please use the text input at the bottom to start chatting. +
+ {% endfor %} +
+ {{ message.user([{text:''}]) }} + {{ message.bot('The Symfony Bot is looking for an answer ...', true) }} +
+
+ +
diff --git a/demo/templates/components/video.html.twig b/demo/templates/components/video.html.twig new file mode 100644 index 000000000..9e9d3c39e --- /dev/null +++ b/demo/templates/components/video.html.twig @@ -0,0 +1,23 @@ +{% import "_message.html.twig" as message %} + +
+
+ {{ ux_icon('tabler:video-filled', { height: '32px', width: '32px' }) }} + Video Bot +
+
+
+
+ +
+ + {{ this.caption }} +
+
+ +
diff --git a/demo/templates/components/wikipedia.html.twig b/demo/templates/components/wikipedia.html.twig new file mode 100644 index 000000000..a187a1706 --- /dev/null +++ b/demo/templates/components/wikipedia.html.twig @@ -0,0 +1,30 @@ +{% import "_message.html.twig" as message %} + +
+
+ {{ ux_icon('mdi:wikipedia', { height: '32px', width: '32px' }) }} + Wikipedia Research Bot + +
+
+ {% for message in this.messages %} + {% include '_message.html.twig' with { message, latest: loop.last } %} + {% else %} +
+ {{ ux_icon('mdi:wikipedia', { height: '200px', width: '200px' }) }} +

Wikipedia Research

+ Please provide the bot with a topic down below to start the research. +
+ {% endfor %} +
+ {{ message.user([{text:''}]) }} + {{ message.bot('The Wikipedia Bot is doing some research ...', true) }} +
+
+ +
diff --git a/demo/templates/components/youtube.html.twig b/demo/templates/components/youtube.html.twig new file mode 100644 index 000000000..3fda82208 --- /dev/null +++ b/demo/templates/components/youtube.html.twig @@ -0,0 +1,38 @@ +{% import "_message.html.twig" as message %} + +
+
+ {{ ux_icon('bi:youtube', { height: '32px', width: '32px' }) }} + YouTube Transcript Bot + +
+
+ {% set messages = this.messages %} + {% for message in messages %} + {% include '_message.html.twig' with { message, latest: loop.last } %} + {% else %} +
+ {{ ux_icon('bi:youtube', { color: '#FF0000', height: '200px', width: '200px' }) }} +

Chat about a YouTube Video

+
+ +
+ https://youtube.com/watch?v= + + +
+
+
+ {% endfor %} +
+ {{ message.user([{text:''}]) }} + {{ message.bot('The Youtube Bot is looking for an answer ...', true) }} +
+
+ +
diff --git a/demo/templates/index.html.twig b/demo/templates/index.html.twig new file mode 100644 index 000000000..f90417f8f --- /dev/null +++ b/demo/templates/index.html.twig @@ -0,0 +1,117 @@ +{% extends 'base.html.twig' %} + +{% block body_class 'index' %} + +{% block content %} +
+

Welcome to the Symfony AI Demo

+

+ This is a small demo app that can be used to explore the capabilities of Symfony AI Components together with + Symfony UX and Twig Live Components.
+ Central to this demo are five chatbot examples that are implemented in src/**/Chat.php and AI + configuration can be found in config/packages/ai.yaml. +

+

Examples

+
+
+
+
+ {{ ux_icon('mdi:symfony', { height: '150px', width: '150px' }) }} +
+
+
Symfony Blog Bot
+

Retrieval Augmented Generation (RAG) based on Symfony's blog dumped to a vector store.

+ Try Symfony Blog Bot +
+ {# Profiler route only available in dev #} + {% if 'dev' == app.environment %} + + {% endif %} +
+
+
+
+
+ {{ ux_icon('bi:youtube', { height: '150px', width: '150px' }) }} +
+
+
YouTube Transcript Bot
+

Question answering started with a YouTube video ID which gets converted into a transcript.

+ Try YouTube Transcript Bot +
+ {# Profiler route only available in dev #} + {% if 'dev' == app.environment %} + + {% endif %} +
+
+
+
+
+ {{ ux_icon('mdi:wikipedia', { height: '150px', width: '150px' }) }} +
+
+
Wikipedia Research Bot
+

A chatbot equipped with tools to search and read on Wikipedia about topics the user asks for.

+ Try Wikipedia Research Bot +
+ {# Profiler route only available in dev #} + {% if 'dev' == app.environment %} + + {% endif %} +
+
+
+
+
+
+
+
+ {{ ux_icon('iconoir:microphone-solid', { height: '150px', width: '150px' }) }} +
+
+
Audio Bot
+

Simple demonstration of speech-to-text with Whisper in combination with GPT.

+ Try Audio Bot +
+ {# Profiler route only available in dev #} + {% if 'dev' == app.environment %} + + {% endif %} +
+
+
+
+
+ {{ ux_icon('tabler:video-filled', { height: '150px', width: '150px' }) }} +
+
+
Video Bot
+

Simple demonstration of vision capabilities of GPT in combination with your webcam.

+ Try Video Bot +
+ {# Profiler route only available in dev #} + {% if 'dev' == app.environment %} + + {% endif %} +
+
+
+
+
+{% endblock %} diff --git a/demo/tests/Blog/LoaderTest.php b/demo/tests/Blog/LoaderTest.php new file mode 100644 index 000000000..57103604e --- /dev/null +++ b/demo/tests/Blog/LoaderTest.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\Tests\Blog; + +use App\Blog\FeedLoader; +use App\Blog\Post; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\HttpClient\Response\MockResponse; + +#[CoversClass(FeedLoader::class)] +#[UsesClass(Post::class)] +final class LoaderTest extends TestCase +{ + public function testLoad(): void + { + $response = MockResponse::fromFile(__DIR__.'/fixtures/blog.rss'); + $client = new MockHttpClient($response); + + $loader = new FeedLoader($client); + $posts = $loader->load(); + + self::assertCount(10, $posts); + + self::assertSame('A Week of Symfony #936 (2-8 December 2024)', $posts[0]->title); + self::assertSame('https://symfony.com/blog/a-week-of-symfony-936-2-8-december-2024?utm_source=Symfony%20Blog%20Feed&utm_medium=feed', $posts[0]->link); + self::assertStringContainsString('This week, Symfony celebrated the SymfonyCon 2024 Vienna conference with great success.', $posts[0]->description); + self::assertStringContainsString('Select a track for a guided path through 100+ video tutorial courses about Symfony', $posts[0]->content); + self::assertSame('Javier Eguiluz', $posts[0]->author); + self::assertEquals(new \DateTimeImmutable('8.12.2024 09:39:00 +0100'), $posts[0]->date); + + self::assertSame('A Week of Symfony #935 (25 November - 1 December 2024)', $posts[1]->title); + self::assertSame('Symfony 7.2 curated new features', $posts[2]->title); + self::assertSame('Symfony 7.2.0 released', $posts[3]->title); + self::assertSame('Symfony 5.4.49 released', $posts[4]->title); + self::assertSame('SymfonyCon Vienna 2024: See you next week!', $posts[5]->title); + self::assertSame('New in Symfony 7.2: Misc. Improvements (Part 2)', $posts[6]->title); + self::assertSame('Symfony 7.1.9 released', $posts[7]->title); + self::assertSame('Symfony 6.4.16 released', $posts[8]->title); + self::assertSame('Symfony 5.4.48 released', $posts[9]->title); + } +} diff --git a/demo/tests/Blog/PostTest.php b/demo/tests/Blog/PostTest.php new file mode 100644 index 000000000..5a34a4be3 --- /dev/null +++ b/demo/tests/Blog/PostTest.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\Tests\Blog; + +use App\Blog\Post; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(Post::class)] +final class PostTest extends TestCase +{ + public function testPostToString(): void + { + $post = new Post( + Uuid::v4(), + 'Hello, World!', + 'https://example.com/hello-world', + 'This is a test description.', + 'This is a test post.', + 'John Doe', + new \DateTimeImmutable('2024-12-08 09:39:00'), + ); + + $expected = <<toString()); + } + + public function testPostToArray(): void + { + $id = Uuid::v4(); + $post = new Post( + $id, + 'Hello, World!', + 'https://example.com/hello-world', + 'This is a test description.', + 'This is a test post.', + 'John Doe', + new \DateTimeImmutable('2024-12-08 09:39:00'), + ); + + $expected = [ + 'id' => $id->toRfc4122(), + 'title' => 'Hello, World!', + 'link' => 'https://example.com/hello-world', + 'description' => 'This is a test description.', + 'content' => 'This is a test post.', + 'author' => 'John Doe', + 'date' => '2024-12-08', + ]; + + self::assertSame($expected, $post->toArray()); + } +} diff --git a/demo/tests/Blog/fixtures/blog.rss b/demo/tests/Blog/fixtures/blog.rss new file mode 100644 index 000000000..9fc7c51d5 --- /dev/null +++ b/demo/tests/Blog/fixtures/blog.rss @@ -0,0 +1,996 @@ + + + + Symfony Blog + + https://symfony.com/blog/ + Most recent posts published on the Symfony project blog + Tue, 10 Dec 2024 23:56:55 +0100 + Sun, 08 Dec 2024 09:39:00 +0100 + en + + <![CDATA[A Week of Symfony #936 (2-8 December 2024)]]> + https://symfony.com/blog/a-week-of-symfony-936-2-8-december-2024?utm_source=Symfony%20Blog%20Feed&utm_medium=feed + This week, Symfony celebrated the SymfonyCon 2024 Vienna conference with great success. This annual event brought together the global Symfony community to exchange ideas, learn new things, and collaborate on contributions to the Symfony project. In addition,… + This week, Symfony celebrated the SymfonyCon 2024 Vienna conference with great success. This annual event brought together the global Symfony community to exchange ideas, learn new things, and collaborate on contributions to the Symfony project. In addition, the upcoming Symfony 7.3 version introduced support for pre-compressing web assets and a new userIsGranted() security method to test user authorization without relying on the session.

+ +

Symfony development highlights

+ +

This week, 57 pull requests were merged (28 in code and 29 in docs) and 28 issues were closed (22 in code and 6 in docs). Excluding merges, 35 authors made 2,784 additions and 954 deletions. See details for code and docs.

+ +

6.4 changelog:

+ +
    +
  • 8c8bab2: [TwigBridge] fix Twig 3.17 compatibility
  • +
  • ffc4dc6: [HttpClient] always set CURLOPT_CUSTOMREQUEST to the correct HTTP method in CurlHttpClient
  • +
  • 74e9163: [PropertyInfo] evaluate access flags for properties with asymmetric visibility
  • +
  • 51d824a: [Console] fix division by 0 error
  • +
  • caa1be7: [ErrorHandler] fix error message in test with PHP 8.5
  • +
  • e25242a: [TwigBridge] add tests covering trans_default_domain with dynamic expressions
  • +
  • 91835ef: [FrameworkBundle] fix notifier push channel bus abstract arg
  • +
+ +

7.1 changelog:

+ +
    +
  • 2d9f2a5: [Scheduler] remove unused code
  • +
+ +

7.2 changelog:

+ +
    +
  • cc1802d: [TwigBridge] generate conflict-free variable names
  • +
  • 6076b87, dcf824a: [Mailer] fix null check on region in Sendgrid mailer
  • +
  • f24ac9e: [FrameworkBundle] make uri_signer lazy and improve error when kernel.secret is empty
  • +
  • 27c0f65: [Notifier] fix desktop channel bus abstract arg
  • +
+ +

7.3 changelog:

+ +
    +
  • 2d1838a: [VarDumper] add caster for Socket instances
  • +
  • 3a804f5: [Mailer, Notifier] add webhooks signature verification on Sweego bridges
  • +
  • 12e4e53: [AssetMapper] add support for assets pre-compression
  • +
  • b6d6adf: [FrameworkBundle] rename TranslationUpdateCommand to TranslationExtract command to match the command name
  • +
  • b7ed0a4: [ErrorHandler] support non-empty-string/non-empty-list when patching return types
  • +
  • 12ff1bf: [Uid] add @return non-empty-string annotations to AbstractUid and relevant functions
  • +
  • 4612ff2: [Security, SecurityBundle] add a userIsGranted() method to test user authorization without relying on the session
  • +
+ +

Newest issues and pull requests

+ + + +

Symfony Jobs

+ +

These are some of the most recent Symfony job offers:

+ +
    +
  • Symfony Developer at Adria Solutions
    +Full-time - £45,000 – £60,000 / year
    +Remote + part-time onsite (Cardiff, United Kingdom)
    +View details
  • +
  • Backend Symfony Developer at Bold Company
    +Full-time - €4,200 / month
    +Remote + part-time onsite (Rotterdam, Netherlands)
    +View details
  • +
  • Symfony Developer at Kennisnet
    +Full-time - €4,104 – €5,673 / month
    +Remote + part-time onsite (Zoetermeer, Netherlands)
    +View details
  • +
+ +

You can publish a Symfony job offer for free on symfony.com.

+ +

SymfonyCasts Updates

+ +

SymfonyCasts is the official way to learn Symfony. +Select a track for a guided path through 100+ video tutorial courses about +Symfony, PHP and JavaScript.

+ +

This week, SymfonyCasts published the following updates:

+ + + +

They talked about us

+ + + +

Call to Action

+ + + +
+
+ Sponsor the Symfony project. +
+ ]]>
+ https://symfony.com/blog/a-week-of-symfony-936-2-8-december-2024?utm_source=Symfony%20Blog%20Feed&utm_medium=feed + + Sun, 08 Dec 2024 09:39:00 +0100 + https://symfony.com/blog/a-week-of-symfony-936-2-8-december-2024?utm_source=Symfony%20Blog%20Feed&utm_medium=feed#comments-list +
+ + <![CDATA[A Week of Symfony #935 (25 November - 1 December 2024)]]> + https://symfony.com/blog/a-week-of-symfony-935-25-november-1-december-2024?utm_source=Symfony%20Blog%20Feed&utm_medium=feed + This week, the stable Symfony 7.2.0 version was released, featuring tens of new additions. Additionally, we announced the Black Friday Symfony promotions. Furthermore, the maintenance releases for Symfony 5.4.48, 6.4.16, and 7.1.9 are now available. Finally,… + This week, the stable Symfony 7.2.0 version was released, featuring tens of new additions. Additionally, we announced the Black Friday Symfony promotions. Furthermore, the maintenance releases for Symfony 5.4.48, 6.4.16, and 7.1.9 are now available. Finally, next week, the global Symfony community will gather in Vienna for the SymfonyCon 2024 conference.

+ +

Symfony development highlights

+ +

This week, 39 pull requests were merged (28 in code and 11 in docs) and 21 issues were closed (19 in code and 2 in docs). Excluding merges, 21 authors made 1,033 additions and 332 deletions. See details for code and docs.

+ +

5.4 changelog:

+ +
    +
  • 5cbdb87: [HttpClient] various cleanups after recent changes
  • +
  • 520e31b: [PropertyInfo] consider write property visibility to decide whether a property is writable
  • +
  • 294a39f: [Translation] fix empty keys array in PUT, DELETE requests causing Lokalise API error
  • +
  • ec691c8: [PropertyInfo] fix write visibility for Asymmetric Visibility and Virtual Properties
  • +
  • 1b7d8b3: [Dotenv] read runtime config from composer.json in debug dotenv command
  • +
  • 9eea677: [HttpClient] close gracefull when the server closes the connection abruptly
  • +
  • 4677f32: [HttpClient] fix checking for private IPs before connecting
  • +
  • 7a2d66a: [HttpClient] fix streaming and redirecting with NoPrivateNetworkHttpClient
  • +
+ +

6.4 changelog:

+ +
    +
  • 76df983: [DoctrineBridge] fix Connection::createSchemaManager() for Doctrine DBAL v2
  • +
  • 9c6b5d5: [HttpClient] more consistency cleanups
  • +
  • a59ff05: [Messenger] fix Envelope::all() conditional return docblock
  • +
+ +

7.2 changelog:

+ +
    +
  • e128d76: [HttpClient] fix amphp/http-client 5 support
  • +
  • 59ceb58: [Form] allow integer for the calendar option of DateType
  • +
+ +

7.3 changelog:

+ +
    +
  • baf98b9: [VarDumper] add caster for AddressInfo objects
  • +
+ +

Newest issues and pull requests

+ + + +

Symfony CLI

+ +

Symfony CLI is a must-have tool when developing +Symfony applications on your local machine. It includes the +Symfony Local Server, +the best way to run local Symfony applications. This week Symfony CLI released +its new 5.10.5, +version with the following changes:

+ +
    +
  • Update fixtures (@fabpot)
  • +
  • Update check-requirements.php script to v2.0.3 (@fabpot)
  • +
  • Fix path on local envs (@fabpot)
  • +
  • Add a warning about the listening IP change in 5.10.3 (@tucksaun)
  • +
+ +

Symfony Jobs

+ +

These are some of the most recent Symfony job offers:

+ +
    +
  • Symfony Developer at Tactiplan
    +Full-time - €4,500 – €8,000 / month
    +Full remote
    +View details
  • +
  • Backend Symfony Developer at 2beGROUP
    +Full-time - €48,000 – €72,000 / year
    +Remote + part-time onsite (Leiderdorp, Netherlands)
    +View details
  • +
  • Symfony Developer at ProcurePro
    +Full-time - A$120,000 – A$150,000 / year
    +Full remote
    +View details
  • +
+ +

You can publish a Symfony job offer for free on symfony.com.

+ +

SymfonyCasts Updates

+ +

SymfonyCasts is the official way to learn Symfony. +Select a track for a guided path through 100+ video tutorial courses about +Symfony, PHP and JavaScript.

+ +

This week, SymfonyCasts published the following updates:

+ + + +

They talked about us

+ + + +

Call to Action

+ + + +
+
+ Sponsor the Symfony project. +
+ ]]>
+ https://symfony.com/blog/a-week-of-symfony-935-25-november-1-december-2024?utm_source=Symfony%20Blog%20Feed&utm_medium=feed + + Sun, 01 Dec 2024 09:54:00 +0100 + https://symfony.com/blog/a-week-of-symfony-935-25-november-1-december-2024?utm_source=Symfony%20Blog%20Feed&utm_medium=feed#comments-list +
+ + <![CDATA[Symfony 7.2 curated new features]]> + https://symfony.com/blog/symfony-7-2-curated-new-features?utm_source=Symfony%20Blog%20Feed&utm_medium=feed + Symfony 7.2.0 has been released. As for any other Symfony release, our backward compatibility promise applies and this means that you should be able to upgrade easily to 7.2 without changing anything in your code. + +During the last couple of months, we've… + Symfony 7.2.0 has been released. As for any other Symfony release, our backward compatibility promise applies and this means that you should be able to upgrade easily to 7.2 without changing anything in your code.

+ +

During the last couple of months, we've blogged about the great 7.2 new features. I highly recommend you to read these articles about Symfony 7.2 as they contain the major changes for this new version:

+ +
    +
  • Week, WordCount and Yaml Constraints: Symfony 7.2 introduces three new constraints: one to validate week numbers, another to check word count, and a third to validate YAML syntax.
  • +
  • Silent Verbosity: Symfony 7.2 introduces a new silent verbosity to supress all output, including errors.
  • +
  • Expression Language Improvements: Symfony 7.2 improves the ExpressionLanguage component with new bitwise and logical operators, easier registration of custom providers and support for comments.
  • +
  • AsMessage Attribute: Symfony 7.2 introduces a new AsMessage attribute, allowing you to configure the transport(s) directly within the message class
  • +
  • Named Serializers: Symfony 7.2 allows you to configure multiple serializer instances with different default contexts, name converters, and sets of normalizers and encoders.
  • +
  • Translations Linter: Symfony 7.2 includes a new lint:translations command to check the validity of your translation contents.
  • +
  • WhenNot Attribute: Symfony 7.2 introduces the WhenNot attribute to exclude a service from certain environments.
  • +
  • Lazy Choice Loader: Symfony 7.2 introduces a new lazy choice loader to improve performance of choice fields with lots of options.
  • +
  • String Component Improvements: Symfony 7.2 improves the String component with a new kebab-case method, new truncation modes and a Spanish inflector.
  • +
  • Compound Constraint Improvements: In Symfony 7.2, Compound constraints are easier to test and can define the validation groups and payload via the constructor.
  • +
  • Mailer and Notifier Integrations: Symfony 7.2 adds some new integrations to the Mailer and Notifier components, adding to the tens of integrations already available.
  • +
  • Improved Translation Extractor: Symfony 7.2 improves the translation extractor command, allowing customization of prefixes, modification of update behavior, and sorting of content.
  • +
  • Desktop Notifications: Symfony 7.2 allows to send notifications directly to your local desktop using the new desktop channel in the Notifier component.
  • +
  • Template DX Improvements: In Symfony 7.2, you can set HTTP headers in static pages and render specific Twig blocks using attributes.
  • +
  • Non-Empty Container Parameters: Symfony 7.2 introduces a new utility to require that some parameters exist and have non-empty values.
  • +
  • Keepalive Messenger Transports: Symfony 7.2 introduces the keepalive feature for Messenger transports, preventing timeouts when processing messages.
  • +
  • Mime Improvements: In Symfony 7.2, the Mime component adds support for custom encoders and Unicode email addresses.
  • +
  • Console Finished Indicator: Symfony 7.2 allows customizing the indicator displayed when a Console command completes.
  • +
  • Constraint Improvements: Symfony 7.2 adds a validation mode for BIC constraint, an errorPath for Unique constraint, format options for Ulid constraint, and context support for When constraint.
  • +
  • Simpler Trusted Proxies Configuration: Symfony 7.2 simplifies trusted proxy configuration with a private subnet shortcut and new environment variables.
  • +
  • Simpler Single-File Symfony Applications: In Symfony 7.2, single-file applications are now simpler and require less configuration.
  • +
  • New Command Options: Symfony 7.2 introduces new command options to lint container env vars, format messenger stats output, and filter assets during debugging.
  • +
  • Redesigned TypeInfo Component: Symfony 7.2 redesigns the TypeInfo component and makes it stable.
  • +
  • Serializer Improvements: Symfony 7.2 enhances the Serializer with support for DateTime subclasses, a new SnakeCaseToCamelCase name converter, updated UUID constants, and optional Webhook integration.
  • +
  • Stateless CSRF: Symfony 7.2 introduces stateless CSRF protection, enabling secure token validation without relying on server-side sessions.
  • +
  • Deprecations: Symfony 7.2 deprecates several features, including session config options, empty user identifiers, and the !tagged tag.
  • +
  • Optional Secret: Symfony 7.2 simplifies application setup by making the secret optional, enhancing security and developer experience.
  • +
  • Misc. Improvements (Part 1): Symfony 7.2 introduces features like custom retry delays for Messenger, improved null-coalesce support in expressions, custom attributes for user login passports, and enhanced VarDumper support for PHP 8.4 property hooks.
  • +
  • Misc. Improvements (Part 2): Symfony 7.2 adds password strength estimation, simpler RequestStack testing, nullable boolean configuration, improved IP anonymization, and Security Profiler upgrades.
  • +
+ +
+
+ Sponsor the Symfony project. +
+ ]]>
+ https://symfony.com/blog/symfony-7-2-curated-new-features?utm_source=Symfony%20Blog%20Feed&utm_medium=feed + + Fri, 29 Nov 2024 09:52:00 +0100 + https://symfony.com/blog/symfony-7-2-curated-new-features?utm_source=Symfony%20Blog%20Feed&utm_medium=feed#comments-list +
+ + <![CDATA[Symfony 7.2.0 released]]> + https://symfony.com/blog/symfony-7-2-0-released?utm_source=Symfony%20Blog%20Feed&utm_medium=feed + Symfony 7.2.0 has just been released. +Check the Living on the Edge +category on this blog to learn about the main features of this new stable release; +or check the release announcement of BETA1 +to get the list of all new features. +Here is the list of the most… + Symfony 7.2.0 has just been released.

+

Check the Living on the Edge +category on this blog to learn about the main features of this new stable release; +or check the release announcement of BETA1 +to get the list of all new features.

+

Here is the list of the most important changes since 7.2.0-RC1:

+
    +
  • bug #59023 [HttpClient] Fix streaming and redirecting with NoPrivateNetworkHttpClient (@nicolas-grekas)
  • +
  • bug #59014 [Form] Allow integer for the calendar option of DateType (@alexandre-daubois)
  • +
  • bug #59013 [HttpClient] Fix checking for private IPs before connecting (@nicolas-grekas)
  • +
  • bug #58562 [HttpClient] Close gracefull when the server closes the connection abruptly (@discordier)
  • +
  • bug #59007 [Dotenv] read runtime config from composer.json in debug dotenv command (@xabbuh)
  • +
  • bug #58963 [PropertyInfo] Fix write visibility for Asymmetric Visibility and Virtual Properties (@xabbuh, @pan93412)
  • +
  • bug #58983 [Translation] [Bridge][Lokalise] Fix empty keys array in PUT, DELETE requests causing Lokalise API error (@DominicLuidold)
  • +
  • bug #58956 [DoctrineBridge] Fix Connection::createSchemaManager() for Doctrine DBAL v2 (@neodevcode)
  • +
  • bug #58959 [PropertyInfo] consider write property visibility to decide whether a property is writable (@xabbuh)
  • +
  • bug #58964 [TwigBridge] do not add child nodes to EmptyNode instances (@xabbuh)
  • +
  • bug #58950 [FrameworkBundle] Revert " Deprecate making cache.app adapter taggable" (@keulinho)
  • +
  • bug #58952 [Cache] silence warnings issued by Redis Sentinel on connection issues (@xabbuh)
  • +
  • bug #58953 [HttpClient] Fix computing stats for PUSH with Amp (@nicolas-grekas)
  • +
  • bug #58943 [FrameworkBundle] Revert " Don't auto-register form/csrf when the corresponding components are not installed" (@nicolas-grekas)
  • +
  • bug #58937 [FrameworkBundle] Don't auto-register form/csrf when the corresponding components are not installed (@nicolas-grekas)
  • +
  • bug #58859 [AssetMapper] ignore missing directory in isVendor() (@alexislefebvre)
  • +
  • bug #58917 [OptionsResolver] Allow Union/Intersection Types in Resolved Closures (@zanbaldwin)
  • +
  • bug #58822 [DependencyInjection] Fix checking for interfaces in ContainerBuilder::getReflectionClass() (@donquixote)
  • +
  • bug #58865 Dynamically fix compatibility with doctrine/data-fixtures v2 (@greg0ire)
  • +
  • bug #58921 [HttpKernel] Ensure HttpCache::getTraceKey() does not throw exception (@lyrixx)
  • +
  • bug #58908 [DoctrineBridge] don't call EntityManager::initializeObject() with scalar values (@xabbuh)
  • +
  • bug #58938 [Cache] make RelayProxyTrait compatible with relay extension 0.9.0 (@xabbuh)
  • +
  • bug #58924 [HttpClient] Fix empty hosts in option "resolve" (@nicolas-grekas)
  • +
  • bug #58915 [HttpClient] Fix option "resolve" with IPv6 addresses (@nicolas-grekas)
  • +
  • bug #58919 [WebProfilerBundle] Twig deprecations (@mazodude)
  • +
  • bug #58914 [HttpClient] Fix option "bindto" with IPv6 addresses (@nicolas-grekas)
  • +
  • bug #58888 [Mailer][Notifier] Sweego is backing their bridges, thanks to them! (@nicolas-grekas)
  • +
  • bug #58885 [PropertyInfo][Serializer][TypeInfo][Validator] TypeInfo 7.1 compatibility (@mtarld)
  • +
  • bug #58870 [Serializer][Validator] prevent failures around not existing TypeInfo classes (@xabbuh)
  • +
  • bug #58872 [PropertyInfo][Serializer][Validator] TypeInfo 7.2 compatibility (@mtarld)
  • +
  • bug #58875 [HttpClient] Removed body size limit (Carl Julian Sauter)
  • +
  • bug #58866 [Validator] fix compatibility with PHP < 8.2.4 (@xabbuh)
  • +
  • bug #58862 [Notifier] Fix GoIpTransport (@nicolas-grekas)
  • +
  • bug #58860 [HttpClient] Fix catching some invalid Location headers (@nicolas-grekas)
  • +
  • bug #58834 [FrameworkBundle] ensure validator.translation_domain parameter is always set (@xabbuh)
  • +
  • bug #58836 Work around parse_url() bug (bis) (@nicolas-grekas)
  • +
  • bug #58818 [Messenger] silence PHP warnings issued by Redis::connect() (@xabbuh)
  • +
  • bug #58828 [PhpUnitBridge] fix dumping tests to skip with data providers (@xabbuh)
  • +
  • bug #58842 [Routing] Fix: lost priority when defining hosts in configuration (@BeBlood)
  • +
  • bug #58850 [HttpClient] fix PHP 7.2 compatibility (@xabbuh)
  • +
+

Want to upgrade to this new release? Because Symfony protects +backwards-compatibility very closely, this should be quite easy. Use +SymfonyInsight upgrade reports +to detect the code you will need to change in your project and +read our upgrade +documentation to learn more.

+

Want to be notified whenever a new Symfony release is published? Or when a +version is not maintained anymore? Or only when a security issue is fixed? +Consider subscribing to the Symfony Roadmap Notifications.

+
+
+ Sponsor the Symfony project. +
+ ]]>
+ https://symfony.com/blog/symfony-7-2-0-released?utm_source=Symfony%20Blog%20Feed&utm_medium=feed + + Fri, 29 Nov 2024 09:46:04 +0100 + https://symfony.com/blog/symfony-7-2-0-released?utm_source=Symfony%20Blog%20Feed&utm_medium=feed#comments-list +
+ + <![CDATA[Symfony 5.4.49 released]]> + https://symfony.com/blog/symfony-5-4-49-released?utm_source=Symfony%20Blog%20Feed&utm_medium=feed + Symfony 5.4.49 has just been released. +Here is the list of the most important changes since 5.4.48: + + bug #59023 [HttpClient] Fix streaming and redirecting with NoPrivateNetworkHttpClient (@nicolas-grekas) + +WARNING: 5.4.49 is the last version for the Symfony… + Symfony 5.4.49 has just been released. +Here is the list of the most important changes since 5.4.48:

+
    +
  • bug #59023 [HttpClient] Fix streaming and redirecting with NoPrivateNetworkHttpClient (@nicolas-grekas)
  • +
+

WARNING: 5.4.49 is the last version for the Symfony 5.4 branch. If some +of your projects are still using this version, consider upgrading as soon as +possible. However, if you can't upgrade soon, note that we still provide +security issue releases according to our release policy.

+

Want to upgrade to this new release? Because Symfony protects +backwards-compatibility very closely, this should be quite easy. Use +SymfonyInsight upgrade reports +to detect the code you will need to change in your project and +read our upgrade +documentation to learn more.

+

Want to be notified whenever a new Symfony release is published? Or when a +version is not maintained anymore? Or only when a security issue is fixed? +Consider subscribing to the Symfony Roadmap Notifications.

+
+
+ Sponsor the Symfony project. +
+ ]]>
+ https://symfony.com/blog/symfony-5-4-49-released?utm_source=Symfony%20Blog%20Feed&utm_medium=feed + + Fri, 29 Nov 2024 09:39:54 +0100 + https://symfony.com/blog/symfony-5-4-49-released?utm_source=Symfony%20Blog%20Feed&utm_medium=feed#comments-list +
+ + <![CDATA[SymfonyCon Vienna 2024: See you next week!]]> + https://symfony.com/blog/symfonycon-vienna-2024-see-you-next-week?utm_source=Symfony%20Blog%20Feed&utm_medium=feed + + + +SymfonyCon Vienna is just around the corner! 🎉 Next week, we’ll come together for an exciting event featuring brand-new talks, inspiring speakers, and everything you need to make the most of this gathering with the Symfony and PHP community. + +💡Pro… + + Sfconvienna2024 Blog + +SymfonyCon Vienna is just around the corner! 🎉 Next week, we’ll come together for an exciting event featuring brand-new talks, inspiring speakers, and everything you need to make the most of this gathering with the Symfony and PHP community.

+ +

💡Pro tip: Use the business meeting feature in your SymfonyLive profile to schedule meetings with sponsors ahead of time!

+ +

Not registered yet? Don’t miss out—there’s still time to grab your tickets for:

+ +
    +
  • December 3-4: Workshop Days – Choose from a variety of 1-day training sessions. Spots are filling fast!
  • +
  • December 5-6: Conference Days – Dive into 3 parallel tracks plus an unconference track, all in English.
  • +
+ +
+ +

🆕What's new in the schedule

+ + + +

🔎 Explore the great lineup of talks

+ +

In just a few days, you'll meet our inspiring experts speakers as Fabien Potencier, Viktor Pikaev, Andreas Braun, Michelle Sanver, , Ondřej Mirtes, Alexander M. Turek, David Buchmann, Marie Minasyan, Nils Adermann, Anne-Julia Seitz, Thibault Milan, Romain Ruaud, Juliette Reinders Folmer, Dave Liddament, Rob Allen, Tugdual Saunier, Simon André, Mathias Arlaud, Adrien Roches, Hubert Lenoir, Antoine Bluchet, Alexander Schranz, Alexandre Salomé, Kévin Dunglas, Nicolas Grekas, Sebastian Plagemann, Stephan Hochdörfer, Raphaël Geffroy, Peter Dietrich, Céline Deis, Johannes Wachter, Matheo Daninos, Robin Chalas, Paul Dragoonis, Antonis Kalipetis, Guillaume Moigneu, Florent Huck, Augustin Delaporte, Celeste Van Der Watt, Greg Qualls, Thomas di Luccio, Nigel Kersten, Moritz Schuh, Sebastian Seggewiß, Haylee Millar and, Kemi Elizabeth Ojogbede.

+ +

Read the detailed content of talks here.

+ +

🧑‍💻Unlock new skills and level up your expertise with our workshops!

+ +

Held on December 3-4, 2024, these workshops are crafted for developers eager to dive deep into Symfony, PHP, and modern coding practices. Here’s what you can look forward to:

+ + + +

Whether you're new to Symfony or looking to master advanced techniques, there’s something here for everyone. Don't miss the chance to learn directly from Symfony experts and apply your skills to real-world projects. Secure your spot now and get ready to accelerate your Symfony journey!

+ +

🎟️ Select the ticket of your choice

+ +

Register by clicking on Buy ticket and choose your ticket:

+ +
    +
  • "Workshops only", December 3-4
  • +
  • "Conference only", December 5-6
  • +
  • Combo ticket "Conference + Workshops" to live a full Symfony week experience!
  • +
+ +

🫵 Participate in the Unconference track

+ +

The Unconference track is a participant-driven format where attendees shape the content and discussions in real-time. Have a topic you're passionate about? Claim your slot by emailing us at events@symfony.com and set the stage for an unforgettable experience.

+ +

Each unconference talk lasts 20 minutes with a screen and projector available on both days.

+ +

🧳 Plan your participation

+ +
    +
  • Use the schedule to organize your visit.

  • +
  • Read our attendee guide for venue, accommodation, and transportation details.

  • +
  • Use the business meeting feature in your Symfony Live profile to schedule meetings with sponsors ahead of time!

  • +
+ +

🎉 Plan to attend the community evening on Thursday, December 5

+ +

Join us for a "Night at the Museum" at one of Vienna's most iconic place: Naturhistorisches Museum Wien (20 minutes by public transport from the conference). From 7:30-10:30 pm. Drinks, music & access to parts of permanent exhibition included!

+ +

💻 Save the date for the Symfony hackathon on Saturday, December 7

+ +

Everyone is welcome to join the hackday! Whether you're an experienced contributor or new to the community, your participation is highly valued as it brings a fresh perspective! More details are available here. Address: Stockwerk, Pater-Schwartz-Gasse 11A, 1150 Wien - Map

+ +

💡 Follow the "conferences" blog posts to stay updated!

+ +

We can't wait to meet you in person to learn and share the latest about Symfony. Join us and be part of the @symfony community! 🫶

+ +
+
+ Sponsor the Symfony project. +
+ ]]>
+ https://symfony.com/blog/symfonycon-vienna-2024-see-you-next-week?utm_source=Symfony%20Blog%20Feed&utm_medium=feed + + Thu, 28 Nov 2024 15:45:00 +0100 + https://symfony.com/blog/symfonycon-vienna-2024-see-you-next-week?utm_source=Symfony%20Blog%20Feed&utm_medium=feed#comments-list +
+ + <![CDATA[New in Symfony 7.2: Misc. Improvements (Part 2)]]> + https://symfony.com/blog/new-in-symfony-7-2-misc-improvements-part-2?utm_source=Symfony%20Blog%20Feed&utm_medium=feed + +Access to the Estimated Password Strength + + + + + + + + Contributed by + Yannick + in + #54881… + +

Access to the Estimated Password Strength

+
+
+ + Yannick + +
+
+ Contributed by + Yannick + in + #54881 + +
+
+

The PasswordStrength constraint validates that the given password has reached +a minimum strength configured in the constraint. In Symfony 7.2, we've changed +the visibility of the estimateStrength() validator method from private to public.

+

This allows you to access the estimated password strength and display it, for +example, in the interface, so users can better understand the quality of their +passwords.

+ +
+

Simpler RequestStack Unit Testing

+
+
+ + Alexander Schranz + +
+
+ Contributed by + Alexander Schranz + in + #57909 + +
+
+

When using the RequestStack in unit tests, you previously needed code like +this to configure the requests:

+
+
+ +
$requestStack = new RequestStack();
+$requestStack->push(Request::create('/'));
+$someCustomClass = new MyCustomClass($requestStack);
+
+
+

In Symfony 7.2, we've simplified this by adding a constructor to RequestStack +that accepts an array of requests:

+
+
+ +
$someCustomClass = new MyCustomClass(new RequestStack([
+    Request::create('/'),
+]));
+
+
+
+
+

Default Action in the HTML Sanitizer

+
+
+ + Jordi Boggiano + +
+
+ Contributed by + Jordi Boggiano + in + #57399 + +
+
+

In Symfony 7.2, we've added a new defaultAction() method in the HtmlSanitizer component. +This method sets the default action for elements that are not explicitly allowed +or blocked:

+
+
+ +
use Symfony\Component\HtmlSanitizer\HtmlSanitizer;
+use Symfony\Component\HtmlSanitizer\HtmlSanitizerAction;
+
+$config = (new HtmlSanitizerConfig())
+    ->defaultAction(HtmlSanitizerAction::Block)
+    ->allowElement('p');
+
+$sanitizer = new HtmlSanitizer($config);
+
+
+

HtmlSanitizerAction is a PHP enum with three cases: Drop (removes the element +and its children); Block (removes the element but keeps its children); and Allow +(keeps the element).

+
+
+

Allow Using defaultNull() on Boolean Nodes

+
+
+ + Alexandre Daubois + +
+
+ Contributed by + Alexandre Daubois + in + #58490 + +
+
+

The current defaultNull() of BooleanNode, used when +defining and processing configuration values, casts null values to true. +In Symfony 7.2, we've updated this method so you can define nullable boolean +values properly:

+
+
+ +
->booleanNode('enabled')->defaultNull()->end()
+
+
+
+
+

Better IP Address Anonymization

+
+
+ + Alexandre Daubois + +
+
+ Contributed by + Alexandre Daubois + in + #58038 + +
+
+

The IpUtils class includes an anonymize() method to obscure part of the IP +address for user privacy. In Symfony 7.2, we've added two new arguments to this +method so you can specify how many bytes to anonymize:

+
+
+ +
use Symfony\Component\HttpFoundation\IpUtils;
+
+$ipv4 = '123.234.235.236';
+// for IPv4 addresses, you can hide 0 to 4 bytes
+$anonymousIpv4 = IpUtils::anonymize($ipv4, 3);
+// $anonymousIpv4 = '123.0.0.0'
+
+$ipv6 = '2a01:198:603:10:396e:4789:8e99:890f';
+// for IPv6 addresses, you can hide 0 to 16 bytes
+// (you must define the second argument (bytes to anonymize in IPv4 addresses)
+// even when you are only anonymizing IPv6 addresses)
+$anonymousIpv6 = IpUtils::anonymize($ipv6, 3, 10);
+// $anonymousIpv6 = '2a01:198:603::'
+
+
+
+
+

String Configuration Node

+
+
+ + Raffaele Carelle + +
+
+ Contributed by + Raffaele Carelle + in + #58428 + +
+
+

When defining a configuration tree, you can use many node types for +configuration values (boolean, integers, floats, enums, arrays, etc.). However, +you couldn't define string values directly; they were specified as scalar nodes.

+

In Symfony 7.2, we've added a string node type and a stringNode() method, +allowing you to define configuration values as strings explicitly:

+
+
+ +
$rootNode
+    ->children()
+        // ...
+        ->stringNode('username')
+            ->defaultValue('root')
+        ->end()
+        ->stringNode('password')
+            ->defaultValue('root')
+        ->end()
+    ->end()
+;
+
+
+
+
+

Security Profiler Improvements

+
+
+ + Mathieu + +
+
+ Contributed by + Mathieu + in + #57525 + , #57369 + and #57692 + +
+
+

In Symfony 7.2, the security panel of the Symfony Profiler has been improved +with several new features. First, the authenticators tab has been updated. +Previously, authenticators that didn't support the request were not shown:

+
+ Symfony security profiler panel with no authenticator shown +
+

Now, to make debugging easier, you can see all the application's authenticators. +If an authenticator doesn't support the request, it will be labeled as "not supported":

+
+ Symfony 7.2 security profiler panel with all authenticators shown +
+

When using a stateful firewall, the token tab of de-authenticated users now +includes a link to the request that contained the previously authenticated user:

+
+ Symfony 7.2 security profiler panel with a link to previous authenticated user +
+

The authenticators tab has also been redesigned to display information more +clearly. It now also shows whether an authenticator is lazy and includes any exception +passed to the onAuthenticationFailure() method:

+
+ Symfony 7.2 security profiler panel with more and redesigned information in the authenticators tab +
+
+

This is the final blog post in the New in Symfony 7.2 series. We hope you +enjoyed it and discovered some of the great new features introduced in Symfony 7.2. +Check out the Symfony minor version upgrade guide to learn how to upgrade to 7.2 +from other 7.x versions. Meanwhile, we've already started working on Symfony 7.3, +which will be released at the end of May 2025.

+
+
+
+ Sponsor the Symfony project. +
+ ]]>
+ https://symfony.com/blog/new-in-symfony-7-2-misc-improvements-part-2?utm_source=Symfony%20Blog%20Feed&utm_medium=feed + + Thu, 28 Nov 2024 08:40:00 +0100 + https://symfony.com/blog/new-in-symfony-7-2-misc-improvements-part-2?utm_source=Symfony%20Blog%20Feed&utm_medium=feed#comments-list +
+ + <![CDATA[Symfony 7.1.9 released]]> + https://symfony.com/blog/symfony-7-1-9-released?utm_source=Symfony%20Blog%20Feed&utm_medium=feed + Symfony 7.1.9 has just been released. +Here is the list of the most important changes since 7.1.8: + + bug #59013 [HttpClient] Fix checking for private IPs before connecting (@nicolas-grekas) +bug #58562 [HttpClient] Close gracefull when the server closes… + Symfony 7.1.9 has just been released. +Here is the list of the most important changes since 7.1.8:

+
    +
  • bug #59013 [HttpClient] Fix checking for private IPs before connecting (@nicolas-grekas)
  • +
  • bug #58562 [HttpClient] Close gracefull when the server closes the connection abruptly (@discordier)
  • +
  • bug #59007 [Dotenv] read runtime config from composer.json in debug dotenv command (@xabbuh)
  • +
  • bug #58963 [PropertyInfo] Fix write visibility for Asymmetric Visibility and Virtual Properties (@xabbuh, @pan93412)
  • +
  • bug #58983 [Translation] [Bridge][Lokalise] Fix empty keys array in PUT, DELETE requests causing Lokalise API error (@DominicLuidold)
  • +
  • bug #58956 [DoctrineBridge] Fix Connection::createSchemaManager() for Doctrine DBAL v2 (@neodevcode)
  • +
  • bug #58959 [PropertyInfo] consider write property visibility to decide whether a property is writable (@xabbuh)
  • +
  • bug #58964 [TwigBridge] do not add child nodes to EmptyNode instances (@xabbuh)
  • +
  • bug #58952 [Cache] silence warnings issued by Redis Sentinel on connection issues (@xabbuh)
  • +
  • bug #58859 [AssetMapper] ignore missing directory in isVendor() (@alexislefebvre)
  • +
  • bug #58917 [OptionsResolver] Allow Union/Intersection Types in Resolved Closures (@zanbaldwin)
  • +
  • bug #58822 [DependencyInjection] Fix checking for interfaces in ContainerBuilder::getReflectionClass() (@donquixote)
  • +
  • bug #58865 Dynamically fix compatibility with doctrine/data-fixtures v2 (@greg0ire)
  • +
  • bug #58921 [HttpKernel] Ensure HttpCache::getTraceKey() does not throw exception (@lyrixx)
  • +
  • bug #58908 [DoctrineBridge] don't call EntityManager::initializeObject() with scalar values (@xabbuh)
  • +
  • bug #58938 [Cache] make RelayProxyTrait compatible with relay extension 0.9.0 (@xabbuh)
  • +
  • bug #58924 [HttpClient] Fix empty hosts in option "resolve" (@nicolas-grekas)
  • +
  • bug #58915 [HttpClient] Fix option "resolve" with IPv6 addresses (@nicolas-grekas)
  • +
  • bug #58919 [WebProfilerBundle] Twig deprecations (@mazodude)
  • +
  • bug #58914 [HttpClient] Fix option "bindto" with IPv6 addresses (@nicolas-grekas)
  • +
  • bug #58870 [Serializer][Validator] prevent failures around not existing TypeInfo classes (@xabbuh)
  • +
  • bug #58872 [PropertyInfo][Serializer][Validator] TypeInfo 7.2 compatibility (@mtarld)
  • +
  • bug #58875 [HttpClient] Removed body size limit (Carl Julian Sauter)
  • +
  • bug #58866 [Validator] fix compatibility with PHP < 8.2.4 (@xabbuh)
  • +
  • bug #58862 [Notifier] Fix GoIpTransport (@nicolas-grekas)
  • +
  • bug #58860 [HttpClient] Fix catching some invalid Location headers (@nicolas-grekas)
  • +
  • bug #58836 Work around parse_url() bug (bis) (@nicolas-grekas)
  • +
  • bug #58818 [Messenger] silence PHP warnings issued by Redis::connect() (@xabbuh)
  • +
  • bug #58828 [PhpUnitBridge] fix dumping tests to skip with data providers (@xabbuh)
  • +
  • bug #58842 [Routing] Fix: lost priority when defining hosts in configuration (@BeBlood)
  • +
  • bug #58850 [HttpClient] fix PHP 7.2 compatibility (@xabbuh)
  • +
+

Want to upgrade to this new release? Because Symfony protects +backwards-compatibility very closely, this should be quite easy. Use +SymfonyInsight upgrade reports +to detect the code you will need to change in your project and +read our upgrade +documentation to learn more.

+

Want to be notified whenever a new Symfony release is published? Or when a +version is not maintained anymore? Or only when a security issue is fixed? +Consider subscribing to the Symfony Roadmap Notifications.

+
+
+ Sponsor the Symfony project. +
+ ]]>
+ https://symfony.com/blog/symfony-7-1-9-released?utm_source=Symfony%20Blog%20Feed&utm_medium=feed + + Wed, 27 Nov 2024 14:02:38 +0100 + https://symfony.com/blog/symfony-7-1-9-released?utm_source=Symfony%20Blog%20Feed&utm_medium=feed#comments-list +
+ + <![CDATA[Symfony 6.4.16 released]]> + https://symfony.com/blog/symfony-6-4-16-released?utm_source=Symfony%20Blog%20Feed&utm_medium=feed + Symfony 6.4.16 has just been released. +Here is the list of the most important changes since 6.4.15: + + bug #59013 [HttpClient] Fix checking for private IPs before connecting (@nicolas-grekas) +bug #58562 [HttpClient] Close gracefull when the server closes… + Symfony 6.4.16 has just been released. +Here is the list of the most important changes since 6.4.15:

+
    +
  • bug #59013 [HttpClient] Fix checking for private IPs before connecting (@nicolas-grekas)
  • +
  • bug #58562 [HttpClient] Close gracefull when the server closes the connection abruptly (@discordier)
  • +
  • bug #59007 [Dotenv] read runtime config from composer.json in debug dotenv command (@xabbuh)
  • +
  • bug #58963 [PropertyInfo] Fix write visibility for Asymmetric Visibility and Virtual Properties (@xabbuh, @pan93412)
  • +
  • bug #58983 [Translation] [Bridge][Lokalise] Fix empty keys array in PUT, DELETE requests causing Lokalise API error (@DominicLuidold)
  • +
  • bug #58956 [DoctrineBridge] Fix Connection::createSchemaManager() for Doctrine DBAL v2 (@neodevcode)
  • +
  • bug #58959 [PropertyInfo] consider write property visibility to decide whether a property is writable (@xabbuh)
  • +
  • bug #58964 [TwigBridge] do not add child nodes to EmptyNode instances (@xabbuh)
  • +
  • bug #58952 [Cache] silence warnings issued by Redis Sentinel on connection issues (@xabbuh)
  • +
  • bug #58859 [AssetMapper] ignore missing directory in isVendor() (@alexislefebvre)
  • +
  • bug #58917 [OptionsResolver] Allow Union/Intersection Types in Resolved Closures (@zanbaldwin)
  • +
  • bug #58822 [DependencyInjection] Fix checking for interfaces in ContainerBuilder::getReflectionClass() (@donquixote)
  • +
  • bug #58865 Dynamically fix compatibility with doctrine/data-fixtures v2 (@greg0ire)
  • +
  • bug #58921 [HttpKernel] Ensure HttpCache::getTraceKey() does not throw exception (@lyrixx)
  • +
  • bug #58908 [DoctrineBridge] don't call EntityManager::initializeObject() with scalar values (@xabbuh)
  • +
  • bug #58938 [Cache] make RelayProxyTrait compatible with relay extension 0.9.0 (@xabbuh)
  • +
  • bug #58924 [HttpClient] Fix empty hosts in option "resolve" (@nicolas-grekas)
  • +
  • bug #58915 [HttpClient] Fix option "resolve" with IPv6 addresses (@nicolas-grekas)
  • +
  • bug #58919 [WebProfilerBundle] Twig deprecations (@mazodude)
  • +
  • bug #58914 [HttpClient] Fix option "bindto" with IPv6 addresses (@nicolas-grekas)
  • +
  • bug #58875 [HttpClient] Removed body size limit (Carl Julian Sauter)
  • +
  • bug #58862 [Notifier] Fix GoIpTransport (@nicolas-grekas)
  • +
  • bug #58860 [HttpClient] Fix catching some invalid Location headers (@nicolas-grekas)
  • +
  • bug #58836 Work around parse_url() bug (bis) (@nicolas-grekas)
  • +
  • bug #58818 [Messenger] silence PHP warnings issued by Redis::connect() (@xabbuh)
  • +
  • bug #58828 [PhpUnitBridge] fix dumping tests to skip with data providers (@xabbuh)
  • +
  • bug #58842 [Routing] Fix: lost priority when defining hosts in configuration (@BeBlood)
  • +
  • bug #58850 [HttpClient] fix PHP 7.2 compatibility (@xabbuh)
  • +
+

Want to upgrade to this new release? Because Symfony protects +backwards-compatibility very closely, this should be quite easy. Use +SymfonyInsight upgrade reports +to detect the code you will need to change in your project and +read our upgrade +documentation to learn more.

+

Want to be notified whenever a new Symfony release is published? Or when a +version is not maintained anymore? Or only when a security issue is fixed? +Consider subscribing to the Symfony Roadmap Notifications.

+
+
+ Sponsor the Symfony project. +
+ ]]>
+ https://symfony.com/blog/symfony-6-4-16-released?utm_source=Symfony%20Blog%20Feed&utm_medium=feed + + Wed, 27 Nov 2024 13:54:27 +0100 + https://symfony.com/blog/symfony-6-4-16-released?utm_source=Symfony%20Blog%20Feed&utm_medium=feed#comments-list +
+ + <![CDATA[Symfony 5.4.48 released]]> + https://symfony.com/blog/symfony-5-4-48-released?utm_source=Symfony%20Blog%20Feed&utm_medium=feed + Symfony 5.4.48 has just been released. +Here is the list of the most important changes since 5.4.47: + + bug #59013 [HttpClient] Fix checking for private IPs before connecting (@nicolas-grekas) +bug #58562 [HttpClient] Close gracefull when the server closes… + Symfony 5.4.48 has just been released. +Here is the list of the most important changes since 5.4.47:

+
    +
  • bug #59013 [HttpClient] Fix checking for private IPs before connecting (@nicolas-grekas)
  • +
  • bug #58562 [HttpClient] Close gracefull when the server closes the connection abruptly (@discordier)
  • +
  • bug #59007 [Dotenv] read runtime config from composer.json in debug dotenv command (@xabbuh)
  • +
  • bug #58963 [PropertyInfo] Fix write visibility for Asymmetric Visibility and Virtual Properties (@xabbuh, @pan93412)
  • +
  • bug #58983 [Translation] [Bridge][Lokalise] Fix empty keys array in PUT, DELETE requests causing Lokalise API error (@DominicLuidold)
  • +
  • bug #58959 [PropertyInfo] consider write property visibility to decide whether a property is writable (@xabbuh)
  • +
  • bug #58964 [TwigBridge] do not add child nodes to EmptyNode instances (@xabbuh)
  • +
  • bug #58822 [DependencyInjection] Fix checking for interfaces in ContainerBuilder::getReflectionClass() (@donquixote)
  • +
  • bug #58865 Dynamically fix compatibility with doctrine/data-fixtures v2 (@greg0ire)
  • +
  • bug #58921 [HttpKernel] Ensure HttpCache::getTraceKey() does not throw exception (@lyrixx)
  • +
  • bug #58908 [DoctrineBridge] don't call EntityManager::initializeObject() with scalar values (@xabbuh)
  • +
  • bug #58924 [HttpClient] Fix empty hosts in option "resolve" (@nicolas-grekas)
  • +
  • bug #58915 [HttpClient] Fix option "resolve" with IPv6 addresses (@nicolas-grekas)
  • +
  • bug #58919 [WebProfilerBundle] Twig deprecations (@mazodude)
  • +
  • bug #58914 [HttpClient] Fix option "bindto" with IPv6 addresses (@nicolas-grekas)
  • +
  • bug #58875 [HttpClient] Removed body size limit (Carl Julian Sauter)
  • +
  • bug #58860 [HttpClient] Fix catching some invalid Location headers (@nicolas-grekas)
  • +
  • bug #58836 Work around parse_url() bug (bis) (@nicolas-grekas)
  • +
  • bug #58818 [Messenger] silence PHP warnings issued by Redis::connect() (@xabbuh)
  • +
  • bug #58828 [PhpUnitBridge] fix dumping tests to skip with data providers (@xabbuh)
  • +
  • bug #58842 [Routing] Fix: lost priority when defining hosts in configuration (@BeBlood)
  • +
  • bug #58850 [HttpClient] fix PHP 7.2 compatibility (@xabbuh)
  • +
+

Want to upgrade to this new release? Because Symfony protects +backwards-compatibility very closely, this should be quite easy. Use +SymfonyInsight upgrade reports +to detect the code you will need to change in your project and +read our upgrade +documentation to learn more.

+

Want to be notified whenever a new Symfony release is published? Or when a +version is not maintained anymore? Or only when a security issue is fixed? +Consider subscribing to the Symfony Roadmap Notifications.

+
+
+ Sponsor the Symfony project. +
+ ]]>
+ https://symfony.com/blog/symfony-5-4-48-released?utm_source=Symfony%20Blog%20Feed&utm_medium=feed + + Wed, 27 Nov 2024 13:48:58 +0100 + https://symfony.com/blog/symfony-5-4-48-released?utm_source=Symfony%20Blog%20Feed&utm_medium=feed#comments-list +
+
+
diff --git a/demo/tests/SmokeTest.php b/demo/tests/SmokeTest.php new file mode 100644 index 000000000..db9567a59 --- /dev/null +++ b/demo/tests/SmokeTest.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\Tests; + +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\DataProvider; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; +use Symfony\UX\LiveComponent\Test\InteractsWithLiveComponents; + +#[CoversNothing] +final class SmokeTest extends WebTestCase +{ + use InteractsWithLiveComponents; + + public function testIndex(): void + { + $client = static::createClient(); + $client->request('GET', '/'); + + self::assertResponseIsSuccessful(); + self::assertSelectorTextSame('h1', 'Welcome to the LLM Chain Demo'); + self::assertSelectorCount(5, '.card'); + } + + #[DataProvider('provideChats')] + public function testChats(string $path, string $expectedHeadline): void + { + $client = static::createClient(); + $client->request('GET', $path); + + self::assertResponseIsSuccessful(); + self::assertSelectorTextSame('h4', $expectedHeadline); + self::assertSelectorCount(1, '#chat-submit'); + } + + /** + * @return iterable + */ + public static function provideChats(): iterable + { + yield 'Blog' => ['/blog', 'Retrieval Augmented Generation based on the Symfony blog']; + yield 'YouTube' => ['/youtube', 'Chat about a YouTube Video']; + yield 'Wikipedia' => ['/wikipedia', 'Wikipedia Research']; + } +} diff --git a/demo/tests/YouTube/TranscriptFetcherTest.php b/demo/tests/YouTube/TranscriptFetcherTest.php new file mode 100644 index 000000000..2d4ac1e8b --- /dev/null +++ b/demo/tests/YouTube/TranscriptFetcherTest.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\Tests\YouTube; + +use App\YouTube\TranscriptFetcher; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\HttpClient\Response\MockResponse; + +#[CoversClass(TranscriptFetcher::class), ] +final class TranscriptFetcherTest extends TestCase +{ + public function testFetchTranscript(): void + { + $videoResponse = MockResponse::fromFile(__DIR__.'/fixtures/video.html'); + $transcriptResponse = MockResponse::fromFile(__DIR__.'/fixtures/transcript.xml'); + $mockClient = new MockHttpClient([$videoResponse, $transcriptResponse]); + + $fetcher = new TranscriptFetcher($mockClient); + $transcript = $fetcher->fetchTranscript('6uXW-ulpj0s'); + + self::assertStringContainsString('symphony is a PHP framework', $transcript); + } +} diff --git a/demo/tests/YouTube/fixtures/transcript.xml b/demo/tests/YouTube/fixtures/transcript.xml new file mode 100644 index 000000000..f93f51bb2 --- /dev/null +++ b/demo/tests/YouTube/fixtures/transcript.xml @@ -0,0 +1,66 @@ + + + symphony is a PHP framework and this is + an advantage why because almost 80 + percent of all websites in the internet + use PHP as a server-side language eighty + percent this does mean that wherever you + are right now there is someone near you + probably searching to hire a PHP + developer Symphony will not only teach + you more PHP but also will teach you + different software architecture patterns + that you can use in different languages + software architecture patterns are so + much important in your skill sets + because they allow you to understand + complex software when you only know the + architecture that was used in that + software please let me tell you a story + that happened to me I had a PHP laravel + interview in a company and the interview + was successful so they invite me for a + test work day and that test work day + they asked me to build an application + using.net and Seashore they told me we + know you didn&#39;t had any previous + experience using C sharp but we want to + see how you can get along with different + programming language I was able to + Google and found out that the dotnet + framework is an MVC architect framework + the same framework is used in Symphony + and Bam I built the application in + c-sharp and I got a wonderful job offer + so yes learning Symphony will teach you + software architecture patterns that are + essential in your skill set symphony is + a full stack framework that mean you can + create deploy ready application you will + be using front-end Technologies like + HTML CSS and JavaScript and back-end or + server Technologies like PHP databases + that will process the user request all + in one place Symphony can integrate + easily with modern JavaScript Frameworks + like vue.js or react.js or even you can + set up different databases like MySQL + postgres or whatever you want Symphony + has a CLI tool that can help build and + speak and debug your application and is + one of the most advanced code generation + tool in the planner is relate in the + comment if you know anything that is + good finally documentation Symphony has + good documentation that will make it + easy for newcomers to learn and have fun + with the technology so that was my 6y2 + simple normally I don&#39;t do this but + right now go and check the description + see the comment and write me what you + think like the video and subscribe to my + channel then go to the channel check the + videos and like each one of them and + comment again and come back to this + video and watch it again thank you + diff --git a/demo/tests/YouTube/fixtures/video.html b/demo/tests/YouTube/fixtures/video.html new file mode 100644 index 000000000..b9d313765 --- /dev/null +++ b/demo/tests/YouTube/fixtures/video.html @@ -0,0 +1,88 @@ +Learn Symfony in 2025, 6 reasons why - YouTube
InfoPresseUrheberrechtKontaktCreatorWerbenEntwicklerImpressumVerträge hier kündigenNutzungsbedingungenDatenschutzRichtlinien & SicherheitWie funktioniert YouTube?Neue Funktionen testen
diff --git a/demo/tests/bootstrap.php b/demo/tests/bootstrap.php new file mode 100644 index 000000000..1a509f888 --- /dev/null +++ b/demo/tests/bootstrap.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Component\Dotenv\Dotenv; +use Symfony\Component\ErrorHandler\ErrorHandler; + +require dirname(__DIR__).'/vendor/autoload.php'; + +set_exception_handler([new ErrorHandler(), 'handleException']); + +if (file_exists(dirname(__DIR__).'/config/bootstrap.php')) { + require dirname(__DIR__).'/config/bootstrap.php'; +} elseif (method_exists(Dotenv::class, 'bootEnv')) { + (new Dotenv())->bootEnv(dirname(__DIR__).'/.env'); +}