Primo rilascio
This commit is contained in:
23
.continue/agents/new-config.yaml
Normal file
23
.continue/agents/new-config.yaml
Normal file
@@ -0,0 +1,23 @@
|
||||
# This is an example configuration file
|
||||
# To learn more, see the full config.yaml reference: https://docs.continue.dev/reference
|
||||
|
||||
name: Example Config
|
||||
version: 1.0.0
|
||||
schema: v1
|
||||
|
||||
# Define which models can be used
|
||||
# https://docs.continue.dev/customization/models
|
||||
models:
|
||||
- name: my gpt-5
|
||||
provider: openai
|
||||
model: gpt-5
|
||||
apiKey: YOUR_OPENAI_API_KEY_HERE
|
||||
- uses: ollama/qwen2.5-coder-7b
|
||||
- uses: anthropic/claude-4-sonnet
|
||||
with:
|
||||
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
|
||||
# MCP Servers that Continue can access
|
||||
# https://docs.continue.dev/customization/mcp-tools
|
||||
mcpServers:
|
||||
- uses: anthropic/memory-mcp
|
||||
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"svn.ignoreMissingSvnWarning": true
|
||||
}
|
||||
60
README.md
Normal file
60
README.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# NurseryApp - Guida all'avvio
|
||||
|
||||
Questo documento ti insegna come avviare sia il **backend** PHP che il **frontend** Angular.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 **Avviamento del Frontend (Angular)**
|
||||
|
||||
1. **Vai nella cartella del frontend:**
|
||||
```bash
|
||||
cd frontend/nursery-app
|
||||
```
|
||||
|
||||
2. **Installa le dipendenze (se non ancora fatto):**
|
||||
```bash
|
||||
npm install
|
||||
# oppure
|
||||
yarn install
|
||||
```
|
||||
|
||||
3. **Avvia lo sviluppo locale:**
|
||||
```bash
|
||||
ng serve --host 0.0.0.0
|
||||
```
|
||||
|
||||
🌐 **Apri il browser su:** `http://localhost:4200`
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ **Avviamento del Backend (PHP)**
|
||||
|
||||
1. **Assicurati di avere PHP e Composer installati.**
|
||||
|
||||
2. **Vai nella cartella del backend:**
|
||||
```bash
|
||||
cd backend
|
||||
```
|
||||
|
||||
3. **Installa le dipendenze PHP:**
|
||||
```bash
|
||||
composer install
|
||||
```
|
||||
|
||||
4. **Configura il file `.env`:**
|
||||
- Se esiste un `.env.example`, copialo:
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
- Modifica le variabili d'ambiente necessarie (es. DB connection string).
|
||||
|
||||
5. **Avvia lo sviluppo del backend:**
|
||||
|
||||
### Opzione A: Laravel (se è un progetto Laravel)
|
||||
```bash
|
||||
php artisan serve --host=0.0.0.0 --port=8000
|
||||
```
|
||||
|
||||
### Opzione B: PHP semplice
|
||||
```bash
|
||||
php -S localhost:8000
|
||||
12
backend/.env
Normal file
12
backend/.env
Normal file
@@ -0,0 +1,12 @@
|
||||
DB_CONNECTION=pdo_mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=nursery_db
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=
|
||||
|
||||
# --- JWT Configuration ---
|
||||
# In produzione, usare una chiave segreta lunga e casuale generata in modo sicuro
|
||||
# Esempio: openssl rand -base64 32
|
||||
JWT_SECRET="your-very-secure-secret-key-here"
|
||||
JWT_EXPIRATION_TIME=3600 # Scadenza token in secondi (es. 1 ora)
|
||||
15
backend/composer.json
Normal file
15
backend/composer.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "nidoai/backend",
|
||||
"description": "Backend API for Nursery Management App",
|
||||
"require": {
|
||||
"nikic/fast-route": "^1.3",
|
||||
"firebase/php-jwt": "^6.11",
|
||||
"doctrine/dbal": "^4.2",
|
||||
"vlucas/phpdotenv": "^5.6"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "src/"
|
||||
}
|
||||
}
|
||||
}
|
||||
845
backend/composer.lock
generated
Normal file
845
backend/composer.lock
generated
Normal file
@@ -0,0 +1,845 @@
|
||||
{
|
||||
"_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": "fc7d23307b3d4dd9d5816294e54d026c",
|
||||
"packages": [
|
||||
{
|
||||
"name": "doctrine/dbal",
|
||||
"version": "4.2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/dbal.git",
|
||||
"reference": "33d2d7fe1269b2301640c44cf2896ea607b30e3e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/dbal/zipball/33d2d7fe1269b2301640c44cf2896ea607b30e3e",
|
||||
"reference": "33d2d7fe1269b2301640c44cf2896ea607b30e3e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/deprecations": "^0.5.3|^1",
|
||||
"php": "^8.1",
|
||||
"psr/cache": "^1|^2|^3",
|
||||
"psr/log": "^1|^2|^3"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "12.0.0",
|
||||
"fig/log-test": "^1",
|
||||
"jetbrains/phpstorm-stubs": "2023.2",
|
||||
"phpstan/phpstan": "2.1.1",
|
||||
"phpstan/phpstan-phpunit": "2.0.3",
|
||||
"phpstan/phpstan-strict-rules": "^2",
|
||||
"phpunit/phpunit": "10.5.39",
|
||||
"slevomat/coding-standard": "8.13.1",
|
||||
"squizlabs/php_codesniffer": "3.10.2",
|
||||
"symfony/cache": "^6.3.8|^7.0",
|
||||
"symfony/console": "^5.4|^6.3|^7.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/console": "For helpful console commands such as SQL execution and import of files."
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\DBAL\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.",
|
||||
"homepage": "https://www.doctrine-project.org/projects/dbal.html",
|
||||
"keywords": [
|
||||
"abstraction",
|
||||
"database",
|
||||
"db2",
|
||||
"dbal",
|
||||
"mariadb",
|
||||
"mssql",
|
||||
"mysql",
|
||||
"oci8",
|
||||
"oracle",
|
||||
"pdo",
|
||||
"pgsql",
|
||||
"postgresql",
|
||||
"queryobject",
|
||||
"sasql",
|
||||
"sql",
|
||||
"sqlite",
|
||||
"sqlserver",
|
||||
"sqlsrv"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/dbal/issues",
|
||||
"source": "https://github.com/doctrine/dbal/tree/4.2.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.doctrine-project.org/sponsorship.html",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/phpdoctrine",
|
||||
"type": "patreon"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdbal",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-03-07T18:29:05+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": "firebase/php-jwt",
|
||||
"version": "v6.11.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/firebase/php-jwt.git",
|
||||
"reference": "d1e91ecf8c598d073d0995afa8cd5c75c6e19e66"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/firebase/php-jwt/zipball/d1e91ecf8c598d073d0995afa8cd5c75c6e19e66",
|
||||
"reference": "d1e91ecf8c598d073d0995afa8cd5c75c6e19e66",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"guzzlehttp/guzzle": "^7.4",
|
||||
"phpspec/prophecy-phpunit": "^2.0",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"psr/cache": "^2.0||^3.0",
|
||||
"psr/http-client": "^1.0",
|
||||
"psr/http-factory": "^1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-sodium": "Support EdDSA (Ed25519) signatures",
|
||||
"paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Firebase\\JWT\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Neuman Vong",
|
||||
"email": "neuman+pear@twilio.com",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Anant Narayanan",
|
||||
"email": "anant@php.net",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.",
|
||||
"homepage": "https://github.com/firebase/php-jwt",
|
||||
"keywords": [
|
||||
"jwt",
|
||||
"php"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/firebase/php-jwt/issues",
|
||||
"source": "https://github.com/firebase/php-jwt/tree/v6.11.1"
|
||||
},
|
||||
"time": "2025-04-09T20:32:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "graham-campbell/result-type",
|
||||
"version": "v1.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/GrahamCampbell/Result-Type.git",
|
||||
"reference": "3ba905c11371512af9d9bdd27d99b782216b6945"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945",
|
||||
"reference": "3ba905c11371512af9d9bdd27d99b782216b6945",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2.5 || ^8.0",
|
||||
"phpoption/phpoption": "^1.9.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"GrahamCampbell\\ResultType\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Graham Campbell",
|
||||
"email": "hello@gjcampbell.co.uk",
|
||||
"homepage": "https://github.com/GrahamCampbell"
|
||||
}
|
||||
],
|
||||
"description": "An Implementation Of The Result Type",
|
||||
"keywords": [
|
||||
"Graham Campbell",
|
||||
"GrahamCampbell",
|
||||
"Result Type",
|
||||
"Result-Type",
|
||||
"result"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/GrahamCampbell/Result-Type/issues",
|
||||
"source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/GrahamCampbell",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-07-20T21:45:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/fast-route",
|
||||
"version": "v1.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/FastRoute.git",
|
||||
"reference": "181d480e08d9476e61381e04a71b34dc0432e812"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812",
|
||||
"reference": "181d480e08d9476e61381e04a71b34dc0432e812",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8.35|~5.7"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/functions.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"FastRoute\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nikita Popov",
|
||||
"email": "nikic@php.net"
|
||||
}
|
||||
],
|
||||
"description": "Fast request router for PHP",
|
||||
"keywords": [
|
||||
"router",
|
||||
"routing"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/FastRoute/issues",
|
||||
"source": "https://github.com/nikic/FastRoute/tree/master"
|
||||
},
|
||||
"time": "2018-02-13T20:26:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpoption/phpoption",
|
||||
"version": "1.9.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/schmittjoh/php-option.git",
|
||||
"reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54",
|
||||
"reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54",
|
||||
"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 || ^10.5.28"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"bamarni-bin": {
|
||||
"bin-links": true,
|
||||
"forward-command": false
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-master": "1.9-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"PhpOption\\": "src/PhpOption/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"Apache-2.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Johannes M. Schmitt",
|
||||
"email": "schmittjoh@gmail.com",
|
||||
"homepage": "https://github.com/schmittjoh"
|
||||
},
|
||||
{
|
||||
"name": "Graham Campbell",
|
||||
"email": "hello@gjcampbell.co.uk",
|
||||
"homepage": "https://github.com/GrahamCampbell"
|
||||
}
|
||||
],
|
||||
"description": "Option Type for PHP",
|
||||
"keywords": [
|
||||
"language",
|
||||
"option",
|
||||
"php",
|
||||
"type"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/schmittjoh/php-option/issues",
|
||||
"source": "https://github.com/schmittjoh/php-option/tree/1.9.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/GrahamCampbell",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-07-20T21:41:07+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/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": "symfony/polyfill-ctype",
|
||||
"version": "v1.31.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"provide": {
|
||||
"ext-ctype": "*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-ctype": "For best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/polyfill",
|
||||
"name": "symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Ctype\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Gert de Pagter",
|
||||
"email": "BackEndTea@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for ctype functions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"ctype",
|
||||
"polyfill",
|
||||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.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-mbstring",
|
||||
"version": "v1.31.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
||||
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"provide": {
|
||||
"ext-mbstring": "*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mbstring": "For best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/polyfill",
|
||||
"name": "symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Mbstring\\": ""
|
||||
}
|
||||
},
|
||||
"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 the Mbstring extension",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"mbstring",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.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-php80",
|
||||
"version": "v1.31.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php80.git",
|
||||
"reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
|
||||
"reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/polyfill",
|
||||
"name": "symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Php80\\": ""
|
||||
},
|
||||
"classmap": [
|
||||
"Resources/stubs"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Ion Bazan",
|
||||
"email": "ion.bazan@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.31.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": "vlucas/phpdotenv",
|
||||
"version": "v5.6.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vlucas/phpdotenv.git",
|
||||
"reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/a59a13791077fe3d44f90e7133eb68e7d22eaff2",
|
||||
"reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-pcre": "*",
|
||||
"graham-campbell/result-type": "^1.1.3",
|
||||
"php": "^7.2.5 || ^8.0",
|
||||
"phpoption/phpoption": "^1.9.3",
|
||||
"symfony/polyfill-ctype": "^1.24",
|
||||
"symfony/polyfill-mbstring": "^1.24",
|
||||
"symfony/polyfill-php80": "^1.24"
|
||||
},
|
||||
"require-dev": {
|
||||
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||
"ext-filter": "*",
|
||||
"phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-filter": "Required to use the boolean validator."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"bamarni-bin": {
|
||||
"bin-links": true,
|
||||
"forward-command": false
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-master": "5.6-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Dotenv\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Graham Campbell",
|
||||
"email": "hello@gjcampbell.co.uk",
|
||||
"homepage": "https://github.com/GrahamCampbell"
|
||||
},
|
||||
{
|
||||
"name": "Vance Lucas",
|
||||
"email": "vance@vancelucas.com",
|
||||
"homepage": "https://github.com/vlucas"
|
||||
}
|
||||
],
|
||||
"description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.",
|
||||
"keywords": [
|
||||
"dotenv",
|
||||
"env",
|
||||
"environment"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/vlucas/phpdotenv/issues",
|
||||
"source": "https://github.com/vlucas/phpdotenv/tree/v5.6.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/GrahamCampbell",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-07-20T21:52:34+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {},
|
||||
"platform-dev": {},
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
BIN
backend/composer.phar
Normal file
BIN
backend/composer.phar
Normal file
Binary file not shown.
17
backend/config/database.php
Normal file
17
backend/config/database.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'driver' => $_ENV['DB_CONNECTION'] ?? 'pdo_mysql',
|
||||
'host' => $_ENV['DB_HOST'] ?? '127.0.0.1',
|
||||
'port' => $_ENV['DB_PORT'] ?? '3306',
|
||||
'dbname' => $_ENV['DB_DATABASE'] ?? 'nursery_db',
|
||||
'user' => $_ENV['DB_USERNAME'] ?? 'root',
|
||||
'password' => $_ENV['DB_PASSWORD'] ?? '',
|
||||
'charset' => 'utf8mb4',
|
||||
'driverOptions' => [
|
||||
// Opzioni specifiche del driver PDO, se necessarie
|
||||
// PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4'
|
||||
],
|
||||
];
|
||||
118
backend/database/schema.sql
Normal file
118
backend/database/schema.sql
Normal file
@@ -0,0 +1,118 @@
|
||||
-- Tabella per le Strutture (Sedi dell'asilo nido)
|
||||
CREATE TABLE structures (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL COMMENT 'Nome della struttura',
|
||||
address VARCHAR(255) NULL COMMENT 'Indirizzo',
|
||||
city VARCHAR(100) NULL COMMENT 'Città',
|
||||
province VARCHAR(100) NULL COMMENT 'Provincia',
|
||||
zip_code VARCHAR(10) NULL COMMENT 'CAP',
|
||||
phone VARCHAR(50) NULL COMMENT 'Numero di telefono',
|
||||
email VARCHAR(255) NULL COMMENT 'Indirizzo email',
|
||||
notes TEXT NULL COMMENT 'Note aggiuntive',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
-- Tabella per gli Insegnanti
|
||||
CREATE TABLE teachers (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
first_name VARCHAR(100) NOT NULL COMMENT 'Nome',
|
||||
last_name VARCHAR(100) NOT NULL COMMENT 'Cognome',
|
||||
email VARCHAR(255) UNIQUE NULL COMMENT 'Email (opzionale, ma unica se presente)',
|
||||
phone VARCHAR(50) NULL COMMENT 'Telefono',
|
||||
date_of_birth DATE NULL COMMENT 'Data di nascita',
|
||||
hire_date DATE NULL COMMENT 'Data di assunzione',
|
||||
qualifications TEXT NULL COMMENT 'Qualifiche o note',
|
||||
is_active BOOLEAN DEFAULT true COMMENT 'Indica se l''insegnante è attualmente attivo',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
|
||||
-- Tabella per gli Anni Scolastici
|
||||
CREATE TABLE school_years (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(50) NOT NULL UNIQUE COMMENT 'Nome anno scolastico (es. 2024/2025)',
|
||||
start_date DATE NOT NULL COMMENT 'Data inizio anno scolastico',
|
||||
end_date DATE NOT NULL COMMENT 'Data fine anno scolastico',
|
||||
is_active BOOLEAN DEFAULT false COMMENT 'Indica se è l''anno scolastico corrente/attivo',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_dates CHECK (end_date > start_date) -- Assicura che la fine sia dopo l'inizio
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
|
||||
-- Tabella per i Contratti degli Insegnanti
|
||||
CREATE TABLE teacher_contracts (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
teacher_id INT NOT NULL COMMENT 'FK a teachers',
|
||||
school_year_id INT NOT NULL COMMENT 'FK a school_years',
|
||||
structure_id INT NULL COMMENT 'FK a structures (opzionale, se il contratto è specifico per una struttura)',
|
||||
contract_type VARCHAR(100) NULL COMMENT 'Tipo di contratto (es. Tempo Indeterminato, Tempo Determinato, Collaborazione)',
|
||||
start_date DATE NOT NULL COMMENT 'Data inizio validità contratto',
|
||||
end_date DATE NULL COMMENT 'Data fine validità contratto (NULL se indeterminato)',
|
||||
weekly_hours DECIMAL(5, 2) NULL COMMENT 'Ore settimanali previste',
|
||||
salary DECIMAL(10, 2) NULL COMMENT 'Stipendio lordo (mensile/annuale a seconda delle policy)',
|
||||
notes TEXT NULL COMMENT 'Note aggiuntive sul contratto',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (teacher_id) REFERENCES teachers(id) ON DELETE CASCADE, -- Se elimino un insegnante, elimino i suoi contratti
|
||||
FOREIGN KEY (school_year_id) REFERENCES school_years(id) ON DELETE RESTRICT, -- Non posso eliminare un anno scolastico se ha contratti
|
||||
FOREIGN KEY (structure_id) REFERENCES structures(id) ON DELETE SET NULL, -- Se elimino una struttura, il contratto rimane ma senza struttura associata
|
||||
UNIQUE KEY unique_teacher_year (teacher_id, school_year_id) -- Un insegnante può avere un solo contratto per anno scolastico? (Da valutare)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
-- Tabella per i Bambini
|
||||
CREATE TABLE children (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
first_name VARCHAR(100) NOT NULL COMMENT 'Nome',
|
||||
last_name VARCHAR(100) NOT NULL COMMENT 'Cognome',
|
||||
date_of_birth DATE NOT NULL COMMENT 'Data di nascita',
|
||||
enrollment_date DATE NOT NULL COMMENT 'Data di iscrizione',
|
||||
structure_id INT NULL COMMENT 'FK a structures (struttura di appartenenza principale)',
|
||||
parent1_name VARCHAR(200) NULL COMMENT 'Nome Genitore 1 / Contatto Principale',
|
||||
parent1_phone VARCHAR(50) NULL COMMENT 'Telefono Genitore 1',
|
||||
parent1_email VARCHAR(255) NULL COMMENT 'Email Genitore 1',
|
||||
parent2_name VARCHAR(200) NULL COMMENT 'Nome Genitore 2 / Contatto Secondario',
|
||||
parent2_phone VARCHAR(50) NULL COMMENT 'Telefono Genitore 2',
|
||||
parent2_email VARCHAR(255) NULL COMMENT 'Email Genitore 2',
|
||||
address VARCHAR(255) NULL COMMENT 'Indirizzo residenza',
|
||||
city VARCHAR(100) NULL COMMENT 'Città residenza',
|
||||
notes TEXT NULL COMMENT 'Note (allergie, esigenze particolari, etc.)',
|
||||
is_active BOOLEAN DEFAULT true COMMENT 'Indica se l''iscrizione è attualmente attiva',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (structure_id) REFERENCES structures(id) ON DELETE SET NULL -- Se elimino struttura, il bambino rimane ma senza struttura
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
|
||||
-- Tabella per le Definizioni dei Turni Standard
|
||||
CREATE TABLE shift_definitions (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL UNIQUE COMMENT 'Nome del turno (es. Mattina, Pomeriggio)',
|
||||
start_time TIME NOT NULL COMMENT 'Orario di inizio previsto',
|
||||
end_time TIME NOT NULL COMMENT 'Orario di fine previsto',
|
||||
notes TEXT NULL COMMENT 'Note aggiuntive',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
-- Potremmo aggiungere un flag 'is_default' o 'is_active' se necessario
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
|
||||
-- Tabella per gli Utenti (Admin, Operator)
|
||||
CREATE TABLE users (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL COMMENT 'Nome e Cognome utente',
|
||||
email VARCHAR(255) NOT NULL UNIQUE COMMENT 'Email per login',
|
||||
password VARCHAR(255) NOT NULL COMMENT 'Password hashata',
|
||||
role ENUM('admin', 'operator') NOT NULL DEFAULT 'operator' COMMENT 'Ruolo utente',
|
||||
structure_id INT NULL COMMENT 'FK a structures (se operatore è legato a una struttura specifica)',
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (structure_id) REFERENCES structures(id) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
|
||||
-- Aggiungi qui le altre tabelle (actual_shifts, etc.)
|
||||
-- man mano che le definiamo.
|
||||
-- Aggiungi qui le altre tabelle (children, shifts, users, etc.)
|
||||
-- man mano che le definiamo.
|
||||
229
backend/public/index.php
Normal file
229
backend/public/index.php
Normal file
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Database;
|
||||
use App\Controllers\AuthController;
|
||||
use App\Controllers\ChildController;
|
||||
use App\Controllers\SchoolYearController;
|
||||
use App\Controllers\ShiftDefinitionController;
|
||||
use App\Controllers\StructureController;
|
||||
use App\Controllers\TeacherContractController;
|
||||
use App\Controllers\TeacherController;
|
||||
use Firebase\JWT\JWT; // Importa JWT
|
||||
use Firebase\JWT\Key; // Importa Key
|
||||
use Firebase\JWT\ExpiredException;
|
||||
use Firebase\JWT\SignatureInvalidException;
|
||||
|
||||
// 1. Carica Autoloader Composer
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// 2. Carica Variabili d'Ambiente
|
||||
try {
|
||||
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/../');
|
||||
$dotenv->load();
|
||||
} catch (\Throwable $th) {
|
||||
error_log("Could not load .env file: " . $th->getMessage());
|
||||
}
|
||||
|
||||
// --- Configurazione JWT ---
|
||||
$jwtSecret = $_ENV['JWT_SECRET'] ?? 'default-secret-change-me';
|
||||
|
||||
// --- Funzione Guardia JWT ---
|
||||
/**
|
||||
* Verifica il token JWT dall'header Authorization.
|
||||
* Restituisce i dati utente dal payload se valido, altrimenti termina con errore 401.
|
||||
* @return array Dati utente dal payload JWT ('sub', 'data')
|
||||
*/
|
||||
function authenticate(): array {
|
||||
global $jwtSecret; // Rende visibile la chiave segreta definita sopra
|
||||
|
||||
$authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? null;
|
||||
|
||||
if (!$authHeader) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['error' => 'Authorization header missing']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Estrai il token "Bearer <token>"
|
||||
if (!preg_match('/Bearer\s(\S+)/', $authHeader, $matches)) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['error' => 'Malformed Authorization header']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$jwt = $matches[1];
|
||||
if (!$jwt) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['error' => 'Access token missing']);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$decoded = JWT::decode($jwt, new Key($jwtSecret, 'HS256'));
|
||||
// Restituisce l'intero payload decodificato come array associativo
|
||||
return (array)$decoded;
|
||||
} catch (ExpiredException $e) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['error' => 'Token expired']);
|
||||
exit;
|
||||
} catch (SignatureInvalidException $e) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['error' => 'Invalid token signature']);
|
||||
exit;
|
||||
} catch (\Throwable $e) { // Cattura altri errori JWT
|
||||
http_response_code(401);
|
||||
error_log("JWT Decode Error: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Invalid token']);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 3. Imposta Headers CORS
|
||||
$allowedOrigin = $_ENV['FRONTEND_URL'] ?? 'http://localhost:4200';
|
||||
header("Access-Control-Allow-Origin: " . $allowedOrigin);
|
||||
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
|
||||
header("Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With");
|
||||
header("Access-Control-Allow-Credentials: true");
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||
http_response_code(204); exit;
|
||||
}
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// 4. Definizione Route
|
||||
$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) {
|
||||
|
||||
// --- Public Routes ---
|
||||
$r->addRoute('POST', '/api/login', [AuthController::class, 'login']);
|
||||
$r->addRoute('GET', '/api/ping', function () { echo json_encode(['message' => 'pong']); });
|
||||
|
||||
// --- Protected Routes (richiedono autenticazione) ---
|
||||
|
||||
// Aggiungiamo un gruppo per applicare la guardia a più route
|
||||
$r->addGroup('/api', function (FastRoute\RouteCollector $r) {
|
||||
// La guardia verrà chiamata prima dell'handler per queste route
|
||||
|
||||
// Route /api/me (protetta)
|
||||
$r->addRoute('GET', '/me', [AuthController::class, 'me']);
|
||||
|
||||
// Structures
|
||||
$r->addRoute('GET', '/structures', [StructureController::class, 'index']);
|
||||
$r->addRoute('POST', '/structures', [StructureController::class, 'store']);
|
||||
$r->addRoute('GET', '/structures/{id:\d+}', [StructureController::class, 'show']);
|
||||
$r->addRoute('PUT', '/structures/{id:\d+}', [StructureController::class, 'update']);
|
||||
$r->addRoute('DELETE', '/structures/{id:\d+}', [StructureController::class, 'delete']);
|
||||
|
||||
// Teachers
|
||||
$r->addRoute('GET', '/teachers', [TeacherController::class, 'index']);
|
||||
$r->addRoute('POST', '/teachers', [TeacherController::class, 'store']);
|
||||
$r->addRoute('GET', '/teachers/{id:\d+}', [TeacherController::class, 'show']);
|
||||
$r->addRoute('PUT', '/teachers/{id:\d+}', [TeacherController::class, 'update']);
|
||||
$r->addRoute('DELETE', '/teachers/{id:\d+}', [TeacherController::class, 'delete']);
|
||||
|
||||
// School Years
|
||||
$r->addRoute('GET', '/school-years', [SchoolYearController::class, 'index']);
|
||||
$r->addRoute('POST', '/school-years', [SchoolYearController::class, 'store']);
|
||||
$r->addRoute('GET', '/school-years/{id:\d+}', [SchoolYearController::class, 'show']);
|
||||
$r->addRoute('PUT', '/school-years/{id:\d+}', [SchoolYearController::class, 'update']);
|
||||
$r->addRoute('DELETE', '/school-years/{id:\d+}', [SchoolYearController::class, 'delete']);
|
||||
|
||||
// Teacher Contracts
|
||||
$r->addRoute('GET', '/teacher-contracts', [TeacherContractController::class, 'index']);
|
||||
$r->addRoute('POST', '/teacher-contracts', [TeacherContractController::class, 'store']);
|
||||
$r->addRoute('GET', '/teacher-contracts/{id:\d+}', [TeacherContractController::class, 'show']);
|
||||
$r->addRoute('PUT', '/teacher-contracts/{id:\d+}', [TeacherContractController::class, 'update']);
|
||||
$r->addRoute('DELETE', '/teacher-contracts/{id:\d+}', [TeacherContractController::class, 'delete']);
|
||||
|
||||
// Children
|
||||
$r->addRoute('GET', '/children', [ChildController::class, 'index']);
|
||||
$r->addRoute('POST', '/children', [ChildController::class, 'store']);
|
||||
$r->addRoute('GET', '/children/{id:\d+}', [ChildController::class, 'show']);
|
||||
$r->addRoute('PUT', '/children/{id:\d+}', [ChildController::class, 'update']);
|
||||
$r->addRoute('DELETE', '/children/{id:\d+}', [ChildController::class, 'delete']);
|
||||
|
||||
// Shift Definitions
|
||||
$r->addRoute('GET', '/shift-definitions', [ShiftDefinitionController::class, 'index']);
|
||||
$r->addRoute('POST', '/shift-definitions', [ShiftDefinitionController::class, 'store']);
|
||||
$r->addRoute('GET', '/shift-definitions/{id:\d+}', [ShiftDefinitionController::class, 'show']);
|
||||
$r->addRoute('PUT', '/shift-definitions/{id:\d+}', [ShiftDefinitionController::class, 'update']);
|
||||
$r->addRoute('DELETE', '/shift-definitions/{id:\d+}', [ShiftDefinitionController::class, 'delete']);
|
||||
|
||||
}); // Fine gruppo /api
|
||||
|
||||
});
|
||||
|
||||
// 5. Gestione della Richiesta
|
||||
$httpMethod = $_SERVER['REQUEST_METHOD'];
|
||||
$uri = $_SERVER['REQUEST_URI'];
|
||||
|
||||
if (false !== $pos = strpos($uri, '?')) {
|
||||
$uri = substr($uri, 0, $pos);
|
||||
}
|
||||
$uri = rawurldecode($uri);
|
||||
|
||||
$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
|
||||
$userData = null; // Inizializza a null
|
||||
|
||||
switch ($routeInfo[0]) {
|
||||
case FastRoute\Dispatcher::NOT_FOUND:
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => 'API Endpoint Not Found']);
|
||||
break;
|
||||
case FastRoute\Dispatcher::METHOD_NOT_ALLOWED:
|
||||
$allowedMethods = $routeInfo[1];
|
||||
http_response_code(405);
|
||||
echo json_encode(['error' => 'Method Not Allowed', 'allowed_methods' => $allowedMethods]);
|
||||
break;
|
||||
case FastRoute\Dispatcher::FOUND:
|
||||
$handler = $routeInfo[1];
|
||||
$vars = $routeInfo[2];
|
||||
|
||||
// --- Applica Guardia JWT se la route è protetta (inizia con /api/ e non è /api/login o /api/ping) ---
|
||||
if (strpos($uri, '/api/') === 0 && !in_array($uri, ['/api/login', '/api/ping'])) {
|
||||
try {
|
||||
$userData = authenticate(); // Verifica token e ottieni dati utente
|
||||
// Potresti aggiungere qui controllo del ruolo se necessario per specifiche route
|
||||
// if ($userData['data']->role !== 'admin' && $uri === '/api/users') { ... }
|
||||
} catch (\Exception $e) {
|
||||
// L'eccezione è già gestita dentro authenticate() con exit
|
||||
// Questo blocco catch è per sicurezza, ma non dovrebbe essere raggiunto
|
||||
http_response_code(500);
|
||||
error_log("Unexpected error during authentication check: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Authentication check failed']);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Esecuzione Handler ---
|
||||
try {
|
||||
if (is_callable($handler)) {
|
||||
call_user_func($handler, $vars); // Passa $vars alla closure
|
||||
} elseif (is_array($handler) && count($handler) === 2 && is_string($handler[0]) && is_string($handler[1])) {
|
||||
[$class, $method] = $handler;
|
||||
if (class_exists($class) && method_exists($class, $method)) {
|
||||
$controller = new $class();
|
||||
// Passa $vars e $userData (se presente) al metodo del controller
|
||||
// Modifica i metodi del controller per accettare $userData opzionale se serve
|
||||
if ($method === 'me' && $userData !== null) { // Caso speciale per AuthController::me
|
||||
call_user_func([$controller, $method], $userData['data']); // Passa solo il payload 'data'
|
||||
} else {
|
||||
call_user_func([$controller, $method], $vars); // Chiamata standard per gli altri
|
||||
}
|
||||
|
||||
} else {
|
||||
http_response_code(500); error_log("Handler class/method not found: {$class}::{$method}"); echo json_encode(['error' => 'Internal Server Error']);
|
||||
}
|
||||
} else {
|
||||
http_response_code(500); error_log("Invalid handler type defined."); echo json_encode(['error' => 'Internal Server Error']);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500); error_log("Unhandled error in route handler: " . $e->getMessage() . "\n" . $e->getTraceAsString()); echo json_encode(['error' => 'Internal Server Error']);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
http_response_code(500); echo json_encode(['error' => 'Internal Server Error - Dispatcher Error']); break;
|
||||
}
|
||||
10
backend/public/php_errors.log
Normal file
10
backend/public/php_errors.log
Normal file
@@ -0,0 +1,10 @@
|
||||
[06-Mar-2026 21:29:32 UTC] PHP Warning: Array to string conversion in D:\Works\NidoAi\backend\public\index.php on line 90
|
||||
[06-Mar-2026 21:29:32 UTC] PHP Warning: Array to string conversion in D:\Works\NidoAi\backend\public\index.php on line 90
|
||||
[06-Mar-2026 21:29:56 UTC] PHP Warning: Array to string conversion in D:\Works\NidoAi\backend\public\index.php on line 90
|
||||
[06-Mar-2026 21:29:56 UTC] PHP Warning: Array to string conversion in D:\Works\NidoAi\backend\public\index.php on line 90
|
||||
[06-Mar-2026 21:30:41 UTC] PHP Warning: Array to string conversion in D:\Works\NidoAi\backend\public\index.php on line 90
|
||||
[06-Mar-2026 21:30:41 UTC] PHP Warning: Array to string conversion in D:\Works\NidoAi\backend\public\index.php on line 90
|
||||
[06-Mar-2026 21:30:41 UTC] PHP Warning: Array to string conversion in D:\Works\NidoAi\backend\public\index.php on line 90
|
||||
[06-Mar-2026 21:30:41 UTC] PHP Warning: Array to string conversion in D:\Works\NidoAi\backend\public\index.php on line 90
|
||||
[06-Mar-2026 21:30:50 UTC] PHP Warning: Array to string conversion in D:\Works\NidoAi\backend\public\index.php on line 90
|
||||
[06-Mar-2026 21:30:50 UTC] PHP Warning: Array to string conversion in D:\Works\NidoAi\backend\public\index.php on line 90
|
||||
138
backend/src/Controllers/AuthController.php
Normal file
138
backend/src/Controllers/AuthController.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Database;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Firebase\JWT\JWT; // Importa la libreria JWT
|
||||
use Firebase\JWT\Key; // Importa Key per la verifica
|
||||
|
||||
class AuthController
|
||||
{
|
||||
private Connection $db;
|
||||
private string $jwtSecret;
|
||||
private int $jwtExpiration;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
try {
|
||||
$this->db = Database::getConnection();
|
||||
// Leggi la configurazione JWT da .env
|
||||
$this->jwtSecret = $_ENV['JWT_SECRET'] ?? 'default-secret-change-me'; // Usa un default se non impostato
|
||||
$this->jwtExpiration = (int)($_ENV['JWT_EXPIRATION_TIME'] ?? 3600); // Default 1 ora
|
||||
} catch (\Throwable $e) {
|
||||
error_log("Failed to get DB connection or JWT config in AuthController: " . $e->getMessage());
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Internal Server Error - Config']);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gestisce il login dell'utente.
|
||||
* POST /api/login
|
||||
*/
|
||||
public function login(): void
|
||||
{
|
||||
// Prova a leggere JSON, fallback a POST
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE || !is_array($input)) {
|
||||
$input = $_POST; // Fallback a POST se JSON non valido o vuoto
|
||||
}
|
||||
if (!is_array($input)) { // Se ancora non è un array, errore
|
||||
http_response_code(400); echo json_encode(['error' => 'Invalid input']); return;
|
||||
}
|
||||
|
||||
$email = $input['email'] ?? null;
|
||||
$password = $input['password'] ?? null;
|
||||
|
||||
if (!$email || !$password) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Email and password are required']);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Trova l'utente per email
|
||||
$user = $this->db->fetchAssociative('SELECT id, name, email, password, role, structure_id, is_active FROM users WHERE email = ?', [$email]);
|
||||
|
||||
// Verifica utente e password
|
||||
if ($user === false || !password_verify($password, $user['password'])) {
|
||||
http_response_code(401); // Unauthorized
|
||||
echo json_encode(['error' => 'Invalid credentials']);
|
||||
return;
|
||||
}
|
||||
|
||||
// Verifica se l'utente è attivo
|
||||
if (!$user['is_active']) {
|
||||
http_response_code(403); // Forbidden
|
||||
echo json_encode(['error' => 'User account is inactive']);
|
||||
return;
|
||||
}
|
||||
|
||||
// Genera il token JWT
|
||||
$issuedAt = time();
|
||||
$expirationTime = $issuedAt + $this->jwtExpiration;
|
||||
$payload = [
|
||||
'iat' => $issuedAt, // Issued at: time when the token was generated
|
||||
'exp' => $expirationTime, // Expiration time
|
||||
'sub' => $user['id'], // Subject: user ID
|
||||
'data' => [ // Dati aggiuntivi (payload)
|
||||
'name' => $user['name'],
|
||||
'email' => $user['email'],
|
||||
'role' => $user['role'],
|
||||
'structure_id' => $user['structure_id']
|
||||
]
|
||||
];
|
||||
|
||||
$jwt = JWT::encode($payload, $this->jwtSecret, 'HS256');
|
||||
|
||||
// Restituisci il token e magari alcuni dati utente
|
||||
http_response_code(200);
|
||||
echo json_encode([
|
||||
'message' => 'Login successful',
|
||||
'access_token' => $jwt,
|
||||
'token_type' => 'Bearer',
|
||||
'expires_in' => $this->jwtExpiration,
|
||||
'user' => [ // Invia dati utente non sensibili
|
||||
'id' => $user['id'],
|
||||
'name' => $user['name'],
|
||||
'email' => $user['email'],
|
||||
'role' => $user['role'],
|
||||
'structure_id' => $user['structure_id']
|
||||
]
|
||||
]);
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Login error: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Login failed']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restituisce i dati dell'utente autenticato.
|
||||
* GET /api/me (Richiede token valido)
|
||||
*/
|
||||
// Questo metodo verrà chiamato DOPO che un middleware/guardia ha verificato il token
|
||||
// e potenzialmente aggiunto i dati utente alla richiesta (o a un contesto).
|
||||
// Per ora, assumiamo che $userData sia disponibile dopo la verifica del token.
|
||||
public function me(array $userData = []): void // $userData verrà iniettato dalla guardia/middleware
|
||||
{
|
||||
if (empty($userData)) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['error' => 'Not authenticated']);
|
||||
return;
|
||||
}
|
||||
// Restituisce i dati utente estratti dal token (o recuperati dal DB usando l'ID)
|
||||
http_response_code(200);
|
||||
echo json_encode($userData); // $userData contiene già i dati dal payload del token
|
||||
}
|
||||
|
||||
|
||||
// TODO: Implementare register() se necessario, con password_hash()
|
||||
// TODO: Implementare refresh() per rinnovare il token se necessario
|
||||
|
||||
}
|
||||
247
backend/src/Controllers/ChildController.php
Normal file
247
backend/src/Controllers/ChildController.php
Normal file
@@ -0,0 +1,247 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Database;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
|
||||
|
||||
class ChildController
|
||||
{
|
||||
private Connection $db;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
try {
|
||||
$this->db = Database::getConnection();
|
||||
} catch (\Throwable $e) {
|
||||
error_log("Failed to get DB connection in ChildController: " . $e->getMessage());
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Internal Server Error - DB Connection']);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mostra un elenco di bambini.
|
||||
* GET /api/children
|
||||
* Accetta query params: structure_id, is_active
|
||||
*/
|
||||
public function index(): void
|
||||
{
|
||||
try {
|
||||
$queryBuilder = $this->db->createQueryBuilder()
|
||||
->select(
|
||||
'c.id', 'c.first_name', 'c.last_name', 'c.date_of_birth',
|
||||
'c.enrollment_date', 'c.structure_id', 'c.is_active',
|
||||
's.name AS structure_name' // Nome struttura associata
|
||||
)
|
||||
->from('children', 'c')
|
||||
->leftJoin('c', 'structures', 's', 'c.structure_id = s.id')
|
||||
->orderBy('c.last_name', 'ASC')
|
||||
->addOrderBy('c.first_name', 'ASC');
|
||||
|
||||
// Filtri opzionali
|
||||
if (isset($_GET['structure_id']) && $_GET['structure_id'] !== '') {
|
||||
$queryBuilder->andWhere('c.structure_id = :structureId')
|
||||
->setParameter('structureId', $_GET['structure_id']);
|
||||
}
|
||||
if (isset($_GET['is_active'])) {
|
||||
// Converte il valore stringa 'true'/'false' o 1/0 in booleano
|
||||
$isActive = filter_var($_GET['is_active'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
||||
if ($isActive !== null) {
|
||||
$queryBuilder->andWhere('c.is_active = :isActive')
|
||||
->setParameter('isActive', $isActive, \Doctrine\DBAL\ParameterType::BOOLEAN);
|
||||
}
|
||||
}
|
||||
|
||||
$children = $queryBuilder->fetchAllAssociative();
|
||||
echo json_encode($children);
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error fetching children: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to fetch children']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mostra un bambino specifico.
|
||||
* GET /api/children/{id}
|
||||
*/
|
||||
public function show(array $vars): void
|
||||
{
|
||||
$id = $vars['id'] ?? null;
|
||||
if ($id === null) { http_response_code(400); echo json_encode(['error' => 'Missing child ID']); return; }
|
||||
|
||||
try {
|
||||
$queryBuilder = $this->db->createQueryBuilder()
|
||||
->select('c.*', 's.name AS structure_name')
|
||||
->from('children', 'c')
|
||||
->leftJoin('c', 'structures', 's', 'c.structure_id = s.id')
|
||||
->where('c.id = :id')
|
||||
->setParameter('id', $id);
|
||||
|
||||
$child = $queryBuilder->fetchAssociative();
|
||||
|
||||
if ($child === false) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => "Child with ID {$id} not found"]);
|
||||
} else {
|
||||
echo json_encode($child);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error fetching child {$id}: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to fetch child']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Crea un nuovo bambino.
|
||||
* POST /api/children
|
||||
*/
|
||||
public function store(): void
|
||||
{
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE || !is_array($input)) {
|
||||
http_response_code(400); echo json_encode(['error' => 'Invalid JSON input']); return;
|
||||
}
|
||||
|
||||
// Validazione campi obbligatori
|
||||
if (empty($input['first_name']) || empty($input['last_name']) || empty($input['date_of_birth']) || empty($input['enrollment_date'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Missing required fields: first_name, last_name, date_of_birth, enrollment_date']);
|
||||
return;
|
||||
}
|
||||
|
||||
$dataToInsert = [
|
||||
'first_name' => $input['first_name'],
|
||||
'last_name' => $input['last_name'],
|
||||
'date_of_birth' => $input['date_of_birth'], // Assumiamo YYYY-MM-DD
|
||||
'enrollment_date' => $input['enrollment_date'], // Assumiamo YYYY-MM-DD
|
||||
'structure_id' => (isset($input['structure_id']) && $input['structure_id'] !== '') ? (int)$input['structure_id'] : null,
|
||||
'parent1_name' => $input['parent1_name'] ?? null,
|
||||
'parent1_phone' => $input['parent1_phone'] ?? null,
|
||||
'parent1_email' => $input['parent1_email'] ?? null,
|
||||
'parent2_name' => $input['parent2_name'] ?? null,
|
||||
'parent2_phone' => $input['parent2_phone'] ?? null,
|
||||
'parent2_email' => $input['parent2_email'] ?? null,
|
||||
'address' => $input['address'] ?? null,
|
||||
'city' => $input['city'] ?? null,
|
||||
'notes' => $input['notes'] ?? null,
|
||||
'is_active' => isset($input['is_active']) ? (bool)$input['is_active'] : true, // Default a true
|
||||
];
|
||||
|
||||
try {
|
||||
$result = $this->db->insert('children', $dataToInsert);
|
||||
if ($result === false || $result === 0) { throw new \Exception("Failed to insert child."); }
|
||||
|
||||
$newId = $this->db->lastInsertId();
|
||||
http_response_code(201);
|
||||
$this->show(['id' => $newId]); // Mostra il bambino appena creato
|
||||
|
||||
} catch (ForeignKeyConstraintViolationException $e) {
|
||||
http_response_code(400);
|
||||
error_log("Error creating child (invalid structure ID?): " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Invalid structure ID provided.']);
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error creating child: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to create child']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggiorna un bambino esistente.
|
||||
* PUT /api/children/{id}
|
||||
*/
|
||||
public function update(array $vars): void
|
||||
{
|
||||
$id = $vars['id'] ?? null;
|
||||
if ($id === null) { http_response_code(400); echo json_encode(['error' => 'Missing child ID']); return; }
|
||||
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE || !is_array($input)) {
|
||||
http_response_code(400); echo json_encode(['error' => 'Invalid JSON input']); return;
|
||||
}
|
||||
if (empty($input)) { http_response_code(400); echo json_encode(['error' => 'Missing update data']); return; }
|
||||
|
||||
$dataToUpdate = [];
|
||||
$allowedFields = [
|
||||
'first_name', 'last_name', 'date_of_birth', 'enrollment_date', 'structure_id',
|
||||
'parent1_name', 'parent1_phone', 'parent1_email',
|
||||
'parent2_name', 'parent2_phone', 'parent2_email',
|
||||
'address', 'city', 'notes', 'is_active'
|
||||
];
|
||||
|
||||
foreach ($allowedFields as $field) {
|
||||
if (array_key_exists($field, $input)) {
|
||||
$value = $input[$field];
|
||||
if ($field === 'is_active') {
|
||||
$dataToUpdate[$field] = (bool)$value;
|
||||
} elseif ($field === 'structure_id' && ($value === '' || $value === null)) {
|
||||
$dataToUpdate[$field] = null;
|
||||
} elseif ($field === 'structure_id') {
|
||||
$dataToUpdate[$field] = (int)$value;
|
||||
} else {
|
||||
$dataToUpdate[$field] = ($value === '') ? null : $value; // Imposta null se stringa vuota per altri campi opzionali
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($dataToUpdate)) { http_response_code(400); echo json_encode(['error' => 'No valid fields provided for update']); return; }
|
||||
|
||||
try {
|
||||
$existing = $this->db->fetchOne('SELECT 1 FROM children WHERE id = ?', [$id]);
|
||||
if ($existing === false) { http_response_code(404); echo json_encode(['error' => "Child with ID {$id} not found"]); return; }
|
||||
|
||||
$this->db->update('children', $dataToUpdate, ['id' => $id]);
|
||||
$this->show(['id' => $id]); // Mostra il bambino aggiornato
|
||||
|
||||
} catch (ForeignKeyConstraintViolationException $e) {
|
||||
http_response_code(400);
|
||||
error_log("Error updating child {$id} (invalid structure ID?): " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Invalid structure ID provided.']);
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error updating child {$id}: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to update child']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Elimina un bambino.
|
||||
* DELETE /api/children/{id}
|
||||
*/
|
||||
public function delete(array $vars): void
|
||||
{
|
||||
$id = $vars['id'] ?? null;
|
||||
if ($id === null) { http_response_code(400); echo json_encode(['error' => 'Missing child ID']); return; }
|
||||
|
||||
try {
|
||||
// Aggiungere qui controlli se il bambino è referenziato altrove (es. presenze, pagamenti)
|
||||
// prima di permettere l'eliminazione.
|
||||
|
||||
$existing = $this->db->fetchOne('SELECT 1 FROM children WHERE id = ?', [$id]);
|
||||
if ($existing === false) { http_response_code(404); echo json_encode(['error' => "Child with ID {$id} not found"]); return; }
|
||||
|
||||
$deletedRows = $this->db->delete('children', ['id' => $id]);
|
||||
|
||||
if ($deletedRows > 0) {
|
||||
http_response_code(204); // No Content
|
||||
} else {
|
||||
http_response_code(500);
|
||||
error_log("Failed to delete child {$id}, delete returned 0 rows affected.");
|
||||
echo json_encode(['error' => 'Failed to delete child']);
|
||||
}
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error deleting child {$id}: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to delete child']);
|
||||
}
|
||||
}
|
||||
}
|
||||
271
backend/src/Controllers/SchoolYearController.php
Normal file
271
backend/src/Controllers/SchoolYearController.php
Normal file
@@ -0,0 +1,271 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Database;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
||||
|
||||
class SchoolYearController
|
||||
{
|
||||
private Connection $db;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
try {
|
||||
$this->db = Database::getConnection();
|
||||
} catch (\Throwable $e) {
|
||||
error_log("Failed to get DB connection in SchoolYearController: " . $e->getMessage());
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Internal Server Error - DB Connection']);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mostra un elenco di anni scolastici.
|
||||
* GET /api/school-years
|
||||
*/
|
||||
public function index(): void
|
||||
{
|
||||
try {
|
||||
$queryBuilder = $this->db->createQueryBuilder();
|
||||
// Ordina per data di inizio decrescente per vedere i più recenti prima
|
||||
$schoolYears = $queryBuilder
|
||||
->select('*')
|
||||
->from('school_years')
|
||||
->orderBy('start_date', 'ASC')
|
||||
->fetchAllAssociative();
|
||||
|
||||
echo json_encode($schoolYears);
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error fetching school years: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to fetch school years']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mostra un anno scolastico specifico.
|
||||
* GET /api/school-years/{id}
|
||||
*/
|
||||
public function show(array $vars): void
|
||||
{
|
||||
$id = $vars['id'] ?? null;
|
||||
if ($id === null) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Missing school year ID']);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$schoolYear = $this->db->fetchAssociative('SELECT * FROM school_years WHERE id = ?', [$id]);
|
||||
|
||||
if ($schoolYear === false) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => "School year with ID {$id} not found"]);
|
||||
} else {
|
||||
echo json_encode($schoolYear);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error fetching school year {$id}: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to fetch school year']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Crea un nuovo anno scolastico.
|
||||
* POST /api/school-years
|
||||
*/
|
||||
public function store(): void
|
||||
{
|
||||
$input = (array) json_decode(file_get_contents('php://input'), true);
|
||||
if (empty($input) && !empty($_POST)) { $input = $_POST; }
|
||||
|
||||
// Validazione
|
||||
if (empty($input['name']) || empty($input['start_date']) || empty($input['end_date'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Missing required fields: name, start_date, end_date']);
|
||||
return;
|
||||
}
|
||||
if (strtotime($input['end_date']) <= strtotime($input['start_date'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'End date must be after start date']);
|
||||
return;
|
||||
}
|
||||
|
||||
$dataToInsert = [
|
||||
'name' => $input['name'],
|
||||
'start_date' => $input['start_date'], // Assumiamo formato YYYY-MM-DD
|
||||
'end_date' => $input['end_date'], // Assumiamo formato YYYY-MM-DD
|
||||
'is_active' => isset($input['is_active']) ? (bool)$input['is_active'] : false, // Default a false
|
||||
];
|
||||
|
||||
try {
|
||||
// Se is_active è true, assicurati che nessun altro anno sia attivo
|
||||
if ($dataToInsert['is_active']) {
|
||||
$this->db->executeStatement('UPDATE school_years SET is_active = false WHERE is_active = true');
|
||||
}
|
||||
|
||||
$result = $this->db->insert('school_years', $dataToInsert);
|
||||
|
||||
if ($result === false || $result === 0) {
|
||||
throw new \Exception("Failed to insert school year.");
|
||||
}
|
||||
|
||||
$newId = $this->db->lastInsertId();
|
||||
http_response_code(201);
|
||||
$newSchoolYear = $this->db->fetchAssociative('SELECT * FROM school_years WHERE id = ?', [$newId]);
|
||||
echo json_encode($newSchoolYear);
|
||||
|
||||
} catch (UniqueConstraintViolationException $e) {
|
||||
http_response_code(409); // Conflict
|
||||
error_log("Error creating school year (duplicate name?): " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to create school year. Name might already exist.']);
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error creating school year: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to create school year']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggiorna un anno scolastico esistente.
|
||||
* PUT /api/school-years/{id}
|
||||
*/
|
||||
public function update(array $vars): void
|
||||
{
|
||||
$id = $vars['id'] ?? null;
|
||||
if ($id === null) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Missing school year ID']);
|
||||
return;
|
||||
}
|
||||
|
||||
$inputJson = file_get_contents('php://input');
|
||||
$input = $inputJson ? (array) json_decode($inputJson, true) : [];
|
||||
if (empty($input) && $inputJson && ($_SERVER['CONTENT_TYPE'] ?? '') === 'application/x-www-form-urlencoded') {
|
||||
parse_str($inputJson, $input);
|
||||
}
|
||||
if (empty($input)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Missing update data']);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validazione date se presenti
|
||||
$startDate = $input['start_date'] ?? null;
|
||||
$endDate = $input['end_date'] ?? null;
|
||||
// Se vengono fornite entrambe le date, valida la loro coerenza
|
||||
if ($startDate && $endDate && strtotime($endDate) <= strtotime($startDate)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'End date must be after start date']);
|
||||
return;
|
||||
}
|
||||
// Se viene fornita solo una data, recupera l'altra dal DB per validare
|
||||
if (($startDate && !$endDate) || (!$startDate && $endDate)) {
|
||||
$currentDates = $this->db->fetchAssociative('SELECT start_date, end_date FROM school_years WHERE id = ?', [$id]);
|
||||
if ($currentDates) {
|
||||
if ($startDate && strtotime($currentDates['end_date']) <= strtotime($startDate)) {
|
||||
http_response_code(400); echo json_encode(['error' => 'Start date must be before existing end date']); return;
|
||||
}
|
||||
if ($endDate && strtotime($endDate) <= strtotime($currentDates['start_date'])) {
|
||||
http_response_code(400); echo json_encode(['error' => 'End date must be after existing start date']); return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$dataToUpdate = [];
|
||||
$allowedFields = ['name', 'start_date', 'end_date', 'is_active'];
|
||||
foreach ($allowedFields as $field) {
|
||||
if (array_key_exists($field, $input)) {
|
||||
if ($field === 'is_active') {
|
||||
$dataToUpdate[$field] = (bool)$input[$field];
|
||||
} else {
|
||||
$dataToUpdate[$field] = $input[$field];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($dataToUpdate)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'No valid fields provided for update']);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$existing = $this->db->fetchOne('SELECT 1 FROM school_years WHERE id = ?', [$id]);
|
||||
if ($existing === false) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => "School year with ID {$id} not found"]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Se si sta attivando questo anno, disattiva gli altri
|
||||
if (isset($dataToUpdate['is_active']) && $dataToUpdate['is_active']) {
|
||||
$this->db->executeStatement('UPDATE school_years SET is_active = false WHERE is_active = true AND id != ?', [$id]);
|
||||
}
|
||||
|
||||
$this->db->update('school_years', $dataToUpdate, ['id' => $id]);
|
||||
|
||||
$updatedSchoolYear = $this->db->fetchAssociative('SELECT * FROM school_years WHERE id = ?', [$id]);
|
||||
echo json_encode($updatedSchoolYear);
|
||||
|
||||
} catch (UniqueConstraintViolationException $e) {
|
||||
http_response_code(409); // Conflict
|
||||
error_log("Error updating school year {$id} (duplicate name?): " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to update school year. Name might already exist.']);
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error updating school year {$id}: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to update school year']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Elimina un anno scolastico.
|
||||
* DELETE /api/school-years/{id}
|
||||
*/
|
||||
public function delete(array $vars): void
|
||||
{
|
||||
$id = $vars['id'] ?? null;
|
||||
if ($id === null) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Missing school year ID']);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Aggiungere qui controlli se l'anno scolastico è referenziato altrove (es. contratti)
|
||||
// prima di permettere l'eliminazione.
|
||||
// Esempio: $count = $this->db->fetchOne('SELECT COUNT(*) FROM contracts WHERE school_year_id = ?', [$id]);
|
||||
// if ($count > 0) { http_response_code(409); echo json_encode(...); return; }
|
||||
|
||||
$existing = $this->db->fetchOne('SELECT 1 FROM school_years WHERE id = ?', [$id]);
|
||||
if ($existing === false) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => "School year with ID {$id} not found"]);
|
||||
return;
|
||||
}
|
||||
|
||||
$deletedRows = $this->db->delete('school_years', ['id' => $id]);
|
||||
|
||||
if ($deletedRows > 0) {
|
||||
http_response_code(204); // No Content
|
||||
} else {
|
||||
http_response_code(500);
|
||||
error_log("Failed to delete school year {$id}, delete returned 0 rows affected.");
|
||||
echo json_encode(['error' => 'Failed to delete school year']);
|
||||
}
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error deleting school year {$id}: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to delete school year']);
|
||||
}
|
||||
}
|
||||
}
|
||||
224
backend/src/Controllers/ShiftDefinitionController.php
Normal file
224
backend/src/Controllers/ShiftDefinitionController.php
Normal file
@@ -0,0 +1,224 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Database;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
||||
|
||||
class ShiftDefinitionController
|
||||
{
|
||||
private Connection $db;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
try {
|
||||
$this->db = Database::getConnection();
|
||||
} catch (\Throwable $e) {
|
||||
error_log("Failed to get DB connection in ShiftDefinitionController: " . $e->getMessage());
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Internal Server Error - DB Connection']);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mostra un elenco di definizioni di turno.
|
||||
* GET /api/shift-definitions
|
||||
*/
|
||||
public function index(): void
|
||||
{
|
||||
try {
|
||||
$queryBuilder = $this->db->createQueryBuilder();
|
||||
$shifts = $queryBuilder
|
||||
->select('*')
|
||||
->from('shift_definitions')
|
||||
->orderBy('start_time', 'ASC') // Ordina per orario inizio
|
||||
->fetchAllAssociative();
|
||||
|
||||
echo json_encode($shifts);
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error fetching shift definitions: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to fetch shift definitions']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mostra una definizione di turno specifica.
|
||||
* GET /api/shift-definitions/{id}
|
||||
*/
|
||||
public function show(array $vars): void
|
||||
{
|
||||
$id = $vars['id'] ?? null;
|
||||
if ($id === null) { http_response_code(400); echo json_encode(['error' => 'Missing shift definition ID']); return; }
|
||||
|
||||
try {
|
||||
$shift = $this->db->fetchAssociative('SELECT * FROM shift_definitions WHERE id = ?', [$id]);
|
||||
|
||||
if ($shift === false) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => "Shift definition with ID {$id} not found"]);
|
||||
} else {
|
||||
echo json_encode($shift);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error fetching shift definition {$id}: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to fetch shift definition']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Crea una nuova definizione di turno.
|
||||
* POST /api/shift-definitions
|
||||
*/
|
||||
public function store(): void
|
||||
{
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE || !is_array($input)) {
|
||||
http_response_code(400); echo json_encode(['error' => 'Invalid JSON input']); return;
|
||||
}
|
||||
|
||||
// Validazione campi obbligatori
|
||||
if (empty($input['name']) || empty($input['start_time']) || empty($input['end_time'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Missing required fields: name, start_time, end_time']);
|
||||
return;
|
||||
}
|
||||
// Validazione formato orario (HH:MM o HH:MM:SS)
|
||||
$timeRegex = '/^([01]\d|2[0-3]):([0-5]\d)(:([0-5]\d))?$/';
|
||||
if (!preg_match($timeRegex, $input['start_time']) || !preg_match($timeRegex, $input['end_time'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Invalid time format. Use HH:MM or HH:MM:SS.']);
|
||||
return;
|
||||
}
|
||||
// Validazione logica orari (opzionale, ma utile)
|
||||
if (strtotime($input['end_time']) <= strtotime($input['start_time'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'End time must be after start time.']);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$dataToInsert = [
|
||||
'name' => $input['name'],
|
||||
'start_time' => $input['start_time'],
|
||||
'end_time' => $input['end_time'],
|
||||
'notes' => $input['notes'] ?? null,
|
||||
];
|
||||
|
||||
try {
|
||||
$result = $this->db->insert('shift_definitions', $dataToInsert);
|
||||
if ($result === false || $result === 0) { throw new \Exception("Failed to insert shift definition."); }
|
||||
|
||||
$newId = $this->db->lastInsertId();
|
||||
http_response_code(201);
|
||||
$this->show(['id' => $newId]);
|
||||
|
||||
} catch (UniqueConstraintViolationException $e) {
|
||||
http_response_code(409);
|
||||
error_log("Error creating shift definition (duplicate name?): " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to create shift definition. Name might already exist.']);
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error creating shift definition: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to create shift definition']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggiorna una definizione di turno esistente.
|
||||
* PUT /api/shift-definitions/{id}
|
||||
*/
|
||||
public function update(array $vars): void
|
||||
{
|
||||
$id = $vars['id'] ?? null;
|
||||
if ($id === null) { http_response_code(400); echo json_encode(['error' => 'Missing shift definition ID']); return; }
|
||||
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE || !is_array($input)) {
|
||||
http_response_code(400); echo json_encode(['error' => 'Invalid JSON input']); return;
|
||||
}
|
||||
if (empty($input)) { http_response_code(400); echo json_encode(['error' => 'Missing update data']); return; }
|
||||
|
||||
// Validazione formato orario se presenti
|
||||
$timeRegex = '/^([01]\d|2[0-3]):([0-5]\d)(:([0-5]\d))?$/';
|
||||
if (isset($input['start_time']) && !preg_match($timeRegex, $input['start_time'])) {
|
||||
http_response_code(400); echo json_encode(['error' => 'Invalid start_time format.']); return;
|
||||
}
|
||||
if (isset($input['end_time']) && !preg_match($timeRegex, $input['end_time'])) {
|
||||
http_response_code(400); echo json_encode(['error' => 'Invalid end_time format.']); return;
|
||||
}
|
||||
// Validazione logica orari se entrambi presenti
|
||||
$startTime = $input['start_time'] ?? null;
|
||||
$endTime = $input['end_time'] ?? null;
|
||||
if ($startTime && $endTime && strtotime($endTime) <= strtotime($startTime)) {
|
||||
http_response_code(400); echo json_encode(['error' => 'End time must be after start time.']); return;
|
||||
}
|
||||
// Validazione con orari esistenti se solo uno viene fornito (più complessa, omessa per brevità)
|
||||
|
||||
|
||||
$dataToUpdate = [];
|
||||
$allowedFields = ['name', 'start_time', 'end_time', 'notes'];
|
||||
foreach ($allowedFields as $field) {
|
||||
if (array_key_exists($field, $input)) {
|
||||
$dataToUpdate[$field] = ($input[$field] === '') ? null : $input[$field];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($dataToUpdate)) { http_response_code(400); echo json_encode(['error' => 'No valid fields provided for update']); return; }
|
||||
|
||||
try {
|
||||
$existing = $this->db->fetchOne('SELECT 1 FROM shift_definitions WHERE id = ?', [$id]);
|
||||
if ($existing === false) { http_response_code(404); echo json_encode(['error' => "Shift definition with ID {$id} not found"]); return; }
|
||||
|
||||
$this->db->update('shift_definitions', $dataToUpdate, ['id' => $id]);
|
||||
$this->show(['id' => $id]);
|
||||
|
||||
} catch (UniqueConstraintViolationException $e) {
|
||||
http_response_code(409);
|
||||
error_log("Error updating shift definition {$id} (duplicate name?): " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to update shift definition. Name might already exist.']);
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error updating shift definition {$id}: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to update shift definition']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Elimina una definizione di turno.
|
||||
* DELETE /api/shift-definitions/{id}
|
||||
*/
|
||||
public function delete(array $vars): void
|
||||
{
|
||||
$id = $vars['id'] ?? null;
|
||||
if ($id === null) { http_response_code(400); echo json_encode(['error' => 'Missing shift definition ID']); return; }
|
||||
|
||||
try {
|
||||
// Aggiungere qui controlli se la definizione è usata in turni effettivi?
|
||||
|
||||
$existing = $this->db->fetchOne('SELECT 1 FROM shift_definitions WHERE id = ?', [$id]);
|
||||
if ($existing === false) { http_response_code(404); echo json_encode(['error' => "Shift definition with ID {$id} not found"]); return; }
|
||||
|
||||
$deletedRows = $this->db->delete('shift_definitions', ['id' => $id]);
|
||||
|
||||
if ($deletedRows > 0) {
|
||||
http_response_code(204); // No Content
|
||||
} else {
|
||||
http_response_code(500);
|
||||
error_log("Failed to delete shift definition {$id}, delete returned 0 rows affected.");
|
||||
echo json_encode(['error' => 'Failed to delete shift definition']);
|
||||
}
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
// Gestire ForeignKeyConstraintViolationException se la definizione è usata altrove
|
||||
http_response_code(500);
|
||||
error_log("Error deleting shift definition {$id}: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to delete shift definition. It might be in use.']);
|
||||
}
|
||||
}
|
||||
}
|
||||
251
backend/src/Controllers/StructureController.php
Normal file
251
backend/src/Controllers/StructureController.php
Normal file
@@ -0,0 +1,251 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Database;
|
||||
use Doctrine\DBAL\Connection;
|
||||
|
||||
class StructureController
|
||||
{
|
||||
private Connection $db;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
// Ottieni la connessione al database
|
||||
// In un'applicazione reale, useresti Dependency Injection
|
||||
try {
|
||||
$this->db = Database::getConnection();
|
||||
} catch (\Throwable $e) {
|
||||
// Gestisci l'errore di connessione iniziale se necessario
|
||||
error_log("Failed to get DB connection in StructureController: " . $e->getMessage());
|
||||
// Potresti voler lanciare un'eccezione o impostare uno stato di errore
|
||||
// Per ora, usciamo o lanciamo un errore HTTP 500 se la connessione fallisce qui
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Internal Server Error - DB Connection']);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mostra un elenco di strutture.
|
||||
* GET /api/structures
|
||||
*/
|
||||
public function index(): void
|
||||
{
|
||||
try {
|
||||
$queryBuilder = $this->db->createQueryBuilder();
|
||||
$structures = $queryBuilder
|
||||
->select('*')
|
||||
->from('structures')
|
||||
->orderBy('name', 'ASC') // Ordina per nome
|
||||
->fetchAllAssociative(); // Recupera tutti i risultati come array associativi
|
||||
|
||||
echo json_encode($structures);
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error fetching structures: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to fetch structures']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mostra una struttura specifica.
|
||||
* GET /api/structures/{id}
|
||||
* @param array $vars Variabili dalla route (es. ['id' => '1'])
|
||||
*/
|
||||
public function show(array $vars): void
|
||||
{
|
||||
$id = $vars['id'] ?? null;
|
||||
if ($id === null) {
|
||||
http_response_code(400); // Bad Request
|
||||
echo json_encode(['error' => 'Missing structure ID']);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Usa fetchAssociative per recuperare una singola riga
|
||||
$structure = $this->db->fetchAssociative('SELECT * FROM structures WHERE id = ?', [$id]);
|
||||
|
||||
if ($structure === false) {
|
||||
// Nessuna struttura trovata con quell'ID
|
||||
http_response_code(404); // Not Found
|
||||
echo json_encode(['error' => "Structure with ID {$id} not found"]);
|
||||
} else {
|
||||
// Struttura trovata, restituiscila
|
||||
echo json_encode($structure);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error fetching structure {$id}: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to fetch structure']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Crea una nuova struttura.
|
||||
* POST /api/structures
|
||||
*/
|
||||
public function store(): void
|
||||
{
|
||||
// Prova a leggere da php://input (per application/json)
|
||||
$inputJson = file_get_contents('php://input');
|
||||
$input = $inputJson ? (array) json_decode($inputJson, true) : [];
|
||||
|
||||
// Se php://input è vuoto o non è JSON valido, prova a leggere da $_POST (per form-data)
|
||||
if (empty($input) && !empty($_POST)) {
|
||||
$input = $_POST;
|
||||
}
|
||||
|
||||
// Validazione semplice (solo il nome è obbligatorio per ora)
|
||||
if (empty($input['name'])) {
|
||||
http_response_code(400); // Bad Request
|
||||
echo json_encode(['error' => 'Missing required field: name']);
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepara i dati per l'inserimento (includi solo i campi validi per la tabella)
|
||||
$dataToInsert = [
|
||||
'name' => $input['name'],
|
||||
'address' => $input['address'] ?? null,
|
||||
'city' => $input['city'] ?? null,
|
||||
'province' => $input['province'] ?? null,
|
||||
'zip_code' => $input['zip_code'] ?? null,
|
||||
'phone' => $input['phone'] ?? null,
|
||||
'email' => $input['email'] ?? null,
|
||||
'notes' => $input['notes'] ?? null,
|
||||
// created_at e updated_at sono gestiti dal DB
|
||||
];
|
||||
|
||||
try {
|
||||
$result = $this->db->insert('structures', $dataToInsert);
|
||||
|
||||
if ($result === false || $result === 0) {
|
||||
// Doctrine DBAL < 3.3 restituisce false, >= 3.3 restituisce 0 in caso di fallimento senza eccezione
|
||||
throw new \Exception("Failed to insert structure, insert returned non-true value.");
|
||||
}
|
||||
|
||||
$newId = $this->db->lastInsertId();
|
||||
http_response_code(201); // Created
|
||||
// Recupera e restituisci la risorsa appena creata
|
||||
$newStructure = $this->db->fetchAssociative('SELECT * FROM structures WHERE id = ?', [$newId]);
|
||||
echo json_encode($newStructure);
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error creating structure: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to create structure']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggiorna una struttura esistente.
|
||||
* PUT /api/structures/{id}
|
||||
* @param array $vars Variabili dalla route (es. ['id' => '1'])
|
||||
*/
|
||||
public function update(array $vars): void
|
||||
{
|
||||
$id = $vars['id'] ?? null;
|
||||
if ($id === null) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Missing structure ID']);
|
||||
return;
|
||||
}
|
||||
|
||||
// Leggi i dati (prova JSON e poi POST/form-urlencoded)
|
||||
$inputJson = file_get_contents('php://input');
|
||||
$input = $inputJson ? (array) json_decode($inputJson, true) : [];
|
||||
// Per PUT con form-urlencoded, php://input contiene la stringa query
|
||||
if (empty($input) && $inputJson && $_SERVER['CONTENT_TYPE'] === 'application/x-www-form-urlencoded') {
|
||||
parse_str($inputJson, $input);
|
||||
}
|
||||
|
||||
if (empty($input)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Missing update data']);
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepara i dati per l'aggiornamento (solo i campi validi e presenti nell'input)
|
||||
$dataToUpdate = [];
|
||||
$allowedFields = ['name', 'address', 'city', 'province', 'zip_code', 'phone', 'email', 'notes'];
|
||||
foreach ($allowedFields as $field) {
|
||||
if (array_key_exists($field, $input)) {
|
||||
// Potresti aggiungere qui ulteriore validazione per tipo/formato
|
||||
$dataToUpdate[$field] = $input[$field];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($dataToUpdate)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'No valid fields provided for update']);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Verifica prima se la risorsa esiste
|
||||
$existing = $this->db->fetchOne('SELECT 1 FROM structures WHERE id = ?', [$id]);
|
||||
if ($existing === false) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => "Structure with ID {$id} not found"]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Esegui l'aggiornamento
|
||||
$this->db->update('structures', $dataToUpdate, ['id' => $id]);
|
||||
|
||||
// Recupera e restituisci la risorsa aggiornata
|
||||
$updatedStructure = $this->db->fetchAssociative('SELECT * FROM structures WHERE id = ?', [$id]);
|
||||
echo json_encode($updatedStructure);
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error updating structure {$id}: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to update structure']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Elimina una struttura.
|
||||
* DELETE /api/structures/{id}
|
||||
* @param array $vars Variabili dalla route (es. ['id' => '1'])
|
||||
*/
|
||||
public function delete(array $vars): void
|
||||
{
|
||||
$id = $vars['id'] ?? null;
|
||||
if ($id === null) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Missing structure ID']);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Verifica prima se la risorsa esiste
|
||||
$existing = $this->db->fetchOne('SELECT 1 FROM structures WHERE id = ?', [$id]);
|
||||
if ($existing === false) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => "Structure with ID {$id} not found"]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Esegui l'eliminazione
|
||||
$deletedRows = $this->db->delete('structures', ['id' => $id]);
|
||||
|
||||
if ($deletedRows > 0) {
|
||||
http_response_code(204); // No Content - Successo
|
||||
// Non c'è corpo della risposta per 204
|
||||
} else {
|
||||
// Questo non dovrebbe accadere se la verifica precedente ha funzionato
|
||||
http_response_code(500);
|
||||
error_log("Failed to delete structure {$id}, delete returned 0 rows affected.");
|
||||
echo json_encode(['error' => 'Failed to delete structure']);
|
||||
}
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error deleting structure {$id}: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to delete structure']);
|
||||
}
|
||||
}
|
||||
}
|
||||
269
backend/src/Controllers/TeacherContractController.php
Normal file
269
backend/src/Controllers/TeacherContractController.php
Normal file
@@ -0,0 +1,269 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Database;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
|
||||
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
||||
|
||||
class TeacherContractController
|
||||
{
|
||||
private Connection $db;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
try {
|
||||
$this->db = Database::getConnection();
|
||||
} catch (\Throwable $e) {
|
||||
error_log("Failed to get DB connection in TeacherContractController: " . $e->getMessage());
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Internal Server Error - DB Connection']);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mostra un elenco di contratti con nomi associati.
|
||||
* GET /api/teacher-contracts
|
||||
* Accetta query params: teacher_id, school_year_id, structure_id
|
||||
*/
|
||||
public function index(): void
|
||||
{
|
||||
try {
|
||||
$queryBuilder = $this->db->createQueryBuilder()
|
||||
->select(
|
||||
'tc.id', 'tc.teacher_id', 'tc.school_year_id', 'tc.structure_id',
|
||||
'tc.contract_type', 'tc.start_date', 'tc.end_date', 'tc.weekly_hours', 'tc.salary',
|
||||
't.first_name AS teacher_first_name', 't.last_name AS teacher_last_name',
|
||||
'sy.name AS school_year_name',
|
||||
's.name AS structure_name'
|
||||
)
|
||||
->from('teacher_contracts', 'tc')
|
||||
->leftJoin('tc', 'teachers', 't', 'tc.teacher_id = t.id')
|
||||
->leftJoin('tc', 'school_years', 'sy', 'tc.school_year_id = sy.id')
|
||||
->leftJoin('tc', 'structures', 's', 'tc.structure_id = s.id')
|
||||
->orderBy('tc.start_date', 'DESC');
|
||||
|
||||
// Filtri opzionali
|
||||
if (!empty($_GET['teacher_id'])) {
|
||||
$queryBuilder->andWhere('tc.teacher_id = :teacherId')
|
||||
->setParameter('teacherId', $_GET['teacher_id']);
|
||||
}
|
||||
if (!empty($_GET['school_year_id'])) {
|
||||
$queryBuilder->andWhere('tc.school_year_id = :schoolYearId')
|
||||
->setParameter('schoolYearId', $_GET['school_year_id']);
|
||||
}
|
||||
if (!empty($_GET['structure_id'])) {
|
||||
$queryBuilder->andWhere('tc.structure_id = :structureId')
|
||||
->setParameter('structureId', $_GET['structure_id']);
|
||||
}
|
||||
|
||||
$contracts = $queryBuilder->fetchAllAssociative();
|
||||
|
||||
echo json_encode($contracts);
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error fetching teacher contracts: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to fetch teacher contracts']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mostra un contratto specifico con nomi associati.
|
||||
* GET /api/teacher-contracts/{id}
|
||||
*/
|
||||
public function show(array $vars): void
|
||||
{
|
||||
$id = $vars['id'] ?? null;
|
||||
if ($id === null) {
|
||||
http_response_code(400); echo json_encode(['error' => 'Missing contract ID']); return;
|
||||
}
|
||||
|
||||
try {
|
||||
$queryBuilder = $this->db->createQueryBuilder()
|
||||
->select(
|
||||
'tc.*',
|
||||
't.first_name AS teacher_first_name', 't.last_name AS teacher_last_name',
|
||||
'sy.name AS school_year_name',
|
||||
's.name AS structure_name'
|
||||
)
|
||||
->from('teacher_contracts', 'tc')
|
||||
->leftJoin('tc', 'teachers', 't', 'tc.teacher_id = t.id')
|
||||
->leftJoin('tc', 'school_years', 'sy', 'tc.school_year_id = sy.id')
|
||||
->leftJoin('tc', 'structures', 's', 'tc.structure_id = s.id')
|
||||
->where('tc.id = :id')
|
||||
->setParameter('id', $id);
|
||||
|
||||
$contract = $queryBuilder->fetchAssociative();
|
||||
|
||||
if ($contract === false) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => "Teacher contract with ID {$id} not found"]);
|
||||
} else {
|
||||
echo json_encode($contract);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error fetching teacher contract {$id}: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to fetch teacher contract']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Crea un nuovo contratto.
|
||||
* POST /api/teacher-contracts
|
||||
*/
|
||||
public function store(): void
|
||||
{
|
||||
// Leggi il corpo JSON della richiesta
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
// Verifica se il JSON è valido e se è un array
|
||||
if (json_last_error() !== JSON_ERROR_NONE || !is_array($input)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Invalid JSON input']);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validazione campi obbligatori
|
||||
if (empty($input['teacher_id']) || empty($input['school_year_id']) || empty($input['start_date'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Missing required fields: teacher_id, school_year_id, start_date']);
|
||||
return;
|
||||
}
|
||||
// Validazione date rimossa - affidata a frontend/DB constraint
|
||||
error_log(json_encode($input));
|
||||
$dataToInsert = [
|
||||
'teacher_id' => $input['teacher_id'],
|
||||
'school_year_id' => $input['school_year_id'],
|
||||
'structure_id' => (isset($input['structure_id']) && $input['structure_id'] !== '' && $input['structure_id'] !== null) ? (int)$input['structure_id'] : null,
|
||||
'contract_type' => $input['contract_type'] ?? null,
|
||||
'start_date' => $input['start_date'],
|
||||
'end_date' => (isset($input['end_date']) && $input['end_date'] !== '') ? $input['end_date'] : null, // Forza null se vuoto/non presente
|
||||
'weekly_hours' => (isset($input['weekly_hours']) && $input['weekly_hours'] !== '') ? (float)$input['weekly_hours'] : null, // Forza null se vuoto/non presente
|
||||
'salary' => (isset($input['salary']) && $input['salary'] !== '') ? (float)$input['salary'] : null, // Forza null se vuoto/non presente
|
||||
'notes' => $input['notes'] ?? null,
|
||||
];
|
||||
|
||||
try {
|
||||
$result = $this->db->insert('teacher_contracts', $dataToInsert);
|
||||
|
||||
if ($result === false || $result === 0) { throw new \Exception("Failed to insert teacher contract."); }
|
||||
|
||||
$newId = $this->db->lastInsertId();
|
||||
http_response_code(201);
|
||||
$this->show(['id' => $newId]); // Mostra il contratto appena creato
|
||||
|
||||
} catch (UniqueConstraintViolationException $e) {
|
||||
http_response_code(409);
|
||||
error_log("Error creating teacher contract (duplicate teacher/year?): " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to create contract. A contract for this teacher and school year might already exist.']);
|
||||
} catch (ForeignKeyConstraintViolationException $e) {
|
||||
http_response_code(400);
|
||||
error_log("Error creating teacher contract (invalid teacher/year/structure ID?): " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Invalid teacher, school year, or structure ID provided.']);
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error creating teacher contract: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to create teacher contract']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggiorna un contratto esistente.
|
||||
* PUT /api/teacher-contracts/{id}
|
||||
*/
|
||||
public function update(array $vars): void
|
||||
{
|
||||
$id = $vars['id'] ?? null;
|
||||
if ($id === null) { http_response_code(400); echo json_encode(['error' => 'Missing contract ID']); return; }
|
||||
|
||||
// Leggi il corpo JSON della richiesta
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE || !is_array($input)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Invalid JSON input']);
|
||||
return;
|
||||
}
|
||||
if (empty($input)) { http_response_code(400); echo json_encode(['error' => 'Missing update data']); return; }
|
||||
|
||||
|
||||
$dataToUpdate = [];
|
||||
$allowedFields = ['teacher_id', 'school_year_id', 'structure_id', 'contract_type', 'start_date', 'end_date', 'weekly_hours', 'salary', 'notes'];
|
||||
foreach ($allowedFields as $field) {
|
||||
if (array_key_exists($field, $input)) {
|
||||
$value = $input[$field];
|
||||
// Gestione specifica per i campi che possono essere NULL
|
||||
if (in_array($field, ['structure_id', 'end_date', 'weekly_hours', 'salary', 'notes'])) {
|
||||
if ($value === '' || $value === null) {
|
||||
$dataToUpdate[$field] = null;
|
||||
} elseif ($field === 'structure_id') {
|
||||
$dataToUpdate[$field] = (int)$value; // Cast a int se non null/vuoto
|
||||
} elseif ($field === 'weekly_hours' || $field === 'salary') {
|
||||
$dataToUpdate[$field] = (float)$value; // Cast a float se non null/vuoto
|
||||
} else {
|
||||
$dataToUpdate[$field] = $value; // Per end_date, contract_type, notes
|
||||
}
|
||||
} else { // Campi obbligatori (teacher_id, school_year_id, start_date)
|
||||
$dataToUpdate[$field] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($dataToUpdate)) { http_response_code(400); echo json_encode(['error' => 'No valid fields provided for update']); return; }
|
||||
|
||||
try {
|
||||
$existing = $this->db->fetchOne('SELECT 1 FROM teacher_contracts WHERE id = ?', [$id]);
|
||||
if ($existing === false) { http_response_code(404); echo json_encode(['error' => "Contract with ID {$id} not found"]); return; }
|
||||
|
||||
$this->db->update('teacher_contracts', $dataToUpdate, ['id' => $id]);
|
||||
|
||||
$this->show(['id' => $id]); // Mostra il contratto aggiornato
|
||||
|
||||
} catch (UniqueConstraintViolationException $e) {
|
||||
http_response_code(409);
|
||||
error_log("Error updating teacher contract {$id} (duplicate teacher/year?): " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to update contract. A contract for this teacher and school year might already exist.']);
|
||||
} catch (ForeignKeyConstraintViolationException $e) {
|
||||
http_response_code(400);
|
||||
error_log("Error updating teacher contract {$id} (invalid teacher/year/structure ID?): " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Invalid teacher, school year, or structure ID provided.']);
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error updating teacher contract {$id}: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to update teacher contract']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Elimina un contratto.
|
||||
* DELETE /api/teacher-contracts/{id}
|
||||
*/
|
||||
public function delete(array $vars): void
|
||||
{
|
||||
$id = $vars['id'] ?? null;
|
||||
if ($id === null) { http_response_code(400); echo json_encode(['error' => 'Missing contract ID']); return; }
|
||||
|
||||
try {
|
||||
$existing = $this->db->fetchOne('SELECT 1 FROM teacher_contracts WHERE id = ?', [$id]);
|
||||
if ($existing === false) { http_response_code(404); echo json_encode(['error' => "Contract with ID {$id} not found"]); return; }
|
||||
|
||||
$deletedRows = $this->db->delete('teacher_contracts', ['id' => $id]);
|
||||
|
||||
if ($deletedRows > 0) {
|
||||
http_response_code(204); // No Content
|
||||
} else {
|
||||
http_response_code(500);
|
||||
error_log("Failed to delete teacher contract {$id}, delete returned 0 rows affected.");
|
||||
echo json_encode(['error' => 'Failed to delete teacher contract']);
|
||||
}
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error deleting teacher contract {$id}: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to delete teacher contract']);
|
||||
}
|
||||
}
|
||||
}
|
||||
236
backend/src/Controllers/TeacherController.php
Normal file
236
backend/src/Controllers/TeacherController.php
Normal file
@@ -0,0 +1,236 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Database;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
||||
|
||||
class TeacherController
|
||||
{
|
||||
private Connection $db;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
try {
|
||||
$this->db = Database::getConnection();
|
||||
} catch (\Throwable $e) {
|
||||
error_log("Failed to get DB connection in TeacherController: " . $e->getMessage());
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Internal Server Error - DB Connection']);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mostra un elenco di insegnanti.
|
||||
* GET /api/teachers
|
||||
*/
|
||||
public function index(): void
|
||||
{
|
||||
try {
|
||||
$queryBuilder = $this->db->createQueryBuilder();
|
||||
$teachers = $queryBuilder
|
||||
->select('id', 'first_name', 'last_name', 'email', 'phone', 'is_active') // Seleziona solo alcuni campi per la lista
|
||||
->from('teachers')
|
||||
->orderBy('last_name', 'ASC')
|
||||
->addOrderBy('first_name', 'ASC')
|
||||
->fetchAllAssociative();
|
||||
|
||||
echo json_encode($teachers);
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error fetching teachers: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to fetch teachers']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mostra un insegnante specifico.
|
||||
* GET /api/teachers/{id}
|
||||
*/
|
||||
public function show(array $vars): void
|
||||
{
|
||||
$id = $vars['id'] ?? null;
|
||||
if ($id === null) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Missing teacher ID']);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$teacher = $this->db->fetchAssociative('SELECT * FROM teachers WHERE id = ?', [$id]);
|
||||
|
||||
if ($teacher === false) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => "Teacher with ID {$id} not found"]);
|
||||
} else {
|
||||
echo json_encode($teacher);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error fetching teacher {$id}: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to fetch teacher']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Crea un nuovo insegnante.
|
||||
* POST /api/teachers
|
||||
*/
|
||||
public function store(): void
|
||||
{
|
||||
$input = (array) json_decode(file_get_contents('php://input'), true);
|
||||
if (empty($input) && !empty($_POST)) { $input = $_POST; }
|
||||
|
||||
// Validazione di base
|
||||
if (empty($input['first_name']) || empty($input['last_name'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Missing required fields: first_name, last_name']);
|
||||
return;
|
||||
}
|
||||
|
||||
$dataToInsert = [
|
||||
'first_name' => $input['first_name'],
|
||||
'last_name' => $input['last_name'],
|
||||
'email' => $input['email'] ?? null,
|
||||
'phone' => $input['phone'] ?? null,
|
||||
'date_of_birth' => !empty($input['date_of_birth']) ? $input['date_of_birth'] : null,
|
||||
'hire_date' => !empty($input['hire_date']) ? $input['hire_date'] : null,
|
||||
'qualifications' => $input['qualifications'] ?? null,
|
||||
'is_active' => isset($input['is_active']) ? (bool)$input['is_active'] : true,
|
||||
];
|
||||
|
||||
try {
|
||||
$result = $this->db->insert('teachers', $dataToInsert);
|
||||
|
||||
if ($result === false || $result === 0) {
|
||||
throw new \Exception("Failed to insert teacher, insert returned non-true value.");
|
||||
}
|
||||
|
||||
$newId = $this->db->lastInsertId();
|
||||
http_response_code(201);
|
||||
$newTeacher = $this->db->fetchAssociative('SELECT * FROM teachers WHERE id = ?', [$newId]);
|
||||
echo json_encode($newTeacher);
|
||||
|
||||
} catch (UniqueConstraintViolationException $e) {
|
||||
http_response_code(409); // Conflict
|
||||
error_log("Error creating teacher (duplicate email?): " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to create teacher. Email might already exist.']);
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error creating teacher: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to create teacher']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggiorna un insegnante esistente.
|
||||
* PUT /api/teachers/{id}
|
||||
*/
|
||||
public function update(array $vars): void
|
||||
{
|
||||
$id = $vars['id'] ?? null;
|
||||
if ($id === null) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Missing teacher ID']);
|
||||
return;
|
||||
}
|
||||
|
||||
$inputJson = file_get_contents('php://input');
|
||||
$input = $inputJson ? (array) json_decode($inputJson, true) : [];
|
||||
if (empty($input) && $inputJson && ($_SERVER['CONTENT_TYPE'] ?? '') === 'application/x-www-form-urlencoded') {
|
||||
parse_str($inputJson, $input);
|
||||
}
|
||||
if (empty($input)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Missing update data']);
|
||||
return;
|
||||
}
|
||||
|
||||
$dataToUpdate = [];
|
||||
$allowedFields = ['first_name', 'last_name', 'email', 'phone', 'date_of_birth', 'hire_date', 'qualifications', 'is_active'];
|
||||
foreach ($allowedFields as $field) {
|
||||
if (array_key_exists($field, $input)) {
|
||||
// Gestione specifica per booleano e date nulle
|
||||
if ($field === 'is_active') {
|
||||
$dataToUpdate[$field] = (bool)$input[$field];
|
||||
} elseif (($field === 'date_of_birth' || $field === 'hire_date') && empty($input[$field])) {
|
||||
$dataToUpdate[$field] = null;
|
||||
} else {
|
||||
$dataToUpdate[$field] = $input[$field];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($dataToUpdate)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'No valid fields provided for update']);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$existing = $this->db->fetchOne('SELECT 1 FROM teachers WHERE id = ?', [$id]);
|
||||
if ($existing === false) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => "Teacher with ID {$id} not found"]);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->update('teachers', $dataToUpdate, ['id' => $id]);
|
||||
|
||||
$updatedTeacher = $this->db->fetchAssociative('SELECT * FROM teachers WHERE id = ?', [$id]);
|
||||
echo json_encode($updatedTeacher);
|
||||
|
||||
} catch (UniqueConstraintViolationException $e) {
|
||||
http_response_code(409); // Conflict
|
||||
error_log("Error updating teacher {$id} (duplicate email?): " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to update teacher. Email might already exist.']);
|
||||
} catch (\Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log("Error updating teacher {$id}: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to update teacher']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Elimina un insegnante.
|
||||
* DELETE /api/teachers/{id}
|
||||
*/
|
||||
public function delete(array $vars): void
|
||||
{
|
||||
$id = $vars['id'] ?? null;
|
||||
if ($id === null) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Missing teacher ID']);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$existing = $this->db->fetchOne('SELECT 1 FROM teachers WHERE id = ?', [$id]);
|
||||
if ($existing === false) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => "Teacher with ID {$id} not found"]);
|
||||
return;
|
||||
}
|
||||
|
||||
$deletedRows = $this->db->delete('teachers', ['id' => $id]);
|
||||
|
||||
if ($deletedRows > 0) {
|
||||
http_response_code(204); // No Content
|
||||
} else {
|
||||
http_response_code(500);
|
||||
error_log("Failed to delete teacher {$id}, delete returned 0 rows affected.");
|
||||
echo json_encode(['error' => 'Failed to delete teacher']);
|
||||
}
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
// Considera gestione Foreign Key Constraints se l'insegnante è referenziato altrove
|
||||
http_response_code(500);
|
||||
error_log("Error deleting teacher {$id}: " . $e->getMessage());
|
||||
echo json_encode(['error' => 'Failed to delete teacher']);
|
||||
}
|
||||
}
|
||||
}
|
||||
42
backend/src/Database.php
Normal file
42
backend/src/Database.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App;
|
||||
|
||||
use Doctrine\DBAL\Configuration;
|
||||
use Doctrine\DBAL\DriverManager;
|
||||
use Doctrine\DBAL\Connection;
|
||||
|
||||
class Database
|
||||
{
|
||||
private static ?Connection $connection = null;
|
||||
|
||||
/**
|
||||
* Ottiene l'istanza della connessione al database (Singleton).
|
||||
*
|
||||
* @return Connection
|
||||
* @throws \Doctrine\DBAL\Exception
|
||||
*/
|
||||
public static function getConnection(): Connection
|
||||
{
|
||||
if (self::$connection === null) {
|
||||
// Carica la configurazione dal file
|
||||
$connectionParams = require __DIR__ . '/../config/database.php';
|
||||
|
||||
// Crea la configurazione di Doctrine (opzionale, per ora vuota)
|
||||
$config = new Configuration();
|
||||
|
||||
// Crea la connessione
|
||||
self::$connection = DriverManager::getConnection($connectionParams, $config);
|
||||
}
|
||||
|
||||
return self::$connection;
|
||||
}
|
||||
|
||||
// Impedisce la clonazione dell'istanza
|
||||
private function __clone() {}
|
||||
|
||||
// Impedisce la deserializzazione dell'istanza
|
||||
public function __wakeup() {}
|
||||
}
|
||||
22
backend/vendor/autoload.php
vendored
Normal file
22
backend/vendor/autoload.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
// autoload.php @generated by Composer
|
||||
|
||||
if (PHP_VERSION_ID < 50600) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, $err);
|
||||
} elseif (!headers_sent()) {
|
||||
echo $err;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException($err);
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInit12c1165ec2a392b21c0fbfeb2574a7bb::getLoader();
|
||||
579
backend/vendor/composer/ClassLoader.php
vendored
Normal file
579
backend/vendor/composer/ClassLoader.php
vendored
Normal file
@@ -0,0 +1,579 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
/**
|
||||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||
*
|
||||
* $loader = new \Composer\Autoload\ClassLoader();
|
||||
*
|
||||
* // register classes with namespaces
|
||||
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||
* $loader->add('Symfony', __DIR__.'/framework');
|
||||
*
|
||||
* // activate the autoloader
|
||||
* $loader->register();
|
||||
*
|
||||
* // to enable searching the include path (eg. for PEAR packages)
|
||||
* $loader->setUseIncludePath(true);
|
||||
*
|
||||
* In this example, if you try to use a class in the Symfony\Component
|
||||
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||
* the autoloader will first look for the class under the component/
|
||||
* directory, and it will then fallback to the framework/ directory if not
|
||||
* found before giving up.
|
||||
*
|
||||
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @see https://www.php-fig.org/psr/psr-0/
|
||||
* @see https://www.php-fig.org/psr/psr-4/
|
||||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
/** @var \Closure(string):void */
|
||||
private static $includeFile;
|
||||
|
||||
/** @var string|null */
|
||||
private $vendorDir;
|
||||
|
||||
// PSR-4
|
||||
/**
|
||||
* @var array<string, array<string, int>>
|
||||
*/
|
||||
private $prefixLengthsPsr4 = array();
|
||||
/**
|
||||
* @var array<string, list<string>>
|
||||
*/
|
||||
private $prefixDirsPsr4 = array();
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
private $fallbackDirsPsr4 = array();
|
||||
|
||||
// PSR-0
|
||||
/**
|
||||
* List of PSR-0 prefixes
|
||||
*
|
||||
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
|
||||
*
|
||||
* @var array<string, array<string, list<string>>>
|
||||
*/
|
||||
private $prefixesPsr0 = array();
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
private $fallbackDirsPsr0 = array();
|
||||
|
||||
/** @var bool */
|
||||
private $useIncludePath = false;
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
private $classMap = array();
|
||||
|
||||
/** @var bool */
|
||||
private $classMapAuthoritative = false;
|
||||
|
||||
/**
|
||||
* @var array<string, bool>
|
||||
*/
|
||||
private $missingClasses = array();
|
||||
|
||||
/** @var string|null */
|
||||
private $apcuPrefix;
|
||||
|
||||
/**
|
||||
* @var array<string, self>
|
||||
*/
|
||||
private static $registeredLoaders = array();
|
||||
|
||||
/**
|
||||
* @param string|null $vendorDir
|
||||
*/
|
||||
public function __construct($vendorDir = null)
|
||||
{
|
||||
$this->vendorDir = $vendorDir;
|
||||
self::initializeIncludeClosure();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<string>>
|
||||
*/
|
||||
public function getPrefixes()
|
||||
{
|
||||
if (!empty($this->prefixesPsr0)) {
|
||||
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<string>>
|
||||
*/
|
||||
public function getPrefixesPsr4()
|
||||
{
|
||||
return $this->prefixDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
return $this->fallbackDirsPsr0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getFallbackDirsPsr4()
|
||||
{
|
||||
return $this->fallbackDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string> Array of classname => path
|
||||
*/
|
||||
public function getClassMap()
|
||||
{
|
||||
return $this->classMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $classMap Class to filename map
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addClassMap(array $classMap)
|
||||
{
|
||||
if ($this->classMap) {
|
||||
$this->classMap = array_merge($this->classMap, $classMap);
|
||||
} else {
|
||||
$this->classMap = $classMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix, either
|
||||
* appending or prepending to the ones previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param list<string>|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add($prefix, $paths, $prepend = false)
|
||||
{
|
||||
$paths = (array) $paths;
|
||||
if (!$prefix) {
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$paths,
|
||||
$this->fallbackDirsPsr0
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$this->fallbackDirsPsr0,
|
||||
$paths
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$first = $prefix[0];
|
||||
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||
$this->prefixesPsr0[$first][$prefix] = $paths;
|
||||
|
||||
return;
|
||||
}
|
||||
if ($prepend) {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$paths,
|
||||
$this->prefixesPsr0[$first][$prefix]
|
||||
);
|
||||
} else {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$this->prefixesPsr0[$first][$prefix],
|
||||
$paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace, either
|
||||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param list<string>|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
$paths = (array) $paths;
|
||||
if (!$prefix) {
|
||||
// Register directories for the root namespace.
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$paths,
|
||||
$this->fallbackDirsPsr4
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$this->fallbackDirsPsr4,
|
||||
$paths
|
||||
);
|
||||
}
|
||||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||
// Register directories for a new namespace.
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = $paths;
|
||||
} elseif ($prepend) {
|
||||
// Prepend directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$paths,
|
||||
$this->prefixDirsPsr4[$prefix]
|
||||
);
|
||||
} else {
|
||||
// Append directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$this->prefixDirsPsr4[$prefix],
|
||||
$paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix,
|
||||
* replacing any others previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param list<string>|string $paths The PSR-0 base directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr0 = (array) $paths;
|
||||
} else {
|
||||
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace,
|
||||
* replacing any others previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param list<string>|string $paths The PSR-4 base directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPsr4($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr4 = (array) $paths;
|
||||
} else {
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on searching the include path for class files.
|
||||
*
|
||||
* @param bool $useIncludePath
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUseIncludePath($useIncludePath)
|
||||
{
|
||||
$this->useIncludePath = $useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to check if the autoloader uses the include path to check
|
||||
* for classes.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getUseIncludePath()
|
||||
{
|
||||
return $this->useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns off searching the prefix and fallback directories for classes
|
||||
* that have not been registered with the class map.
|
||||
*
|
||||
* @param bool $classMapAuthoritative
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||
{
|
||||
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should class lookup fail if not found in the current class map?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isClassMapAuthoritative()
|
||||
{
|
||||
return $this->classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||
*
|
||||
* @param string|null $apcuPrefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setApcuPrefix($apcuPrefix)
|
||||
{
|
||||
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getApcuPrefix()
|
||||
{
|
||||
return $this->apcuPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param bool $prepend Whether to prepend the autoloader or not
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
|
||||
if (null === $this->vendorDir) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($prepend) {
|
||||
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||
} else {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
self::$registeredLoaders[$this->vendorDir] = $this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'loadClass'));
|
||||
|
||||
if (null !== $this->vendorDir) {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
* @return true|null True if loaded, null otherwise
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
$includeFile = self::$includeFile;
|
||||
$includeFile($file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the path to the file where the class is defined.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return string|false The path if found, false otherwise
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
// class map lookup
|
||||
if (isset($this->classMap[$class])) {
|
||||
return $this->classMap[$class];
|
||||
}
|
||||
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||
return false;
|
||||
}
|
||||
if (null !== $this->apcuPrefix) {
|
||||
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||
if ($hit) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
$file = $this->findFileWithExtension($class, '.php');
|
||||
|
||||
// Search for Hack files if we are running on HHVM
|
||||
if (false === $file && defined('HHVM_VERSION')) {
|
||||
$file = $this->findFileWithExtension($class, '.hh');
|
||||
}
|
||||
|
||||
if (null !== $this->apcuPrefix) {
|
||||
apcu_add($this->apcuPrefix.$class, $file);
|
||||
}
|
||||
|
||||
if (false === $file) {
|
||||
// Remember that this class does not exist.
|
||||
$this->missingClasses[$class] = true;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently registered loaders keyed by their corresponding vendor directories.
|
||||
*
|
||||
* @return array<string, self>
|
||||
*/
|
||||
public static function getRegisteredLoaders()
|
||||
{
|
||||
return self::$registeredLoaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string $ext
|
||||
* @return string|false
|
||||
*/
|
||||
private function findFileWithExtension($class, $ext)
|
||||
{
|
||||
// PSR-4 lookup
|
||||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||
|
||||
$first = $class[0];
|
||||
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||
$subPath = $class;
|
||||
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||
$subPath = substr($subPath, 0, $lastPos);
|
||||
$search = $subPath . '\\';
|
||||
if (isset($this->prefixDirsPsr4[$search])) {
|
||||
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||
if (file_exists($file = $dir . $pathEnd)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-4 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 lookup
|
||||
if (false !== $pos = strrpos($class, '\\')) {
|
||||
// namespaced class name
|
||||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||
} else {
|
||||
// PEAR-like class name
|
||||
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||
}
|
||||
|
||||
if (isset($this->prefixesPsr0[$first])) {
|
||||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 include paths.
|
||||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private static function initializeIncludeClosure()
|
||||
{
|
||||
if (self::$includeFile !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope isolated include.
|
||||
*
|
||||
* Prevents access to $this/self from included files.
|
||||
*
|
||||
* @param string $file
|
||||
* @return void
|
||||
*/
|
||||
self::$includeFile = \Closure::bind(static function($file) {
|
||||
include $file;
|
||||
}, null, null);
|
||||
}
|
||||
}
|
||||
396
backend/vendor/composer/InstalledVersions.php
vendored
Normal file
396
backend/vendor/composer/InstalledVersions.php
vendored
Normal file
@@ -0,0 +1,396 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer;
|
||||
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use Composer\Semver\VersionParser;
|
||||
|
||||
/**
|
||||
* This class is copied in every Composer installed project and available to all
|
||||
*
|
||||
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
||||
*
|
||||
* To require its presence, you can require `composer-runtime-api ^2.0`
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class InstalledVersions
|
||||
{
|
||||
/**
|
||||
* @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
|
||||
* @internal
|
||||
*/
|
||||
private static $selfDir = null;
|
||||
|
||||
/**
|
||||
* @var mixed[]|null
|
||||
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
|
||||
*/
|
||||
private static $installed;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private static $installedIsLocalDir;
|
||||
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
private static $canGetVendors;
|
||||
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
private static $installedByVendor = array();
|
||||
|
||||
/**
|
||||
* Returns a list of all package names which are present, either by being installed, replaced or provided
|
||||
*
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackages()
|
||||
{
|
||||
$packages = array();
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
$packages[] = array_keys($installed['versions']);
|
||||
}
|
||||
|
||||
if (1 === \count($packages)) {
|
||||
return $packages[0];
|
||||
}
|
||||
|
||||
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all package names with a specific type e.g. 'library'
|
||||
*
|
||||
* @param string $type
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackagesByType($type)
|
||||
{
|
||||
$packagesByType = array();
|
||||
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
foreach ($installed['versions'] as $name => $package) {
|
||||
if (isset($package['type']) && $package['type'] === $type) {
|
||||
$packagesByType[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $packagesByType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given package is installed
|
||||
*
|
||||
* This also returns true if the package name is provided or replaced by another package
|
||||
*
|
||||
* @param string $packageName
|
||||
* @param bool $includeDevRequirements
|
||||
* @return bool
|
||||
*/
|
||||
public static function isInstalled($packageName, $includeDevRequirements = true)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (isset($installed['versions'][$packageName])) {
|
||||
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given package satisfies a version constraint
|
||||
*
|
||||
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
|
||||
*
|
||||
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
|
||||
*
|
||||
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
|
||||
* @param string $packageName
|
||||
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
|
||||
* @return bool
|
||||
*/
|
||||
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
||||
{
|
||||
$constraint = $parser->parseConstraints((string) $constraint);
|
||||
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
|
||||
|
||||
return $provided->matches($constraint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a version constraint representing all the range(s) which are installed for a given package
|
||||
*
|
||||
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
|
||||
* whether a given version of a package is installed, and not just whether it exists
|
||||
*
|
||||
* @param string $packageName
|
||||
* @return string Version constraint usable with composer/semver
|
||||
*/
|
||||
public static function getVersionRanges($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$ranges = array();
|
||||
if (isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
|
||||
}
|
||||
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
|
||||
}
|
||||
if (array_key_exists('provided', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
|
||||
}
|
||||
|
||||
return implode(' || ', $ranges);
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||
*/
|
||||
public static function getVersion($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['version'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||
*/
|
||||
public static function getPrettyVersion($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
|
||||
*/
|
||||
public static function getReference($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['reference'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['reference'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
|
||||
*/
|
||||
public static function getInstallPath($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
|
||||
*/
|
||||
public static function getRootPackage()
|
||||
{
|
||||
$installed = self::getInstalled();
|
||||
|
||||
return $installed[0]['root'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw installed.php data for custom implementations
|
||||
*
|
||||
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
|
||||
* @return array[]
|
||||
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
|
||||
*/
|
||||
public static function getRawData()
|
||||
{
|
||||
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
|
||||
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||
self::$installed = include __DIR__ . '/installed.php';
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
|
||||
return self::$installed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
||||
*
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
public static function getAllRawData()
|
||||
{
|
||||
return self::getInstalled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lets you reload the static array from another file
|
||||
*
|
||||
* This is only useful for complex integrations in which a project needs to use
|
||||
* this class but then also needs to execute another project's autoloader in process,
|
||||
* and wants to ensure both projects have access to their version of installed.php.
|
||||
*
|
||||
* A typical case would be PHPUnit, where it would need to make sure it reads all
|
||||
* the data it needs from this class, then call reload() with
|
||||
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
|
||||
* the project in which it runs can then also use this class safely, without
|
||||
* interference between PHPUnit's dependencies and the project's dependencies.
|
||||
*
|
||||
* @param array[] $data A vendor/composer/installed.php data set
|
||||
* @return void
|
||||
*
|
||||
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
|
||||
*/
|
||||
public static function reload($data)
|
||||
{
|
||||
self::$installed = $data;
|
||||
self::$installedByVendor = array();
|
||||
|
||||
// when using reload, we disable the duplicate protection to ensure that self::$installed data is
|
||||
// always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
|
||||
// so we have to assume it does not, and that may result in duplicate data being returned when listing
|
||||
// all installed packages for example
|
||||
self::$installedIsLocalDir = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private static function getSelfDir()
|
||||
{
|
||||
if (self::$selfDir === null) {
|
||||
self::$selfDir = strtr(__DIR__, '\\', '/');
|
||||
}
|
||||
|
||||
return self::$selfDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
private static function getInstalled()
|
||||
{
|
||||
if (null === self::$canGetVendors) {
|
||||
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
|
||||
}
|
||||
|
||||
$installed = array();
|
||||
$copiedLocalDir = false;
|
||||
|
||||
if (self::$canGetVendors) {
|
||||
$selfDir = self::getSelfDir();
|
||||
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||
$vendorDir = strtr($vendorDir, '\\', '/');
|
||||
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||
$installed[] = self::$installedByVendor[$vendorDir];
|
||||
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||
$required = require $vendorDir.'/composer/installed.php';
|
||||
self::$installedByVendor[$vendorDir] = $required;
|
||||
$installed[] = $required;
|
||||
if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
|
||||
self::$installed = $required;
|
||||
self::$installedIsLocalDir = true;
|
||||
}
|
||||
}
|
||||
if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
|
||||
$copiedLocalDir = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||
$required = require __DIR__ . '/installed.php';
|
||||
self::$installed = $required;
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
|
||||
if (self::$installed !== array() && !$copiedLocalDir) {
|
||||
$installed[] = self::$installed;
|
||||
}
|
||||
|
||||
return $installed;
|
||||
}
|
||||
}
|
||||
21
backend/vendor/composer/LICENSE
vendored
Normal file
21
backend/vendor/composer/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
Copyright (c) Nils Adermann, Jordi Boggiano
|
||||
|
||||
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.
|
||||
|
||||
15
backend/vendor/composer/autoload_classmap.php
vendored
Normal file
15
backend/vendor/composer/autoload_classmap.php
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
// autoload_classmap.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
|
||||
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||
'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
|
||||
'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
|
||||
'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
|
||||
'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
|
||||
);
|
||||
13
backend/vendor/composer/autoload_files.php
vendored
Normal file
13
backend/vendor/composer/autoload_files.php
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
// autoload_files.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
|
||||
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
|
||||
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
|
||||
'253c157292f75eb38082b5acb06f3f01' => $vendorDir . '/nikic/fast-route/src/functions.php',
|
||||
);
|
||||
9
backend/vendor/composer/autoload_namespaces.php
vendored
Normal file
9
backend/vendor/composer/autoload_namespaces.php
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
// autoload_namespaces.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
);
|
||||
22
backend/vendor/composer/autoload_psr4.php
vendored
Normal file
22
backend/vendor/composer/autoload_psr4.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
// autoload_psr4.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
|
||||
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
|
||||
'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
|
||||
'Psr\\Log\\' => array($vendorDir . '/psr/log/src'),
|
||||
'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'),
|
||||
'PhpOption\\' => array($vendorDir . '/phpoption/phpoption/src/PhpOption'),
|
||||
'GrahamCampbell\\ResultType\\' => array($vendorDir . '/graham-campbell/result-type/src'),
|
||||
'Firebase\\JWT\\' => array($vendorDir . '/firebase/php-jwt/src'),
|
||||
'FastRoute\\' => array($vendorDir . '/nikic/fast-route/src'),
|
||||
'Dotenv\\' => array($vendorDir . '/vlucas/phpdotenv/src'),
|
||||
'Doctrine\\Deprecations\\' => array($vendorDir . '/doctrine/deprecations/src'),
|
||||
'Doctrine\\DBAL\\' => array($vendorDir . '/doctrine/dbal/src'),
|
||||
'App\\' => array($baseDir . '/src'),
|
||||
);
|
||||
50
backend/vendor/composer/autoload_real.php
vendored
Normal file
50
backend/vendor/composer/autoload_real.php
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInit12c1165ec2a392b21c0fbfeb2574a7bb
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
public static function loadClassLoader($class)
|
||||
{
|
||||
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||
require __DIR__ . '/ClassLoader.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Composer\Autoload\ClassLoader
|
||||
*/
|
||||
public static function getLoader()
|
||||
{
|
||||
if (null !== self::$loader) {
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
require __DIR__ . '/platform_check.php';
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInit12c1165ec2a392b21c0fbfeb2574a7bb', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit12c1165ec2a392b21c0fbfeb2574a7bb', 'loadClassLoader'));
|
||||
|
||||
require __DIR__ . '/autoload_static.php';
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInit12c1165ec2a392b21c0fbfeb2574a7bb::getInitializer($loader));
|
||||
|
||||
$loader->register(true);
|
||||
|
||||
$filesToLoad = \Composer\Autoload\ComposerStaticInit12c1165ec2a392b21c0fbfeb2574a7bb::$files;
|
||||
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
|
||||
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||
|
||||
require $file;
|
||||
}
|
||||
}, null, null);
|
||||
foreach ($filesToLoad as $fileIdentifier => $file) {
|
||||
$requireFile($fileIdentifier, $file);
|
||||
}
|
||||
|
||||
return $loader;
|
||||
}
|
||||
}
|
||||
123
backend/vendor/composer/autoload_static.php
vendored
Normal file
123
backend/vendor/composer/autoload_static.php
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
// autoload_static.php @generated by Composer
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInit12c1165ec2a392b21c0fbfeb2574a7bb
|
||||
{
|
||||
public static $files = array (
|
||||
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
|
||||
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
|
||||
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
|
||||
'253c157292f75eb38082b5acb06f3f01' => __DIR__ . '/..' . '/nikic/fast-route/src/functions.php',
|
||||
);
|
||||
|
||||
public static $prefixLengthsPsr4 = array (
|
||||
'S' =>
|
||||
array (
|
||||
'Symfony\\Polyfill\\Php80\\' => 23,
|
||||
'Symfony\\Polyfill\\Mbstring\\' => 26,
|
||||
'Symfony\\Polyfill\\Ctype\\' => 23,
|
||||
),
|
||||
'P' =>
|
||||
array (
|
||||
'Psr\\Log\\' => 8,
|
||||
'Psr\\Cache\\' => 10,
|
||||
'PhpOption\\' => 10,
|
||||
),
|
||||
'G' =>
|
||||
array (
|
||||
'GrahamCampbell\\ResultType\\' => 26,
|
||||
),
|
||||
'F' =>
|
||||
array (
|
||||
'Firebase\\JWT\\' => 13,
|
||||
'FastRoute\\' => 10,
|
||||
),
|
||||
'D' =>
|
||||
array (
|
||||
'Dotenv\\' => 7,
|
||||
'Doctrine\\Deprecations\\' => 22,
|
||||
'Doctrine\\DBAL\\' => 14,
|
||||
),
|
||||
'A' =>
|
||||
array (
|
||||
'App\\' => 4,
|
||||
),
|
||||
);
|
||||
|
||||
public static $prefixDirsPsr4 = array (
|
||||
'Symfony\\Polyfill\\Php80\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/symfony/polyfill-php80',
|
||||
),
|
||||
'Symfony\\Polyfill\\Mbstring\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
|
||||
),
|
||||
'Symfony\\Polyfill\\Ctype\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
|
||||
),
|
||||
'Psr\\Log\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/psr/log/src',
|
||||
),
|
||||
'Psr\\Cache\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/psr/cache/src',
|
||||
),
|
||||
'PhpOption\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/phpoption/phpoption/src/PhpOption',
|
||||
),
|
||||
'GrahamCampbell\\ResultType\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/graham-campbell/result-type/src',
|
||||
),
|
||||
'Firebase\\JWT\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/firebase/php-jwt/src',
|
||||
),
|
||||
'FastRoute\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/nikic/fast-route/src',
|
||||
),
|
||||
'Dotenv\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/vlucas/phpdotenv/src',
|
||||
),
|
||||
'Doctrine\\Deprecations\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/doctrine/deprecations/src',
|
||||
),
|
||||
'Doctrine\\DBAL\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/doctrine/dbal/src',
|
||||
),
|
||||
'App\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/../..' . '/src',
|
||||
),
|
||||
);
|
||||
|
||||
public static $classMap = array (
|
||||
'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
|
||||
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||
'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
|
||||
'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
|
||||
'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
|
||||
'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInit12c1165ec2a392b21c0fbfeb2574a7bb::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInit12c1165ec2a392b21c0fbfeb2574a7bb::$prefixDirsPsr4;
|
||||
$loader->classMap = ComposerStaticInit12c1165ec2a392b21c0fbfeb2574a7bb::$classMap;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
}
|
||||
868
backend/vendor/composer/installed.json
vendored
Normal file
868
backend/vendor/composer/installed.json
vendored
Normal file
@@ -0,0 +1,868 @@
|
||||
{
|
||||
"packages": [
|
||||
{
|
||||
"name": "doctrine/dbal",
|
||||
"version": "4.2.3",
|
||||
"version_normalized": "4.2.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/dbal.git",
|
||||
"reference": "33d2d7fe1269b2301640c44cf2896ea607b30e3e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/dbal/zipball/33d2d7fe1269b2301640c44cf2896ea607b30e3e",
|
||||
"reference": "33d2d7fe1269b2301640c44cf2896ea607b30e3e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/deprecations": "^0.5.3|^1",
|
||||
"php": "^8.1",
|
||||
"psr/cache": "^1|^2|^3",
|
||||
"psr/log": "^1|^2|^3"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "12.0.0",
|
||||
"fig/log-test": "^1",
|
||||
"jetbrains/phpstorm-stubs": "2023.2",
|
||||
"phpstan/phpstan": "2.1.1",
|
||||
"phpstan/phpstan-phpunit": "2.0.3",
|
||||
"phpstan/phpstan-strict-rules": "^2",
|
||||
"phpunit/phpunit": "10.5.39",
|
||||
"slevomat/coding-standard": "8.13.1",
|
||||
"squizlabs/php_codesniffer": "3.10.2",
|
||||
"symfony/cache": "^6.3.8|^7.0",
|
||||
"symfony/console": "^5.4|^6.3|^7.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/console": "For helpful console commands such as SQL execution and import of files."
|
||||
},
|
||||
"time": "2025-03-07T18:29:05+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\DBAL\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.",
|
||||
"homepage": "https://www.doctrine-project.org/projects/dbal.html",
|
||||
"keywords": [
|
||||
"abstraction",
|
||||
"database",
|
||||
"db2",
|
||||
"dbal",
|
||||
"mariadb",
|
||||
"mssql",
|
||||
"mysql",
|
||||
"oci8",
|
||||
"oracle",
|
||||
"pdo",
|
||||
"pgsql",
|
||||
"postgresql",
|
||||
"queryobject",
|
||||
"sasql",
|
||||
"sql",
|
||||
"sqlite",
|
||||
"sqlserver",
|
||||
"sqlsrv"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/dbal/issues",
|
||||
"source": "https://github.com/doctrine/dbal/tree/4.2.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.doctrine-project.org/sponsorship.html",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/phpdoctrine",
|
||||
"type": "patreon"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdbal",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"install-path": "../doctrine/dbal"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/deprecations",
|
||||
"version": "1.1.5",
|
||||
"version_normalized": "1.1.5.0",
|
||||
"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"
|
||||
},
|
||||
"time": "2025-04-07T20:06:18+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"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"
|
||||
},
|
||||
"install-path": "../doctrine/deprecations"
|
||||
},
|
||||
{
|
||||
"name": "firebase/php-jwt",
|
||||
"version": "v6.11.1",
|
||||
"version_normalized": "6.11.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/firebase/php-jwt.git",
|
||||
"reference": "d1e91ecf8c598d073d0995afa8cd5c75c6e19e66"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/firebase/php-jwt/zipball/d1e91ecf8c598d073d0995afa8cd5c75c6e19e66",
|
||||
"reference": "d1e91ecf8c598d073d0995afa8cd5c75c6e19e66",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"guzzlehttp/guzzle": "^7.4",
|
||||
"phpspec/prophecy-phpunit": "^2.0",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"psr/cache": "^2.0||^3.0",
|
||||
"psr/http-client": "^1.0",
|
||||
"psr/http-factory": "^1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-sodium": "Support EdDSA (Ed25519) signatures",
|
||||
"paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present"
|
||||
},
|
||||
"time": "2025-04-09T20:32:01+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Firebase\\JWT\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Neuman Vong",
|
||||
"email": "neuman+pear@twilio.com",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Anant Narayanan",
|
||||
"email": "anant@php.net",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.",
|
||||
"homepage": "https://github.com/firebase/php-jwt",
|
||||
"keywords": [
|
||||
"jwt",
|
||||
"php"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/firebase/php-jwt/issues",
|
||||
"source": "https://github.com/firebase/php-jwt/tree/v6.11.1"
|
||||
},
|
||||
"install-path": "../firebase/php-jwt"
|
||||
},
|
||||
{
|
||||
"name": "graham-campbell/result-type",
|
||||
"version": "v1.1.3",
|
||||
"version_normalized": "1.1.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/GrahamCampbell/Result-Type.git",
|
||||
"reference": "3ba905c11371512af9d9bdd27d99b782216b6945"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945",
|
||||
"reference": "3ba905c11371512af9d9bdd27d99b782216b6945",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2.5 || ^8.0",
|
||||
"phpoption/phpoption": "^1.9.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28"
|
||||
},
|
||||
"time": "2024-07-20T21:45:45+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"GrahamCampbell\\ResultType\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Graham Campbell",
|
||||
"email": "hello@gjcampbell.co.uk",
|
||||
"homepage": "https://github.com/GrahamCampbell"
|
||||
}
|
||||
],
|
||||
"description": "An Implementation Of The Result Type",
|
||||
"keywords": [
|
||||
"Graham Campbell",
|
||||
"GrahamCampbell",
|
||||
"Result Type",
|
||||
"Result-Type",
|
||||
"result"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/GrahamCampbell/Result-Type/issues",
|
||||
"source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/GrahamCampbell",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"install-path": "../graham-campbell/result-type"
|
||||
},
|
||||
{
|
||||
"name": "nikic/fast-route",
|
||||
"version": "v1.3.0",
|
||||
"version_normalized": "1.3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/FastRoute.git",
|
||||
"reference": "181d480e08d9476e61381e04a71b34dc0432e812"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812",
|
||||
"reference": "181d480e08d9476e61381e04a71b34dc0432e812",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8.35|~5.7"
|
||||
},
|
||||
"time": "2018-02-13T20:26:39+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/functions.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"FastRoute\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nikita Popov",
|
||||
"email": "nikic@php.net"
|
||||
}
|
||||
],
|
||||
"description": "Fast request router for PHP",
|
||||
"keywords": [
|
||||
"router",
|
||||
"routing"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/FastRoute/issues",
|
||||
"source": "https://github.com/nikic/FastRoute/tree/master"
|
||||
},
|
||||
"install-path": "../nikic/fast-route"
|
||||
},
|
||||
{
|
||||
"name": "phpoption/phpoption",
|
||||
"version": "1.9.3",
|
||||
"version_normalized": "1.9.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/schmittjoh/php-option.git",
|
||||
"reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54",
|
||||
"reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54",
|
||||
"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 || ^10.5.28"
|
||||
},
|
||||
"time": "2024-07-20T21:41:07+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"bamarni-bin": {
|
||||
"bin-links": true,
|
||||
"forward-command": false
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-master": "1.9-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"PhpOption\\": "src/PhpOption/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"Apache-2.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Johannes M. Schmitt",
|
||||
"email": "schmittjoh@gmail.com",
|
||||
"homepage": "https://github.com/schmittjoh"
|
||||
},
|
||||
{
|
||||
"name": "Graham Campbell",
|
||||
"email": "hello@gjcampbell.co.uk",
|
||||
"homepage": "https://github.com/GrahamCampbell"
|
||||
}
|
||||
],
|
||||
"description": "Option Type for PHP",
|
||||
"keywords": [
|
||||
"language",
|
||||
"option",
|
||||
"php",
|
||||
"type"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/schmittjoh/php-option/issues",
|
||||
"source": "https://github.com/schmittjoh/php-option/tree/1.9.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/GrahamCampbell",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"install-path": "../phpoption/phpoption"
|
||||
},
|
||||
{
|
||||
"name": "psr/cache",
|
||||
"version": "3.0.0",
|
||||
"version_normalized": "3.0.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"
|
||||
},
|
||||
"time": "2021-02-03T23:26:27+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"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"
|
||||
},
|
||||
"install-path": "../psr/cache"
|
||||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
"version": "3.0.2",
|
||||
"version_normalized": "3.0.2.0",
|
||||
"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"
|
||||
},
|
||||
"time": "2024-09-11T13:17:53+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.x-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"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"
|
||||
},
|
||||
"install-path": "../psr/log"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.31.0",
|
||||
"version_normalized": "1.31.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"provide": {
|
||||
"ext-ctype": "*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-ctype": "For best performance"
|
||||
},
|
||||
"time": "2024-09-09T11:45:10+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/polyfill",
|
||||
"name": "symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Ctype\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Gert de Pagter",
|
||||
"email": "BackEndTea@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for ctype functions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"ctype",
|
||||
"polyfill",
|
||||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.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"
|
||||
}
|
||||
],
|
||||
"install-path": "../symfony/polyfill-ctype"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.31.0",
|
||||
"version_normalized": "1.31.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
||||
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"provide": {
|
||||
"ext-mbstring": "*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mbstring": "For best performance"
|
||||
},
|
||||
"time": "2024-09-09T11:45:10+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/polyfill",
|
||||
"name": "symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Mbstring\\": ""
|
||||
}
|
||||
},
|
||||
"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 the Mbstring extension",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"mbstring",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.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"
|
||||
}
|
||||
],
|
||||
"install-path": "../symfony/polyfill-mbstring"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php80",
|
||||
"version": "v1.31.0",
|
||||
"version_normalized": "1.31.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php80.git",
|
||||
"reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
|
||||
"reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"time": "2024-09-09T11:45:10+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/polyfill",
|
||||
"name": "symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Php80\\": ""
|
||||
},
|
||||
"classmap": [
|
||||
"Resources/stubs"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Ion Bazan",
|
||||
"email": "ion.bazan@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.31.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"
|
||||
}
|
||||
],
|
||||
"install-path": "../symfony/polyfill-php80"
|
||||
},
|
||||
{
|
||||
"name": "vlucas/phpdotenv",
|
||||
"version": "v5.6.1",
|
||||
"version_normalized": "5.6.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vlucas/phpdotenv.git",
|
||||
"reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/a59a13791077fe3d44f90e7133eb68e7d22eaff2",
|
||||
"reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-pcre": "*",
|
||||
"graham-campbell/result-type": "^1.1.3",
|
||||
"php": "^7.2.5 || ^8.0",
|
||||
"phpoption/phpoption": "^1.9.3",
|
||||
"symfony/polyfill-ctype": "^1.24",
|
||||
"symfony/polyfill-mbstring": "^1.24",
|
||||
"symfony/polyfill-php80": "^1.24"
|
||||
},
|
||||
"require-dev": {
|
||||
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||
"ext-filter": "*",
|
||||
"phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-filter": "Required to use the boolean validator."
|
||||
},
|
||||
"time": "2024-07-20T21:52:34+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"bamarni-bin": {
|
||||
"bin-links": true,
|
||||
"forward-command": false
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-master": "5.6-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Dotenv\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Graham Campbell",
|
||||
"email": "hello@gjcampbell.co.uk",
|
||||
"homepage": "https://github.com/GrahamCampbell"
|
||||
},
|
||||
{
|
||||
"name": "Vance Lucas",
|
||||
"email": "vance@vancelucas.com",
|
||||
"homepage": "https://github.com/vlucas"
|
||||
}
|
||||
],
|
||||
"description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.",
|
||||
"keywords": [
|
||||
"dotenv",
|
||||
"env",
|
||||
"environment"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/vlucas/phpdotenv/issues",
|
||||
"source": "https://github.com/vlucas/phpdotenv/tree/v5.6.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/GrahamCampbell",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"install-path": "../vlucas/phpdotenv"
|
||||
}
|
||||
],
|
||||
"dev": true,
|
||||
"dev-package-names": []
|
||||
}
|
||||
131
backend/vendor/composer/installed.php
vendored
Normal file
131
backend/vendor/composer/installed.php
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
<?php return array(
|
||||
'root' => array(
|
||||
'name' => 'nidoai/backend',
|
||||
'pretty_version' => '1.0.0+no-version-set',
|
||||
'version' => '1.0.0.0',
|
||||
'reference' => null,
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'dev' => true,
|
||||
),
|
||||
'versions' => array(
|
||||
'doctrine/dbal' => array(
|
||||
'pretty_version' => '4.2.3',
|
||||
'version' => '4.2.3.0',
|
||||
'reference' => '33d2d7fe1269b2301640c44cf2896ea607b30e3e',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../doctrine/dbal',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'doctrine/deprecations' => array(
|
||||
'pretty_version' => '1.1.5',
|
||||
'version' => '1.1.5.0',
|
||||
'reference' => '459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../doctrine/deprecations',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'firebase/php-jwt' => array(
|
||||
'pretty_version' => 'v6.11.1',
|
||||
'version' => '6.11.1.0',
|
||||
'reference' => 'd1e91ecf8c598d073d0995afa8cd5c75c6e19e66',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../firebase/php-jwt',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'graham-campbell/result-type' => array(
|
||||
'pretty_version' => 'v1.1.3',
|
||||
'version' => '1.1.3.0',
|
||||
'reference' => '3ba905c11371512af9d9bdd27d99b782216b6945',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../graham-campbell/result-type',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'nidoai/backend' => array(
|
||||
'pretty_version' => '1.0.0+no-version-set',
|
||||
'version' => '1.0.0.0',
|
||||
'reference' => null,
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'nikic/fast-route' => array(
|
||||
'pretty_version' => 'v1.3.0',
|
||||
'version' => '1.3.0.0',
|
||||
'reference' => '181d480e08d9476e61381e04a71b34dc0432e812',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../nikic/fast-route',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'phpoption/phpoption' => array(
|
||||
'pretty_version' => '1.9.3',
|
||||
'version' => '1.9.3.0',
|
||||
'reference' => 'e3fac8b24f56113f7cb96af14958c0dd16330f54',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../phpoption/phpoption',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'psr/cache' => array(
|
||||
'pretty_version' => '3.0.0',
|
||||
'version' => '3.0.0.0',
|
||||
'reference' => 'aa5030cfa5405eccfdcb1083ce040c2cb8d253bf',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../psr/cache',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'psr/log' => array(
|
||||
'pretty_version' => '3.0.2',
|
||||
'version' => '3.0.2.0',
|
||||
'reference' => 'f16e1d5863e37f8d8c2a01719f5b34baa2b714d3',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../psr/log',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'symfony/polyfill-ctype' => array(
|
||||
'pretty_version' => 'v1.31.0',
|
||||
'version' => '1.31.0.0',
|
||||
'reference' => 'a3cc8b044a6ea513310cbd48ef7333b384945638',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'symfony/polyfill-mbstring' => array(
|
||||
'pretty_version' => 'v1.31.0',
|
||||
'version' => '1.31.0.0',
|
||||
'reference' => '85181ba99b2345b0ef10ce42ecac37612d9fd341',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'symfony/polyfill-php80' => array(
|
||||
'pretty_version' => 'v1.31.0',
|
||||
'version' => '1.31.0.0',
|
||||
'reference' => '60328e362d4c2c802a54fcbf04f9d3fb892b4cf8',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../symfony/polyfill-php80',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'vlucas/phpdotenv' => array(
|
||||
'pretty_version' => 'v5.6.1',
|
||||
'version' => '5.6.1.0',
|
||||
'reference' => 'a59a13791077fe3d44f90e7133eb68e7d22eaff2',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../vlucas/phpdotenv',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
),
|
||||
);
|
||||
26
backend/vendor/composer/platform_check.php
vendored
Normal file
26
backend/vendor/composer/platform_check.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
// platform_check.php @generated by Composer
|
||||
|
||||
$issues = array();
|
||||
|
||||
if (!(PHP_VERSION_ID >= 80100)) {
|
||||
$issues[] = 'Your Composer dependencies require a PHP version ">= 8.1.0". You are running ' . PHP_VERSION . '.';
|
||||
}
|
||||
|
||||
if ($issues) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
|
||||
} elseif (!headers_sent()) {
|
||||
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
6
backend/vendor/doctrine/dbal/CONTRIBUTING.md
vendored
Normal file
6
backend/vendor/doctrine/dbal/CONTRIBUTING.md
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
This repository has [guidelines specific to testing][testing guidelines], and
|
||||
Doctrine has [general contributing guidelines][contributor workflow], make
|
||||
sure you follow both.
|
||||
|
||||
[contributor workflow]: https://www.doctrine-project.org/contribute/index.html
|
||||
[testing guidelines]: https://www.doctrine-project.org/projects/doctrine-dbal/en/stable/reference/testing.html
|
||||
19
backend/vendor/doctrine/dbal/LICENSE
vendored
Normal file
19
backend/vendor/doctrine/dbal/LICENSE
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2006-2018 Doctrine Project
|
||||
|
||||
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.
|
||||
55
backend/vendor/doctrine/dbal/README.md
vendored
Normal file
55
backend/vendor/doctrine/dbal/README.md
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
# Doctrine DBAL
|
||||
|
||||
| [5.0-dev][5.0] | [4.3-dev][4.3] | [4.2][4.2] | [3.10][3.10] | [3.9][3.9] |
|
||||
|:---------------------------------------------------:|:---------------------------------------------------:|:---------------------------------------------------:|:-----------------------------------------------------:|:---------------------------------------------------:|
|
||||
| [![GitHub Actions][GA 5.0 image]][GA 5.0] | [![GitHub Actions][GA 4.3 image]][GA 4.3] | [![GitHub Actions][GA 4.2 image]][GA 4.2] | [![GitHub Actions][GA 3.10 image]][GA 3.10] | [![GitHub Actions][GA 3.9 image]][GA 3.9] |
|
||||
| [![AppVeyor][AppVeyor 5.0 image]][AppVeyor 5.0] | [![AppVeyor][AppVeyor 4.3 image]][AppVeyor 4.3] | [![AppVeyor][AppVeyor 4.2 image]][AppVeyor 4.2] | [![AppVeyor][AppVeyor 3.10 image]][AppVeyor 3.10] | [![AppVeyor][AppVeyor 3.9 image]][AppVeyor 3.9] |
|
||||
| [![Code Coverage][Coverage 5.0 image]][CodeCov 5.0] | [![Code Coverage][Coverage 4.3 image]][CodeCov 4.3] | [![Code Coverage][Coverage 4.2 image]][CodeCov 4.2] | [![Code Coverage][Coverage 3.10 image]][CodeCov 3.10] | [![Code Coverage][Coverage 3.9 image]][CodeCov 3.9] |
|
||||
|
||||
Powerful ***D***ata***B***ase ***A***bstraction ***L***ayer with many features for database schema introspection and schema management.
|
||||
|
||||
## More resources:
|
||||
|
||||
* [Website](http://www.doctrine-project.org/projects/dbal.html)
|
||||
* [Documentation](http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/)
|
||||
* [Issue Tracker](https://github.com/doctrine/dbal/issues)
|
||||
|
||||
[Coverage 5.0 image]: https://codecov.io/gh/doctrine/dbal/branch/5.0.x/graph/badge.svg
|
||||
[5.0]: https://github.com/doctrine/dbal/tree/5.0.x
|
||||
[CodeCov 5.0]: https://codecov.io/gh/doctrine/dbal/branch/5.0.x
|
||||
[AppVeyor 5.0]: https://ci.appveyor.com/project/doctrine/dbal/branch/5.0.x
|
||||
[AppVeyor 5.0 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/5.0.x?svg=true
|
||||
[GA 5.0]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A5.0.x
|
||||
[GA 5.0 image]: https://github.com/doctrine/dbal/actions/workflows/continuous-integration.yml/badge.svg?branch=5.0.x
|
||||
|
||||
[Coverage 4.3 image]: https://codecov.io/gh/doctrine/dbal/branch/4.3.x/graph/badge.svg
|
||||
[4.3]: https://github.com/doctrine/dbal/tree/4.3.x
|
||||
[CodeCov 4.3]: https://codecov.io/gh/doctrine/dbal/branch/4.3.x
|
||||
[AppVeyor 4.3]: https://ci.appveyor.com/project/doctrine/dbal/branch/4.3.x
|
||||
[AppVeyor 4.3 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/4.3.x?svg=true
|
||||
[GA 4.3]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A4.3.x
|
||||
[GA 4.3 image]: https://github.com/doctrine/dbal/actions/workflows/continuous-integration.yml/badge.svg?branch=4.3.x
|
||||
|
||||
[Coverage 4.2 image]: https://codecov.io/gh/doctrine/dbal/branch/4.2.x/graph/badge.svg
|
||||
[4.2]: https://github.com/doctrine/dbal/tree/4.2.x
|
||||
[CodeCov 4.2]: https://codecov.io/gh/doctrine/dbal/branch/4.2.x
|
||||
[AppVeyor 4.2]: https://ci.appveyor.com/project/doctrine/dbal/branch/4.2.x
|
||||
[AppVeyor 4.2 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/4.2.x?svg=true
|
||||
[GA 4.2]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A4.2.x
|
||||
[GA 4.2 image]: https://github.com/doctrine/dbal/actions/workflows/continuous-integration.yml/badge.svg?branch=4.2.x
|
||||
|
||||
[Coverage 3.10 image]: https://codecov.io/gh/doctrine/dbal/branch/3.10.x/graph/badge.svg
|
||||
[3.10]: https://github.com/doctrine/dbal/tree/3.10.x
|
||||
[CodeCov 3.10]: https://codecov.io/gh/doctrine/dbal/branch/3.10.x
|
||||
[AppVeyor 3.10]: https://ci.appveyor.com/project/doctrine/dbal/branch/3.10.x
|
||||
[AppVeyor 3.10 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/3.10.x?svg=true
|
||||
[GA 3.10]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A3.10.x
|
||||
[GA 3.10 image]: https://github.com/doctrine/dbal/actions/workflows/continuous-integration.yml/badge.svg?branch=3.10.x
|
||||
|
||||
[Coverage 3.9 image]: https://codecov.io/gh/doctrine/dbal/branch/3.9.x/graph/badge.svg
|
||||
[3.9]: https://github.com/doctrine/dbal/tree/3.9.x
|
||||
[CodeCov 3.9]: https://codecov.io/gh/doctrine/dbal/branch/3.9.x
|
||||
[AppVeyor 3.9]: https://ci.appveyor.com/project/doctrine/dbal/branch/3.9.x
|
||||
[AppVeyor 3.9 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/3.9.x?svg=true
|
||||
[GA 3.9]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A3.9.x
|
||||
[GA 3.9 image]: https://github.com/doctrine/dbal/actions/workflows/continuous-integration.yml/badge.svg?branch=3.9.x
|
||||
68
backend/vendor/doctrine/dbal/composer.json
vendored
Normal file
68
backend/vendor/doctrine/dbal/composer.json
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"name": "doctrine/dbal",
|
||||
"type": "library",
|
||||
"description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.",
|
||||
"keywords": [
|
||||
"abstraction",
|
||||
"database",
|
||||
"dbal",
|
||||
"db2",
|
||||
"mariadb",
|
||||
"mssql",
|
||||
"mysql",
|
||||
"pgsql",
|
||||
"postgresql",
|
||||
"oci8",
|
||||
"oracle",
|
||||
"pdo",
|
||||
"queryobject",
|
||||
"sasql",
|
||||
"sql",
|
||||
"sqlite",
|
||||
"sqlserver",
|
||||
"sqlsrv"
|
||||
],
|
||||
"homepage": "https://www.doctrine-project.org/projects/dbal.html",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"},
|
||||
{"name": "Roman Borschel", "email": "roman@code-factory.org"},
|
||||
{"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"},
|
||||
{"name": "Jonathan Wage", "email": "jonwage@gmail.com"}
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.1",
|
||||
"doctrine/deprecations": "^0.5.3|^1",
|
||||
"psr/cache": "^1|^2|^3",
|
||||
"psr/log": "^1|^2|^3"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "12.0.0",
|
||||
"fig/log-test": "^1",
|
||||
"jetbrains/phpstorm-stubs": "2023.2",
|
||||
"phpstan/phpstan": "2.1.1",
|
||||
"phpstan/phpstan-phpunit": "2.0.3",
|
||||
"phpstan/phpstan-strict-rules": "^2",
|
||||
"phpunit/phpunit": "10.5.39",
|
||||
"slevomat/coding-standard": "8.13.1",
|
||||
"squizlabs/php_codesniffer": "3.10.2",
|
||||
"symfony/cache": "^6.3.8|^7.0",
|
||||
"symfony/console": "^5.4|^6.3|^7.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/console": "For helpful console commands such as SQL execution and import of files."
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true,
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true,
|
||||
"composer/package-versions-deprecated": true
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Doctrine\\DBAL\\": "src" }
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": { "Doctrine\\DBAL\\Tests\\": "tests" }
|
||||
}
|
||||
}
|
||||
91
backend/vendor/doctrine/dbal/phpstan-baseline.neon
vendored
Normal file
91
backend/vendor/doctrine/dbal/phpstan-baseline.neon
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
parameters:
|
||||
ignoreErrors:
|
||||
-
|
||||
message: '#^Method Doctrine\\DBAL\\Driver\\IBMDB2\\Connection\:\:exec\(\) never returns numeric\-string so it can be removed from the return type\.$#'
|
||||
identifier: return.unusedType
|
||||
count: 1
|
||||
path: src/Driver/IBMDB2/Connection.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\DBAL\\Driver\\OCI8\\Connection\:\:exec\(\) never returns numeric\-string so it can be removed from the return type\.$#'
|
||||
identifier: return.unusedType
|
||||
count: 1
|
||||
path: src/Driver/OCI8/Connection.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\DBAL\\Driver\\OCI8\\Result\:\:fetchAllAssociative\(\) should return list\<array\<string, mixed\>\> but returns array\<mixed\>\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Driver/OCI8/Result.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\DBAL\\Driver\\OCI8\\Result\:\:fetchAllNumeric\(\) should return list\<list\<mixed\>\> but returns array\<mixed\>\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Driver/OCI8/Result.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\DBAL\\Driver\\PDO\\Result\:\:fetchAll\(\) should return list\<mixed\> but returns array\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Driver/PDO/Result.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\DBAL\\Driver\\PgSQL\\Result\:\:fetchAllAssociative\(\) should return list\<array\<string, mixed\>\> but returns array\<int, array\<string, mixed\>\>\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Driver/PgSQL/Result.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\DBAL\\Driver\\PgSQL\\Result\:\:fetchAllNumeric\(\) should return list\<list\<mixed\>\> but returns array\<int, list\<mixed\>\>\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Driver/PgSQL/Result.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\DBAL\\Driver\\PgSQL\\Result\:\:fetchFirstColumn\(\) should return list\<mixed\> but returns array\<int, bool\|float\|int\|string\|null\>\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Driver/PgSQL/Result.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\DBAL\\Driver\\SQLite3\\Result\:\:fetchNumeric\(\) should return list\<mixed\>\|false but returns array\|false\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Driver/SQLite3/Result.php
|
||||
|
||||
-
|
||||
message: '#^Template type T is declared as covariant, but occurs in invariant position in property Doctrine\\DBAL\\Schema\\AbstractSchemaManager\:\:\$platform\.$#'
|
||||
identifier: generics.variance
|
||||
count: 1
|
||||
path: src/Schema/AbstractSchemaManager.php
|
||||
|
||||
-
|
||||
message: '#^Loose comparison via "\!\=" is not allowed\.$#'
|
||||
identifier: notEqual.notAllowed
|
||||
count: 1
|
||||
path: src/Schema/ColumnDiff.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\DBAL\\Schema\\SQLiteSchemaManager\:\:addDetailsToTableForeignKeyColumns\(\) should return list\<array\<string, mixed\>\> but returns array\<int\<0, max\>, array\<string, mixed\>\>\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Schema/SQLiteSchemaManager.php
|
||||
|
||||
-
|
||||
message: '#^Offset string might not exist on array\{application_name\?\: string, charset\?\: string, dbname\?\: string, defaultTableOptions\?\: array\<string, mixed\>, driver\?\: ''ibm_db2''\|''mysqli''\|''oci8''\|''pdo_mysql''\|''pdo_oci''\|''pdo_pgsql''\|''pdo_sqlite''\|''pdo_sqlsrv''\|''pgsql''\|''sqlite3''\|''sqlsrv'', driverClass\?\: class\-string\<Doctrine\\DBAL\\Driver\>, driverOptions\?\: array\<mixed\>, host\?\: string, \.\.\.\}\.$#'
|
||||
identifier: offsetAccess.notFound
|
||||
count: 1
|
||||
path: tests/DriverManagerTest.php
|
||||
|
||||
-
|
||||
message: '#^Call to new Doctrine\\DBAL\\Driver\\PgSQL\\Result\(\) on a separate line has no effect\.$#'
|
||||
identifier: new.resultUnused
|
||||
count: 1
|
||||
path: tests/Functional/Driver/PgSQL/ResultTest.php
|
||||
|
||||
-
|
||||
message: '#^Call to function array_filter\(\) requires parameter \#2 to be passed to avoid loose comparison semantics\.$#'
|
||||
identifier: arrayFilter.strict
|
||||
count: 1
|
||||
path: tests/Functional/Schema/MySQL/JsonCollationTest.php
|
||||
39
backend/vendor/doctrine/dbal/src/ArrayParameterType.php
vendored
Normal file
39
backend/vendor/doctrine/dbal/src/ArrayParameterType.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL;
|
||||
|
||||
enum ArrayParameterType
|
||||
{
|
||||
/**
|
||||
* Represents an array of ints to be expanded by Doctrine SQL parsing.
|
||||
*/
|
||||
case INTEGER;
|
||||
|
||||
/**
|
||||
* Represents an array of strings to be expanded by Doctrine SQL parsing.
|
||||
*/
|
||||
case STRING;
|
||||
|
||||
/**
|
||||
* Represents an array of ascii strings to be expanded by Doctrine SQL parsing.
|
||||
*/
|
||||
case ASCII;
|
||||
|
||||
/**
|
||||
* Represents an array of ascii strings to be expanded by Doctrine SQL parsing.
|
||||
*/
|
||||
case BINARY;
|
||||
|
||||
/** @internal */
|
||||
public static function toElementParameterType(self $type): ParameterType
|
||||
{
|
||||
return match ($type) {
|
||||
self::INTEGER => ParameterType::INTEGER,
|
||||
self::STRING => ParameterType::STRING,
|
||||
self::ASCII => ParameterType::ASCII,
|
||||
self::BINARY => ParameterType::BINARY,
|
||||
};
|
||||
}
|
||||
}
|
||||
12
backend/vendor/doctrine/dbal/src/ArrayParameters/Exception.php
vendored
Normal file
12
backend/vendor/doctrine/dbal/src/ArrayParameters/Exception.php
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\ArrayParameters;
|
||||
|
||||
use Throwable;
|
||||
|
||||
/** @internal */
|
||||
interface Exception extends Throwable
|
||||
{
|
||||
}
|
||||
20
backend/vendor/doctrine/dbal/src/ArrayParameters/Exception/MissingNamedParameter.php
vendored
Normal file
20
backend/vendor/doctrine/dbal/src/ArrayParameters/Exception/MissingNamedParameter.php
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\ArrayParameters\Exception;
|
||||
|
||||
use Doctrine\DBAL\ArrayParameters\Exception;
|
||||
use LogicException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
class MissingNamedParameter extends LogicException implements Exception
|
||||
{
|
||||
public static function new(string $name): self
|
||||
{
|
||||
return new self(
|
||||
sprintf('Named parameter "%s" does not have a bound value.', $name),
|
||||
);
|
||||
}
|
||||
}
|
||||
21
backend/vendor/doctrine/dbal/src/ArrayParameters/Exception/MissingPositionalParameter.php
vendored
Normal file
21
backend/vendor/doctrine/dbal/src/ArrayParameters/Exception/MissingPositionalParameter.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\ArrayParameters\Exception;
|
||||
|
||||
use Doctrine\DBAL\ArrayParameters\Exception;
|
||||
use LogicException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
/** @internal */
|
||||
class MissingPositionalParameter extends LogicException implements Exception
|
||||
{
|
||||
public static function new(int $index): self
|
||||
{
|
||||
return new self(
|
||||
sprintf('Positional parameter at index %d does not have a bound value.', $index),
|
||||
);
|
||||
}
|
||||
}
|
||||
136
backend/vendor/doctrine/dbal/src/Cache/ArrayResult.php
vendored
Normal file
136
backend/vendor/doctrine/dbal/src/Cache/ArrayResult.php
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Cache;
|
||||
|
||||
use Doctrine\DBAL\Driver\FetchUtils;
|
||||
use Doctrine\DBAL\Driver\Result;
|
||||
use Doctrine\DBAL\Exception\InvalidColumnIndex;
|
||||
|
||||
use function array_combine;
|
||||
use function array_keys;
|
||||
use function array_map;
|
||||
use function array_values;
|
||||
use function count;
|
||||
|
||||
/** @internal The class is internal to the caching layer implementation. */
|
||||
final class ArrayResult implements Result
|
||||
{
|
||||
private int $num = 0;
|
||||
|
||||
/**
|
||||
* @param list<string> $columnNames The names of the result columns. Must be non-empty.
|
||||
* @param list<list<mixed>> $rows The rows of the result. Each row must have the same number of columns
|
||||
* as the number of column names.
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly array $columnNames,
|
||||
private array $rows,
|
||||
) {
|
||||
}
|
||||
|
||||
public function fetchNumeric(): array|false
|
||||
{
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
public function fetchAssociative(): array|false
|
||||
{
|
||||
$row = $this->fetch();
|
||||
|
||||
if ($row === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return array_combine($this->columnNames, $row);
|
||||
}
|
||||
|
||||
public function fetchOne(): mixed
|
||||
{
|
||||
$row = $this->fetch();
|
||||
|
||||
if ($row === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $row[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function fetchAllNumeric(): array
|
||||
{
|
||||
return FetchUtils::fetchAllNumeric($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function fetchAllAssociative(): array
|
||||
{
|
||||
return FetchUtils::fetchAllAssociative($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function fetchFirstColumn(): array
|
||||
{
|
||||
return FetchUtils::fetchFirstColumn($this);
|
||||
}
|
||||
|
||||
public function rowCount(): int
|
||||
{
|
||||
return count($this->rows);
|
||||
}
|
||||
|
||||
public function columnCount(): int
|
||||
{
|
||||
return count($this->columnNames);
|
||||
}
|
||||
|
||||
public function getColumnName(int $index): string
|
||||
{
|
||||
return $this->columnNames[$index] ?? throw InvalidColumnIndex::new($index);
|
||||
}
|
||||
|
||||
public function free(): void
|
||||
{
|
||||
$this->rows = [];
|
||||
}
|
||||
|
||||
/** @return array{list<string>, list<list<mixed>>} */
|
||||
public function __serialize(): array
|
||||
{
|
||||
return [$this->columnNames, $this->rows];
|
||||
}
|
||||
|
||||
/** @param mixed[] $data */
|
||||
public function __unserialize(array $data): void
|
||||
{
|
||||
// Handle objects serialized with DBAL 4.1 and earlier.
|
||||
if (isset($data["\0" . self::class . "\0data"])) {
|
||||
/** @var list<array<string, mixed>> $legacyData */
|
||||
$legacyData = $data["\0" . self::class . "\0data"];
|
||||
|
||||
$this->columnNames = array_keys($legacyData[0] ?? []);
|
||||
$this->rows = array_map(array_values(...), $legacyData);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
[$this->columnNames, $this->rows] = $data;
|
||||
}
|
||||
|
||||
/** @return list<mixed>|false */
|
||||
private function fetch(): array|false
|
||||
{
|
||||
if (! isset($this->rows[$this->num])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->rows[$this->num++];
|
||||
}
|
||||
}
|
||||
11
backend/vendor/doctrine/dbal/src/Cache/CacheException.php
vendored
Normal file
11
backend/vendor/doctrine/dbal/src/Cache/CacheException.php
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Cache;
|
||||
|
||||
use Doctrine\DBAL\Exception;
|
||||
|
||||
class CacheException extends \Exception implements Exception
|
||||
{
|
||||
}
|
||||
15
backend/vendor/doctrine/dbal/src/Cache/Exception/NoCacheKey.php
vendored
Normal file
15
backend/vendor/doctrine/dbal/src/Cache/Exception/NoCacheKey.php
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Cache\Exception;
|
||||
|
||||
use Doctrine\DBAL\Cache\CacheException;
|
||||
|
||||
final class NoCacheKey extends CacheException
|
||||
{
|
||||
public static function new(): self
|
||||
{
|
||||
return new self('No cache key was set.');
|
||||
}
|
||||
}
|
||||
15
backend/vendor/doctrine/dbal/src/Cache/Exception/NoResultDriverConfigured.php
vendored
Normal file
15
backend/vendor/doctrine/dbal/src/Cache/Exception/NoResultDriverConfigured.php
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Cache\Exception;
|
||||
|
||||
use Doctrine\DBAL\Cache\CacheException;
|
||||
|
||||
final class NoResultDriverConfigured extends CacheException
|
||||
{
|
||||
public static function new(): self
|
||||
{
|
||||
return new self('Trying to cache a query but no result driver is configured.');
|
||||
}
|
||||
}
|
||||
91
backend/vendor/doctrine/dbal/src/Cache/QueryCacheProfile.php
vendored
Normal file
91
backend/vendor/doctrine/dbal/src/Cache/QueryCacheProfile.php
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Cache;
|
||||
|
||||
use Doctrine\DBAL\Cache\Exception\NoCacheKey;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
|
||||
use function hash;
|
||||
use function serialize;
|
||||
use function sha1;
|
||||
|
||||
/**
|
||||
* Query Cache Profile handles the data relevant for query caching.
|
||||
*
|
||||
* It is a value object, setter methods return NEW instances.
|
||||
*
|
||||
* @phpstan-import-type WrapperParameterType from Connection
|
||||
*/
|
||||
class QueryCacheProfile
|
||||
{
|
||||
public function __construct(
|
||||
private readonly int $lifetime = 0,
|
||||
private readonly ?string $cacheKey = null,
|
||||
private readonly ?CacheItemPoolInterface $resultCache = null,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getResultCache(): ?CacheItemPoolInterface
|
||||
{
|
||||
return $this->resultCache;
|
||||
}
|
||||
|
||||
public function getLifetime(): int
|
||||
{
|
||||
return $this->lifetime;
|
||||
}
|
||||
|
||||
/** @throws CacheException */
|
||||
public function getCacheKey(): string
|
||||
{
|
||||
if ($this->cacheKey === null) {
|
||||
throw NoCacheKey::new();
|
||||
}
|
||||
|
||||
return $this->cacheKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the real cache key from query, params, types and connection parameters.
|
||||
*
|
||||
* @param list<mixed>|array<string, mixed> $params
|
||||
* @param array<string, mixed> $connectionParams
|
||||
* @phpstan-param array<int, WrapperParameterType>|array<string, WrapperParameterType> $types
|
||||
*
|
||||
* @return array{string, string}
|
||||
*/
|
||||
public function generateCacheKeys(string $sql, array $params, array $types, array $connectionParams = []): array
|
||||
{
|
||||
if (isset($connectionParams['password'])) {
|
||||
unset($connectionParams['password']);
|
||||
}
|
||||
|
||||
$realCacheKey = 'query=' . $sql .
|
||||
'¶ms=' . serialize($params) .
|
||||
'&types=' . serialize($types) .
|
||||
'&connectionParams=' . hash('sha256', serialize($connectionParams));
|
||||
|
||||
// should the key be automatically generated using the inputs or is the cache key set?
|
||||
$cacheKey = $this->cacheKey ?? sha1($realCacheKey);
|
||||
|
||||
return [$cacheKey, $realCacheKey];
|
||||
}
|
||||
|
||||
public function setResultCache(CacheItemPoolInterface $cache): QueryCacheProfile
|
||||
{
|
||||
return new QueryCacheProfile($this->lifetime, $this->cacheKey, $cache);
|
||||
}
|
||||
|
||||
public function setCacheKey(?string $cacheKey): self
|
||||
{
|
||||
return new QueryCacheProfile($this->lifetime, $cacheKey, $this->resultCache);
|
||||
}
|
||||
|
||||
public function setLifetime(int $lifetime): self
|
||||
{
|
||||
return new QueryCacheProfile($lifetime, $this->cacheKey, $this->resultCache);
|
||||
}
|
||||
}
|
||||
21
backend/vendor/doctrine/dbal/src/ColumnCase.php
vendored
Normal file
21
backend/vendor/doctrine/dbal/src/ColumnCase.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL;
|
||||
|
||||
/**
|
||||
* Contains portable column case conversions.
|
||||
*/
|
||||
enum ColumnCase
|
||||
{
|
||||
/**
|
||||
* Convert column names to upper case.
|
||||
*/
|
||||
case UPPER;
|
||||
|
||||
/**
|
||||
* Convert column names to lower case.
|
||||
*/
|
||||
case LOWER;
|
||||
}
|
||||
156
backend/vendor/doctrine/dbal/src/Configuration.php
vendored
Normal file
156
backend/vendor/doctrine/dbal/src/Configuration.php
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL;
|
||||
|
||||
use Doctrine\DBAL\Driver\Middleware;
|
||||
use Doctrine\DBAL\Exception\InvalidArgumentException;
|
||||
use Doctrine\DBAL\Schema\SchemaManagerFactory;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
|
||||
/**
|
||||
* Configuration container for the Doctrine DBAL.
|
||||
*/
|
||||
class Configuration
|
||||
{
|
||||
/** @var Middleware[] */
|
||||
private array $middlewares = [];
|
||||
|
||||
/**
|
||||
* The cache driver implementation that is used for query result caching.
|
||||
*/
|
||||
private ?CacheItemPoolInterface $resultCache = null;
|
||||
|
||||
/**
|
||||
* The callable to use to filter schema assets.
|
||||
*
|
||||
* @var callable
|
||||
*/
|
||||
protected $schemaAssetsFilter;
|
||||
|
||||
/**
|
||||
* The default auto-commit mode for connections.
|
||||
*/
|
||||
protected bool $autoCommit = true;
|
||||
|
||||
private ?SchemaManagerFactory $schemaManagerFactory = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->schemaAssetsFilter = static function (): bool {
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cache driver implementation that is used for query result caching.
|
||||
*/
|
||||
public function getResultCache(): ?CacheItemPoolInterface
|
||||
{
|
||||
return $this->resultCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cache driver implementation that is used for query result caching.
|
||||
*/
|
||||
public function setResultCache(CacheItemPoolInterface $cache): void
|
||||
{
|
||||
$this->resultCache = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the callable to use to filter schema assets.
|
||||
*/
|
||||
public function setSchemaAssetsFilter(callable $schemaAssetsFilter): void
|
||||
{
|
||||
$this->schemaAssetsFilter = $schemaAssetsFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the callable to use to filter schema assets.
|
||||
*/
|
||||
public function getSchemaAssetsFilter(): callable
|
||||
{
|
||||
return $this->schemaAssetsFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default auto-commit mode for connections.
|
||||
*
|
||||
* If a connection is in auto-commit mode, then all its SQL statements will be executed and committed as individual
|
||||
* transactions. Otherwise, its SQL statements are grouped into transactions that are terminated by a call to either
|
||||
* the method commit or the method rollback. By default, new connections are in auto-commit mode.
|
||||
*
|
||||
* @see getAutoCommit
|
||||
*
|
||||
* @param bool $autoCommit True to enable auto-commit mode; false to disable it
|
||||
*/
|
||||
public function setAutoCommit(bool $autoCommit): void
|
||||
{
|
||||
$this->autoCommit = $autoCommit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default auto-commit mode for connections.
|
||||
*
|
||||
* @see setAutoCommit
|
||||
*
|
||||
* @return bool True if auto-commit mode is enabled by default for connections, false otherwise.
|
||||
*/
|
||||
public function getAutoCommit(): bool
|
||||
{
|
||||
return $this->autoCommit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Middleware[] $middlewares
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setMiddlewares(array $middlewares): self
|
||||
{
|
||||
$this->middlewares = $middlewares;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @return Middleware[] */
|
||||
public function getMiddlewares(): array
|
||||
{
|
||||
return $this->middlewares;
|
||||
}
|
||||
|
||||
public function getSchemaManagerFactory(): ?SchemaManagerFactory
|
||||
{
|
||||
return $this->schemaManagerFactory;
|
||||
}
|
||||
|
||||
/** @return $this */
|
||||
public function setSchemaManagerFactory(SchemaManagerFactory $schemaManagerFactory): self
|
||||
{
|
||||
$this->schemaManagerFactory = $schemaManagerFactory;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @return true */
|
||||
public function getDisableTypeComments(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param true $disableTypeComments
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setDisableTypeComments(bool $disableTypeComments): self
|
||||
{
|
||||
if (! $disableTypeComments) {
|
||||
throw new InvalidArgumentException('Column comments cannot be enabled anymore.');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
1426
backend/vendor/doctrine/dbal/src/Connection.php
vendored
Normal file
1426
backend/vendor/doctrine/dbal/src/Connection.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
19
backend/vendor/doctrine/dbal/src/Connection/StaticServerVersionProvider.php
vendored
Normal file
19
backend/vendor/doctrine/dbal/src/Connection/StaticServerVersionProvider.php
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Connection;
|
||||
|
||||
use Doctrine\DBAL\ServerVersionProvider;
|
||||
|
||||
class StaticServerVersionProvider implements ServerVersionProvider
|
||||
{
|
||||
public function __construct(private readonly string $version)
|
||||
{
|
||||
}
|
||||
|
||||
public function getServerVersion(): string
|
||||
{
|
||||
return $this->version;
|
||||
}
|
||||
}
|
||||
9
backend/vendor/doctrine/dbal/src/ConnectionException.php
vendored
Normal file
9
backend/vendor/doctrine/dbal/src/ConnectionException.php
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL;
|
||||
|
||||
class ConnectionException extends \Exception implements Exception
|
||||
{
|
||||
}
|
||||
327
backend/vendor/doctrine/dbal/src/Connections/PrimaryReadReplicaConnection.php
vendored
Normal file
327
backend/vendor/doctrine/dbal/src/Connections/PrimaryReadReplicaConnection.php
vendored
Normal file
@@ -0,0 +1,327 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Connections;
|
||||
|
||||
use Doctrine\DBAL\Configuration;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Driver;
|
||||
use Doctrine\DBAL\Driver\Connection as DriverConnection;
|
||||
use Doctrine\DBAL\Driver\Exception as DriverException;
|
||||
use Doctrine\DBAL\DriverManager;
|
||||
use Doctrine\DBAL\Exception;
|
||||
use Doctrine\DBAL\Statement;
|
||||
use InvalidArgumentException;
|
||||
use SensitiveParameter;
|
||||
|
||||
use function array_rand;
|
||||
use function assert;
|
||||
use function count;
|
||||
|
||||
/**
|
||||
* Primary-Replica Connection
|
||||
*
|
||||
* Connection can be used with primary-replica setups.
|
||||
*
|
||||
* Important for the understanding of this connection should be how and when
|
||||
* it picks the replica or primary.
|
||||
*
|
||||
* 1. Replica if primary was never picked before and ONLY if 'getWrappedConnection'
|
||||
* or 'executeQuery' is used.
|
||||
* 2. Primary picked when 'executeStatement', 'insert', 'delete', 'update', 'createSavepoint',
|
||||
* 'releaseSavepoint', 'beginTransaction', 'rollback', 'commit' or 'prepare' is called.
|
||||
* 3. If Primary was picked once during the lifetime of the connection it will always get picked afterwards.
|
||||
* 4. One replica connection is randomly picked ONCE during a request.
|
||||
*
|
||||
* ATTENTION: You can write to the replica with this connection if you execute a write query without
|
||||
* opening up a transaction. For example:
|
||||
*
|
||||
* $conn = DriverManager::getConnection(...);
|
||||
* $conn->executeQuery("DELETE FROM table");
|
||||
*
|
||||
* Be aware that Connection#executeQuery is a method specifically for READ
|
||||
* operations only.
|
||||
*
|
||||
* Use Connection#executeStatement for any SQL statement that changes/updates
|
||||
* state in the database (UPDATE, INSERT, DELETE or DDL statements).
|
||||
*
|
||||
* This connection is limited to replica operations using the
|
||||
* Connection#executeQuery operation only, because it wouldn't be compatible
|
||||
* with the ORM or SchemaManager code otherwise. Both use all the other
|
||||
* operations in a context where writes could happen to a replica, which makes
|
||||
* this restricted approach necessary.
|
||||
*
|
||||
* You can manually connect to the primary at any time by calling:
|
||||
*
|
||||
* $conn->ensureConnectedToPrimary();
|
||||
*
|
||||
* Instantiation through the DriverManager looks like:
|
||||
*
|
||||
* @phpstan-import-type Params from DriverManager
|
||||
* @phpstan-import-type OverrideParams from DriverManager
|
||||
* @example
|
||||
*
|
||||
* $conn = DriverManager::getConnection(array(
|
||||
* 'wrapperClass' => 'Doctrine\DBAL\Connections\PrimaryReadReplicaConnection',
|
||||
* 'driver' => 'pdo_mysql',
|
||||
* 'primary' => array('user' => '', 'password' => '', 'host' => '', 'dbname' => ''),
|
||||
* 'replica' => array(
|
||||
* array('user' => 'replica1', 'password' => '', 'host' => '', 'dbname' => ''),
|
||||
* array('user' => 'replica2', 'password' => '', 'host' => '', 'dbname' => ''),
|
||||
* )
|
||||
* ));
|
||||
*
|
||||
* You can also pass 'driverOptions' and any other documented option to each of this drivers
|
||||
* to pass additional information.
|
||||
*/
|
||||
class PrimaryReadReplicaConnection extends Connection
|
||||
{
|
||||
/**
|
||||
* Primary and Replica connection (one of the randomly picked replicas).
|
||||
*
|
||||
* @var array<string, DriverConnection|null>
|
||||
*/
|
||||
protected array $connections = ['primary' => null, 'replica' => null];
|
||||
|
||||
/**
|
||||
* You can keep the replica connection and then switch back to it
|
||||
* during the request if you know what you are doing.
|
||||
*/
|
||||
protected bool $keepReplica = false;
|
||||
|
||||
/**
|
||||
* Creates Primary Replica Connection.
|
||||
*
|
||||
* @internal The connection can be only instantiated by the driver manager.
|
||||
*
|
||||
* @param array<string, mixed> $params
|
||||
* @phpstan-param Params $params
|
||||
*/
|
||||
public function __construct(array $params, Driver $driver, ?Configuration $config = null)
|
||||
{
|
||||
if (! isset($params['replica'], $params['primary'])) {
|
||||
throw new InvalidArgumentException('primary or replica configuration missing');
|
||||
}
|
||||
|
||||
if (count($params['replica']) === 0) {
|
||||
throw new InvalidArgumentException('You have to configure at least one replica.');
|
||||
}
|
||||
|
||||
if (isset($params['driver'])) {
|
||||
$params['primary']['driver'] = $params['driver'];
|
||||
|
||||
foreach ($params['replica'] as $replicaKey => $replica) {
|
||||
$params['replica'][$replicaKey]['driver'] = $params['driver'];
|
||||
}
|
||||
}
|
||||
|
||||
$this->keepReplica = ! empty($params['keepReplica']);
|
||||
|
||||
parent::__construct($params, $driver, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the connection is currently towards the primary or not.
|
||||
*/
|
||||
public function isConnectedToPrimary(): bool
|
||||
{
|
||||
return $this->_conn !== null && $this->_conn === $this->connections['primary'];
|
||||
}
|
||||
|
||||
public function connect(?string $connectionName = null): DriverConnection
|
||||
{
|
||||
if ($connectionName !== null) {
|
||||
throw new InvalidArgumentException(
|
||||
'Passing a connection name as first argument is not supported anymore.'
|
||||
. ' Use ensureConnectedToPrimary()/ensureConnectedToReplica() instead.',
|
||||
);
|
||||
}
|
||||
|
||||
return $this->performConnect();
|
||||
}
|
||||
|
||||
protected function performConnect(?string $connectionName = null): DriverConnection
|
||||
{
|
||||
$requestedConnectionChange = ($connectionName !== null);
|
||||
$connectionName ??= 'replica';
|
||||
|
||||
if ($connectionName !== 'replica' && $connectionName !== 'primary') {
|
||||
throw new InvalidArgumentException('Invalid option to connect(), only primary or replica allowed.');
|
||||
}
|
||||
|
||||
// If we have a connection open, and this is not an explicit connection
|
||||
// change request, then abort right here, because we are already done.
|
||||
// This prevents writes to the replica in case of "keepReplica" option enabled.
|
||||
if ($this->_conn !== null && ! $requestedConnectionChange) {
|
||||
return $this->_conn;
|
||||
}
|
||||
|
||||
$forcePrimaryAsReplica = false;
|
||||
|
||||
if ($this->getTransactionNestingLevel() > 0) {
|
||||
$connectionName = 'primary';
|
||||
$forcePrimaryAsReplica = true;
|
||||
}
|
||||
|
||||
if (isset($this->connections[$connectionName])) {
|
||||
$this->_conn = $this->connections[$connectionName];
|
||||
|
||||
if ($forcePrimaryAsReplica && ! $this->keepReplica) {
|
||||
$this->connections['replica'] = $this->_conn;
|
||||
}
|
||||
|
||||
return $this->_conn;
|
||||
}
|
||||
|
||||
if ($connectionName === 'primary') {
|
||||
$this->connections['primary'] = $this->_conn = $this->connectTo($connectionName);
|
||||
|
||||
// Set replica connection to primary to avoid invalid reads
|
||||
if (! $this->keepReplica) {
|
||||
$this->connections['replica'] = $this->connections['primary'];
|
||||
}
|
||||
} else {
|
||||
$this->connections['replica'] = $this->_conn = $this->connectTo($connectionName);
|
||||
}
|
||||
|
||||
return $this->_conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to the primary node of the database cluster.
|
||||
*
|
||||
* All following statements after this will be executed against the primary node.
|
||||
*/
|
||||
public function ensureConnectedToPrimary(): void
|
||||
{
|
||||
$this->performConnect('primary');
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to a replica node of the database cluster.
|
||||
*
|
||||
* All following statements after this will be executed against the replica node,
|
||||
* unless the keepReplica option is set to false and a primary connection
|
||||
* was already opened.
|
||||
*/
|
||||
public function ensureConnectedToReplica(): void
|
||||
{
|
||||
$this->performConnect('replica');
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to a specific connection.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function connectTo(string $connectionName): DriverConnection
|
||||
{
|
||||
$params = $this->getParams();
|
||||
assert(isset($params['primary']));
|
||||
|
||||
if ($connectionName === 'primary') {
|
||||
$connectionParams = $params['primary'];
|
||||
} else {
|
||||
assert(isset($params['replica']));
|
||||
$connectionParams = $this->chooseReplicaConnectionParameters($params['primary'], $params['replica']);
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->driver->connect($connectionParams);
|
||||
} catch (DriverException $e) {
|
||||
throw $this->convertException($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OverrideParams $primary
|
||||
* @param array<OverrideParams> $replicas
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
* @phpstan-return OverrideParams
|
||||
*/
|
||||
protected function chooseReplicaConnectionParameters(
|
||||
#[SensitiveParameter]
|
||||
array $primary,
|
||||
#[SensitiveParameter]
|
||||
array $replicas,
|
||||
): array {
|
||||
$params = $replicas[array_rand($replicas)];
|
||||
|
||||
if (! isset($params['charset']) && isset($primary['charset'])) {
|
||||
$params['charset'] = $primary['charset'];
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function executeStatement(string $sql, array $params = [], array $types = []): int|string
|
||||
{
|
||||
$this->ensureConnectedToPrimary();
|
||||
|
||||
return parent::executeStatement($sql, $params, $types);
|
||||
}
|
||||
|
||||
public function beginTransaction(): void
|
||||
{
|
||||
$this->ensureConnectedToPrimary();
|
||||
|
||||
parent::beginTransaction();
|
||||
}
|
||||
|
||||
public function commit(): void
|
||||
{
|
||||
$this->ensureConnectedToPrimary();
|
||||
|
||||
parent::commit();
|
||||
}
|
||||
|
||||
public function rollBack(): void
|
||||
{
|
||||
$this->ensureConnectedToPrimary();
|
||||
|
||||
parent::rollBack();
|
||||
}
|
||||
|
||||
public function close(): void
|
||||
{
|
||||
unset($this->connections['primary'], $this->connections['replica']);
|
||||
|
||||
parent::close();
|
||||
|
||||
$this->_conn = null;
|
||||
$this->connections = ['primary' => null, 'replica' => null];
|
||||
}
|
||||
|
||||
public function createSavepoint(string $savepoint): void
|
||||
{
|
||||
$this->ensureConnectedToPrimary();
|
||||
|
||||
parent::createSavepoint($savepoint);
|
||||
}
|
||||
|
||||
public function releaseSavepoint(string $savepoint): void
|
||||
{
|
||||
$this->ensureConnectedToPrimary();
|
||||
|
||||
parent::releaseSavepoint($savepoint);
|
||||
}
|
||||
|
||||
public function rollbackSavepoint(string $savepoint): void
|
||||
{
|
||||
$this->ensureConnectedToPrimary();
|
||||
|
||||
parent::rollbackSavepoint($savepoint);
|
||||
}
|
||||
|
||||
public function prepare(string $sql): Statement
|
||||
{
|
||||
$this->ensureConnectedToPrimary();
|
||||
|
||||
return parent::prepare($sql);
|
||||
}
|
||||
}
|
||||
48
backend/vendor/doctrine/dbal/src/Driver.php
vendored
Normal file
48
backend/vendor/doctrine/dbal/src/Driver.php
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL;
|
||||
|
||||
use Doctrine\DBAL\Driver\API\ExceptionConverter;
|
||||
use Doctrine\DBAL\Driver\Connection as DriverConnection;
|
||||
use Doctrine\DBAL\Driver\Exception;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use SensitiveParameter;
|
||||
|
||||
/**
|
||||
* Driver interface.
|
||||
* Interface that all DBAL drivers must implement.
|
||||
*
|
||||
* @phpstan-import-type Params from DriverManager
|
||||
*/
|
||||
interface Driver
|
||||
{
|
||||
/**
|
||||
* Attempts to create a connection with the database.
|
||||
*
|
||||
* @param array<string, mixed> $params All connection parameters.
|
||||
* @phpstan-param Params $params All connection parameters.
|
||||
*
|
||||
* @return DriverConnection The database connection.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function connect(
|
||||
#[SensitiveParameter]
|
||||
array $params,
|
||||
): DriverConnection;
|
||||
|
||||
/**
|
||||
* Gets the DatabasePlatform instance that provides all the metadata about
|
||||
* the platform this driver connects to.
|
||||
*
|
||||
* @return AbstractPlatform The database platform.
|
||||
*/
|
||||
public function getDatabasePlatform(ServerVersionProvider $versionProvider): AbstractPlatform;
|
||||
|
||||
/**
|
||||
* Gets the ExceptionConverter that can be used to convert driver-level exceptions into DBAL exceptions.
|
||||
*/
|
||||
public function getExceptionConverter(): ExceptionConverter;
|
||||
}
|
||||
25
backend/vendor/doctrine/dbal/src/Driver/API/ExceptionConverter.php
vendored
Normal file
25
backend/vendor/doctrine/dbal/src/Driver/API/ExceptionConverter.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\API;
|
||||
|
||||
use Doctrine\DBAL\Driver\Exception;
|
||||
use Doctrine\DBAL\Exception\DriverException;
|
||||
use Doctrine\DBAL\Query;
|
||||
|
||||
interface ExceptionConverter
|
||||
{
|
||||
/**
|
||||
* Converts a given driver-level exception into a DBAL-level driver exception.
|
||||
*
|
||||
* Implementors should use the vendor-specific error code and SQLSTATE of the exception
|
||||
* and instantiate the most appropriate specialized {@see DriverException} subclass.
|
||||
*
|
||||
* @param Exception $exception The driver exception to convert.
|
||||
* @param Query|null $query The SQL query that triggered the exception, if any.
|
||||
*
|
||||
* @return DriverException An instance of {@see DriverException} or one of its subclasses.
|
||||
*/
|
||||
public function convert(Exception $exception, ?Query $query): DriverException;
|
||||
}
|
||||
47
backend/vendor/doctrine/dbal/src/Driver/API/IBMDB2/ExceptionConverter.php
vendored
Normal file
47
backend/vendor/doctrine/dbal/src/Driver/API/IBMDB2/ExceptionConverter.php
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\API\IBMDB2;
|
||||
|
||||
use Doctrine\DBAL\Driver\API\ExceptionConverter as ExceptionConverterInterface;
|
||||
use Doctrine\DBAL\Driver\Exception;
|
||||
use Doctrine\DBAL\Exception\ConnectionException;
|
||||
use Doctrine\DBAL\Exception\DriverException;
|
||||
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
|
||||
use Doctrine\DBAL\Exception\InvalidFieldNameException;
|
||||
use Doctrine\DBAL\Exception\NonUniqueFieldNameException;
|
||||
use Doctrine\DBAL\Exception\NotNullConstraintViolationException;
|
||||
use Doctrine\DBAL\Exception\SyntaxErrorException;
|
||||
use Doctrine\DBAL\Exception\TableExistsException;
|
||||
use Doctrine\DBAL\Exception\TableNotFoundException;
|
||||
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
||||
use Doctrine\DBAL\Query;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @link https://www.ibm.com/docs/en/db2/11.5?topic=messages-sql
|
||||
*/
|
||||
final class ExceptionConverter implements ExceptionConverterInterface
|
||||
{
|
||||
public function convert(Exception $exception, ?Query $query): DriverException
|
||||
{
|
||||
return match ($exception->getCode()) {
|
||||
-104 => new SyntaxErrorException($exception, $query),
|
||||
-203 => new NonUniqueFieldNameException($exception, $query),
|
||||
-204 => new TableNotFoundException($exception, $query),
|
||||
-206 => new InvalidFieldNameException($exception, $query),
|
||||
-407 => new NotNullConstraintViolationException($exception, $query),
|
||||
-530,
|
||||
-531,
|
||||
-532,
|
||||
-20356 => new ForeignKeyConstraintViolationException($exception, $query),
|
||||
-601 => new TableExistsException($exception, $query),
|
||||
-803 => new UniqueConstraintViolationException($exception, $query),
|
||||
-1336,
|
||||
-30082 => new ConnectionException($exception, $query),
|
||||
default => new DriverException($exception, $query),
|
||||
};
|
||||
}
|
||||
}
|
||||
94
backend/vendor/doctrine/dbal/src/Driver/API/MySQL/ExceptionConverter.php
vendored
Normal file
94
backend/vendor/doctrine/dbal/src/Driver/API/MySQL/ExceptionConverter.php
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\API\MySQL;
|
||||
|
||||
use Doctrine\DBAL\Driver\API\ExceptionConverter as ExceptionConverterInterface;
|
||||
use Doctrine\DBAL\Driver\Exception;
|
||||
use Doctrine\DBAL\Exception\ConnectionException;
|
||||
use Doctrine\DBAL\Exception\ConnectionLost;
|
||||
use Doctrine\DBAL\Exception\DatabaseDoesNotExist;
|
||||
use Doctrine\DBAL\Exception\DeadlockException;
|
||||
use Doctrine\DBAL\Exception\DriverException;
|
||||
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
|
||||
use Doctrine\DBAL\Exception\InvalidFieldNameException;
|
||||
use Doctrine\DBAL\Exception\LockWaitTimeoutException;
|
||||
use Doctrine\DBAL\Exception\NonUniqueFieldNameException;
|
||||
use Doctrine\DBAL\Exception\NotNullConstraintViolationException;
|
||||
use Doctrine\DBAL\Exception\SyntaxErrorException;
|
||||
use Doctrine\DBAL\Exception\TableExistsException;
|
||||
use Doctrine\DBAL\Exception\TableNotFoundException;
|
||||
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
||||
use Doctrine\DBAL\Query;
|
||||
|
||||
/** @internal */
|
||||
final class ExceptionConverter implements ExceptionConverterInterface
|
||||
{
|
||||
/**
|
||||
* @link https://dev.mysql.com/doc/mysql-errors/8.0/en/client-error-reference.html
|
||||
* @link https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html
|
||||
*/
|
||||
public function convert(Exception $exception, ?Query $query): DriverException
|
||||
{
|
||||
return match ($exception->getCode()) {
|
||||
1008 => new DatabaseDoesNotExist($exception, $query),
|
||||
1213 => new DeadlockException($exception, $query),
|
||||
1205 => new LockWaitTimeoutException($exception, $query),
|
||||
1050 => new TableExistsException($exception, $query),
|
||||
1051,
|
||||
1146 => new TableNotFoundException($exception, $query),
|
||||
1216,
|
||||
1217,
|
||||
1451,
|
||||
1452,
|
||||
1701 => new ForeignKeyConstraintViolationException($exception, $query),
|
||||
1062,
|
||||
1557,
|
||||
1569,
|
||||
1586 => new UniqueConstraintViolationException($exception, $query),
|
||||
1054,
|
||||
1166,
|
||||
1611 => new InvalidFieldNameException($exception, $query),
|
||||
1052,
|
||||
1060,
|
||||
1110 => new NonUniqueFieldNameException($exception, $query),
|
||||
1064,
|
||||
1149,
|
||||
1287,
|
||||
1341,
|
||||
1342,
|
||||
1343,
|
||||
1344,
|
||||
1382,
|
||||
1479,
|
||||
1541,
|
||||
1554,
|
||||
1626 => new SyntaxErrorException($exception, $query),
|
||||
1044,
|
||||
1045,
|
||||
1046,
|
||||
1049,
|
||||
1095,
|
||||
1142,
|
||||
1143,
|
||||
1227,
|
||||
1370,
|
||||
1429,
|
||||
2002,
|
||||
2005,
|
||||
2054 => new ConnectionException($exception, $query),
|
||||
2006,
|
||||
4031 => new ConnectionLost($exception, $query),
|
||||
1048,
|
||||
1121,
|
||||
1138,
|
||||
1171,
|
||||
1252,
|
||||
1263,
|
||||
1364,
|
||||
1566 => new NotNullConstraintViolationException($exception, $query),
|
||||
default => new DriverException($exception, $query),
|
||||
};
|
||||
}
|
||||
}
|
||||
80
backend/vendor/doctrine/dbal/src/Driver/API/OCI/ExceptionConverter.php
vendored
Normal file
80
backend/vendor/doctrine/dbal/src/Driver/API/OCI/ExceptionConverter.php
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\API\OCI;
|
||||
|
||||
use Doctrine\DBAL\Driver\API\ExceptionConverter as ExceptionConverterInterface;
|
||||
use Doctrine\DBAL\Driver\Exception;
|
||||
use Doctrine\DBAL\Driver\OCI8\Exception\Error;
|
||||
use Doctrine\DBAL\Driver\PDO\Exception as DriverPDOException;
|
||||
use Doctrine\DBAL\Exception\ConnectionException;
|
||||
use Doctrine\DBAL\Exception\DatabaseDoesNotExist;
|
||||
use Doctrine\DBAL\Exception\DatabaseObjectNotFoundException;
|
||||
use Doctrine\DBAL\Exception\DriverException;
|
||||
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
|
||||
use Doctrine\DBAL\Exception\InvalidFieldNameException;
|
||||
use Doctrine\DBAL\Exception\NonUniqueFieldNameException;
|
||||
use Doctrine\DBAL\Exception\NotNullConstraintViolationException;
|
||||
use Doctrine\DBAL\Exception\SyntaxErrorException;
|
||||
use Doctrine\DBAL\Exception\TableExistsException;
|
||||
use Doctrine\DBAL\Exception\TableNotFoundException;
|
||||
use Doctrine\DBAL\Exception\TransactionRolledBack;
|
||||
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
||||
use Doctrine\DBAL\Query;
|
||||
|
||||
use function assert;
|
||||
use function count;
|
||||
use function explode;
|
||||
use function str_replace;
|
||||
|
||||
/** @internal */
|
||||
final class ExceptionConverter implements ExceptionConverterInterface
|
||||
{
|
||||
/** @link http://www.dba-oracle.com/t_error_code_list.htm */
|
||||
public function convert(Exception $exception, ?Query $query): DriverException
|
||||
{
|
||||
return match ($exception->getCode()) {
|
||||
1,
|
||||
2299,
|
||||
38911 => new UniqueConstraintViolationException($exception, $query),
|
||||
904 => new InvalidFieldNameException($exception, $query),
|
||||
918,
|
||||
960 => new NonUniqueFieldNameException($exception, $query),
|
||||
923 => new SyntaxErrorException($exception, $query),
|
||||
942 => new TableNotFoundException($exception, $query),
|
||||
955 => new TableExistsException($exception, $query),
|
||||
1017,
|
||||
12545 => new ConnectionException($exception, $query),
|
||||
1400 => new NotNullConstraintViolationException($exception, $query),
|
||||
1918 => new DatabaseDoesNotExist($exception, $query),
|
||||
2091 => (function () use ($exception, $query) {
|
||||
//SQLSTATE[HY000]: General error: 2091 OCITransCommit: ORA-02091: transaction rolled back
|
||||
//ORA-00001: unique constraint (DOCTRINE.GH3423_UNIQUE) violated
|
||||
$lines = explode("\n", $exception->getMessage(), 2);
|
||||
assert(count($lines) >= 2);
|
||||
|
||||
[, $causeError] = $lines;
|
||||
|
||||
[$causeCode] = explode(': ', $causeError, 2);
|
||||
$code = (int) str_replace('ORA-', '', $causeCode);
|
||||
|
||||
$sqlState = $exception->getSQLState();
|
||||
if ($exception instanceof DriverPDOException) {
|
||||
$why = $this->convert(new DriverPDOException($causeError, $sqlState, $code, $exception), $query);
|
||||
} else {
|
||||
$why = $this->convert(new Error($causeError, $sqlState, $code, $exception), $query);
|
||||
}
|
||||
|
||||
return new TransactionRolledBack($why, $query);
|
||||
})(),
|
||||
2289,
|
||||
2443,
|
||||
4080 => new DatabaseObjectNotFoundException($exception, $query),
|
||||
2266,
|
||||
2291,
|
||||
2292 => new ForeignKeyConstraintViolationException($exception, $query),
|
||||
default => new DriverException($exception, $query),
|
||||
};
|
||||
}
|
||||
}
|
||||
87
backend/vendor/doctrine/dbal/src/Driver/API/PostgreSQL/ExceptionConverter.php
vendored
Normal file
87
backend/vendor/doctrine/dbal/src/Driver/API/PostgreSQL/ExceptionConverter.php
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\API\PostgreSQL;
|
||||
|
||||
use Doctrine\DBAL\Driver\API\ExceptionConverter as ExceptionConverterInterface;
|
||||
use Doctrine\DBAL\Driver\Exception;
|
||||
use Doctrine\DBAL\Exception\ConnectionException;
|
||||
use Doctrine\DBAL\Exception\ConnectionLost;
|
||||
use Doctrine\DBAL\Exception\DatabaseDoesNotExist;
|
||||
use Doctrine\DBAL\Exception\DeadlockException;
|
||||
use Doctrine\DBAL\Exception\DriverException;
|
||||
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
|
||||
use Doctrine\DBAL\Exception\InvalidFieldNameException;
|
||||
use Doctrine\DBAL\Exception\NonUniqueFieldNameException;
|
||||
use Doctrine\DBAL\Exception\NotNullConstraintViolationException;
|
||||
use Doctrine\DBAL\Exception\SchemaDoesNotExist;
|
||||
use Doctrine\DBAL\Exception\SyntaxErrorException;
|
||||
use Doctrine\DBAL\Exception\TableExistsException;
|
||||
use Doctrine\DBAL\Exception\TableNotFoundException;
|
||||
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
||||
use Doctrine\DBAL\Query;
|
||||
|
||||
use function str_contains;
|
||||
|
||||
/** @internal */
|
||||
final class ExceptionConverter implements ExceptionConverterInterface
|
||||
{
|
||||
/** @link http://www.postgresql.org/docs/9.4/static/errcodes-appendix.html */
|
||||
public function convert(Exception $exception, ?Query $query): DriverException
|
||||
{
|
||||
switch ($exception->getSQLState()) {
|
||||
case '40001':
|
||||
case '40P01':
|
||||
return new DeadlockException($exception, $query);
|
||||
|
||||
case '0A000':
|
||||
// Foreign key constraint violations during a TRUNCATE operation
|
||||
// are considered "feature not supported" in PostgreSQL.
|
||||
if (str_contains($exception->getMessage(), 'truncate')) {
|
||||
return new ForeignKeyConstraintViolationException($exception, $query);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case '23502':
|
||||
return new NotNullConstraintViolationException($exception, $query);
|
||||
|
||||
case '23503':
|
||||
return new ForeignKeyConstraintViolationException($exception, $query);
|
||||
|
||||
case '23505':
|
||||
return new UniqueConstraintViolationException($exception, $query);
|
||||
|
||||
case '3D000':
|
||||
return new DatabaseDoesNotExist($exception, $query);
|
||||
|
||||
case '3F000':
|
||||
return new SchemaDoesNotExist($exception, $query);
|
||||
|
||||
case '42601':
|
||||
return new SyntaxErrorException($exception, $query);
|
||||
|
||||
case '42702':
|
||||
return new NonUniqueFieldNameException($exception, $query);
|
||||
|
||||
case '42703':
|
||||
return new InvalidFieldNameException($exception, $query);
|
||||
|
||||
case '42P01':
|
||||
return new TableNotFoundException($exception, $query);
|
||||
|
||||
case '42P07':
|
||||
return new TableExistsException($exception, $query);
|
||||
|
||||
case '08006':
|
||||
return new ConnectionException($exception, $query);
|
||||
}
|
||||
|
||||
if (str_contains($exception->getMessage(), 'terminating connection')) {
|
||||
return new ConnectionLost($exception, $query);
|
||||
}
|
||||
|
||||
return new DriverException($exception, $query);
|
||||
}
|
||||
}
|
||||
49
backend/vendor/doctrine/dbal/src/Driver/API/SQLSrv/ExceptionConverter.php
vendored
Normal file
49
backend/vendor/doctrine/dbal/src/Driver/API/SQLSrv/ExceptionConverter.php
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\API\SQLSrv;
|
||||
|
||||
use Doctrine\DBAL\Driver\API\ExceptionConverter as ExceptionConverterInterface;
|
||||
use Doctrine\DBAL\Driver\Exception;
|
||||
use Doctrine\DBAL\Exception\ConnectionException;
|
||||
use Doctrine\DBAL\Exception\DatabaseObjectNotFoundException;
|
||||
use Doctrine\DBAL\Exception\DriverException;
|
||||
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
|
||||
use Doctrine\DBAL\Exception\InvalidFieldNameException;
|
||||
use Doctrine\DBAL\Exception\NonUniqueFieldNameException;
|
||||
use Doctrine\DBAL\Exception\NotNullConstraintViolationException;
|
||||
use Doctrine\DBAL\Exception\SyntaxErrorException;
|
||||
use Doctrine\DBAL\Exception\TableExistsException;
|
||||
use Doctrine\DBAL\Exception\TableNotFoundException;
|
||||
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
||||
use Doctrine\DBAL\Query;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @link https://docs.microsoft.com/en-us/sql/relational-databases/errors-events/database-engine-events-and-errors
|
||||
*/
|
||||
final class ExceptionConverter implements ExceptionConverterInterface
|
||||
{
|
||||
public function convert(Exception $exception, ?Query $query): DriverException
|
||||
{
|
||||
return match ($exception->getCode()) {
|
||||
102 => new SyntaxErrorException($exception, $query),
|
||||
207 => new InvalidFieldNameException($exception, $query),
|
||||
208 => new TableNotFoundException($exception, $query),
|
||||
209 => new NonUniqueFieldNameException($exception, $query),
|
||||
515 => new NotNullConstraintViolationException($exception, $query),
|
||||
547,
|
||||
4712 => new ForeignKeyConstraintViolationException($exception, $query),
|
||||
2601,
|
||||
2627 => new UniqueConstraintViolationException($exception, $query),
|
||||
2714 => new TableExistsException($exception, $query),
|
||||
3701,
|
||||
15151 => new DatabaseObjectNotFoundException($exception, $query),
|
||||
11001,
|
||||
18456 => new ConnectionException($exception, $query),
|
||||
default => new DriverException($exception, $query),
|
||||
};
|
||||
}
|
||||
}
|
||||
85
backend/vendor/doctrine/dbal/src/Driver/API/SQLite/ExceptionConverter.php
vendored
Normal file
85
backend/vendor/doctrine/dbal/src/Driver/API/SQLite/ExceptionConverter.php
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\API\SQLite;
|
||||
|
||||
use Doctrine\DBAL\Driver\API\ExceptionConverter as ExceptionConverterInterface;
|
||||
use Doctrine\DBAL\Driver\Exception;
|
||||
use Doctrine\DBAL\Exception\ConnectionException;
|
||||
use Doctrine\DBAL\Exception\DriverException;
|
||||
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
|
||||
use Doctrine\DBAL\Exception\InvalidFieldNameException;
|
||||
use Doctrine\DBAL\Exception\LockWaitTimeoutException;
|
||||
use Doctrine\DBAL\Exception\NonUniqueFieldNameException;
|
||||
use Doctrine\DBAL\Exception\NotNullConstraintViolationException;
|
||||
use Doctrine\DBAL\Exception\ReadOnlyException;
|
||||
use Doctrine\DBAL\Exception\SyntaxErrorException;
|
||||
use Doctrine\DBAL\Exception\TableExistsException;
|
||||
use Doctrine\DBAL\Exception\TableNotFoundException;
|
||||
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
||||
use Doctrine\DBAL\Query;
|
||||
|
||||
use function str_contains;
|
||||
|
||||
/** @internal */
|
||||
final class ExceptionConverter implements ExceptionConverterInterface
|
||||
{
|
||||
/** @link http://www.sqlite.org/c3ref/c_abort.html */
|
||||
public function convert(Exception $exception, ?Query $query): DriverException
|
||||
{
|
||||
if (str_contains($exception->getMessage(), 'database is locked')) {
|
||||
return new LockWaitTimeoutException($exception, $query);
|
||||
}
|
||||
|
||||
if (
|
||||
str_contains($exception->getMessage(), 'must be unique') ||
|
||||
str_contains($exception->getMessage(), 'is not unique') ||
|
||||
str_contains($exception->getMessage(), 'are not unique') ||
|
||||
str_contains($exception->getMessage(), 'UNIQUE constraint failed')
|
||||
) {
|
||||
return new UniqueConstraintViolationException($exception, $query);
|
||||
}
|
||||
|
||||
if (
|
||||
str_contains($exception->getMessage(), 'may not be NULL') ||
|
||||
str_contains($exception->getMessage(), 'NOT NULL constraint failed')
|
||||
) {
|
||||
return new NotNullConstraintViolationException($exception, $query);
|
||||
}
|
||||
|
||||
if (str_contains($exception->getMessage(), 'no such table:')) {
|
||||
return new TableNotFoundException($exception, $query);
|
||||
}
|
||||
|
||||
if (str_contains($exception->getMessage(), 'already exists')) {
|
||||
return new TableExistsException($exception, $query);
|
||||
}
|
||||
|
||||
if (str_contains($exception->getMessage(), 'has no column named')) {
|
||||
return new InvalidFieldNameException($exception, $query);
|
||||
}
|
||||
|
||||
if (str_contains($exception->getMessage(), 'ambiguous column name')) {
|
||||
return new NonUniqueFieldNameException($exception, $query);
|
||||
}
|
||||
|
||||
if (str_contains($exception->getMessage(), 'syntax error')) {
|
||||
return new SyntaxErrorException($exception, $query);
|
||||
}
|
||||
|
||||
if (str_contains($exception->getMessage(), 'attempt to write a readonly database')) {
|
||||
return new ReadOnlyException($exception, $query);
|
||||
}
|
||||
|
||||
if (str_contains($exception->getMessage(), 'unable to open database file')) {
|
||||
return new ConnectionException($exception, $query);
|
||||
}
|
||||
|
||||
if (str_contains($exception->getMessage(), 'FOREIGN KEY constraint failed')) {
|
||||
return new ForeignKeyConstraintViolationException($exception, $query);
|
||||
}
|
||||
|
||||
return new DriverException($exception, $query);
|
||||
}
|
||||
}
|
||||
27
backend/vendor/doctrine/dbal/src/Driver/AbstractDB2Driver.php
vendored
Normal file
27
backend/vendor/doctrine/dbal/src/Driver/AbstractDB2Driver.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver;
|
||||
|
||||
use Doctrine\DBAL\Driver;
|
||||
use Doctrine\DBAL\Driver\API\ExceptionConverter as ExceptionConverterInterface;
|
||||
use Doctrine\DBAL\Driver\API\IBMDB2\ExceptionConverter;
|
||||
use Doctrine\DBAL\Platforms\DB2Platform;
|
||||
use Doctrine\DBAL\ServerVersionProvider;
|
||||
|
||||
/**
|
||||
* Abstract base implementation of the {@see Driver} interface for IBM DB2 based drivers.
|
||||
*/
|
||||
abstract class AbstractDB2Driver implements Driver
|
||||
{
|
||||
public function getDatabasePlatform(ServerVersionProvider $versionProvider): DB2Platform
|
||||
{
|
||||
return new DB2Platform();
|
||||
}
|
||||
|
||||
public function getExceptionConverter(): ExceptionConverterInterface
|
||||
{
|
||||
return new ExceptionConverter();
|
||||
}
|
||||
}
|
||||
34
backend/vendor/doctrine/dbal/src/Driver/AbstractException.php
vendored
Normal file
34
backend/vendor/doctrine/dbal/src/Driver/AbstractException.php
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver;
|
||||
|
||||
use Exception as BaseException;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Abstract base implementation of the {@see DriverException} interface.
|
||||
*/
|
||||
abstract class AbstractException extends BaseException implements Exception
|
||||
{
|
||||
/**
|
||||
* @param string $message The driver error message.
|
||||
* @param string|null $sqlState The SQLSTATE the driver is in at the time the error occurred, if any.
|
||||
* @param int $code The driver specific error code if any.
|
||||
* @param Throwable|null $previous The previous throwable used for the exception chaining.
|
||||
*/
|
||||
public function __construct(
|
||||
string $message,
|
||||
private readonly ?string $sqlState = null,
|
||||
int $code = 0,
|
||||
?Throwable $previous = null,
|
||||
) {
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
public function getSQLState(): ?string
|
||||
{
|
||||
return $this->sqlState;
|
||||
}
|
||||
}
|
||||
109
backend/vendor/doctrine/dbal/src/Driver/AbstractMySQLDriver.php
vendored
Normal file
109
backend/vendor/doctrine/dbal/src/Driver/AbstractMySQLDriver.php
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver;
|
||||
|
||||
use Doctrine\DBAL\Driver;
|
||||
use Doctrine\DBAL\Driver\API\ExceptionConverter as ExceptionConverterInterface;
|
||||
use Doctrine\DBAL\Driver\API\MySQL\ExceptionConverter;
|
||||
use Doctrine\DBAL\Platforms\AbstractMySQLPlatform;
|
||||
use Doctrine\DBAL\Platforms\Exception\InvalidPlatformVersion;
|
||||
use Doctrine\DBAL\Platforms\MariaDB1010Platform;
|
||||
use Doctrine\DBAL\Platforms\MariaDB1052Platform;
|
||||
use Doctrine\DBAL\Platforms\MariaDB1060Platform;
|
||||
use Doctrine\DBAL\Platforms\MariaDBPlatform;
|
||||
use Doctrine\DBAL\Platforms\MySQL80Platform;
|
||||
use Doctrine\DBAL\Platforms\MySQL84Platform;
|
||||
use Doctrine\DBAL\Platforms\MySQLPlatform;
|
||||
use Doctrine\DBAL\ServerVersionProvider;
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
|
||||
use function preg_match;
|
||||
use function stripos;
|
||||
use function version_compare;
|
||||
|
||||
/**
|
||||
* Abstract base implementation of the {@see Driver} interface for MySQL based drivers.
|
||||
*/
|
||||
abstract class AbstractMySQLDriver implements Driver
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws InvalidPlatformVersion
|
||||
*/
|
||||
public function getDatabasePlatform(ServerVersionProvider $versionProvider): AbstractMySQLPlatform
|
||||
{
|
||||
$version = $versionProvider->getServerVersion();
|
||||
if (stripos($version, 'mariadb') !== false) {
|
||||
$mariaDbVersion = $this->getMariaDbMysqlVersionNumber($version);
|
||||
if (version_compare($mariaDbVersion, '10.10.0', '>=')) {
|
||||
return new MariaDB1010Platform();
|
||||
}
|
||||
|
||||
if (version_compare($mariaDbVersion, '10.6.0', '>=')) {
|
||||
return new MariaDB1060Platform();
|
||||
}
|
||||
|
||||
if (version_compare($mariaDbVersion, '10.5.2', '>=')) {
|
||||
return new MariaDB1052Platform();
|
||||
}
|
||||
|
||||
Deprecation::trigger(
|
||||
'doctrine/dbal',
|
||||
'https://github.com/doctrine/dbal/pull/6343',
|
||||
'Support for MariaDB < 10.5.2 is deprecated and will be removed in DBAL 5',
|
||||
);
|
||||
|
||||
return new MariaDBPlatform();
|
||||
}
|
||||
|
||||
if (version_compare($version, '8.4.0', '>=')) {
|
||||
return new MySQL84Platform();
|
||||
}
|
||||
|
||||
if (version_compare($version, '8.0.0', '>=')) {
|
||||
return new MySQL80Platform();
|
||||
}
|
||||
|
||||
Deprecation::trigger(
|
||||
'doctrine/dbal',
|
||||
'https://github.com/doctrine/dbal/pull/6343',
|
||||
'Support for MySQL < 8 is deprecated and will be removed in DBAL 5',
|
||||
);
|
||||
|
||||
return new MySQLPlatform();
|
||||
}
|
||||
|
||||
public function getExceptionConverter(): ExceptionConverterInterface
|
||||
{
|
||||
return new ExceptionConverter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect MariaDB server version, including hack for some mariadb distributions
|
||||
* that starts with the prefix '5.5.5-'
|
||||
*
|
||||
* @param string $versionString Version string as returned by mariadb server, i.e. '5.5.5-Mariadb-10.0.8-xenial'
|
||||
*
|
||||
* @throws InvalidPlatformVersion
|
||||
*/
|
||||
private function getMariaDbMysqlVersionNumber(string $versionString): string
|
||||
{
|
||||
if (
|
||||
preg_match(
|
||||
'/^(?:5\.5\.5-)?(mariadb-)?(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)/i',
|
||||
$versionString,
|
||||
$versionParts,
|
||||
) !== 1
|
||||
) {
|
||||
throw InvalidPlatformVersion::new(
|
||||
$versionString,
|
||||
'^(?:5\.5\.5-)?(mariadb-)?<major_version>.<minor_version>.<patch_version>',
|
||||
);
|
||||
}
|
||||
|
||||
return $versionParts['major'] . '.' . $versionParts['minor'] . '.' . $versionParts['patch'];
|
||||
}
|
||||
}
|
||||
38
backend/vendor/doctrine/dbal/src/Driver/AbstractOracleDriver.php
vendored
Normal file
38
backend/vendor/doctrine/dbal/src/Driver/AbstractOracleDriver.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver;
|
||||
|
||||
use Doctrine\DBAL\Driver;
|
||||
use Doctrine\DBAL\Driver\AbstractOracleDriver\EasyConnectString;
|
||||
use Doctrine\DBAL\Driver\API\ExceptionConverter as ExceptionConverterInterface;
|
||||
use Doctrine\DBAL\Driver\API\OCI\ExceptionConverter;
|
||||
use Doctrine\DBAL\Platforms\OraclePlatform;
|
||||
use Doctrine\DBAL\ServerVersionProvider;
|
||||
|
||||
/**
|
||||
* Abstract base implementation of the {@see Driver} interface for Oracle based drivers.
|
||||
*/
|
||||
abstract class AbstractOracleDriver implements Driver
|
||||
{
|
||||
public function getDatabasePlatform(ServerVersionProvider $versionProvider): OraclePlatform
|
||||
{
|
||||
return new OraclePlatform();
|
||||
}
|
||||
|
||||
public function getExceptionConverter(): ExceptionConverterInterface
|
||||
{
|
||||
return new ExceptionConverter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an appropriate Easy Connect String for the given parameters.
|
||||
*
|
||||
* @param array<string, mixed> $params The connection parameters to return the Easy Connect String for.
|
||||
*/
|
||||
protected function getEasyConnectString(array $params): string
|
||||
{
|
||||
return (string) EasyConnectString::fromConnectionParameters($params);
|
||||
}
|
||||
}
|
||||
112
backend/vendor/doctrine/dbal/src/Driver/AbstractOracleDriver/EasyConnectString.php
vendored
Normal file
112
backend/vendor/doctrine/dbal/src/Driver/AbstractOracleDriver/EasyConnectString.php
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\AbstractOracleDriver;
|
||||
|
||||
use function implode;
|
||||
use function is_array;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Represents an Oracle Easy Connect string
|
||||
*
|
||||
* @link https://docs.oracle.com/database/121/NETAG/naming.htm
|
||||
*/
|
||||
final class EasyConnectString
|
||||
{
|
||||
private function __construct(private readonly string $string)
|
||||
{
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the object from an array representation
|
||||
*
|
||||
* @param mixed[] $params
|
||||
*/
|
||||
public static function fromArray(array $params): self
|
||||
{
|
||||
return new self(self::renderParams($params));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the object from the given DBAL connection parameters.
|
||||
*
|
||||
* @param mixed[] $params
|
||||
*/
|
||||
public static function fromConnectionParameters(array $params): self
|
||||
{
|
||||
if (isset($params['connectstring'])) {
|
||||
return new self($params['connectstring']);
|
||||
}
|
||||
|
||||
if (! isset($params['host'])) {
|
||||
return new self($params['dbname'] ?? '');
|
||||
}
|
||||
|
||||
$connectData = [];
|
||||
|
||||
if (isset($params['servicename']) || isset($params['dbname'])) {
|
||||
$serviceKey = 'SID';
|
||||
|
||||
if (isset($params['service'])) {
|
||||
$serviceKey = 'SERVICE_NAME';
|
||||
}
|
||||
|
||||
$serviceName = $params['servicename'] ?? $params['dbname'];
|
||||
|
||||
$connectData[$serviceKey] = $serviceName;
|
||||
}
|
||||
|
||||
if (isset($params['instancename'])) {
|
||||
$connectData['INSTANCE_NAME'] = $params['instancename'];
|
||||
}
|
||||
|
||||
if (! empty($params['pooled'])) {
|
||||
$connectData['SERVER'] = 'POOLED';
|
||||
}
|
||||
|
||||
return self::fromArray([
|
||||
'DESCRIPTION' => [
|
||||
'ADDRESS' => [
|
||||
'PROTOCOL' => $params['driverOptions']['protocol'] ?? 'TCP',
|
||||
'HOST' => $params['host'],
|
||||
'PORT' => $params['port'] ?? 1521,
|
||||
],
|
||||
'CONNECT_DATA' => $connectData,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/** @param mixed[] $params */
|
||||
private static function renderParams(array $params): string
|
||||
{
|
||||
$chunks = [];
|
||||
|
||||
foreach ($params as $key => $value) {
|
||||
$string = self::renderValue($value);
|
||||
|
||||
if ($string === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$chunks[] = sprintf('(%s=%s)', $key, $string);
|
||||
}
|
||||
|
||||
return implode('', $chunks);
|
||||
}
|
||||
|
||||
private static function renderValue(mixed $value): string
|
||||
{
|
||||
if (is_array($value)) {
|
||||
return self::renderParams($value);
|
||||
}
|
||||
|
||||
return (string) $value;
|
||||
}
|
||||
}
|
||||
57
backend/vendor/doctrine/dbal/src/Driver/AbstractPostgreSQLDriver.php
vendored
Normal file
57
backend/vendor/doctrine/dbal/src/Driver/AbstractPostgreSQLDriver.php
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver;
|
||||
|
||||
use Doctrine\DBAL\Driver;
|
||||
use Doctrine\DBAL\Driver\API\ExceptionConverter as ExceptionConverterInterface;
|
||||
use Doctrine\DBAL\Driver\API\PostgreSQL\ExceptionConverter;
|
||||
use Doctrine\DBAL\Platforms\Exception\InvalidPlatformVersion;
|
||||
use Doctrine\DBAL\Platforms\PostgreSQL120Platform;
|
||||
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
|
||||
use Doctrine\DBAL\ServerVersionProvider;
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
|
||||
use function preg_match;
|
||||
use function version_compare;
|
||||
|
||||
/**
|
||||
* Abstract base implementation of the {@see Driver} interface for PostgreSQL based drivers.
|
||||
*/
|
||||
abstract class AbstractPostgreSQLDriver implements Driver
|
||||
{
|
||||
public function getDatabasePlatform(ServerVersionProvider $versionProvider): PostgreSQLPlatform
|
||||
{
|
||||
$version = $versionProvider->getServerVersion();
|
||||
|
||||
if (preg_match('/^(?P<major>\d+)(?:\.(?P<minor>\d+)(?:\.(?P<patch>\d+))?)?/', $version, $versionParts) !== 1) {
|
||||
throw InvalidPlatformVersion::new(
|
||||
$version,
|
||||
'<major_version>.<minor_version>.<patch_version>',
|
||||
);
|
||||
}
|
||||
|
||||
$majorVersion = $versionParts['major'];
|
||||
$minorVersion = $versionParts['minor'] ?? 0;
|
||||
$patchVersion = $versionParts['patch'] ?? 0;
|
||||
$version = $majorVersion . '.' . $minorVersion . '.' . $patchVersion;
|
||||
|
||||
if (version_compare($version, '12.0', '>=')) {
|
||||
return new PostgreSQL120Platform();
|
||||
}
|
||||
|
||||
Deprecation::trigger(
|
||||
'doctrine/dbal',
|
||||
'https://github.com/doctrine/dbal/pull/6495',
|
||||
'Support for Postgres < 12 is deprecated and will be removed in DBAL 5',
|
||||
);
|
||||
|
||||
return new PostgreSQLPlatform();
|
||||
}
|
||||
|
||||
public function getExceptionConverter(): ExceptionConverterInterface
|
||||
{
|
||||
return new ExceptionConverter();
|
||||
}
|
||||
}
|
||||
27
backend/vendor/doctrine/dbal/src/Driver/AbstractSQLServerDriver.php
vendored
Normal file
27
backend/vendor/doctrine/dbal/src/Driver/AbstractSQLServerDriver.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver;
|
||||
|
||||
use Doctrine\DBAL\Driver;
|
||||
use Doctrine\DBAL\Driver\API\ExceptionConverter as ExceptionConverterInterface;
|
||||
use Doctrine\DBAL\Driver\API\SQLSrv\ExceptionConverter;
|
||||
use Doctrine\DBAL\Platforms\SQLServerPlatform;
|
||||
use Doctrine\DBAL\ServerVersionProvider;
|
||||
|
||||
/**
|
||||
* Abstract base implementation of the {@see Driver} interface for Microsoft SQL Server based drivers.
|
||||
*/
|
||||
abstract class AbstractSQLServerDriver implements Driver
|
||||
{
|
||||
public function getDatabasePlatform(ServerVersionProvider $versionProvider): SQLServerPlatform
|
||||
{
|
||||
return new SQLServerPlatform();
|
||||
}
|
||||
|
||||
public function getExceptionConverter(): ExceptionConverterInterface
|
||||
{
|
||||
return new ExceptionConverter();
|
||||
}
|
||||
}
|
||||
16
backend/vendor/doctrine/dbal/src/Driver/AbstractSQLServerDriver/Exception/PortWithoutHost.php
vendored
Normal file
16
backend/vendor/doctrine/dbal/src/Driver/AbstractSQLServerDriver/Exception/PortWithoutHost.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\AbstractSQLServerDriver\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
|
||||
/** @internal */
|
||||
final class PortWithoutHost extends AbstractException
|
||||
{
|
||||
public static function new(): self
|
||||
{
|
||||
return new self('Connection port specified without the host');
|
||||
}
|
||||
}
|
||||
27
backend/vendor/doctrine/dbal/src/Driver/AbstractSQLiteDriver.php
vendored
Normal file
27
backend/vendor/doctrine/dbal/src/Driver/AbstractSQLiteDriver.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver;
|
||||
|
||||
use Doctrine\DBAL\Driver;
|
||||
use Doctrine\DBAL\Driver\API\ExceptionConverter as ExceptionConverterInterface;
|
||||
use Doctrine\DBAL\Driver\API\SQLite\ExceptionConverter;
|
||||
use Doctrine\DBAL\Platforms\SQLitePlatform;
|
||||
use Doctrine\DBAL\ServerVersionProvider;
|
||||
|
||||
/**
|
||||
* Abstract base implementation of the {@see Driver} interface for SQLite based drivers.
|
||||
*/
|
||||
abstract class AbstractSQLiteDriver implements Driver
|
||||
{
|
||||
public function getDatabasePlatform(ServerVersionProvider $versionProvider): SQLitePlatform
|
||||
{
|
||||
return new SQLitePlatform();
|
||||
}
|
||||
|
||||
public function getExceptionConverter(): ExceptionConverterInterface
|
||||
{
|
||||
return new ExceptionConverter();
|
||||
}
|
||||
}
|
||||
33
backend/vendor/doctrine/dbal/src/Driver/AbstractSQLiteDriver/Middleware/EnableForeignKeys.php
vendored
Normal file
33
backend/vendor/doctrine/dbal/src/Driver/AbstractSQLiteDriver/Middleware/EnableForeignKeys.php
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\AbstractSQLiteDriver\Middleware;
|
||||
|
||||
use Doctrine\DBAL\Driver;
|
||||
use Doctrine\DBAL\Driver\Connection;
|
||||
use Doctrine\DBAL\Driver\Middleware;
|
||||
use Doctrine\DBAL\Driver\Middleware\AbstractDriverMiddleware;
|
||||
use SensitiveParameter;
|
||||
|
||||
final class EnableForeignKeys implements Middleware
|
||||
{
|
||||
public function wrap(Driver $driver): Driver
|
||||
{
|
||||
return new class ($driver) extends AbstractDriverMiddleware {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function connect(
|
||||
#[SensitiveParameter]
|
||||
array $params,
|
||||
): Connection {
|
||||
$connection = parent::connect($params);
|
||||
|
||||
$connection->exec('PRAGMA foreign_keys=ON');
|
||||
|
||||
return $connection;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
93
backend/vendor/doctrine/dbal/src/Driver/Connection.php
vendored
Normal file
93
backend/vendor/doctrine/dbal/src/Driver/Connection.php
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver;
|
||||
|
||||
use Doctrine\DBAL\ServerVersionProvider;
|
||||
|
||||
/**
|
||||
* Connection interface.
|
||||
* Driver connections must implement this interface.
|
||||
*/
|
||||
interface Connection extends ServerVersionProvider
|
||||
{
|
||||
/**
|
||||
* Prepares a statement for execution and returns a Statement object.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function prepare(string $sql): Statement;
|
||||
|
||||
/**
|
||||
* Executes an SQL statement, returning a result set as a Statement object.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function query(string $sql): Result;
|
||||
|
||||
/**
|
||||
* Quotes a string for use in a query.
|
||||
*
|
||||
* The usage of this method is discouraged. Use prepared statements
|
||||
* or {@see AbstractPlatform::quoteStringLiteral()} instead.
|
||||
*/
|
||||
public function quote(string $value): string;
|
||||
|
||||
/**
|
||||
* Executes an SQL statement and return the number of affected rows.
|
||||
* If the number of affected rows is greater than the maximum int value (PHP_INT_MAX),
|
||||
* the number of affected rows may be returned as a string.
|
||||
*
|
||||
* @return int|numeric-string
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function exec(string $sql): int|string;
|
||||
|
||||
/**
|
||||
* Returns the ID of the last inserted row.
|
||||
*
|
||||
* This method returns an integer or a string representing the value of the auto-increment column
|
||||
* from the last row inserted into the database, if any, or throws an exception if a value cannot be returned,
|
||||
* in particular when:
|
||||
*
|
||||
* - the driver does not support identity columns;
|
||||
* - the last statement dit not return an identity (caution: see note below).
|
||||
*
|
||||
* Note: if the last statement was not an INSERT to an autoincrement column, this method MAY return an ID from a
|
||||
* previous statement. DO NOT RELY ON THIS BEHAVIOR which is driver-dependent: always call this method right after
|
||||
* executing an INSERT statement.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function lastInsertId(): int|string;
|
||||
|
||||
/**
|
||||
* Initiates a transaction.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function beginTransaction(): void;
|
||||
|
||||
/**
|
||||
* Commits a transaction.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function commit(): void;
|
||||
|
||||
/**
|
||||
* Rolls back the current transaction, as initiated by beginTransaction().
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function rollBack(): void;
|
||||
|
||||
/**
|
||||
* Provides access to the native database connection.
|
||||
*
|
||||
* @return resource|object
|
||||
*/
|
||||
public function getNativeConnection();
|
||||
}
|
||||
23
backend/vendor/doctrine/dbal/src/Driver/Exception.php
vendored
Normal file
23
backend/vendor/doctrine/dbal/src/Driver/Exception.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver;
|
||||
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Contract for a driver exception.
|
||||
*
|
||||
* Driver exceptions provide the SQLSTATE of the driver
|
||||
* and the driver specific error code at the time the error occurred.
|
||||
*/
|
||||
interface Exception extends Throwable
|
||||
{
|
||||
/**
|
||||
* Returns the SQLSTATE the driver was in at the time the error occurred.
|
||||
*
|
||||
* Returns null if the driver does not provide a SQLSTATE for the error occurred.
|
||||
*/
|
||||
public function getSQLState(): ?string;
|
||||
}
|
||||
17
backend/vendor/doctrine/dbal/src/Driver/Exception/IdentityColumnsNotSupported.php
vendored
Normal file
17
backend/vendor/doctrine/dbal/src/Driver/Exception/IdentityColumnsNotSupported.php
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
use Throwable;
|
||||
|
||||
/** @internal */
|
||||
final class IdentityColumnsNotSupported extends AbstractException
|
||||
{
|
||||
public static function new(?Throwable $previous = null): self
|
||||
{
|
||||
return new self('The driver does not support identity columns.', null, 0, $previous);
|
||||
}
|
||||
}
|
||||
17
backend/vendor/doctrine/dbal/src/Driver/Exception/NoIdentityValue.php
vendored
Normal file
17
backend/vendor/doctrine/dbal/src/Driver/Exception/NoIdentityValue.php
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
use Throwable;
|
||||
|
||||
/** @internal */
|
||||
final class NoIdentityValue extends AbstractException
|
||||
{
|
||||
public static function new(?Throwable $previous = null): self
|
||||
{
|
||||
return new self('No identity value was generated by the last statement.', null, 0, $previous);
|
||||
}
|
||||
}
|
||||
69
backend/vendor/doctrine/dbal/src/Driver/FetchUtils.php
vendored
Normal file
69
backend/vendor/doctrine/dbal/src/Driver/FetchUtils.php
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver;
|
||||
|
||||
/** @internal */
|
||||
final class FetchUtils
|
||||
{
|
||||
/** @throws Exception */
|
||||
public static function fetchOne(Result $result): mixed
|
||||
{
|
||||
$row = $result->fetchNumeric();
|
||||
|
||||
if ($row === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $row[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<list<mixed>>
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function fetchAllNumeric(Result $result): array
|
||||
{
|
||||
$rows = [];
|
||||
|
||||
while (($row = $result->fetchNumeric()) !== false) {
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array<string,mixed>>
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function fetchAllAssociative(Result $result): array
|
||||
{
|
||||
$rows = [];
|
||||
|
||||
while (($row = $result->fetchAssociative()) !== false) {
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<mixed>
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function fetchFirstColumn(Result $result): array
|
||||
{
|
||||
$rows = [];
|
||||
|
||||
while (($row = $result->fetchOne()) !== false) {
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
}
|
||||
131
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/Connection.php
vendored
Normal file
131
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/Connection.php
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\IBMDB2;
|
||||
|
||||
use Doctrine\DBAL\Driver\Connection as ConnectionInterface;
|
||||
use Doctrine\DBAL\Driver\Exception\NoIdentityValue;
|
||||
use Doctrine\DBAL\Driver\IBMDB2\Exception\ConnectionError;
|
||||
use Doctrine\DBAL\Driver\IBMDB2\Exception\PrepareFailed;
|
||||
use Doctrine\DBAL\Driver\IBMDB2\Exception\StatementError;
|
||||
use stdClass;
|
||||
|
||||
use function assert;
|
||||
use function db2_autocommit;
|
||||
use function db2_commit;
|
||||
use function db2_escape_string;
|
||||
use function db2_exec;
|
||||
use function db2_last_insert_id;
|
||||
use function db2_num_rows;
|
||||
use function db2_prepare;
|
||||
use function db2_rollback;
|
||||
use function db2_server_info;
|
||||
use function error_get_last;
|
||||
|
||||
use const DB2_AUTOCOMMIT_OFF;
|
||||
use const DB2_AUTOCOMMIT_ON;
|
||||
|
||||
final class Connection implements ConnectionInterface
|
||||
{
|
||||
/**
|
||||
* @internal The connection can be only instantiated by its driver.
|
||||
*
|
||||
* @param resource $connection
|
||||
*/
|
||||
public function __construct(private readonly mixed $connection)
|
||||
{
|
||||
}
|
||||
|
||||
public function getServerVersion(): string
|
||||
{
|
||||
$serverInfo = db2_server_info($this->connection);
|
||||
assert($serverInfo instanceof stdClass);
|
||||
|
||||
return $serverInfo->DBMS_VER;
|
||||
}
|
||||
|
||||
public function prepare(string $sql): Statement
|
||||
{
|
||||
$stmt = @db2_prepare($this->connection, $sql);
|
||||
|
||||
if ($stmt === false) {
|
||||
throw PrepareFailed::new(error_get_last());
|
||||
}
|
||||
|
||||
return new Statement($stmt);
|
||||
}
|
||||
|
||||
public function query(string $sql): Result
|
||||
{
|
||||
return $this->prepare($sql)->execute();
|
||||
}
|
||||
|
||||
public function quote(string $value): string
|
||||
{
|
||||
return "'" . db2_escape_string($value) . "'";
|
||||
}
|
||||
|
||||
public function exec(string $sql): int|string
|
||||
{
|
||||
$stmt = @db2_exec($this->connection, $sql);
|
||||
|
||||
if ($stmt === false) {
|
||||
throw StatementError::new();
|
||||
}
|
||||
|
||||
$numRows = db2_num_rows($stmt);
|
||||
|
||||
if ($numRows === false) {
|
||||
throw StatementError::new();
|
||||
}
|
||||
|
||||
return $numRows;
|
||||
}
|
||||
|
||||
public function lastInsertId(): string
|
||||
{
|
||||
$lastInsertId = db2_last_insert_id($this->connection);
|
||||
|
||||
if ($lastInsertId === null) {
|
||||
throw NoIdentityValue::new();
|
||||
}
|
||||
|
||||
return $lastInsertId;
|
||||
}
|
||||
|
||||
public function beginTransaction(): void
|
||||
{
|
||||
if (db2_autocommit($this->connection, DB2_AUTOCOMMIT_OFF) !== true) {
|
||||
throw ConnectionError::new($this->connection);
|
||||
}
|
||||
}
|
||||
|
||||
public function commit(): void
|
||||
{
|
||||
if (! db2_commit($this->connection)) {
|
||||
throw ConnectionError::new($this->connection);
|
||||
}
|
||||
|
||||
if (db2_autocommit($this->connection, DB2_AUTOCOMMIT_ON) !== true) {
|
||||
throw ConnectionError::new($this->connection);
|
||||
}
|
||||
}
|
||||
|
||||
public function rollBack(): void
|
||||
{
|
||||
if (! db2_rollback($this->connection)) {
|
||||
throw ConnectionError::new($this->connection);
|
||||
}
|
||||
|
||||
if (db2_autocommit($this->connection, DB2_AUTOCOMMIT_ON) !== true) {
|
||||
throw ConnectionError::new($this->connection);
|
||||
}
|
||||
}
|
||||
|
||||
/** @return resource */
|
||||
public function getNativeConnection()
|
||||
{
|
||||
return $this->connection;
|
||||
}
|
||||
}
|
||||
80
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/DataSourceName.php
vendored
Normal file
80
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/DataSourceName.php
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\IBMDB2;
|
||||
|
||||
use SensitiveParameter;
|
||||
|
||||
use function implode;
|
||||
use function sprintf;
|
||||
use function str_contains;
|
||||
|
||||
/**
|
||||
* IBM DB2 DSN
|
||||
*/
|
||||
final class DataSourceName
|
||||
{
|
||||
private function __construct(
|
||||
#[SensitiveParameter]
|
||||
private readonly string $string,
|
||||
) {
|
||||
}
|
||||
|
||||
public function toString(): string
|
||||
{
|
||||
return $this->string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the object from an array representation
|
||||
*
|
||||
* @param array<string,mixed> $params
|
||||
*/
|
||||
public static function fromArray(
|
||||
#[SensitiveParameter]
|
||||
array $params,
|
||||
): self {
|
||||
$chunks = [];
|
||||
|
||||
foreach ($params as $key => $value) {
|
||||
$chunks[] = sprintf('%s=%s', $key, $value);
|
||||
}
|
||||
|
||||
return new self(implode(';', $chunks));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the object from the given DBAL connection parameters.
|
||||
*
|
||||
* @param array<string,mixed> $params
|
||||
*/
|
||||
public static function fromConnectionParameters(#[SensitiveParameter]
|
||||
array $params,): self
|
||||
{
|
||||
if (isset($params['dbname']) && str_contains($params['dbname'], '=')) {
|
||||
return new self($params['dbname']);
|
||||
}
|
||||
|
||||
$dsnParams = [];
|
||||
|
||||
foreach (
|
||||
[
|
||||
'host' => 'HOSTNAME',
|
||||
'port' => 'PORT',
|
||||
'protocol' => 'PROTOCOL',
|
||||
'dbname' => 'DATABASE',
|
||||
'user' => 'UID',
|
||||
'password' => 'PWD',
|
||||
] as $dbalParam => $dsnParam
|
||||
) {
|
||||
if (! isset($params[$dbalParam])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$dsnParams[$dsnParam] = $params[$dbalParam];
|
||||
}
|
||||
|
||||
return self::fromArray($dsnParams);
|
||||
}
|
||||
}
|
||||
41
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/Driver.php
vendored
Normal file
41
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/Driver.php
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\IBMDB2;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractDB2Driver;
|
||||
use Doctrine\DBAL\Driver\IBMDB2\Exception\ConnectionFailed;
|
||||
use SensitiveParameter;
|
||||
|
||||
use function db2_connect;
|
||||
use function db2_pconnect;
|
||||
|
||||
final class Driver extends AbstractDB2Driver
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function connect(
|
||||
#[SensitiveParameter]
|
||||
array $params,
|
||||
): Connection {
|
||||
$dataSourceName = DataSourceName::fromConnectionParameters($params)->toString();
|
||||
|
||||
$username = $params['user'] ?? '';
|
||||
$password = $params['password'] ?? '';
|
||||
$driverOptions = $params['driverOptions'] ?? [];
|
||||
|
||||
if (! empty($params['persistent'])) {
|
||||
$connection = db2_pconnect($dataSourceName, $username, $password, $driverOptions);
|
||||
} else {
|
||||
$connection = db2_connect($dataSourceName, $username, $password, $driverOptions);
|
||||
}
|
||||
|
||||
if ($connection === false) {
|
||||
throw ConnectionFailed::new();
|
||||
}
|
||||
|
||||
return new Connection($connection);
|
||||
}
|
||||
}
|
||||
23
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/CannotCopyStreamToStream.php
vendored
Normal file
23
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/CannotCopyStreamToStream.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\IBMDB2\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
|
||||
/** @internal */
|
||||
final class CannotCopyStreamToStream extends AbstractException
|
||||
{
|
||||
/** @phpstan-param array{message: string, ...}|null $error */
|
||||
public static function new(?array $error): self
|
||||
{
|
||||
$message = 'Could not copy source stream to temporary file';
|
||||
|
||||
if ($error !== null) {
|
||||
$message .= ': ' . $error['message'];
|
||||
}
|
||||
|
||||
return new self($message);
|
||||
}
|
||||
}
|
||||
23
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/CannotCreateTemporaryFile.php
vendored
Normal file
23
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/CannotCreateTemporaryFile.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\IBMDB2\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
|
||||
/** @internal */
|
||||
final class CannotCreateTemporaryFile extends AbstractException
|
||||
{
|
||||
/** @phpstan-param array{message: string, ...}|null $error */
|
||||
public static function new(?array $error): self
|
||||
{
|
||||
$message = 'Could not create temporary file';
|
||||
|
||||
if ($error !== null) {
|
||||
$message .= ': ' . $error['message'];
|
||||
}
|
||||
|
||||
return new self($message);
|
||||
}
|
||||
}
|
||||
25
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/ConnectionError.php
vendored
Normal file
25
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/ConnectionError.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\IBMDB2\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
|
||||
use function db2_conn_error;
|
||||
use function db2_conn_errormsg;
|
||||
|
||||
/** @internal */
|
||||
final class ConnectionError extends AbstractException
|
||||
{
|
||||
/** @param resource $connection */
|
||||
public static function new($connection): self
|
||||
{
|
||||
$message = db2_conn_errormsg($connection);
|
||||
$sqlState = db2_conn_error($connection);
|
||||
|
||||
return Factory::create($message, static function (int $code) use ($message, $sqlState): self {
|
||||
return new self($message, $sqlState, $code);
|
||||
});
|
||||
}
|
||||
}
|
||||
24
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/ConnectionFailed.php
vendored
Normal file
24
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/ConnectionFailed.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\IBMDB2\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
|
||||
use function db2_conn_error;
|
||||
use function db2_conn_errormsg;
|
||||
|
||||
/** @internal */
|
||||
final class ConnectionFailed extends AbstractException
|
||||
{
|
||||
public static function new(): self
|
||||
{
|
||||
$message = db2_conn_errormsg();
|
||||
$sqlState = db2_conn_error();
|
||||
|
||||
return Factory::create($message, static function (int $code) use ($message, $sqlState): self {
|
||||
return new self($message, $sqlState, $code);
|
||||
});
|
||||
}
|
||||
}
|
||||
31
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/Factory.php
vendored
Normal file
31
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/Factory.php
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\IBMDB2\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
|
||||
use function preg_match;
|
||||
|
||||
/** @internal */
|
||||
final class Factory
|
||||
{
|
||||
/**
|
||||
* @param callable(int): T $constructor
|
||||
*
|
||||
* @return T
|
||||
*
|
||||
* @template T of AbstractException
|
||||
*/
|
||||
public static function create(string $message, callable $constructor): AbstractException
|
||||
{
|
||||
$code = 0;
|
||||
|
||||
if (preg_match('/ SQL(\d+)N /', $message, $matches) === 1) {
|
||||
$code = -(int) $matches[1];
|
||||
}
|
||||
|
||||
return $constructor($code);
|
||||
}
|
||||
}
|
||||
21
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/PrepareFailed.php
vendored
Normal file
21
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/PrepareFailed.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\IBMDB2\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
|
||||
/** @internal */
|
||||
final class PrepareFailed extends AbstractException
|
||||
{
|
||||
/** @phpstan-param array{message: string, ...}|null $error */
|
||||
public static function new(?array $error): self
|
||||
{
|
||||
if ($error === null) {
|
||||
return new self('Unknown error');
|
||||
}
|
||||
|
||||
return new self($error['message']);
|
||||
}
|
||||
}
|
||||
30
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/StatementError.php
vendored
Normal file
30
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/StatementError.php
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\IBMDB2\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
|
||||
use function db2_stmt_error;
|
||||
use function db2_stmt_errormsg;
|
||||
|
||||
/** @internal */
|
||||
final class StatementError extends AbstractException
|
||||
{
|
||||
/** @param resource|null $statement */
|
||||
public static function new($statement = null): self
|
||||
{
|
||||
if ($statement !== null) {
|
||||
$message = db2_stmt_errormsg($statement);
|
||||
$sqlState = db2_stmt_error($statement);
|
||||
} else {
|
||||
$message = db2_stmt_errormsg();
|
||||
$sqlState = db2_stmt_error();
|
||||
}
|
||||
|
||||
return Factory::create($message, static function (int $code) use ($message, $sqlState): self {
|
||||
return new self($message, $sqlState, $code);
|
||||
});
|
||||
}
|
||||
}
|
||||
118
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/Result.php
vendored
Normal file
118
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/Result.php
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\IBMDB2;
|
||||
|
||||
use Doctrine\DBAL\Driver\FetchUtils;
|
||||
use Doctrine\DBAL\Driver\IBMDB2\Exception\StatementError;
|
||||
use Doctrine\DBAL\Driver\Result as ResultInterface;
|
||||
use Doctrine\DBAL\Exception\InvalidColumnIndex;
|
||||
|
||||
use function db2_fetch_array;
|
||||
use function db2_fetch_assoc;
|
||||
use function db2_free_result;
|
||||
use function db2_num_fields;
|
||||
use function db2_num_rows;
|
||||
use function db2_stmt_error;
|
||||
|
||||
final class Result implements ResultInterface
|
||||
{
|
||||
/**
|
||||
* @internal The result can be only instantiated by its driver connection or statement.
|
||||
*
|
||||
* @param resource $statement
|
||||
*/
|
||||
public function __construct(private readonly mixed $statement)
|
||||
{
|
||||
}
|
||||
|
||||
public function fetchNumeric(): array|false
|
||||
{
|
||||
$row = @db2_fetch_array($this->statement);
|
||||
|
||||
if ($row === false && db2_stmt_error($this->statement) !== '02000') {
|
||||
throw StatementError::new($this->statement);
|
||||
}
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
public function fetchAssociative(): array|false
|
||||
{
|
||||
$row = @db2_fetch_assoc($this->statement);
|
||||
|
||||
if ($row === false && db2_stmt_error($this->statement) !== '02000') {
|
||||
throw StatementError::new($this->statement);
|
||||
}
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
public function fetchOne(): mixed
|
||||
{
|
||||
return FetchUtils::fetchOne($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function fetchAllNumeric(): array
|
||||
{
|
||||
return FetchUtils::fetchAllNumeric($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function fetchAllAssociative(): array
|
||||
{
|
||||
return FetchUtils::fetchAllAssociative($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function fetchFirstColumn(): array
|
||||
{
|
||||
return FetchUtils::fetchFirstColumn($this);
|
||||
}
|
||||
|
||||
public function rowCount(): int
|
||||
{
|
||||
$numRows = @db2_num_rows($this->statement);
|
||||
|
||||
if ($numRows === false) {
|
||||
throw StatementError::new($this->statement);
|
||||
}
|
||||
|
||||
return $numRows;
|
||||
}
|
||||
|
||||
public function columnCount(): int
|
||||
{
|
||||
$count = db2_num_fields($this->statement);
|
||||
|
||||
if ($count !== false) {
|
||||
return $count;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getColumnName(int $index): string
|
||||
{
|
||||
$name = db2_field_name($this->statement, $index);
|
||||
|
||||
if ($name === false) {
|
||||
throw InvalidColumnIndex::new($index);
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
public function free(): void
|
||||
{
|
||||
db2_free_result($this->statement);
|
||||
}
|
||||
}
|
||||
156
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/Statement.php
vendored
Normal file
156
backend/vendor/doctrine/dbal/src/Driver/IBMDB2/Statement.php
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\IBMDB2;
|
||||
|
||||
use Doctrine\DBAL\Driver\Exception;
|
||||
use Doctrine\DBAL\Driver\IBMDB2\Exception\CannotCopyStreamToStream;
|
||||
use Doctrine\DBAL\Driver\IBMDB2\Exception\CannotCreateTemporaryFile;
|
||||
use Doctrine\DBAL\Driver\IBMDB2\Exception\StatementError;
|
||||
use Doctrine\DBAL\Driver\Statement as StatementInterface;
|
||||
use Doctrine\DBAL\ParameterType;
|
||||
|
||||
use function assert;
|
||||
use function db2_bind_param;
|
||||
use function db2_execute;
|
||||
use function error_get_last;
|
||||
use function fclose;
|
||||
use function is_int;
|
||||
use function is_resource;
|
||||
use function stream_copy_to_stream;
|
||||
use function stream_get_meta_data;
|
||||
use function tmpfile;
|
||||
|
||||
use const DB2_BINARY;
|
||||
use const DB2_CHAR;
|
||||
use const DB2_LONG;
|
||||
use const DB2_PARAM_FILE;
|
||||
use const DB2_PARAM_IN;
|
||||
|
||||
final class Statement implements StatementInterface
|
||||
{
|
||||
/** @var mixed[] */
|
||||
private array $parameters = [];
|
||||
|
||||
/**
|
||||
* Map of LOB parameter positions to the tuples containing reference to the variable bound to the driver statement
|
||||
* and the temporary file handle bound to the underlying statement
|
||||
*
|
||||
* @var array<int,string|resource|null>
|
||||
*/
|
||||
private array $lobs = [];
|
||||
|
||||
/**
|
||||
* @internal The statement can be only instantiated by its driver connection.
|
||||
*
|
||||
* @param resource $stmt
|
||||
*/
|
||||
public function __construct(private readonly mixed $stmt)
|
||||
{
|
||||
}
|
||||
|
||||
public function bindValue(int|string $param, mixed $value, ParameterType $type): void
|
||||
{
|
||||
assert(is_int($param));
|
||||
|
||||
switch ($type) {
|
||||
case ParameterType::INTEGER:
|
||||
$this->bind($param, $value, DB2_PARAM_IN, DB2_LONG);
|
||||
break;
|
||||
|
||||
case ParameterType::LARGE_OBJECT:
|
||||
$this->lobs[$param] = &$value;
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->bind($param, $value, DB2_PARAM_IN, DB2_CHAR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** @throws Exception */
|
||||
private function bind(int $position, mixed &$variable, int $parameterType, int $dataType): void
|
||||
{
|
||||
$this->parameters[$position] =& $variable;
|
||||
|
||||
if (! db2_bind_param($this->stmt, $position, '', $parameterType, $dataType)) {
|
||||
throw StatementError::new($this->stmt);
|
||||
}
|
||||
}
|
||||
|
||||
public function execute(): Result
|
||||
{
|
||||
$handles = $this->bindLobs();
|
||||
|
||||
$result = @db2_execute($this->stmt, $this->parameters);
|
||||
|
||||
foreach ($handles as $handle) {
|
||||
fclose($handle);
|
||||
}
|
||||
|
||||
$this->lobs = [];
|
||||
|
||||
if ($result === false) {
|
||||
throw StatementError::new($this->stmt);
|
||||
}
|
||||
|
||||
return new Result($this->stmt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<resource>
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
private function bindLobs(): array
|
||||
{
|
||||
$handles = [];
|
||||
|
||||
foreach ($this->lobs as $param => $value) {
|
||||
if (is_resource($value)) {
|
||||
$handle = $handles[] = $this->createTemporaryFile();
|
||||
$path = stream_get_meta_data($handle)['uri'];
|
||||
|
||||
$this->copyStreamToStream($value, $handle);
|
||||
|
||||
$this->bind($param, $path, DB2_PARAM_FILE, DB2_BINARY);
|
||||
} else {
|
||||
$this->bind($param, $value, DB2_PARAM_IN, DB2_CHAR);
|
||||
}
|
||||
|
||||
unset($value);
|
||||
}
|
||||
|
||||
return $handles;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return resource
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
private function createTemporaryFile()
|
||||
{
|
||||
$handle = @tmpfile();
|
||||
|
||||
if ($handle === false) {
|
||||
throw CannotCreateTemporaryFile::new(error_get_last());
|
||||
}
|
||||
|
||||
return $handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resource $source
|
||||
* @param resource $target
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
private function copyStreamToStream($source, $target): void
|
||||
{
|
||||
if (@stream_copy_to_stream($source, $target) === false) {
|
||||
throw CannotCopyStreamToStream::new(error_get_last());
|
||||
}
|
||||
}
|
||||
}
|
||||
12
backend/vendor/doctrine/dbal/src/Driver/Middleware.php
vendored
Normal file
12
backend/vendor/doctrine/dbal/src/Driver/Middleware.php
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver;
|
||||
|
||||
use Doctrine\DBAL\Driver;
|
||||
|
||||
interface Middleware
|
||||
{
|
||||
public function wrap(Driver $driver): Driver;
|
||||
}
|
||||
69
backend/vendor/doctrine/dbal/src/Driver/Middleware/AbstractConnectionMiddleware.php
vendored
Normal file
69
backend/vendor/doctrine/dbal/src/Driver/Middleware/AbstractConnectionMiddleware.php
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Middleware;
|
||||
|
||||
use Doctrine\DBAL\Driver\Connection;
|
||||
use Doctrine\DBAL\Driver\Result;
|
||||
use Doctrine\DBAL\Driver\Statement;
|
||||
|
||||
abstract class AbstractConnectionMiddleware implements Connection
|
||||
{
|
||||
public function __construct(private readonly Connection $wrappedConnection)
|
||||
{
|
||||
}
|
||||
|
||||
public function prepare(string $sql): Statement
|
||||
{
|
||||
return $this->wrappedConnection->prepare($sql);
|
||||
}
|
||||
|
||||
public function query(string $sql): Result
|
||||
{
|
||||
return $this->wrappedConnection->query($sql);
|
||||
}
|
||||
|
||||
public function quote(string $value): string
|
||||
{
|
||||
return $this->wrappedConnection->quote($value);
|
||||
}
|
||||
|
||||
public function exec(string $sql): int|string
|
||||
{
|
||||
return $this->wrappedConnection->exec($sql);
|
||||
}
|
||||
|
||||
public function lastInsertId(): int|string
|
||||
{
|
||||
return $this->wrappedConnection->lastInsertId();
|
||||
}
|
||||
|
||||
public function beginTransaction(): void
|
||||
{
|
||||
$this->wrappedConnection->beginTransaction();
|
||||
}
|
||||
|
||||
public function commit(): void
|
||||
{
|
||||
$this->wrappedConnection->commit();
|
||||
}
|
||||
|
||||
public function rollBack(): void
|
||||
{
|
||||
$this->wrappedConnection->rollBack();
|
||||
}
|
||||
|
||||
public function getServerVersion(): string
|
||||
{
|
||||
return $this->wrappedConnection->getServerVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getNativeConnection()
|
||||
{
|
||||
return $this->wrappedConnection->getNativeConnection();
|
||||
}
|
||||
}
|
||||
39
backend/vendor/doctrine/dbal/src/Driver/Middleware/AbstractDriverMiddleware.php
vendored
Normal file
39
backend/vendor/doctrine/dbal/src/Driver/Middleware/AbstractDriverMiddleware.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Middleware;
|
||||
|
||||
use Doctrine\DBAL\Driver;
|
||||
use Doctrine\DBAL\Driver\API\ExceptionConverter;
|
||||
use Doctrine\DBAL\Driver\Connection as DriverConnection;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\DBAL\ServerVersionProvider;
|
||||
use SensitiveParameter;
|
||||
|
||||
abstract class AbstractDriverMiddleware implements Driver
|
||||
{
|
||||
public function __construct(private readonly Driver $wrappedDriver)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function connect(
|
||||
#[SensitiveParameter]
|
||||
array $params,
|
||||
): DriverConnection {
|
||||
return $this->wrappedDriver->connect($params);
|
||||
}
|
||||
|
||||
public function getDatabasePlatform(ServerVersionProvider $versionProvider): AbstractPlatform
|
||||
{
|
||||
return $this->wrappedDriver->getDatabasePlatform($versionProvider);
|
||||
}
|
||||
|
||||
public function getExceptionConverter(): ExceptionConverter
|
||||
{
|
||||
return $this->wrappedDriver->getExceptionConverter();
|
||||
}
|
||||
}
|
||||
85
backend/vendor/doctrine/dbal/src/Driver/Middleware/AbstractResultMiddleware.php
vendored
Normal file
85
backend/vendor/doctrine/dbal/src/Driver/Middleware/AbstractResultMiddleware.php
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Middleware;
|
||||
|
||||
use Doctrine\DBAL\Driver\Result;
|
||||
use LogicException;
|
||||
|
||||
use function get_debug_type;
|
||||
use function method_exists;
|
||||
use function sprintf;
|
||||
|
||||
abstract class AbstractResultMiddleware implements Result
|
||||
{
|
||||
public function __construct(private readonly Result $wrappedResult)
|
||||
{
|
||||
}
|
||||
|
||||
public function fetchNumeric(): array|false
|
||||
{
|
||||
return $this->wrappedResult->fetchNumeric();
|
||||
}
|
||||
|
||||
public function fetchAssociative(): array|false
|
||||
{
|
||||
return $this->wrappedResult->fetchAssociative();
|
||||
}
|
||||
|
||||
public function fetchOne(): mixed
|
||||
{
|
||||
return $this->wrappedResult->fetchOne();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function fetchAllNumeric(): array
|
||||
{
|
||||
return $this->wrappedResult->fetchAllNumeric();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function fetchAllAssociative(): array
|
||||
{
|
||||
return $this->wrappedResult->fetchAllAssociative();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function fetchFirstColumn(): array
|
||||
{
|
||||
return $this->wrappedResult->fetchFirstColumn();
|
||||
}
|
||||
|
||||
public function rowCount(): int|string
|
||||
{
|
||||
return $this->wrappedResult->rowCount();
|
||||
}
|
||||
|
||||
public function columnCount(): int
|
||||
{
|
||||
return $this->wrappedResult->columnCount();
|
||||
}
|
||||
|
||||
public function getColumnName(int $index): string
|
||||
{
|
||||
if (! method_exists($this->wrappedResult, 'getColumnName')) {
|
||||
throw new LogicException(sprintf(
|
||||
'The driver result %s does not support accessing the column name.',
|
||||
get_debug_type($this->wrappedResult),
|
||||
));
|
||||
}
|
||||
|
||||
return $this->wrappedResult->getColumnName($index);
|
||||
}
|
||||
|
||||
public function free(): void
|
||||
{
|
||||
$this->wrappedResult->free();
|
||||
}
|
||||
}
|
||||
26
backend/vendor/doctrine/dbal/src/Driver/Middleware/AbstractStatementMiddleware.php
vendored
Normal file
26
backend/vendor/doctrine/dbal/src/Driver/Middleware/AbstractStatementMiddleware.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Middleware;
|
||||
|
||||
use Doctrine\DBAL\Driver\Result;
|
||||
use Doctrine\DBAL\Driver\Statement;
|
||||
use Doctrine\DBAL\ParameterType;
|
||||
|
||||
abstract class AbstractStatementMiddleware implements Statement
|
||||
{
|
||||
public function __construct(private readonly Statement $wrappedStatement)
|
||||
{
|
||||
}
|
||||
|
||||
public function bindValue(int|string $param, mixed $value, ParameterType $type): void
|
||||
{
|
||||
$this->wrappedStatement->bindValue($param, $value, $type);
|
||||
}
|
||||
|
||||
public function execute(): Result
|
||||
{
|
||||
return $this->wrappedStatement->execute();
|
||||
}
|
||||
}
|
||||
114
backend/vendor/doctrine/dbal/src/Driver/Mysqli/Connection.php
vendored
Normal file
114
backend/vendor/doctrine/dbal/src/Driver/Mysqli/Connection.php
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli;
|
||||
|
||||
use Doctrine\DBAL\Driver\Connection as ConnectionInterface;
|
||||
use Doctrine\DBAL\Driver\Exception;
|
||||
use Doctrine\DBAL\Driver\Mysqli\Exception\ConnectionError;
|
||||
use mysqli;
|
||||
use mysqli_sql_exception;
|
||||
|
||||
final class Connection implements ConnectionInterface
|
||||
{
|
||||
/**
|
||||
* Name of the option to set connection flags
|
||||
*/
|
||||
public const OPTION_FLAGS = 'flags';
|
||||
|
||||
/** @internal The connection can be only instantiated by its driver. */
|
||||
public function __construct(private readonly mysqli $connection)
|
||||
{
|
||||
}
|
||||
|
||||
public function getServerVersion(): string
|
||||
{
|
||||
return $this->connection->get_server_info();
|
||||
}
|
||||
|
||||
public function prepare(string $sql): Statement
|
||||
{
|
||||
try {
|
||||
$stmt = $this->connection->prepare($sql);
|
||||
} catch (mysqli_sql_exception $e) {
|
||||
throw ConnectionError::upcast($e);
|
||||
}
|
||||
|
||||
if ($stmt === false) {
|
||||
throw ConnectionError::new($this->connection);
|
||||
}
|
||||
|
||||
return new Statement($stmt);
|
||||
}
|
||||
|
||||
public function query(string $sql): Result
|
||||
{
|
||||
return $this->prepare($sql)->execute();
|
||||
}
|
||||
|
||||
public function quote(string $value): string
|
||||
{
|
||||
return "'" . $this->connection->escape_string($value) . "'";
|
||||
}
|
||||
|
||||
public function exec(string $sql): int|string
|
||||
{
|
||||
try {
|
||||
$result = $this->connection->query($sql);
|
||||
} catch (mysqli_sql_exception $e) {
|
||||
throw ConnectionError::upcast($e);
|
||||
}
|
||||
|
||||
if ($result === false) {
|
||||
throw ConnectionError::new($this->connection);
|
||||
}
|
||||
|
||||
return $this->connection->affected_rows;
|
||||
}
|
||||
|
||||
public function lastInsertId(): int|string
|
||||
{
|
||||
$lastInsertId = $this->connection->insert_id;
|
||||
|
||||
if ($lastInsertId === 0) {
|
||||
throw Exception\NoIdentityValue::new();
|
||||
}
|
||||
|
||||
return $this->connection->insert_id;
|
||||
}
|
||||
|
||||
public function beginTransaction(): void
|
||||
{
|
||||
if (! $this->connection->begin_transaction()) {
|
||||
throw ConnectionError::new($this->connection);
|
||||
}
|
||||
}
|
||||
|
||||
public function commit(): void
|
||||
{
|
||||
try {
|
||||
if (! $this->connection->commit()) {
|
||||
throw ConnectionError::new($this->connection);
|
||||
}
|
||||
} catch (mysqli_sql_exception $e) {
|
||||
throw ConnectionError::upcast($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function rollBack(): void
|
||||
{
|
||||
try {
|
||||
if (! $this->connection->rollback()) {
|
||||
throw ConnectionError::new($this->connection);
|
||||
}
|
||||
} catch (mysqli_sql_exception $e) {
|
||||
throw ConnectionError::upcast($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function getNativeConnection(): mysqli
|
||||
{
|
||||
return $this->connection;
|
||||
}
|
||||
}
|
||||
117
backend/vendor/doctrine/dbal/src/Driver/Mysqli/Driver.php
vendored
Normal file
117
backend/vendor/doctrine/dbal/src/Driver/Mysqli/Driver.php
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractMySQLDriver;
|
||||
use Doctrine\DBAL\Driver\Mysqli\Exception\ConnectionFailed;
|
||||
use Doctrine\DBAL\Driver\Mysqli\Exception\HostRequired;
|
||||
use Doctrine\DBAL\Driver\Mysqli\Initializer\Charset;
|
||||
use Doctrine\DBAL\Driver\Mysqli\Initializer\Options;
|
||||
use Doctrine\DBAL\Driver\Mysqli\Initializer\Secure;
|
||||
use Generator;
|
||||
use mysqli;
|
||||
use mysqli_sql_exception;
|
||||
use SensitiveParameter;
|
||||
|
||||
final class Driver extends AbstractMySQLDriver
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function connect(
|
||||
#[SensitiveParameter]
|
||||
array $params,
|
||||
): Connection {
|
||||
if (! empty($params['persistent'])) {
|
||||
if (! isset($params['host'])) {
|
||||
throw HostRequired::forPersistentConnection();
|
||||
}
|
||||
|
||||
$host = 'p:' . $params['host'];
|
||||
} else {
|
||||
$host = $params['host'] ?? '';
|
||||
}
|
||||
|
||||
$connection = new mysqli();
|
||||
|
||||
foreach ($this->compilePreInitializers($params) as $initializer) {
|
||||
$initializer->initialize($connection);
|
||||
}
|
||||
|
||||
try {
|
||||
$success = @$connection->real_connect(
|
||||
$host,
|
||||
$params['user'] ?? '',
|
||||
$params['password'] ?? '',
|
||||
$params['dbname'] ?? '',
|
||||
$params['port'] ?? 0,
|
||||
$params['unix_socket'] ?? '',
|
||||
$params['driverOptions'][Connection::OPTION_FLAGS] ?? 0,
|
||||
);
|
||||
} catch (mysqli_sql_exception $e) {
|
||||
throw ConnectionFailed::upcast($e);
|
||||
}
|
||||
|
||||
if (! $success) {
|
||||
throw ConnectionFailed::new($connection);
|
||||
}
|
||||
|
||||
foreach ($this->compilePostInitializers($params) as $initializer) {
|
||||
$initializer->initialize($connection);
|
||||
}
|
||||
|
||||
return new Connection($connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $params
|
||||
*
|
||||
* @return Generator<int, Initializer>
|
||||
*/
|
||||
private function compilePreInitializers(
|
||||
#[SensitiveParameter]
|
||||
array $params,
|
||||
): Generator {
|
||||
unset($params['driverOptions'][Connection::OPTION_FLAGS]);
|
||||
|
||||
if (isset($params['driverOptions']) && $params['driverOptions'] !== []) {
|
||||
yield new Options($params['driverOptions']);
|
||||
}
|
||||
|
||||
if (
|
||||
! isset($params['ssl_key']) &&
|
||||
! isset($params['ssl_cert']) &&
|
||||
! isset($params['ssl_ca']) &&
|
||||
! isset($params['ssl_capath']) &&
|
||||
! isset($params['ssl_cipher'])
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
yield new Secure(
|
||||
$params['ssl_key'] ?? '',
|
||||
$params['ssl_cert'] ?? '',
|
||||
$params['ssl_ca'] ?? '',
|
||||
$params['ssl_capath'] ?? '',
|
||||
$params['ssl_cipher'] ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $params
|
||||
*
|
||||
* @return Generator<int, Initializer>
|
||||
*/
|
||||
private function compilePostInitializers(
|
||||
#[SensitiveParameter]
|
||||
array $params,
|
||||
): Generator {
|
||||
if (! isset($params['charset'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
yield new Charset($params['charset']);
|
||||
}
|
||||
}
|
||||
26
backend/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/ConnectionError.php
vendored
Normal file
26
backend/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/ConnectionError.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
use mysqli;
|
||||
use mysqli_sql_exception;
|
||||
use ReflectionProperty;
|
||||
|
||||
/** @internal */
|
||||
final class ConnectionError extends AbstractException
|
||||
{
|
||||
public static function new(mysqli $connection): self
|
||||
{
|
||||
return new self($connection->error, $connection->sqlstate, $connection->errno);
|
||||
}
|
||||
|
||||
public static function upcast(mysqli_sql_exception $exception): self
|
||||
{
|
||||
$p = new ReflectionProperty(mysqli_sql_exception::class, 'sqlstate');
|
||||
|
||||
return new self($exception->getMessage(), $p->getValue($exception), $exception->getCode(), $exception);
|
||||
}
|
||||
}
|
||||
31
backend/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/ConnectionFailed.php
vendored
Normal file
31
backend/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/ConnectionFailed.php
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
use mysqli;
|
||||
use mysqli_sql_exception;
|
||||
use ReflectionProperty;
|
||||
|
||||
use function assert;
|
||||
|
||||
/** @internal */
|
||||
final class ConnectionFailed extends AbstractException
|
||||
{
|
||||
public static function new(mysqli $connection): self
|
||||
{
|
||||
$error = $connection->connect_error;
|
||||
assert($error !== null);
|
||||
|
||||
return new self($error, 'HY000', $connection->connect_errno);
|
||||
}
|
||||
|
||||
public static function upcast(mysqli_sql_exception $exception): self
|
||||
{
|
||||
$p = new ReflectionProperty(mysqli_sql_exception::class, 'sqlstate');
|
||||
|
||||
return new self($exception->getMessage(), $p->getValue($exception), $exception->getCode(), $exception);
|
||||
}
|
||||
}
|
||||
18
backend/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/FailedReadingStreamOffset.php
vendored
Normal file
18
backend/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/FailedReadingStreamOffset.php
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
/** @internal */
|
||||
final class FailedReadingStreamOffset extends AbstractException
|
||||
{
|
||||
public static function new(int $parameter): self
|
||||
{
|
||||
return new self(sprintf('Failed reading the stream resource for parameter #%d.', $parameter));
|
||||
}
|
||||
}
|
||||
16
backend/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/HostRequired.php
vendored
Normal file
16
backend/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/HostRequired.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
|
||||
/** @internal */
|
||||
final class HostRequired extends AbstractException
|
||||
{
|
||||
public static function forPersistentConnection(): self
|
||||
{
|
||||
return new self('The "host" parameter is required for a persistent connection');
|
||||
}
|
||||
}
|
||||
37
backend/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/InvalidCharset.php
vendored
Normal file
37
backend/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/InvalidCharset.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
use mysqli;
|
||||
use mysqli_sql_exception;
|
||||
use ReflectionProperty;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
/** @internal */
|
||||
final class InvalidCharset extends AbstractException
|
||||
{
|
||||
public static function fromCharset(mysqli $connection, string $charset): self
|
||||
{
|
||||
return new self(
|
||||
sprintf('Failed to set charset "%s": %s', $charset, $connection->error),
|
||||
$connection->sqlstate,
|
||||
$connection->errno,
|
||||
);
|
||||
}
|
||||
|
||||
public static function upcast(mysqli_sql_exception $exception, string $charset): self
|
||||
{
|
||||
$p = new ReflectionProperty(mysqli_sql_exception::class, 'sqlstate');
|
||||
|
||||
return new self(
|
||||
sprintf('Failed to set charset "%s": %s', $charset, $exception->getMessage()),
|
||||
$p->getValue($exception),
|
||||
$exception->getCode(),
|
||||
$exception,
|
||||
);
|
||||
}
|
||||
}
|
||||
20
backend/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/InvalidOption.php
vendored
Normal file
20
backend/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/InvalidOption.php
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\DBAL\Driver\Mysqli\Exception;
|
||||
|
||||
use Doctrine\DBAL\Driver\AbstractException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
/** @internal */
|
||||
final class InvalidOption extends AbstractException
|
||||
{
|
||||
public static function fromOption(int $option, mixed $value): self
|
||||
{
|
||||
return new self(
|
||||
sprintf('Failed to set option %d with value "%s"', $option, $value),
|
||||
);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user