feat(controller): add post lists controller
This commit is contained in:
parent
58f43f096a
commit
a99f6244b4
19
.gitignore
vendored
19
.gitignore
vendored
@ -1,4 +1,3 @@
|
||||
|
||||
###> symfony/framework-bundle ###
|
||||
/.env.local
|
||||
/.env.local.php
|
||||
@ -18,8 +17,18 @@
|
||||
.phpunit.result.cache
|
||||
/phpunit.xml
|
||||
###< symfony/phpunit-bridge ###
|
||||
###> phpstan/phpstan ###
|
||||
phpstan.neon
|
||||
###< phpstan/phpstan ###
|
||||
|
||||
###> symfony/asset-mapper ###
|
||||
/public/assets/
|
||||
/assets/vendor/
|
||||
###< symfony/asset-mapper ###
|
||||
###> squizlabs/php_codesniffer ###
|
||||
/.phpcs-cache
|
||||
/phpcs.xml
|
||||
###< squizlabs/php_codesniffer ###
|
||||
|
||||
###> symfony/webpack-encore-bundle ###
|
||||
/node_modules/
|
||||
/public/build/
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
###< symfony/webpack-encore-bundle ###
|
||||
|
@ -1,4 +1,3 @@
|
||||
import './bootstrap.js';
|
||||
/*
|
||||
* Welcome to your app's main JavaScript file!
|
||||
*
|
||||
@ -6,5 +5,7 @@ import './bootstrap.js';
|
||||
* which should already be in your base.html.twig.
|
||||
*/
|
||||
import './styles/app.css';
|
||||
import './styles/global.scss';
|
||||
|
||||
console.log('This log comes from assets/app.js - welcome to AssetMapper! 🎉');
|
||||
require('bootstrap');
|
||||
|
5
assets/bootstrap.js
vendored
5
assets/bootstrap.js
vendored
@ -1,5 +0,0 @@
|
||||
import { startStimulusApp } from '@symfony/stimulus-bundle';
|
||||
|
||||
const app = startStimulusApp();
|
||||
// register any custom, 3rd party controllers here
|
||||
// app.register('some_controller_name', SomeImportedController);
|
@ -1,15 +0,0 @@
|
||||
{
|
||||
"controllers": {
|
||||
"@symfony/ux-turbo": {
|
||||
"turbo-core": {
|
||||
"enabled": true,
|
||||
"fetch": "eager"
|
||||
},
|
||||
"mercure-turbo-stream": {
|
||||
"enabled": false,
|
||||
"fetch": "eager"
|
||||
}
|
||||
}
|
||||
},
|
||||
"entrypoints": []
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
import { Controller } from '@hotwired/stimulus';
|
||||
|
||||
/*
|
||||
* This is an example Stimulus controller!
|
||||
*
|
||||
* Any element with a data-controller="hello" attribute will cause
|
||||
* this controller to be executed. The name "hello" comes from the filename:
|
||||
* hello_controller.js -> "hello"
|
||||
*
|
||||
* Delete this file or adapt it for your use!
|
||||
*/
|
||||
export default class extends Controller {
|
||||
connect() {
|
||||
this.element.textContent = 'Hello Stimulus! Edit me in assets/controllers/hello_controller.js';
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
body {
|
||||
background-color: skyblue;
|
||||
}
|
3
assets/styles/global.scss
Normal file
3
assets/styles/global.scss
Normal file
@ -0,0 +1,3 @@
|
||||
$primary: darken(#66531e, 20%);
|
||||
|
||||
@import "~bootstrap/scss/bootstrap";
|
7
assets/vendor/@hotwired/stimulus/stimulus.index.js
vendored
Normal file
7
assets/vendor/@hotwired/stimulus/stimulus.index.js
vendored
Normal file
File diff suppressed because one or more lines are too long
30
assets/vendor/@hotwired/turbo/turbo.index.js
vendored
Normal file
30
assets/vendor/@hotwired/turbo/turbo.index.js
vendored
Normal file
File diff suppressed because one or more lines are too long
22
assets/vendor/installed.php
vendored
Normal file
22
assets/vendor/installed.php
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
<?php return array (
|
||||
'@hotwired/stimulus' =>
|
||||
array (
|
||||
'version' => '3.2.2',
|
||||
'dependencies' =>
|
||||
array (
|
||||
),
|
||||
'extraFiles' =>
|
||||
array (
|
||||
),
|
||||
),
|
||||
'@hotwired/turbo' =>
|
||||
array (
|
||||
'version' => '7.3.0',
|
||||
'dependencies' =>
|
||||
array (
|
||||
),
|
||||
'extraFiles' =>
|
||||
array (
|
||||
),
|
||||
),
|
||||
);
|
@ -16,7 +16,6 @@
|
||||
"phpdocumentor/reflection-docblock": "^5.4",
|
||||
"phpstan/phpdoc-parser": "^1.29",
|
||||
"symfony/asset": "7.1.*",
|
||||
"symfony/asset-mapper": "7.1.*",
|
||||
"symfony/console": "7.1.*",
|
||||
"symfony/doctrine-messenger": "7.1.*",
|
||||
"symfony/dotenv": "7.1.*",
|
||||
@ -37,15 +36,15 @@
|
||||
"symfony/runtime": "7.1.*",
|
||||
"symfony/security-bundle": "7.1.*",
|
||||
"symfony/serializer": "7.1.*",
|
||||
"symfony/stimulus-bundle": "^2.18",
|
||||
"symfony/string": "7.1.*",
|
||||
"symfony/translation": "7.1.*",
|
||||
"symfony/twig-bundle": "7.1.*",
|
||||
"symfony/ux-turbo": "^2.18",
|
||||
"symfony/validator": "7.1.*",
|
||||
"symfony/web-link": "7.1.*",
|
||||
"symfony/webpack-encore-bundle": "^2.1",
|
||||
"symfony/yaml": "7.1.*",
|
||||
"twig/extra-bundle": "^2.12|^3.0",
|
||||
"twig/string-extra": "^3.10",
|
||||
"twig/twig": "^2.12|^3.0"
|
||||
},
|
||||
"config": {
|
||||
@ -80,8 +79,7 @@
|
||||
"scripts": {
|
||||
"auto-scripts": {
|
||||
"cache:clear": "symfony-cmd",
|
||||
"assets:install %PUBLIC_DIR%": "symfony-cmd",
|
||||
"importmap:install": "symfony-cmd"
|
||||
"assets:install %PUBLIC_DIR%": "symfony-cmd"
|
||||
},
|
||||
"post-install-cmd": [
|
||||
"@auto-scripts"
|
||||
|
466
composer.lock
generated
466
composer.lock
generated
@ -4,89 +4,8 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "131c365156daf6fd97b5e15f509f17eb",
|
||||
"content-hash": "3e172a49e6d5bdaae8e4224364e75043",
|
||||
"packages": [
|
||||
{
|
||||
"name": "composer/semver",
|
||||
"version": "3.4.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/semver.git",
|
||||
"reference": "c51258e759afdb17f1fd1fe83bc12baaef6309d6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/semver/zipball/c51258e759afdb17f1fd1fe83bc12baaef6309d6",
|
||||
"reference": "c51258e759afdb17f1fd1fe83bc12baaef6309d6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.3.2 || ^7.0 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^1.4",
|
||||
"symfony/phpunit-bridge": "^4.2 || ^5"
|
||||
},
|
||||
"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.2"
|
||||
},
|
||||
"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-07-12T11:35:52+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/cache",
|
||||
"version": "2.2.0",
|
||||
@ -2178,85 +2097,6 @@
|
||||
],
|
||||
"time": "2024-05-31T14:57:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/asset-mapper",
|
||||
"version": "v7.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/asset-mapper.git",
|
||||
"reference": "b496ba0c1ca69abbbc2413b853decad2eed9a74b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/asset-mapper/zipball/b496ba0c1ca69abbbc2413b853decad2eed9a74b",
|
||||
"reference": "b496ba0c1ca69abbbc2413b853decad2eed9a74b",
|
||||
"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.1.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-07-09T19:36:07+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/cache",
|
||||
"version": "v7.1.3",
|
||||
@ -6352,75 +6192,6 @@
|
||||
],
|
||||
"time": "2024-04-18T09:32:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/stimulus-bundle",
|
||||
"version": "v2.18.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/stimulus-bundle.git",
|
||||
"reference": "017b60e036c366c8ce0e77864d5aabab436ad73d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/stimulus-bundle/zipball/017b60e036c366c8ce0e77864d5aabab436ad73d",
|
||||
"reference": "017b60e036c366c8ce0e77864d5aabab436ad73d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.1",
|
||||
"symfony/config": "^5.4|^6.0|^7.0",
|
||||
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
|
||||
"symfony/deprecation-contracts": "^2.0|^3.0",
|
||||
"symfony/finder": "^5.4|^6.0|^7.0",
|
||||
"symfony/http-kernel": "^5.4|^6.0|^7.0",
|
||||
"twig/twig": "^2.15.3|^3.8"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/asset-mapper": "^6.3|^7.0",
|
||||
"symfony/framework-bundle": "^5.4|^6.0|^7.0",
|
||||
"symfony/phpunit-bridge": "^5.4|^6.0|^7.0",
|
||||
"symfony/twig-bundle": "^5.4|^6.0|^7.0",
|
||||
"zenstruck/browser": "^1.4"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\UX\\StimulusBundle\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Integration with your Symfony app & Stimulus!",
|
||||
"keywords": [
|
||||
"symfony-ux"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/stimulus-bundle/tree/v2.18.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-06-11T13:21:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/stopwatch",
|
||||
"version": "v7.1.1",
|
||||
@ -7017,103 +6788,6 @@
|
||||
],
|
||||
"time": "2024-05-31T14:59:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/ux-turbo",
|
||||
"version": "v2.18.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/ux-turbo.git",
|
||||
"reference": "e447231ddcc09ab68d29047f47d31a524837dc7a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/ux-turbo/zipball/e447231ddcc09ab68d29047f47d31a524837dc7a",
|
||||
"reference": "e447231ddcc09ab68d29047f47d31a524837dc7a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.1",
|
||||
"symfony/stimulus-bundle": "^2.9.1"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/flex": "<1.13"
|
||||
},
|
||||
"require-dev": {
|
||||
"dbrekelmans/bdi": "dev-main",
|
||||
"doctrine/doctrine-bundle": "^2.4.3",
|
||||
"doctrine/orm": "^2.8 | 3.0",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"symfony/debug-bundle": "^5.4|^6.0|^7.0",
|
||||
"symfony/expression-language": "^5.4|^6.0|^7.0",
|
||||
"symfony/form": "^5.4|^6.0|^7.0",
|
||||
"symfony/framework-bundle": "^5.4|^6.0|^7.0",
|
||||
"symfony/mercure-bundle": "^0.3.7",
|
||||
"symfony/messenger": "^5.4|^6.0|^7.0",
|
||||
"symfony/panther": "^1.0|^2.0",
|
||||
"symfony/phpunit-bridge": "^5.4|^6.0|^7.0",
|
||||
"symfony/process": "^5.4|6.3.*|^7.0",
|
||||
"symfony/property-access": "^5.4|^6.0|^7.0",
|
||||
"symfony/security-core": "^5.4|^6.0|^7.0",
|
||||
"symfony/stopwatch": "^5.4|^6.0|^7.0",
|
||||
"symfony/twig-bundle": "^5.4|^6.0|^7.0",
|
||||
"symfony/web-profiler-bundle": "^5.4|^6.0|^7.0",
|
||||
"symfony/webpack-encore-bundle": "^2.1.1"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"name": "symfony/ux",
|
||||
"url": "https://github.com/symfony/ux"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\UX\\Turbo\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Kévin Dunglas",
|
||||
"email": "kevin@dunglas.fr"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Hotwire Turbo integration for Symfony",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"hotwire",
|
||||
"javascript",
|
||||
"mercure",
|
||||
"symfony-ux",
|
||||
"turbo",
|
||||
"turbo-stream"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/ux-turbo/tree/v2.18.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-06-01T17:56:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/validator",
|
||||
"version": "v7.1.3",
|
||||
@ -7453,6 +7127,77 @@
|
||||
],
|
||||
"time": "2024-05-31T14:57:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/webpack-encore-bundle",
|
||||
"version": "v2.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/webpack-encore-bundle.git",
|
||||
"reference": "75cb918df3f65e28cf0d4bc03042bc45ccb19dd0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/webpack-encore-bundle/zipball/75cb918df3f65e28cf0d4bc03042bc45ccb19dd0",
|
||||
"reference": "75cb918df3f65e28cf0d4bc03042bc45ccb19dd0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.1.0",
|
||||
"symfony/asset": "^5.4 || ^6.2 || ^7.0",
|
||||
"symfony/config": "^5.4 || ^6.2 || ^7.0",
|
||||
"symfony/dependency-injection": "^5.4 || ^6.2 || ^7.0",
|
||||
"symfony/http-kernel": "^5.4 || ^6.2 || ^7.0",
|
||||
"symfony/service-contracts": "^1.1.9 || ^2.1.3 || ^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/framework-bundle": "^5.4 || ^6.2 || ^7.0",
|
||||
"symfony/phpunit-bridge": "^5.4 || ^6.2 || ^7.0",
|
||||
"symfony/twig-bundle": "^5.4 || ^6.2 || ^7.0",
|
||||
"symfony/web-link": "^5.4 || ^6.2 || ^7.0"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"name": "symfony/webpack-encore",
|
||||
"url": "https://github.com/symfony/webpack-encore"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\WebpackEncoreBundle\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Integration with your Symfony app & Webpack Encore!",
|
||||
"support": {
|
||||
"issues": "https://github.com/symfony/webpack-encore-bundle/issues",
|
||||
"source": "https://github.com/symfony/webpack-encore-bundle/tree/v2.1.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-10-22T18:53:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v7.1.1",
|
||||
@ -7598,6 +7343,73 @@
|
||||
],
|
||||
"time": "2024-05-11T07:35:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "twig/string-extra",
|
||||
"version": "v3.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/string-extra.git",
|
||||
"reference": "cd76ed8ae081bcd4fddf549e92e20c5df76c358a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/string-extra/zipball/cd76ed8ae081bcd4fddf549e92e20c5df76c358a",
|
||||
"reference": "cd76ed8ae081bcd4fddf549e92e20c5df76c358a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2.5",
|
||||
"symfony/string": "^5.4|^6.4|^7.0",
|
||||
"symfony/translation-contracts": "^1.1|^2|^3",
|
||||
"twig/twig": "^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "^6.4|^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Twig\\Extra\\String\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com",
|
||||
"homepage": "http://fabien.potencier.org",
|
||||
"role": "Lead Developer"
|
||||
}
|
||||
],
|
||||
"description": "A Twig extension for Symfony String",
|
||||
"homepage": "https://twig.symfony.com",
|
||||
"keywords": [
|
||||
"html",
|
||||
"string",
|
||||
"twig",
|
||||
"unicode"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/twigphp/string-extra/tree/v3.10.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/twig/twig",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-05-11T07:35:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v3.10.3",
|
||||
|
@ -7,10 +7,9 @@ return [
|
||||
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true],
|
||||
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
|
||||
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
|
||||
Symfony\UX\StimulusBundle\StimulusBundle::class => ['all' => true],
|
||||
Symfony\UX\Turbo\TurboBundle::class => ['all' => true],
|
||||
Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
|
||||
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
|
||||
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
|
||||
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
|
||||
Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
|
||||
];
|
||||
|
@ -1,5 +0,0 @@
|
||||
framework:
|
||||
asset_mapper:
|
||||
# The paths to make available to the asset mapper.
|
||||
paths:
|
||||
- assets/
|
45
config/packages/webpack_encore.yaml
Normal file
45
config/packages/webpack_encore.yaml
Normal file
@ -0,0 +1,45 @@
|
||||
webpack_encore:
|
||||
# The path where Encore is building the assets - i.e. Encore.setOutputPath()
|
||||
output_path: '%kernel.project_dir%/public/build'
|
||||
# If multiple builds are defined (as shown below), you can disable the default build:
|
||||
# output_path: false
|
||||
|
||||
# Set attributes that will be rendered on all script and link tags
|
||||
script_attributes:
|
||||
defer: true
|
||||
# Uncomment (also under link_attributes) if using Turbo Drive
|
||||
# https://turbo.hotwired.dev/handbook/drive#reloading-when-assets-change
|
||||
# 'data-turbo-track': reload
|
||||
# link_attributes:
|
||||
# Uncomment if using Turbo Drive
|
||||
# 'data-turbo-track': reload
|
||||
|
||||
# If using Encore.enableIntegrityHashes() and need the crossorigin attribute (default: false, or use 'anonymous' or 'use-credentials')
|
||||
# crossorigin: 'anonymous'
|
||||
|
||||
# Preload all rendered script and link tags automatically via the HTTP/2 Link header
|
||||
# preload: true
|
||||
|
||||
# Throw an exception if the entrypoints.json file is missing or an entry is missing from the data
|
||||
# strict_mode: false
|
||||
|
||||
# If you have multiple builds:
|
||||
# builds:
|
||||
# frontend: '%kernel.project_dir%/public/frontend/build'
|
||||
|
||||
# pass the build name as the 3rd argument to the Twig functions
|
||||
# {{ encore_entry_script_tags('entry1', null, 'frontend') }}
|
||||
|
||||
framework:
|
||||
assets:
|
||||
json_manifest_path: '%kernel.project_dir%/public/build/manifest.json'
|
||||
|
||||
#when@prod:
|
||||
# webpack_encore:
|
||||
# # Cache the entrypoints.json (rebuild Symfony's cache when entrypoints.json changes)
|
||||
# # Available in version 1.2
|
||||
# cache: true
|
||||
|
||||
#when@test:
|
||||
# webpack_encore:
|
||||
# strict_mode: false
|
@ -4,6 +4,8 @@
|
||||
# Put parameters here that don't need to change on each machine where the app is deployed
|
||||
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
|
||||
parameters:
|
||||
list.page.size: 24
|
||||
list.page.max_visible_pages: 3
|
||||
|
||||
services:
|
||||
# default configuration for services in *this* file
|
||||
@ -23,5 +25,11 @@ services:
|
||||
App\Command\RefreshDatabaseCommand:
|
||||
arguments:
|
||||
$name: "brilo:refresh-database"
|
||||
|
||||
App\Controller\ListPostController:
|
||||
arguments:
|
||||
$pageSize: '%list.page.size%'
|
||||
$maxVisiblePages: '%list.page.max_visible_pages%'
|
||||
|
||||
# add more service definitions when explicit configuration is needed
|
||||
# please note that last definitions always *replace* previous ones
|
||||
|
@ -1,3 +1,7 @@
|
||||
parameters:
|
||||
list.page.size: 3
|
||||
list.page.max_visible_pages: 3
|
||||
|
||||
services:
|
||||
App\Service\Remote\BriloApiUsers:
|
||||
public: true
|
||||
|
@ -1,28 +0,0 @@
|
||||
<?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,
|
||||
],
|
||||
'@hotwired/stimulus' => [
|
||||
'version' => '3.2.2',
|
||||
],
|
||||
'@symfony/stimulus-bundle' => [
|
||||
'path' => './vendor/symfony/stimulus-bundle/assets/dist/loader.js',
|
||||
],
|
||||
'@hotwired/turbo' => [
|
||||
'version' => '7.3.0',
|
||||
],
|
||||
];
|
8252
package-lock.json
generated
Normal file
8252
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
14
package.json
Normal file
14
package.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@symfony/webpack-encore": "^4.6.1",
|
||||
"bootstrap": "^5.3.3",
|
||||
"jquery": "^3.7.1",
|
||||
"sass": "^1.77.8",
|
||||
"sass-loader": "^14.2.1",
|
||||
"webpack-notifier": "^1.15.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"webpack": "^5.93.0"
|
||||
}
|
||||
}
|
@ -21,6 +21,12 @@
|
||||
<testsuite name="unit">
|
||||
<directory>tests/Unit</directory>
|
||||
</testsuite>
|
||||
<testsuite name="db">
|
||||
<directory>tests/Db</directory>
|
||||
</testsuite>
|
||||
<testsuite name="web">
|
||||
<directory>tests/Web</directory>
|
||||
</testsuite>
|
||||
<testsuite name="integration">
|
||||
<directory>tests/Integration</directory>
|
||||
</testsuite>
|
||||
|
8
src/Controller/DetailPostController.php
Normal file
8
src/Controller/DetailPostController.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
class DetailPostController
|
||||
{
|
||||
|
||||
}
|
56
src/Controller/ListPostController.php
Normal file
56
src/Controller/ListPostController.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Repository\Post\PostRepository;
|
||||
use App\Utils\Paginator\Paginator;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
final class ListPostController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly int $pageSize,
|
||||
private readonly int $maxVisiblePages,
|
||||
private readonly PostRepository $postRepository,
|
||||
private readonly Paginator $paginator,
|
||||
) {
|
||||
}
|
||||
|
||||
#[Route('/', name: 'default')]
|
||||
public function default(): Response
|
||||
{
|
||||
return $this->forward(ListPostController::class . '::pageList', ['page' => 1]);
|
||||
}
|
||||
|
||||
#[Route('/posts/{page}', name: 'page_list', requirements: ['page' => '\d+'], defaults: ['page' => 1])]
|
||||
public function pageList(int $page): Response
|
||||
{
|
||||
$totalPages = (int) ceil($this->postRepository->count([]) / $this->pageSize); /* TODO: tohle by si zaslouzilo asi cache */
|
||||
|
||||
if ($totalPages === 0) {
|
||||
$this->logger->error('No posts found. Try run brilo:refresh-database command.');
|
||||
throw new NotFoundHttpException('No posts found.');
|
||||
}
|
||||
|
||||
if ($page === 0) {
|
||||
return $this->redirectToRoute('page_list', ['page' => 1]);
|
||||
}
|
||||
|
||||
// If page number is out of range, redirect to the last page.
|
||||
if ($page > $totalPages) {
|
||||
return $this->redirectToRoute('page_list', ['page' => $totalPages]);
|
||||
}
|
||||
|
||||
$posts = $this->postRepository->getPaginatedPosts($page, $this->pageSize);
|
||||
|
||||
return $this->render('list_post/list.html.twig', [
|
||||
'posts' => $posts,
|
||||
'page' => $this->paginator->getVisiblePages($page, $totalPages, $this->maxVisiblePages),
|
||||
]);
|
||||
}
|
||||
}
|
@ -18,4 +18,20 @@ class PostRepository extends ServiceEntityRepository
|
||||
{
|
||||
parent::__construct($registry, Post::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $page
|
||||
* @param int $pageSize
|
||||
* @return array<Post>
|
||||
*/
|
||||
public function getPaginatedPosts(int $page, int $pageSize): array
|
||||
{
|
||||
$query = $this->createQueryBuilder('p')
|
||||
->orderBy('p.id', 'DESC')
|
||||
->setFirstResult(($page - 1) * $pageSize)
|
||||
->setMaxResults($pageSize)
|
||||
->getQuery();
|
||||
|
||||
return $query->getResult();
|
||||
}
|
||||
}
|
||||
|
45
src/Utils/Paginator/Paginator.php
Normal file
45
src/Utils/Paginator/Paginator.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Utils\Paginator;
|
||||
|
||||
class Paginator
|
||||
{
|
||||
/**
|
||||
* Determinate which pages are visible in the paginator
|
||||
* @param int $page
|
||||
* @param int $totalPages
|
||||
* @param int $maxVisiblePages
|
||||
* @return PaginatorResult
|
||||
*/
|
||||
public function getVisiblePages(int $page, int $totalPages, int $maxVisiblePages): PaginatorResult
|
||||
{
|
||||
$half = floor($maxVisiblePages / 2);
|
||||
|
||||
if ($page <= $half) {
|
||||
$start = 1;
|
||||
$end = min($totalPages, $maxVisiblePages);
|
||||
} elseif ($page > $totalPages - $half) {
|
||||
$start = max(1, $totalPages - $maxVisiblePages + 1);
|
||||
$end = $totalPages;
|
||||
} else {
|
||||
$start = $page - $half;
|
||||
$end = min($totalPages, $page + $half);
|
||||
}
|
||||
|
||||
/**
|
||||
* @var array<int> $range
|
||||
*/
|
||||
$range = range($start, $end);
|
||||
|
||||
return new PaginatorResult(
|
||||
$page,
|
||||
$start == 1,
|
||||
$end == $totalPages,
|
||||
$totalPages,
|
||||
$totalPages,
|
||||
$range
|
||||
);
|
||||
}
|
||||
}
|
21
src/Utils/Paginator/PaginatorResult.php
Normal file
21
src/Utils/Paginator/PaginatorResult.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Utils\Paginator;
|
||||
|
||||
readonly class PaginatorResult
|
||||
{
|
||||
public function __construct(
|
||||
public int $currentPage,
|
||||
public bool $firstPageVisible,
|
||||
public bool $lastPageVisible,
|
||||
public int $totalPages,
|
||||
public int $lastPage,
|
||||
/**
|
||||
* @var array<int>
|
||||
*/
|
||||
public array $visiblePages,
|
||||
) {
|
||||
}
|
||||
}
|
48
symfony.lock
48
symfony.lock
@ -64,21 +64,6 @@
|
||||
"phpcs.xml.dist"
|
||||
]
|
||||
},
|
||||
"symfony/asset-mapper": {
|
||||
"version": "7.1",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "6.4",
|
||||
"ref": "6c28c471640cc2c6e60812ebcb961c526ef8997f"
|
||||
},
|
||||
"files": [
|
||||
"assets/app.js",
|
||||
"assets/styles/app.css",
|
||||
"config/packages/asset_mapper.yaml",
|
||||
"importmap.php"
|
||||
]
|
||||
},
|
||||
"symfony/console": {
|
||||
"version": "7.1",
|
||||
"recipe": {
|
||||
@ -244,20 +229,6 @@
|
||||
"config/routes/security.yaml"
|
||||
]
|
||||
},
|
||||
"symfony/stimulus-bundle": {
|
||||
"version": "2.18",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "2.13",
|
||||
"ref": "6acd9ff4f7fd5626d2962109bd4ebab351d43c43"
|
||||
},
|
||||
"files": [
|
||||
"assets/bootstrap.js",
|
||||
"assets/controllers.json",
|
||||
"assets/controllers/hello_controller.js"
|
||||
]
|
||||
},
|
||||
"symfony/translation": {
|
||||
"version": "7.1",
|
||||
"recipe": {
|
||||
@ -284,9 +255,6 @@
|
||||
"templates/base.html.twig"
|
||||
]
|
||||
},
|
||||
"symfony/ux-turbo": {
|
||||
"version": "v2.18.0"
|
||||
},
|
||||
"symfony/validator": {
|
||||
"version": "7.1",
|
||||
"recipe": {
|
||||
@ -312,6 +280,22 @@
|
||||
"config/routes/web_profiler.yaml"
|
||||
]
|
||||
},
|
||||
"symfony/webpack-encore-bundle": {
|
||||
"version": "2.1",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "2.0",
|
||||
"ref": "082d754b3bd54b3fc669f278f1eea955cfd23cf5"
|
||||
},
|
||||
"files": [
|
||||
"assets/app.js",
|
||||
"assets/styles/app.css",
|
||||
"config/packages/webpack_encore.yaml",
|
||||
"package.json",
|
||||
"webpack.config.js"
|
||||
]
|
||||
},
|
||||
"twig/extra-bundle": {
|
||||
"version": "v3.10.0"
|
||||
}
|
||||
|
@ -2,16 +2,20 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{% block title %}Welcome!{% endblock %}</title>
|
||||
<title>{% block title %}Post App{% endblock %}</title>
|
||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
|
||||
{% block stylesheets %}
|
||||
{{ encore_entry_link_tags('app') }}
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
{% block importmap %}{{ importmap('app') }}{% endblock %}
|
||||
{{ encore_entry_script_tags('app') }}
|
||||
{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
{% block body %}{% endblock %}
|
||||
{% include 'header.html.twig' %}
|
||||
<div class="container container-lg">
|
||||
{% block body %}{% endblock %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
5
templates/header.html.twig
Normal file
5
templates/header.html.twig
Normal file
@ -0,0 +1,5 @@
|
||||
<div class="container">
|
||||
<header class="d-flex justify-content-center py-3">
|
||||
<h1>{{ 'List App' | trans }}</h1>
|
||||
</header>
|
||||
</div>
|
36
templates/list_post/list.html.twig
Normal file
36
templates/list_post/list.html.twig
Normal file
@ -0,0 +1,36 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block body %}
|
||||
{% for post in posts %}
|
||||
<div class="card t-post-detail">
|
||||
<div class="card-header">
|
||||
<a class="t-detail-a" href="{{ path('detail_post', {postId: post.id}) }}">#{{ post.id }} - <span class="t-post-title">{{ post.title|u.truncate(80, '...', true)}}</span></a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="card-text t-post-body">
|
||||
{{ post.body|u.truncate(80, '...', true) }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination t-pagination">
|
||||
{% if not page.firstPageVisible %}
|
||||
<li class="page-item t-page-item"><a class="page-link t-page-link" href="{{ path('page_list', {page: 1}) }}">1…</a></li>
|
||||
{% endif %}
|
||||
{% for i in page.visiblePages %}
|
||||
<li class="page-item {% if i == page.currentPage %}active{% endif %} t-page-item">
|
||||
{% if i == page.currentPage %}
|
||||
<span class="page-link">{{ i }}</span>
|
||||
{% else %}
|
||||
<a class="page-link t-page-link" href="{{ path('page_list', {page: i}) }}">{{ i }}</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% if not page.lastPageVisible %}
|
||||
<li class="page-item t-page-item"><a class="page-link t-page-link" href="{{ path('page_list', {page: page.lastPage}) }}">…{{ page.lastPage }}</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endblock %}
|
123
tests/Web/ListPostControllerTest.php
Normal file
123
tests/Web/ListPostControllerTest.php
Normal file
@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Web;
|
||||
|
||||
use App\Entity\Database\Posts\Post;
|
||||
use App\Tests\Common\DatabaseTestTrait;
|
||||
use App\Tests\Common\FakerTrait;
|
||||
use App\Tests\Common\Generators\PostGeneratorTrait;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Symfony\Component\BrowserKit\AbstractBrowser;
|
||||
|
||||
class ListPostControllerTest extends WebTestCase
|
||||
{
|
||||
use DatabaseTestTrait;
|
||||
use FakerTrait;
|
||||
use PostGeneratorTrait;
|
||||
|
||||
protected AbstractBrowser $client;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->client = static::createClient();
|
||||
$this->bootDatabase();
|
||||
$this->bootFaker();
|
||||
$this->getFaker()->unique();
|
||||
}
|
||||
|
||||
public function testPostListed(): void
|
||||
{
|
||||
|
||||
$posts = $this->createTestPosts();
|
||||
|
||||
$crawler = $this->client->request('GET', '/posts/1');
|
||||
|
||||
|
||||
$this->assertResponseIsSuccessful();
|
||||
$this->assertSelectorCount(3, '.t-detail-a'); // 3 posts are listed
|
||||
|
||||
$displayedPosts = array_reverse(array_slice($posts, count($posts) - 3, 3)); // in ORDER by ID DESC
|
||||
|
||||
/**
|
||||
* @var Post $post
|
||||
*/
|
||||
foreach ($displayedPosts as $i => $post) { // check texts
|
||||
$this->assertSelectorTextContains('.t-post-detail:nth-child(' . ($i + 1) . ') .t-post-title', $this->truncateToWholeWords($post->title, 70));
|
||||
$text = $crawler->filter('.t-post-detail:nth-child(' . ($i + 1) . ') .t-post-title')->text();
|
||||
$this->assertLessThan(83, strlen($text), "Text $text too long"); // 80 + 3 extra characters for ellipsis
|
||||
$this->assertSelectorTextContains('.t-post-detail:nth-child(' . ($i + 1) . ') .t-post-body', $this->truncateToWholeWords($post->body, 70));
|
||||
$text = $crawler->filter('.t-post-detail:nth-child(' . ($i + 1) . ') .t-post-body')->text();
|
||||
$this->assertLessThan(83, strlen($text), "Text $text too long"); // 80 + 3 extra characters for ellipsis
|
||||
}
|
||||
}
|
||||
|
||||
public function testPagination(): void
|
||||
{
|
||||
$posts = $this->createTestPosts();
|
||||
$crawler = $this->client->request('GET', '/posts/1');
|
||||
|
||||
$this->assertResponseIsSuccessful();
|
||||
$this->assertSelectorCount(4 /* 3 -> normal, 1 -> last page */, '.t-pagination .t-page-item');
|
||||
|
||||
$crawler = $this->client->click($crawler->filter('.t-pagination .t-page-item:nth-child(3) .t-page-link')->link());
|
||||
$this->assertSelectorCount(5 /* 3 -> normal, 2 -> first page, last page */, '.t-pagination .t-page-item');
|
||||
}
|
||||
|
||||
public function testGoToNonExistentPage(): void
|
||||
{
|
||||
$this->createTestPosts();
|
||||
$this->client->request('GET', '/posts/999999');
|
||||
$this->assertResponseStatusCodeSame(302);
|
||||
$this->assertResponseHeaderSame('Location', '/posts/10' /* last page (30 posts /3 per page) */);
|
||||
}
|
||||
|
||||
public function testGoToPageZero(): void
|
||||
{
|
||||
$this->createTestPosts();
|
||||
$this->client->request('GET', '/posts/0');
|
||||
$this->assertResponseStatusCodeSame(302);
|
||||
$this->assertResponseHeaderSame('Location', '/posts' /* go to first page */);
|
||||
}
|
||||
|
||||
public function testGoToDefault(): void
|
||||
{
|
||||
$this->createTestPosts();
|
||||
$this->client->request('GET', '/');
|
||||
$this->assertResponseIsSuccessful();
|
||||
$this->assertSelectorCount(3, '.t-detail-a'); // 3 posts are listed
|
||||
}
|
||||
|
||||
private function truncateToWholeWords(string $string, int $length): string
|
||||
{
|
||||
if (strlen($string) <= $length) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
// Find the last space within the allowed length
|
||||
$truncated = substr($string, 0, $length);
|
||||
$lastSpace = strrpos($truncated, ' ');
|
||||
|
||||
// If there's no space, truncate to the exact length
|
||||
if ($lastSpace === false) {
|
||||
return substr($truncated, 0, $length);
|
||||
}
|
||||
|
||||
return substr($truncated, 0, $lastSpace);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Post[]
|
||||
*/
|
||||
private function createTestPosts(): array
|
||||
{
|
||||
$posts = [];
|
||||
|
||||
for ($i = 1; $i <= 30; $i++) {
|
||||
$posts[] = $this->createPost($i);
|
||||
}
|
||||
|
||||
return $posts;
|
||||
}
|
||||
}
|
73
webpack.config.js
Normal file
73
webpack.config.js
Normal file
@ -0,0 +1,73 @@
|
||||
const Encore = require('@symfony/webpack-encore');
|
||||
|
||||
// Manually configure the runtime environment if not already configured yet by the "encore" command.
|
||||
// It's useful when you use tools that rely on webpack.config.js file.
|
||||
if (!Encore.isRuntimeEnvironmentConfigured()) {
|
||||
Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev');
|
||||
}
|
||||
|
||||
Encore
|
||||
// directory where compiled assets will be stored
|
||||
.setOutputPath('public/build/')
|
||||
// public path used by the web server to access the output path
|
||||
.setPublicPath('/build')
|
||||
// only needed for CDN's or subdirectory deploy
|
||||
//.setManifestKeyPrefix('build/')
|
||||
|
||||
/*
|
||||
* ENTRY CONFIG
|
||||
*
|
||||
* Each entry will result in one JavaScript file (e.g. app.js)
|
||||
* and one CSS file (e.g. app.css) if your JavaScript imports CSS.
|
||||
*/
|
||||
.addEntry('app', './assets/app.js')
|
||||
|
||||
// When enabled, Webpack "splits" your files into smaller pieces for greater optimization.
|
||||
.splitEntryChunks()
|
||||
|
||||
// will require an extra script tag for runtime.js
|
||||
// but, you probably want this, unless you're building a single-page app
|
||||
.enableSingleRuntimeChunk()
|
||||
|
||||
/*
|
||||
* FEATURE CONFIG
|
||||
*
|
||||
* Enable & configure other features below. For a full
|
||||
* list of features, see:
|
||||
* https://symfony.com/doc/current/frontend.html#adding-more-features
|
||||
*/
|
||||
.cleanupOutputBeforeBuild()
|
||||
.enableBuildNotifications()
|
||||
.enableSourceMaps(!Encore.isProduction())
|
||||
// enables hashed filenames (e.g. app.abc123.css)
|
||||
.enableVersioning(Encore.isProduction())
|
||||
|
||||
// configure Babel
|
||||
// .configureBabel((config) => {
|
||||
// config.plugins.push('@babel/a-babel-plugin');
|
||||
// })
|
||||
|
||||
// enables and configure @babel/preset-env polyfills
|
||||
.configureBabelPresetEnv((config) => {
|
||||
config.useBuiltIns = 'usage';
|
||||
config.corejs = '3.23';
|
||||
})
|
||||
|
||||
// enables Sass/SCSS support
|
||||
.enableSassLoader()
|
||||
|
||||
// uncomment if you use TypeScript
|
||||
//.enableTypeScriptLoader()
|
||||
|
||||
// uncomment if you use React
|
||||
//.enableReactPreset()
|
||||
|
||||
// uncomment to get integrity="..." attributes on your script & link tags
|
||||
// requires WebpackEncoreBundle 1.4 or higher
|
||||
//.enableIntegrityHashes(Encore.isProduction())
|
||||
|
||||
// uncomment if you're having problems with a jQuery plugin
|
||||
//.autoProvidejQuery()
|
||||
;
|
||||
|
||||
module.exports = Encore.getWebpackConfig();
|
Loading…
Reference in New Issue
Block a user