add tailiwindi
This commit is contained in:
parent
314063f15c
commit
f38c05d97c
27 changed files with 1139 additions and 494 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -17,3 +17,8 @@
|
||||||
###< phpunit/phpunit ###
|
###< phpunit/phpunit ###
|
||||||
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
###> symfony/asset-mapper ###
|
||||||
|
/public/assets/
|
||||||
|
/assets/vendor/
|
||||||
|
###< symfony/asset-mapper ###
|
||||||
|
|
156
.junie/guidelines.md
Normal file
156
.junie/guidelines.md
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
# Development Guidelines
|
||||||
|
|
||||||
|
This document provides guidelines and instructions for developing and maintaining the Futtern project.
|
||||||
|
|
||||||
|
## Build/Configuration Instructions
|
||||||
|
|
||||||
|
### Environment Setup
|
||||||
|
|
||||||
|
1. **PHP Requirements**: The project requires PHP 8.4 or higher with the following extensions:
|
||||||
|
- ctype
|
||||||
|
- iconv
|
||||||
|
|
||||||
|
2. **Composer**: Install dependencies using Composer:
|
||||||
|
```bash
|
||||||
|
composer install
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Environment Configuration**: Copy `.env` to `.env.local` and adjust the settings as needed for your local environment.
|
||||||
|
|
||||||
|
### Development Server
|
||||||
|
|
||||||
|
Start the Symfony development server:
|
||||||
|
```bash
|
||||||
|
symfony server:start
|
||||||
|
```
|
||||||
|
|
||||||
|
### Building Assets
|
||||||
|
|
||||||
|
The project uses Tailwind CSS via the symfonycasts/tailwind-bundle:
|
||||||
|
```bash
|
||||||
|
# Install importmap assets
|
||||||
|
symfony console importmap:install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
The project includes several deployment scripts:
|
||||||
|
|
||||||
|
1. **Prepare for Deployment**:
|
||||||
|
```bash
|
||||||
|
./deploy/prepare-deploy.sh
|
||||||
|
```
|
||||||
|
This script creates a clean copy of the application with only production dependencies.
|
||||||
|
|
||||||
|
2. **Local Deployment**:
|
||||||
|
```bash
|
||||||
|
./deploy/local-deploy.sh
|
||||||
|
```
|
||||||
|
This script deploys the application to a remote server, backing up the database and restarting the service.
|
||||||
|
|
||||||
|
3. **Update After Deployment**:
|
||||||
|
```bash
|
||||||
|
./deploy/update.sh
|
||||||
|
```
|
||||||
|
This script is run on the remote server to clear cache, warm up cache, and run database migrations.
|
||||||
|
|
||||||
|
## Testing Information
|
||||||
|
|
||||||
|
### Testing Framework
|
||||||
|
|
||||||
|
The project uses Pest PHP, a testing framework built on top of PHPUnit, for testing. Tests are organized into:
|
||||||
|
- **Feature Tests**: For testing controllers and API endpoints
|
||||||
|
- **Unit Tests**: For testing individual components
|
||||||
|
|
||||||
|
### Running Tests
|
||||||
|
|
||||||
|
Run all tests:
|
||||||
|
```bash
|
||||||
|
composer test
|
||||||
|
# or
|
||||||
|
./vendor/bin/pest
|
||||||
|
```
|
||||||
|
|
||||||
|
Run specific tests:
|
||||||
|
```bash
|
||||||
|
./vendor/bin/pest tests/Unit/ExampleTest.php
|
||||||
|
```
|
||||||
|
|
||||||
|
Run tests in parallel:
|
||||||
|
```bash
|
||||||
|
./vendor/bin/pest --parallel
|
||||||
|
```
|
||||||
|
|
||||||
|
### Creating Tests
|
||||||
|
|
||||||
|
1. **Unit Tests**: Create files in the `tests/Unit` directory.
|
||||||
|
2. **Feature Tests**:
|
||||||
|
- Controller tests: Create files in `tests/Feature/Controller`
|
||||||
|
- API tests: Create files in `tests/Feature/Api`
|
||||||
|
|
||||||
|
### Example Test
|
||||||
|
|
||||||
|
Here's a simple example of a Pest PHP test:
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
test('example test', function (): void {
|
||||||
|
expect(true)->toBeTrue();
|
||||||
|
expect(1 + 1)->toBe(2);
|
||||||
|
expect('hello world')->toContain('world');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('array operations', function (): void {
|
||||||
|
$array = [1, 2, 3];
|
||||||
|
|
||||||
|
expect($array)->toHaveCount(3);
|
||||||
|
expect($array)->toContain(2);
|
||||||
|
expect($array[0])->toBe(1);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test Base Classes
|
||||||
|
|
||||||
|
- `DbWebTest`: Base class for controller tests
|
||||||
|
- `DbApiTestCase`: Base class for API tests
|
||||||
|
|
||||||
|
## Code Quality and Style
|
||||||
|
|
||||||
|
### Code Style
|
||||||
|
|
||||||
|
The project uses Easy Coding Standard (ECS) for code style checking:
|
||||||
|
```bash
|
||||||
|
composer lint
|
||||||
|
# or
|
||||||
|
./vendor/bin/ecs --fix
|
||||||
|
```
|
||||||
|
|
||||||
|
The code style is defined in `ecs.php` and includes:
|
||||||
|
- Custom rules from `Lubiana\CodeQuality\LubiSetList::ECS`
|
||||||
|
- All classes should be declared as final
|
||||||
|
|
||||||
|
### Code Refactoring
|
||||||
|
|
||||||
|
The project uses Rector for automated code refactoring:
|
||||||
|
```bash
|
||||||
|
./vendor/bin/rector
|
||||||
|
```
|
||||||
|
|
||||||
|
The refactoring rules are defined in `rector.php` and include:
|
||||||
|
- Custom rules from `Lubiana\CodeQuality\LubiSetList::RECTOR`
|
||||||
|
- StaticClosureRector is skipped in the tests directory
|
||||||
|
|
||||||
|
### Development Workflow
|
||||||
|
|
||||||
|
1. Make changes to the code
|
||||||
|
2. Run tests to ensure functionality: `composer test`
|
||||||
|
3. Fix code style issues: `composer lint`
|
||||||
|
4. Commit and push changes
|
||||||
|
5. Deploy using the deployment scripts
|
||||||
|
|
||||||
|
## Debugging
|
||||||
|
|
||||||
|
- Use the Symfony Web Profiler in development mode
|
||||||
|
- Check logs in `var/log/`
|
||||||
|
- For API debugging, use the API Platform documentation at `/api`
|
3
.symfony.local.yaml
Normal file
3
.symfony.local.yaml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
workers:
|
||||||
|
tailwind:
|
||||||
|
cmd: ['symfony', 'console', 'tailwind:build', '--watch']
|
9
assets/app.js
Normal file
9
assets/app.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
/*
|
||||||
|
* Welcome to your app's main JavaScript file!
|
||||||
|
*
|
||||||
|
* This file will be included onto the page via the importmap() Twig function,
|
||||||
|
* which should already be in your base.html.twig.
|
||||||
|
*/
|
||||||
|
import './styles/app.css';
|
||||||
|
|
||||||
|
console.log('This log comes from assets/app.js - welcome to AssetMapper! 🎉');
|
7
assets/styles/app.css
Normal file
7
assets/styles/app.css
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: skyblue;
|
||||||
|
}
|
|
@ -33,7 +33,8 @@
|
||||||
"symfony/twig-bundle": "7.1.*",
|
"symfony/twig-bundle": "7.1.*",
|
||||||
"symfony/uid": "7.1.*",
|
"symfony/uid": "7.1.*",
|
||||||
"symfony/validator": "7.1.*",
|
"symfony/validator": "7.1.*",
|
||||||
"symfony/yaml": "7.1.*"
|
"symfony/yaml": "7.1.*",
|
||||||
|
"symfonycasts/tailwind-bundle": "^0.10.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"doctrine/doctrine-fixtures-bundle": "^4.0",
|
"doctrine/doctrine-fixtures-bundle": "^4.0",
|
||||||
|
@ -85,7 +86,8 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"auto-scripts": {
|
"auto-scripts": {
|
||||||
"cache:clear": "symfony-cmd",
|
"cache:clear": "symfony-cmd",
|
||||||
"assets:install %PUBLIC_DIR%": "symfony-cmd"
|
"assets:install %PUBLIC_DIR%": "symfony-cmd",
|
||||||
|
"importmap:install": "symfony-cmd"
|
||||||
},
|
},
|
||||||
"post-install-cmd": [
|
"post-install-cmd": [
|
||||||
"@auto-scripts"
|
"@auto-scripts"
|
||||||
|
|
686
composer.lock
generated
686
composer.lock
generated
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "d7745d305c728e9812365f75052d1031",
|
"content-hash": "1c86a4bdee669d314840de214b23cf19",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "api-platform/doctrine-common",
|
"name": "api-platform/doctrine-common",
|
||||||
|
@ -1112,6 +1112,87 @@
|
||||||
},
|
},
|
||||||
"time": "2025-04-11T09:32:56+00:00"
|
"time": "2025-04-11T09:32:56+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "composer/semver",
|
||||||
|
"version": "3.4.3",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/composer/semver.git",
|
||||||
|
"reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12",
|
||||||
|
"reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^5.3.2 || ^7.0 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpstan/phpstan": "^1.11",
|
||||||
|
"symfony/phpunit-bridge": "^3 || ^7"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "3.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Composer\\Semver\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nils Adermann",
|
||||||
|
"email": "naderman@naderman.de",
|
||||||
|
"homepage": "http://www.naderman.de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jordi Boggiano",
|
||||||
|
"email": "j.boggiano@seld.be",
|
||||||
|
"homepage": "http://seld.be"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Rob Bast",
|
||||||
|
"email": "rob.bast@gmail.com",
|
||||||
|
"homepage": "http://robbast.nl"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Semver library that offers utilities, version constraint parsing and validation.",
|
||||||
|
"keywords": [
|
||||||
|
"semantic",
|
||||||
|
"semver",
|
||||||
|
"validation",
|
||||||
|
"versioning"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"irc": "ircs://irc.libera.chat:6697/composer",
|
||||||
|
"issues": "https://github.com/composer/semver/issues",
|
||||||
|
"source": "https://github.com/composer/semver/tree/3.4.3"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://packagist.com",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/composer",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-09-19T14:15:21+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "doctrine/collections",
|
"name": "doctrine/collections",
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
|
@ -2983,6 +3064,85 @@
|
||||||
],
|
],
|
||||||
"time": "2024-10-25T15:15:23+00:00"
|
"time": "2024-10-25T15:15:23+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/asset-mapper",
|
||||||
|
"version": "v7.2.5",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/asset-mapper.git",
|
||||||
|
"reference": "6428e4b6d8cff9c5fe6f40ddbee4c9f6bfdaa0b8"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/asset-mapper/zipball/6428e4b6d8cff9c5fe6f40ddbee4c9f6bfdaa0b8",
|
||||||
|
"reference": "6428e4b6d8cff9c5fe6f40ddbee4c9f6bfdaa0b8",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"composer/semver": "^3.0",
|
||||||
|
"php": ">=8.2",
|
||||||
|
"symfony/deprecation-contracts": "^2.1|^3",
|
||||||
|
"symfony/filesystem": "^7.1",
|
||||||
|
"symfony/http-client": "^6.4|^7.0"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"symfony/framework-bundle": "<6.4"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"symfony/asset": "^6.4|^7.0",
|
||||||
|
"symfony/browser-kit": "^6.4|^7.0",
|
||||||
|
"symfony/console": "^6.4|^7.0",
|
||||||
|
"symfony/event-dispatcher-contracts": "^3.0",
|
||||||
|
"symfony/finder": "^6.4|^7.0",
|
||||||
|
"symfony/framework-bundle": "^6.4|^7.0",
|
||||||
|
"symfony/http-foundation": "^6.4|^7.0",
|
||||||
|
"symfony/http-kernel": "^6.4|^7.0",
|
||||||
|
"symfony/web-link": "^6.4|^7.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\AssetMapper\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Maps directories of assets & makes them available in a public directory with versioned filenames.",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/asset-mapper/tree/v7.2.5"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-03-26T11:29:07+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/cache",
|
"name": "symfony/cache",
|
||||||
"version": "v7.2.5",
|
"version": "v7.2.5",
|
||||||
|
@ -4467,6 +4627,179 @@
|
||||||
],
|
],
|
||||||
"time": "2025-01-29T07:13:42+00:00"
|
"time": "2025-01-29T07:13:42+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/http-client",
|
||||||
|
"version": "v7.2.4",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/http-client.git",
|
||||||
|
"reference": "78981a2ffef6437ed92d4d7e2a86a82f256c6dc6"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/http-client/zipball/78981a2ffef6437ed92d4d7e2a86a82f256c6dc6",
|
||||||
|
"reference": "78981a2ffef6437ed92d4d7e2a86a82f256c6dc6",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.2",
|
||||||
|
"psr/log": "^1|^2|^3",
|
||||||
|
"symfony/deprecation-contracts": "^2.5|^3",
|
||||||
|
"symfony/http-client-contracts": "~3.4.4|^3.5.2",
|
||||||
|
"symfony/service-contracts": "^2.5|^3"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"amphp/amp": "<2.5",
|
||||||
|
"php-http/discovery": "<1.15",
|
||||||
|
"symfony/http-foundation": "<6.4"
|
||||||
|
},
|
||||||
|
"provide": {
|
||||||
|
"php-http/async-client-implementation": "*",
|
||||||
|
"php-http/client-implementation": "*",
|
||||||
|
"psr/http-client-implementation": "1.0",
|
||||||
|
"symfony/http-client-implementation": "3.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"amphp/http-client": "^4.2.1|^5.0",
|
||||||
|
"amphp/http-tunnel": "^1.0|^2.0",
|
||||||
|
"amphp/socket": "^1.1",
|
||||||
|
"guzzlehttp/promises": "^1.4|^2.0",
|
||||||
|
"nyholm/psr7": "^1.0",
|
||||||
|
"php-http/httplug": "^1.0|^2.0",
|
||||||
|
"psr/http-client": "^1.0",
|
||||||
|
"symfony/amphp-http-client-meta": "^1.0|^2.0",
|
||||||
|
"symfony/dependency-injection": "^6.4|^7.0",
|
||||||
|
"symfony/http-kernel": "^6.4|^7.0",
|
||||||
|
"symfony/messenger": "^6.4|^7.0",
|
||||||
|
"symfony/process": "^6.4|^7.0",
|
||||||
|
"symfony/rate-limiter": "^6.4|^7.0",
|
||||||
|
"symfony/stopwatch": "^6.4|^7.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\HttpClient\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"http"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/http-client/tree/v7.2.4"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-02-13T10:27:23+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/http-client-contracts",
|
||||||
|
"version": "v3.5.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/http-client-contracts.git",
|
||||||
|
"reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ee8d807ab20fcb51267fdace50fbe3494c31e645",
|
||||||
|
"reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.1"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"thanks": {
|
||||||
|
"url": "https://github.com/symfony/contracts",
|
||||||
|
"name": "symfony/contracts"
|
||||||
|
},
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "3.5-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Contracts\\HttpClient\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Test/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Generic abstractions related to HTTP clients",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"abstractions",
|
||||||
|
"contracts",
|
||||||
|
"decoupling",
|
||||||
|
"interfaces",
|
||||||
|
"interoperability",
|
||||||
|
"standards"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/http-client-contracts/tree/v3.5.2"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-12-07T08:49:48+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/http-foundation",
|
"name": "symfony/http-foundation",
|
||||||
"version": "v7.2.5",
|
"version": "v7.2.5",
|
||||||
|
@ -5276,6 +5609,67 @@
|
||||||
],
|
],
|
||||||
"time": "2024-09-09T11:45:10+00:00"
|
"time": "2024-09-09T11:45:10+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/process",
|
||||||
|
"version": "v7.2.5",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/process.git",
|
||||||
|
"reference": "87b7c93e57df9d8e39a093d32587702380ff045d"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/process/zipball/87b7c93e57df9d8e39a093d32587702380ff045d",
|
||||||
|
"reference": "87b7c93e57df9d8e39a093d32587702380ff045d",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.2"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\Process\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Executes commands in sub-processes",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/process/tree/v7.2.5"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-03-13T12:21:46+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/property-access",
|
"name": "symfony/property-access",
|
||||||
"version": "v7.2.3",
|
"version": "v7.2.3",
|
||||||
|
@ -7107,6 +7501,62 @@
|
||||||
],
|
],
|
||||||
"time": "2025-01-07T12:50:05+00:00"
|
"time": "2025-01-07T12:50:05+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfonycasts/tailwind-bundle",
|
||||||
|
"version": "v0.10.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/SymfonyCasts/tailwind-bundle.git",
|
||||||
|
"reference": "380502c39bf403f772d050ff9904932040de8cf1"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/SymfonyCasts/tailwind-bundle/zipball/380502c39bf403f772d050ff9904932040de8cf1",
|
||||||
|
"reference": "380502c39bf403f772d050ff9904932040de8cf1",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.1",
|
||||||
|
"symfony/asset-mapper": "^6.3|^7.0",
|
||||||
|
"symfony/cache": "^6.3|^7.0",
|
||||||
|
"symfony/console": "^5.4|^6.3|^7.0",
|
||||||
|
"symfony/deprecation-contracts": "^2.2|^3.0",
|
||||||
|
"symfony/http-client": "^5.4|^6.3|^7.0",
|
||||||
|
"symfony/process": "^5.4|^6.3|^7.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^9.6",
|
||||||
|
"symfony/filesystem": "^6.3|^7.0",
|
||||||
|
"symfony/framework-bundle": "^6.3|^7.0",
|
||||||
|
"symfony/phpunit-bridge": "^6.3.9|^7.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfonycasts\\TailwindBundle\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Ryan Weaver",
|
||||||
|
"homepage": "https://symfonycasts.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Delightful Tailwind Support for Symfony + AssetMapper",
|
||||||
|
"keywords": [
|
||||||
|
"asset-mapper",
|
||||||
|
"tailwind"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/SymfonyCasts/tailwind-bundle/issues",
|
||||||
|
"source": "https://github.com/SymfonyCasts/tailwind-bundle/tree/v0.10.0"
|
||||||
|
},
|
||||||
|
"time": "2025-04-09T15:18:46+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "twig/twig",
|
"name": "twig/twig",
|
||||||
"version": "v3.20.0",
|
"version": "v3.20.0",
|
||||||
|
@ -10627,179 +11077,6 @@
|
||||||
],
|
],
|
||||||
"time": "2025-02-17T15:53:07+00:00"
|
"time": "2025-02-17T15:53:07+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "symfony/http-client",
|
|
||||||
"version": "v7.2.4",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/symfony/http-client.git",
|
|
||||||
"reference": "78981a2ffef6437ed92d4d7e2a86a82f256c6dc6"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/symfony/http-client/zipball/78981a2ffef6437ed92d4d7e2a86a82f256c6dc6",
|
|
||||||
"reference": "78981a2ffef6437ed92d4d7e2a86a82f256c6dc6",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": ">=8.2",
|
|
||||||
"psr/log": "^1|^2|^3",
|
|
||||||
"symfony/deprecation-contracts": "^2.5|^3",
|
|
||||||
"symfony/http-client-contracts": "~3.4.4|^3.5.2",
|
|
||||||
"symfony/service-contracts": "^2.5|^3"
|
|
||||||
},
|
|
||||||
"conflict": {
|
|
||||||
"amphp/amp": "<2.5",
|
|
||||||
"php-http/discovery": "<1.15",
|
|
||||||
"symfony/http-foundation": "<6.4"
|
|
||||||
},
|
|
||||||
"provide": {
|
|
||||||
"php-http/async-client-implementation": "*",
|
|
||||||
"php-http/client-implementation": "*",
|
|
||||||
"psr/http-client-implementation": "1.0",
|
|
||||||
"symfony/http-client-implementation": "3.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"amphp/http-client": "^4.2.1|^5.0",
|
|
||||||
"amphp/http-tunnel": "^1.0|^2.0",
|
|
||||||
"amphp/socket": "^1.1",
|
|
||||||
"guzzlehttp/promises": "^1.4|^2.0",
|
|
||||||
"nyholm/psr7": "^1.0",
|
|
||||||
"php-http/httplug": "^1.0|^2.0",
|
|
||||||
"psr/http-client": "^1.0",
|
|
||||||
"symfony/amphp-http-client-meta": "^1.0|^2.0",
|
|
||||||
"symfony/dependency-injection": "^6.4|^7.0",
|
|
||||||
"symfony/http-kernel": "^6.4|^7.0",
|
|
||||||
"symfony/messenger": "^6.4|^7.0",
|
|
||||||
"symfony/process": "^6.4|^7.0",
|
|
||||||
"symfony/rate-limiter": "^6.4|^7.0",
|
|
||||||
"symfony/stopwatch": "^6.4|^7.0"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Symfony\\Component\\HttpClient\\": ""
|
|
||||||
},
|
|
||||||
"exclude-from-classmap": [
|
|
||||||
"/Tests/"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Nicolas Grekas",
|
|
||||||
"email": "p@tchwork.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Symfony Community",
|
|
||||||
"homepage": "https://symfony.com/contributors"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously",
|
|
||||||
"homepage": "https://symfony.com",
|
|
||||||
"keywords": [
|
|
||||||
"http"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"source": "https://github.com/symfony/http-client/tree/v7.2.4"
|
|
||||||
},
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"url": "https://symfony.com/sponsor",
|
|
||||||
"type": "custom"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://github.com/fabpot",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
|
||||||
"type": "tidelift"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"time": "2025-02-13T10:27:23+00:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "symfony/http-client-contracts",
|
|
||||||
"version": "v3.5.2",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/symfony/http-client-contracts.git",
|
|
||||||
"reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ee8d807ab20fcb51267fdace50fbe3494c31e645",
|
|
||||||
"reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": ">=8.1"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"extra": {
|
|
||||||
"thanks": {
|
|
||||||
"url": "https://github.com/symfony/contracts",
|
|
||||||
"name": "symfony/contracts"
|
|
||||||
},
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-main": "3.5-dev"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Symfony\\Contracts\\HttpClient\\": ""
|
|
||||||
},
|
|
||||||
"exclude-from-classmap": [
|
|
||||||
"/Test/"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Nicolas Grekas",
|
|
||||||
"email": "p@tchwork.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Symfony Community",
|
|
||||||
"homepage": "https://symfony.com/contributors"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Generic abstractions related to HTTP clients",
|
|
||||||
"homepage": "https://symfony.com",
|
|
||||||
"keywords": [
|
|
||||||
"abstractions",
|
|
||||||
"contracts",
|
|
||||||
"decoupling",
|
|
||||||
"interfaces",
|
|
||||||
"interoperability",
|
|
||||||
"standards"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"source": "https://github.com/symfony/http-client-contracts/tree/v3.5.2"
|
|
||||||
},
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"url": "https://symfony.com/sponsor",
|
|
||||||
"type": "custom"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://github.com/fabpot",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
|
||||||
"type": "tidelift"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"time": "2024-12-07T08:49:48+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "symfony/maker-bundle",
|
"name": "symfony/maker-bundle",
|
||||||
"version": "v1.62.1",
|
"version": "v1.62.1",
|
||||||
|
@ -10892,67 +11169,6 @@
|
||||||
],
|
],
|
||||||
"time": "2025-01-15T00:21:40+00:00"
|
"time": "2025-01-15T00:21:40+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "symfony/process",
|
|
||||||
"version": "v7.2.5",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/symfony/process.git",
|
|
||||||
"reference": "87b7c93e57df9d8e39a093d32587702380ff045d"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/symfony/process/zipball/87b7c93e57df9d8e39a093d32587702380ff045d",
|
|
||||||
"reference": "87b7c93e57df9d8e39a093d32587702380ff045d",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": ">=8.2"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Symfony\\Component\\Process\\": ""
|
|
||||||
},
|
|
||||||
"exclude-from-classmap": [
|
|
||||||
"/Tests/"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Fabien Potencier",
|
|
||||||
"email": "fabien@symfony.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Symfony Community",
|
|
||||||
"homepage": "https://symfony.com/contributors"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Executes commands in sub-processes",
|
|
||||||
"homepage": "https://symfony.com",
|
|
||||||
"support": {
|
|
||||||
"source": "https://github.com/symfony/process/tree/v7.2.5"
|
|
||||||
},
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"url": "https://symfony.com/sponsor",
|
|
||||||
"type": "custom"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://github.com/fabpot",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
|
||||||
"type": "tidelift"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"time": "2025-03-13T12:21:46+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "symfony/web-profiler-bundle",
|
"name": "symfony/web-profiler-bundle",
|
||||||
"version": "v7.2.4",
|
"version": "v7.2.4",
|
||||||
|
|
|
@ -1,52 +1,16 @@
|
||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
|
||||||
use ApiPlatform\Symfony\Bundle\ApiPlatformBundle;
|
|
||||||
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
|
|
||||||
use Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle;
|
|
||||||
use Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle;
|
|
||||||
use Liip\TestFixturesBundle\LiipTestFixturesBundle;
|
|
||||||
use Nelmio\CorsBundle\NelmioCorsBundle;
|
|
||||||
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
|
|
||||||
use Symfony\Bundle\MakerBundle\MakerBundle;
|
|
||||||
use Symfony\Bundle\SecurityBundle\SecurityBundle;
|
|
||||||
use Symfony\Bundle\TwigBundle\TwigBundle;
|
|
||||||
use Symfony\Bundle\WebProfilerBundle\WebProfilerBundle;
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
FrameworkBundle::class => [
|
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
|
||||||
'all' => true,
|
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
|
||||||
],
|
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
|
||||||
MakerBundle::class => [
|
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
|
||||||
'dev' => true,
|
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
|
||||||
],
|
Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
|
||||||
DoctrineBundle::class => [
|
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
|
||||||
'all' => true,
|
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
|
||||||
],
|
Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true],
|
||||||
DoctrineMigrationsBundle::class => [
|
ApiPlatform\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
|
||||||
'all' => true,
|
Liip\TestFixturesBundle\LiipTestFixturesBundle::class => ['dev' => true, 'test' => true],
|
||||||
],
|
Symfonycasts\TailwindBundle\SymfonycastsTailwindBundle::class => ['all' => true],
|
||||||
TwigBundle::class => [
|
|
||||||
'all' => true,
|
|
||||||
],
|
|
||||||
DoctrineFixturesBundle::class => [
|
|
||||||
'dev' => true,
|
|
||||||
'test' => true,
|
|
||||||
],
|
|
||||||
WebProfilerBundle::class => [
|
|
||||||
'dev' => true,
|
|
||||||
'test' => true,
|
|
||||||
],
|
|
||||||
SecurityBundle::class => [
|
|
||||||
'all' => true,
|
|
||||||
],
|
|
||||||
NelmioCorsBundle::class => [
|
|
||||||
'all' => true,
|
|
||||||
],
|
|
||||||
ApiPlatformBundle::class => [
|
|
||||||
'all' => true,
|
|
||||||
],
|
|
||||||
LiipTestFixturesBundle::class => [
|
|
||||||
'dev' => true,
|
|
||||||
'test' => true,
|
|
||||||
],
|
|
||||||
];
|
];
|
||||||
|
|
23
config/packages/asset_mapper.php
Normal file
23
config/packages/asset_mapper.php
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||||
|
|
||||||
|
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||||
|
$containerConfigurator->extension('framework', [
|
||||||
|
'asset_mapper' => [
|
||||||
|
'paths' => [
|
||||||
|
'assets/',
|
||||||
|
],
|
||||||
|
'missing_import_mode' => 'strict',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
if ($containerConfigurator->env() === 'prod') {
|
||||||
|
$containerConfigurator->extension('framework', [
|
||||||
|
'asset_mapper' => [
|
||||||
|
'missing_import_mode' => 'warn',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
11
config/packages/symfonycasts_tailwind.php
Normal file
11
config/packages/symfonycasts_tailwind.php
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||||
|
|
||||||
|
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||||
|
$containerConfigurator->extension('symfonycasts_tailwind', [
|
||||||
|
'binary_version' => 'v3.4.17',
|
||||||
|
]);
|
||||||
|
};
|
19
importmap.php
Normal file
19
importmap.php
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the importmap for this application.
|
||||||
|
*
|
||||||
|
* - "path" is a path inside the asset mapper system. Use the
|
||||||
|
* "debug:asset-map" command to see the full list of paths.
|
||||||
|
*
|
||||||
|
* - "entrypoint" (JavaScript only) set to true for any module that will
|
||||||
|
* be used as an "entrypoint" (and passed to the importmap() Twig function).
|
||||||
|
*
|
||||||
|
* The "importmap:require" command can be used to add new entries to this file.
|
||||||
|
*/
|
||||||
|
return [
|
||||||
|
'app' => [
|
||||||
|
'path' => './assets/app.js',
|
||||||
|
'entrypoint' => true,
|
||||||
|
],
|
||||||
|
];
|
27
symfony.lock
27
symfony.lock
|
@ -99,6 +99,21 @@
|
||||||
"ref": "1019e5c08d4821cb9b77f4891f8e9c31ff20ac6f"
|
"ref": "1019e5c08d4821cb9b77f4891f8e9c31ff20ac6f"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"symfony/asset-mapper": {
|
||||||
|
"version": "7.2",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "6.4",
|
||||||
|
"ref": "5ad1308aa756d58f999ffbe1540d1189f5d7d14a"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"assets/app.js",
|
||||||
|
"assets/styles/app.css",
|
||||||
|
"config/packages/asset_mapper.yaml",
|
||||||
|
"importmap.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
"symfony/console": {
|
"symfony/console": {
|
||||||
"version": "7.1",
|
"version": "7.1",
|
||||||
"recipe": {
|
"recipe": {
|
||||||
|
@ -223,5 +238,17 @@
|
||||||
"config/packages/web_profiler.yaml",
|
"config/packages/web_profiler.yaml",
|
||||||
"config/routes/web_profiler.yaml"
|
"config/routes/web_profiler.yaml"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"symfonycasts/tailwind-bundle": {
|
||||||
|
"version": "0.10",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "0.8",
|
||||||
|
"ref": "4ea7c9488fdce8943520daf3fdc31e93e5b59c64"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"config/packages/symfonycasts_tailwind.yaml"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
11
tailwind.config.js
Normal file
11
tailwind.config.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
module.exports = {
|
||||||
|
content: [
|
||||||
|
"./assets/**/*.js",
|
||||||
|
"./templates/**/*.html.twig",
|
||||||
|
],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
}
|
|
@ -1,4 +1,24 @@
|
||||||
{{ form_start(form) }}
|
{{ form_start(form, {'attr': {'class': 'space-y-6'}}) }}
|
||||||
{{ form_widget(form) }}
|
{% for field in form %}
|
||||||
<button class="btn">{{ button_label|default('Save') }}</button>
|
{% if field.vars.name != '_token' %}
|
||||||
|
<div class="space-y-2">
|
||||||
|
{{ form_label(field, null, {'label_attr': {'class': 'block text-sm font-medium leading-6 text-gray-900'}}) }}
|
||||||
|
<div>
|
||||||
|
{{ form_widget(field, {'attr': {'class': 'block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6'}}) }}
|
||||||
|
</div>
|
||||||
|
{% if field.vars.errors|length > 0 %}
|
||||||
|
<div class="mt-1 text-sm text-red-600">
|
||||||
|
{{ form_errors(field) }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if field.vars.help is defined and field.vars.help %}
|
||||||
|
<p class="mt-1 text-sm text-gray-500">{{ field.vars.help }}</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
<div class="mt-6 flex items-center justify-end gap-x-6">
|
||||||
|
<a href="{{ app.request.headers.get('referer', '/') }}" class="text-sm font-semibold leading-6 text-gray-900">Cancel</a>
|
||||||
|
<button type="submit" class="rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">{{ button_label|default('Save') }}</button>
|
||||||
|
</div>
|
||||||
{{ form_end(form) }}
|
{{ form_end(form) }}
|
||||||
|
|
|
@ -1,46 +1,90 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html class="h-full bg-gray-100">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="color-scheme" content="dark light">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta name="theme-color" content="#0000ff" media="(prefers-color-scheme: light)">
|
<title>{% block title %}Welcome!{% endblock %} - Futtern</title>
|
||||||
<meta name="theme-color" content="#222222" media="(prefers-color-scheme: dark)">
|
<link rel="icon" type="image/svg+xml" href="{{ favicon }}" />
|
||||||
<title>{% block title %}Welcome!{% endblock %}</title>
|
|
||||||
<link rel="icon" type="image/svg+xml"
|
|
||||||
href="{{ favicon }}" />
|
|
||||||
{% set currentDate = "now"|date("d") %}
|
|
||||||
{% if currentDate % 4 == 0 %}
|
|
||||||
<link rel="stylesheet" href="/static/css/new.min.css">
|
|
||||||
{% elseif currentDate % 4 == 1 %}
|
|
||||||
<link rel="stylesheet" href="/static/css/simple.min.css">
|
|
||||||
{% elseif currentDate % 4 == 2 %}
|
|
||||||
<link rel="stylesheet" href="/static/css/water.min.css">
|
|
||||||
{% else %}
|
|
||||||
<link rel="stylesheet" href="/static/css/fieber.css">
|
|
||||||
{% endif %}
|
|
||||||
<style>
|
|
||||||
label{
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script src="/static/js/htmx.min.js"></script>
|
<script src="/static/js/htmx.min.js"></script>
|
||||||
|
{% block stylesheets %}
|
||||||
|
<link rel="stylesheet" href="{{ asset('styles/app.css') }}">
|
||||||
|
{% endblock %}
|
||||||
|
{% block javascripts %}
|
||||||
|
{{ importmap() }}
|
||||||
|
{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body class="h-full">
|
||||||
<header>
|
<div class="min-h-full">
|
||||||
<p>Hello {{ app.request.cookies.get('username', 'nobody') }} - <a href="{{ path('username') }}">change name</a></p>
|
<nav class="bg-indigo-600">
|
||||||
<nav>
|
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||||
<a href="{{ path('app_food_order_index') }}">Orders</a> /
|
<div class="flex h-16 items-center justify-between">
|
||||||
<a href="{{ path('app_food_vendor_index') }}">Vendors</a> /
|
<div class="flex items-center">
|
||||||
<a
|
<div class="flex-shrink-0">
|
||||||
href="https://git.hannover.ccc.de/lubiana/futtern/issues/new"
|
<span class="text-white text-xl font-bold">Futtern</span>
|
||||||
target="_blank"
|
</div>
|
||||||
>Create Issue</a> /
|
<div class="hidden md:block">
|
||||||
<a href="/api">API</a>
|
<div class="ml-10 flex items-baseline space-x-4">
|
||||||
|
<a href="{{ path('app_food_order_index') }}" class="text-white hover:bg-indigo-500 hover:bg-opacity-75 rounded-md px-3 py-2 text-sm font-medium">Orders</a>
|
||||||
|
<a href="{{ path('app_food_vendor_index') }}" class="text-white hover:bg-indigo-500 hover:bg-opacity-75 rounded-md px-3 py-2 text-sm font-medium">Vendors</a>
|
||||||
|
<a href="https://git.hannover.ccc.de/lubiana/futtern/issues/new" target="_blank" class="text-white hover:bg-indigo-500 hover:bg-opacity-75 rounded-md px-3 py-2 text-sm font-medium">Create Issue</a>
|
||||||
|
<a href="/api" class="text-white hover:bg-indigo-500 hover:bg-opacity-75 rounded-md px-3 py-2 text-sm font-medium">API</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hidden md:block">
|
||||||
|
<div class="ml-4 flex items-center md:ml-6">
|
||||||
|
<div class="text-white">
|
||||||
|
Hello {{ app.request.cookies.get('username', 'nobody') }} -
|
||||||
|
<a href="{{ path('username') }}" class="text-indigo-200 hover:text-white">change name</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="-mr-2 flex md:hidden">
|
||||||
|
<!-- Mobile menu button -->
|
||||||
|
<button type="button" class="relative inline-flex items-center justify-center rounded-md bg-indigo-600 p-2 text-indigo-200 hover:bg-indigo-500 hover:bg-opacity-75 hover:text-white focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-indigo-600" aria-controls="mobile-menu" aria-expanded="false">
|
||||||
|
<span class="absolute -inset-0.5"></span>
|
||||||
|
<span class="sr-only">Open main menu</span>
|
||||||
|
<!-- Menu open: "hidden", Menu closed: "block" -->
|
||||||
|
<svg class="block h-6 w-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Mobile menu, show/hide based on menu state. -->
|
||||||
|
<div class="md:hidden" id="mobile-menu">
|
||||||
|
<div class="space-y-1 px-2 pb-3 pt-2 sm:px-3">
|
||||||
|
<a href="{{ path('app_food_order_index') }}" class="text-white hover:bg-indigo-500 hover:bg-opacity-75 block rounded-md px-3 py-2 text-base font-medium">Orders</a>
|
||||||
|
<a href="{{ path('app_food_vendor_index') }}" class="text-white hover:bg-indigo-500 hover:bg-opacity-75 block rounded-md px-3 py-2 text-base font-medium">Vendors</a>
|
||||||
|
<a href="https://git.hannover.ccc.de/lubiana/futtern/issues/new" target="_blank" class="text-white hover:bg-indigo-500 hover:bg-opacity-75 block rounded-md px-3 py-2 text-base font-medium">Create Issue</a>
|
||||||
|
<a href="/api" class="text-white hover:bg-indigo-500 hover:bg-opacity-75 block rounded-md px-3 py-2 text-base font-medium">API</a>
|
||||||
|
</div>
|
||||||
|
<div class="border-t border-indigo-700 pb-3 pt-4">
|
||||||
|
<div class="flex items-center px-5">
|
||||||
|
<div class="text-base font-medium text-white">
|
||||||
|
Hello {{ app.request.cookies.get('username', 'nobody') }} -
|
||||||
|
<a href="{{ path('username') }}" class="text-indigo-200 hover:text-white">change name</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
|
||||||
<main>
|
<header class="bg-white shadow">
|
||||||
{% block body %}{% endblock %}
|
<div class="mx-auto max-w-7xl px-4 py-6 sm:px-6 lg:px-8">
|
||||||
</main>
|
<h1 class="text-3xl font-bold tracking-tight text-gray-900">{% block header %}{% endblock %}</h1>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<div class="mx-auto max-w-7xl py-6 sm:px-6 lg:px-8">
|
||||||
|
<div class="px-4 py-6 sm:px-0">
|
||||||
|
{% block body %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
@ -1,45 +1,69 @@
|
||||||
{% extends 'base.html.twig' %}
|
{% extends 'base.html.twig' %}
|
||||||
|
|
||||||
{% block title %}FoodOrder index{% endblock %}
|
{% block title %}Food Orders{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}Food Orders{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<h1>FoodOrder index</h1>
|
<div class="sm:flex sm:items-center sm:justify-between mb-6">
|
||||||
<div>
|
<div class="min-w-0 flex-1">
|
||||||
<button
|
<p class="text-sm text-gray-500">
|
||||||
|
Manage your food orders and create new ones.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="mt-4 flex sm:ml-4 sm:mt-0">
|
||||||
|
<button
|
||||||
hx-get="{{ path('app_food_order_new') }}"
|
hx-get="{{ path('app_food_order_new') }}"
|
||||||
hx-trigger="click"
|
hx-trigger="click"
|
||||||
hx-target="closest div"
|
hx-target="#new-order-form"
|
||||||
>Create new</button>
|
class="block rounded-md bg-indigo-600 px-3 py-2 text-center text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
|
||||||
|
>Create new order</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
|
||||||
<table class="table">
|
<div id="new-order-form" class="mb-8"></div>
|
||||||
<thead>
|
|
||||||
<tr>
|
<div class="mt-8 flow-root">
|
||||||
<th>CreatedBy</th>
|
<div class="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
|
||||||
<th>Vendor</th>
|
<div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
|
||||||
<th>CreatedAt</th>
|
<div class="overflow-hidden shadow ring-1 ring-black ring-opacity-5 sm:rounded-lg">
|
||||||
<th>ClosedAt</th>
|
<table class="min-w-full divide-y divide-gray-300">
|
||||||
<th>actions</th>
|
<thead class="bg-gray-50">
|
||||||
</tr>
|
<tr>
|
||||||
</thead>
|
<th scope="col" class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6">Created By</th>
|
||||||
<tbody>
|
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">Vendor</th>
|
||||||
{% for food_order in food_orders %}
|
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">Created At</th>
|
||||||
{{ include('food_order/table_row.html.twig') }}
|
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">Closed At</th>
|
||||||
{% endfor %}
|
<th scope="col" class="relative py-3.5 pl-3 pr-4 sm:pr-6">
|
||||||
{% if food_orders|length < 10 %}
|
<span class="sr-only">Actions</span>
|
||||||
<tr>
|
</th>
|
||||||
<td colspan="5">
|
</tr>
|
||||||
check the <a href="{{ path('app_food_order_archive') }}">archive</a>
|
</thead>
|
||||||
for older orders
|
<tbody class="divide-y divide-gray-200 bg-white">
|
||||||
</td>
|
{% for food_order in food_orders %}
|
||||||
</tr>
|
{{ include('food_order/table_row.html.twig') }}
|
||||||
|
{% endfor %}
|
||||||
|
{% if food_orders|length < 10 %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="5" class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-500 sm:pl-6">
|
||||||
|
Check the <a href="{{ path('app_food_order_archive') }}" class="text-indigo-600 hover:text-indigo-900">archive</a>
|
||||||
|
for older orders
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-6 flex items-center justify-center gap-x-6">
|
||||||
|
{% if prev_page > 0 %}
|
||||||
|
<a href="{{ path('app_food_order_archive', {'page': prev_page}) }}" class="rounded-md bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50">Previous Page</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tbody>
|
{% if next_page > current_page %}
|
||||||
</table>
|
<a href="{{ path('app_food_order_archive', {'page': next_page}) }}" class="rounded-md bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50">Next Page</a>
|
||||||
{% if prev_page > 0 %}
|
{% endif %}
|
||||||
<a href="{{ path('app_food_order_archive', {'page': prev_page}) }}">previous page</a> |
|
</div>
|
||||||
{% endif %}
|
|
||||||
{% if next_page > current_page %}
|
|
||||||
<a href="{{ path('app_food_order_archive', {'page': next_page}) }}">next page</a>
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,2 +1,11 @@
|
||||||
{{ include('_form.html.twig') }}
|
<div class="bg-white shadow sm:rounded-lg">
|
||||||
|
<div class="px-4 py-5 sm:p-6">
|
||||||
|
<h3 class="text-base font-semibold leading-6 text-gray-900">Create New Order</h3>
|
||||||
|
<div class="mt-2 max-w-xl text-sm text-gray-500">
|
||||||
|
<p>Fill out the form below to create a new food order.</p>
|
||||||
|
</div>
|
||||||
|
<div class="mt-5">
|
||||||
|
{{ include('_form.html.twig') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -1,71 +1,101 @@
|
||||||
{% extends 'base.html.twig' %}
|
{% extends 'base.html.twig' %}
|
||||||
|
|
||||||
{% block title %}FoodOrder{% endblock %}
|
{% block title %}Order Details{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}Order Details{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<h1>FoodOrder</h1>
|
<div class="bg-white shadow sm:rounded-lg mb-8">
|
||||||
|
<div class="px-4 py-5 sm:px-6">
|
||||||
|
<h3 class="text-lg font-medium leading-6 text-gray-900">Order Information</h3>
|
||||||
|
<p class="mt-1 max-w-2xl text-sm text-gray-500">Details about the food order from {{ food_order.foodVendor.name }}.</p>
|
||||||
|
</div>
|
||||||
|
<div class="border-t border-gray-200">
|
||||||
|
<dl>
|
||||||
|
<div class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
|
<dt class="text-sm font-medium text-gray-500">Vendor</dt>
|
||||||
|
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">{{ food_order.foodVendor.name }}</dd>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
|
<dt class="text-sm font-medium text-gray-500">Vendor Phone</dt>
|
||||||
|
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">{{ food_order.foodVendor.phone }}</dd>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
|
<dt class="text-sm font-medium text-gray-500">Created By</dt>
|
||||||
|
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">{{ food_order.createdBy }}</dd>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
|
<dt class="text-sm font-medium text-gray-500">Created At</dt>
|
||||||
|
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">{{ food_order.createdAt ? food_order.createdAt|date('Y-m-d H:i:s', 'Europe/Berlin') : '' }}</dd>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
|
<dt class="text-sm font-medium text-gray-500">Closed At</dt>
|
||||||
|
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">{{ food_order.closedAt ? food_order.closedAt|date('Y-m-d H:i:s', 'Europe/Berlin') : 'Not closed yet' }}</dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<table class="table">
|
<div class="flex space-x-4 mb-8">
|
||||||
<tbody>
|
<a href="{{ path('app_food_order_index') }}" class="inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50">
|
||||||
<tr>
|
Back to list
|
||||||
<th>Vendor</th>
|
</a>
|
||||||
<td>{{ food_order.foodVendor.name }}</td>
|
{% if(food_order.isClosed) %}
|
||||||
</tr>
|
<a href="{{ path('app_food_order_open', {'id': food_order.id}) }}" class="inline-flex items-center rounded-md bg-green-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-green-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600">
|
||||||
<tr>
|
Reopen Order
|
||||||
<th>Vendorphone</th>
|
</a>
|
||||||
<td>{{ food_order.foodVendor.phone }}</td>
|
{% else %}
|
||||||
</tr>
|
<a href="{{ path('app_food_order_close', {'id': food_order.id}) }}" class="inline-flex items-center rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600">
|
||||||
<tr>
|
Close Order
|
||||||
<th>Created By</th>
|
</a>
|
||||||
<td>{{ food_order.createdBy }}</td>
|
{% endif %}
|
||||||
</tr>
|
</div>
|
||||||
<tr>
|
|
||||||
<th>CreatedAt</th>
|
|
||||||
<td>{{ food_order.createdAt ? food_order.createdAt|date('Y-m-d H:i:s', 'Europe/Berlin') : '' }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>ClosedAt</th>
|
|
||||||
<td>{{ food_order.closedAt ? food_order.closedAt|date('Y-m-d H:i:s', 'Europe/Berlin') : '' }}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<a class="button" href="{{ path('app_food_order_index') }}">back to list</a>
|
|
||||||
{% if(food_order.isClosed) %}
|
|
||||||
<a class="button" href="{{ path('app_food_order_open', {'id': food_order.id}) }}">reopen</a>
|
|
||||||
{% else %}
|
|
||||||
<a class="button" href="{{ path('app_food_order_close', {'id': food_order.id}) }}">close</a>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<h2>Items</h2>
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Index</th>
|
|
||||||
<th>username</th>
|
|
||||||
<th>name</th>
|
|
||||||
<th>extras</th>
|
|
||||||
<th>actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for item in food_order.orderItemsSortedByName %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ loop.index }}</td>
|
|
||||||
<td>{{ item.createdBy }}</td>
|
|
||||||
<td>{{ item.name }}</td>
|
|
||||||
<td>{{ item.extras }}</td>
|
|
||||||
<td>
|
|
||||||
{% if(food_order.isClosed) %}
|
|
||||||
{% else %}
|
|
||||||
<a href="{{ path('app_order_item_edit', {'id': item.id}) }}">edit</a>
|
|
||||||
<a href="{{ path('app_order_item_copy', {'id': item.id}) }}">copy</a>
|
|
||||||
<a href="{{ path('app_order_item_delete', {'id': item.id}) }}">remove</a>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<a class="button" href="{{ path('app_order_item_new', {'foodOrder': food_order.id}) }}">New Item</a>
|
|
||||||
|
|
||||||
|
<div class="bg-white shadow sm:rounded-lg mb-8">
|
||||||
|
<div class="px-4 py-5 sm:px-6 flex justify-between items-center">
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-medium leading-6 text-gray-900">Order Items</h3>
|
||||||
|
<p class="mt-1 max-w-2xl text-sm text-gray-500">Items included in this order.</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="{{ path('app_order_item_new', {'foodOrder': food_order.id}) }}" class="inline-flex items-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">
|
||||||
|
Add New Item
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="overflow-hidden shadow ring-1 ring-black ring-opacity-5">
|
||||||
|
<table class="min-w-full divide-y divide-gray-300">
|
||||||
|
<thead class="bg-gray-50">
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6">#</th>
|
||||||
|
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">Username</th>
|
||||||
|
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">Item Name</th>
|
||||||
|
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">Extras</th>
|
||||||
|
<th scope="col" class="relative py-3.5 pl-3 pr-4 sm:pr-6">
|
||||||
|
<span class="sr-only">Actions</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="divide-y divide-gray-200 bg-white">
|
||||||
|
{% for item in food_order.orderItemsSortedByName %}
|
||||||
|
<tr class="hover:bg-gray-50">
|
||||||
|
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6">{{ loop.index }}</td>
|
||||||
|
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ item.createdBy }}</td>
|
||||||
|
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ item.name }}</td>
|
||||||
|
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ item.extras }}</td>
|
||||||
|
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6">
|
||||||
|
{% if(food_order.isClosed) %}
|
||||||
|
<span class="text-gray-400">Order closed</span>
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ path('app_order_item_edit', {'id': item.id}) }}" class="text-indigo-600 hover:text-indigo-900 mr-2">Edit</a>
|
||||||
|
<a href="{{ path('app_order_item_copy', {'id': item.id}) }}" class="text-indigo-600 hover:text-indigo-900 mr-2">Copy</a>
|
||||||
|
<a href="{{ path('app_order_item_delete', {'id': item.id}) }}" class="text-red-600 hover:text-red-900">Remove</a>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<tr>
|
<tr class="hover:bg-gray-50">
|
||||||
<td>{{ food_order.createdBy }}</td>
|
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6">{{ food_order.createdBy }}</td>
|
||||||
<td>{{ food_order.foodVendor.name }}</td>
|
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ food_order.foodVendor.name }}</td>
|
||||||
<td>{{ food_order.createdAt ? food_order.createdAt|date('Y-m-d H:i:s', 'Europe/Berlin') : '' }}</td>
|
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ food_order.createdAt ? food_order.createdAt|date('Y-m-d H:i:s', 'Europe/Berlin') : '' }}</td>
|
||||||
<td>{{ food_order.closedAt ? food_order.closedAt|date('Y-m-d H:i:s', 'Europe/Berlin') : '' }}</td>
|
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{{ food_order.closedAt ? food_order.closedAt|date('Y-m-d H:i:s', 'Europe/Berlin') : '' }}</td>
|
||||||
<td>
|
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6">
|
||||||
<a href="{{ path('app_food_order_show', {'id': food_order.id}) }}">show</a>
|
<a href="{{ path('app_food_order_show', {'id': food_order.id}) }}" class="text-indigo-600 hover:text-indigo-900">View<span class="sr-only">, order from {{ food_order.createdBy }}</span></a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
|
@ -1,4 +1,24 @@
|
||||||
{{ form_start(form) }}
|
{{ form_start(form, {'attr': {'class': 'space-y-6'}}) }}
|
||||||
{{ form_widget(form) }}
|
{% for field in form %}
|
||||||
<button class="btn">{{ button_label|default('Save') }}</button>
|
{% if field.vars.name != '_token' %}
|
||||||
|
<div class="space-y-2">
|
||||||
|
{{ form_label(field, null, {'label_attr': {'class': 'block text-sm font-medium leading-6 text-gray-900'}}) }}
|
||||||
|
<div>
|
||||||
|
{{ form_widget(field, {'attr': {'class': 'block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6'}}) }}
|
||||||
|
</div>
|
||||||
|
{% if field.vars.errors|length > 0 %}
|
||||||
|
<div class="mt-1 text-sm text-red-600">
|
||||||
|
{{ form_errors(field) }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if field.vars.help is defined and field.vars.help %}
|
||||||
|
<p class="mt-1 text-sm text-gray-500">{{ field.vars.help }}</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
<div class="mt-6 flex items-center justify-end gap-x-6">
|
||||||
|
<a href="{{ app.request.headers.get('referer', '/') }}" class="text-sm font-semibold leading-6 text-gray-900">Cancel</a>
|
||||||
|
<button type="submit" class="rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">{{ button_label|default('Save') }}</button>
|
||||||
|
</div>
|
||||||
{{ form_end(form) }}
|
{{ form_end(form) }}
|
||||||
|
|
|
@ -1,33 +1,54 @@
|
||||||
{% extends 'base.html.twig' %}
|
{% extends 'base.html.twig' %}
|
||||||
|
|
||||||
{% block title %}FoodVendor index{% endblock %}
|
{% block title %}Food Vendors{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}Food Vendors{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<h1>FoodVendor index</h1>
|
<div class="sm:flex sm:items-center sm:justify-between mb-6">
|
||||||
|
<div class="min-w-0 flex-1">
|
||||||
|
<p class="text-sm text-gray-500">
|
||||||
|
Manage your food vendors and create new ones.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="mt-4 flex sm:ml-4 sm:mt-0">
|
||||||
|
<a href="{{ path('app_food_vendor_new') }}" class="block rounded-md bg-indigo-600 px-3 py-2 text-center text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">
|
||||||
|
Create new vendor
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<table class="table">
|
<div class="mt-8 flow-root">
|
||||||
<thead>
|
<div class="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
|
||||||
<tr>
|
<div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
|
||||||
<th>Name</th>
|
<div class="overflow-hidden shadow ring-1 ring-black ring-opacity-5 sm:rounded-lg">
|
||||||
<th>actions</th>
|
<table class="min-w-full divide-y divide-gray-300">
|
||||||
</tr>
|
<thead class="bg-gray-50">
|
||||||
</thead>
|
<tr>
|
||||||
<tbody>
|
<th scope="col" class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6">Name</th>
|
||||||
{% for food_vendor in food_vendors %}
|
<th scope="col" class="relative py-3.5 pl-3 pr-4 sm:pr-6">
|
||||||
<tr>
|
<span class="sr-only">Actions</span>
|
||||||
<td>{{ food_vendor.name }}</td>
|
</th>
|
||||||
<td>
|
</tr>
|
||||||
<a href="{{ path('app_food_vendor_show', {'id': food_vendor.id}) }}">show</a>
|
</thead>
|
||||||
<a href="{{ path('app_food_vendor_edit', {'id': food_vendor.id}) }}">edit</a>
|
<tbody class="divide-y divide-gray-200 bg-white">
|
||||||
</td>
|
{% for food_vendor in food_vendors %}
|
||||||
</tr>
|
<tr class="hover:bg-gray-50">
|
||||||
{% else %}
|
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6">{{ food_vendor.name }}</td>
|
||||||
<tr>
|
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6">
|
||||||
<td colspan="3">no records found</td>
|
<a href="{{ path('app_food_vendor_show', {'id': food_vendor.id}) }}" class="text-indigo-600 hover:text-indigo-900 mr-2">View</a>
|
||||||
</tr>
|
<a href="{{ path('app_food_vendor_edit', {'id': food_vendor.id}) }}" class="text-indigo-600 hover:text-indigo-900">Edit</a>
|
||||||
{% endfor %}
|
</td>
|
||||||
</tbody>
|
</tr>
|
||||||
</table>
|
{% else %}
|
||||||
|
<tr>
|
||||||
<a href="{{ path('app_food_vendor_new') }}">Create new</a>
|
<td colspan="2" class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-500 sm:pl-6">No vendors found</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -2,8 +2,15 @@
|
||||||
|
|
||||||
{% block title %}Tell me your name{% endblock %}
|
{% block title %}Tell me your name{% endblock %}
|
||||||
|
|
||||||
|
{% block header %}Tell me your name{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<h1>Tell me your name</h1>
|
<div class="bg-white shadow sm:rounded-lg">
|
||||||
<p>By submitting the form, you agree that your username will be stored as a cookie.</p>
|
<div class="px-4 py-5 sm:p-6">
|
||||||
{{ include('_form.html.twig') }}
|
<div class="max-w-xl text-sm text-gray-500 mb-6">
|
||||||
|
<p>By submitting the form, you agree that your username will be stored as a cookie.</p>
|
||||||
|
</div>
|
||||||
|
{{ include('_form.html.twig') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -44,7 +44,7 @@ describe(FoodOrderController::class, function (): void {
|
||||||
|
|
||||||
$crawler = $this->client->request('GET', "{$this->path}list");
|
$crawler = $this->client->request('GET', "{$this->path}list");
|
||||||
$this->assertResponseStatusCodeSame(200);
|
$this->assertResponseStatusCodeSame(200);
|
||||||
$this->assertPageTitleContains('FoodOrder index');
|
$this->assertPageTitleContains('Food Orders');
|
||||||
$this->assertCount(
|
$this->assertCount(
|
||||||
1,
|
1,
|
||||||
$crawler->filter('td')
|
$crawler->filter('td')
|
||||||
|
@ -99,17 +99,20 @@ describe(FoodOrderController::class, function (): void {
|
||||||
|
|
||||||
$crawler = $this->client->request('GET', "{$this->path}{$order->getId()}");
|
$crawler = $this->client->request('GET', "{$this->path}{$order->getId()}");
|
||||||
$this->assertResponseIsSuccessful();
|
$this->assertResponseIsSuccessful();
|
||||||
$tdContent = $crawler->filter(
|
|
||||||
'table.table:nth-child(6) > tbody:nth-child(2) > tr:nth-child(1) > td:nth-child(3)'
|
// Find all tables and get the last one (order items table)
|
||||||
)->text();
|
$tables = $crawler->filter('table');
|
||||||
|
$lastTable = $tables->eq($tables->count() - 1);
|
||||||
|
|
||||||
|
// Get the item names from the table rows
|
||||||
|
$rows = $lastTable->filter('tbody tr');
|
||||||
|
$tdContent = $rows->eq(0)->filter('td')->eq(2)->text();
|
||||||
$this->assertEquals('A', $tdContent);
|
$this->assertEquals('A', $tdContent);
|
||||||
$tdContent = $crawler->filter(
|
|
||||||
'table.table:nth-child(6) > tbody:nth-child(2) > tr:nth-child(2) > td:nth-child(3)'
|
$tdContent = $rows->eq(1)->filter('td')->eq(2)->text();
|
||||||
)->text();
|
|
||||||
$this->assertEquals('B', $tdContent);
|
$this->assertEquals('B', $tdContent);
|
||||||
$tdContent = $crawler->filter(
|
|
||||||
'table.table:nth-child(6) > tbody:nth-child(2) > tr:nth-child(3) > td:nth-child(3)'
|
$tdContent = $rows->eq(2)->filter('td')->eq(2)->text();
|
||||||
)->text();
|
|
||||||
$this->assertEquals('C', $tdContent);
|
$this->assertEquals('C', $tdContent);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -124,12 +127,12 @@ describe(FoodOrderController::class, function (): void {
|
||||||
$this->manager->flush();
|
$this->manager->flush();
|
||||||
$crawler = $this->client->request('GET', "{$this->path}list");
|
$crawler = $this->client->request('GET', "{$this->path}list");
|
||||||
$this->assertResponseStatusCodeSame(200);
|
$this->assertResponseStatusCodeSame(200);
|
||||||
$this->assertPageTitleContains('FoodOrder index');
|
$this->assertPageTitleContains('Food Orders');
|
||||||
$this->assertElementContainsCount(
|
$this->assertElementContainsCount(
|
||||||
$crawler,
|
$crawler,
|
||||||
'td',
|
'td',
|
||||||
1,
|
1,
|
||||||
'older orders'
|
'for older orders'
|
||||||
);
|
);
|
||||||
$this->assertElementContainsCount(
|
$this->assertElementContainsCount(
|
||||||
$crawler,
|
$crawler,
|
||||||
|
@ -139,7 +142,7 @@ describe(FoodOrderController::class, function (): void {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('paginatedFirstPage', function (int $page, int $prevPage, int $nextPage, int $items = 10): void {
|
test('paginatedFirstPage', function (int $page, int $prevPage, int $nextPage, int $items = 20): void {
|
||||||
foreach (range(1, 35) as $i) {
|
foreach (range(1, 35) as $i) {
|
||||||
$order = new FoodOrder($this->generateOldUlid());
|
$order = new FoodOrder($this->generateOldUlid());
|
||||||
$order->setFoodVendor($this->vendor);
|
$order->setFoodVendor($this->vendor);
|
||||||
|
@ -150,7 +153,7 @@ describe(FoodOrderController::class, function (): void {
|
||||||
$this->manager->flush();
|
$this->manager->flush();
|
||||||
$crawler = $this->client->request('GET', "{$this->path}list/archive/{$page}");
|
$crawler = $this->client->request('GET', "{$this->path}list/archive/{$page}");
|
||||||
$this->assertResponseStatusCodeSame(200);
|
$this->assertResponseStatusCodeSame(200);
|
||||||
$this->assertPageTitleContains('FoodOrder index');
|
$this->assertPageTitleContains('Food Orders');
|
||||||
$this->assertElementContainsCount(
|
$this->assertElementContainsCount(
|
||||||
$crawler,
|
$crawler,
|
||||||
'td',
|
'td',
|
||||||
|
@ -160,14 +163,14 @@ describe(FoodOrderController::class, function (): void {
|
||||||
if ($prevPage > 0) {
|
if ($prevPage > 0) {
|
||||||
$prevPage = $prevPage === 1 ? '' : "/{$prevPage}";
|
$prevPage = $prevPage === 1 ? '' : "/{$prevPage}";
|
||||||
$node = $crawler->filter('a')
|
$node = $crawler->filter('a')
|
||||||
->reduce(static fn(Crawler $node, $i): bool => $node->text() === 'previous page')
|
->reduce(static fn(Crawler $node, $i): bool => $node->text() === 'Previous Page')
|
||||||
->first();
|
->first();
|
||||||
$target = $node->attr('href');
|
$target = $node->attr('href');
|
||||||
$this->assertTrue(str_ends_with((string) $target, $prevPage));
|
$this->assertTrue(str_ends_with((string) $target, $prevPage));
|
||||||
}
|
}
|
||||||
if ($prevPage > 3) {
|
if ($prevPage > 3) {
|
||||||
$node = $crawler->filter('a')
|
$node = $crawler->filter('a')
|
||||||
->reduce(static fn(Crawler $node, $i): bool => $node->text() === 'next page')
|
->reduce(static fn(Crawler $node, $i): bool => $node->text() === 'Next Page')
|
||||||
->first();
|
->first();
|
||||||
$target = $node->attr('href');
|
$target = $node->attr('href');
|
||||||
$this->assertTrue(str_ends_with((string) $target, "/{$nextPage}"));
|
$this->assertTrue(str_ends_with((string) $target, "/{$nextPage}"));
|
||||||
|
@ -178,7 +181,7 @@ describe(FoodOrderController::class, function (): void {
|
||||||
[1, 0, 2],
|
[1, 0, 2],
|
||||||
[2, 1, 3],
|
[2, 1, 3],
|
||||||
[3, 2, 4],
|
[3, 2, 4],
|
||||||
[4, 3, 0, 5],
|
[4, 3, 0, 10],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ describe(FoodVendorController::class, function (): void {
|
||||||
$this->client->request('GET', $this->path);
|
$this->client->request('GET', $this->path);
|
||||||
|
|
||||||
$this->assertResponseStatusCodeSame(200);
|
$this->assertResponseStatusCodeSame(200);
|
||||||
$this->assertPageTitleContains('FoodVendor index');
|
$this->assertPageTitleContains('Food Vendors');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('new', function (): void {
|
test('new', function (): void {
|
||||||
|
|
|
@ -136,10 +136,9 @@ describe(MenuItemController::class, function (): void {
|
||||||
$this->assertTrue($menuItem->isDeleted());
|
$this->assertTrue($menuItem->isDeleted());
|
||||||
|
|
||||||
$crawler = $this->client->request('GET', '/order/item/new/' . $order->getId());
|
$crawler = $this->client->request('GET', '/order/item/new/' . $order->getId());
|
||||||
$count = $crawler->filter('body > main:nth-child(2) > div:nth-child(5)')
|
$count = $crawler->filter('form')
|
||||||
->children()
|
|
||||||
->count();
|
->count();
|
||||||
$this->assertSame(2, $count);
|
$this->assertSame(1, $count);
|
||||||
|
|
||||||
$this->assertResponseIsSuccessful();
|
$this->assertResponseIsSuccessful();
|
||||||
|
|
||||||
|
|
|
@ -60,8 +60,7 @@ describe(OrderItemController::class, function (): void {
|
||||||
sprintf('%snew/%s', $this->path, $this->order->getId())
|
sprintf('%snew/%s', $this->path, $this->order->getId())
|
||||||
);
|
);
|
||||||
|
|
||||||
$children = $crawler->filter('body > main:nth-child(2) > div:nth-child(5)')
|
$children = $crawler->filter('form');
|
||||||
->children();
|
|
||||||
|
|
||||||
$this->assertCount(1, $children);
|
$this->assertCount(1, $children);
|
||||||
|
|
||||||
|
|
16
tests/Unit/ExampleTest.php
Normal file
16
tests/Unit/ExampleTest.php
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
test('example test', function (): void {
|
||||||
|
// This is a simple example test
|
||||||
|
expect(true)->toBeTrue();
|
||||||
|
expect(1 + 1)->toBe(2);
|
||||||
|
expect('hello world')->toContain('world');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('array operations', function (): void {
|
||||||
|
$array = [1, 2, 3];
|
||||||
|
|
||||||
|
expect($array)->toHaveCount(3);
|
||||||
|
expect($array)->toContain(2);
|
||||||
|
expect($array[0])->toBe(1);
|
||||||
|
});
|
Loading…
Add table
Add a link
Reference in a new issue