diff --git a/.env b/.env index 1226bf4..e6f8fef 100644 --- a/.env +++ b/.env @@ -4,3 +4,4 @@ DATABASE_URL="mysql://user:changeme@mariadb:3306/ninecompta" MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0 APP_NAME=Ninecompta +APP_NOREPLY=admin@noreply.fr \ No newline at end of file diff --git a/.gitignore b/.gitignore index 4daae38..a535897 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,12 @@ /public/assets/ /assets/vendor/ ###< symfony/asset-mapper ### + +###> phpstan/phpstan ### +phpstan.neon +###< phpstan/phpstan ### + +###> friendsofphp/php-cs-fixer ### +/.php-cs-fixer.php +/.php-cs-fixer.cache +###< friendsofphp/php-cs-fixer ### diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 0000000..989e143 --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,45 @@ +in(__DIR__.'/src') + ->name('*.php') +; + +// TODO: Définir les règles de style communes +// spécifiques au projet +return (new PhpCsFixer\Config()) + ->setRules([ + '@Symfony' => true, + 'concat_space' => ['spacing' => 'none'], + 'array_syntax' => ['syntax' => 'short'], + 'combine_consecutive_issets' => true, + 'explicit_indirect_variable' => true, + 'no_useless_return' => true, + 'ordered_imports' => true, + 'no_unused_imports' => true, + 'no_spaces_after_function_name' => true, + 'no_spaces_inside_parenthesis' => true, + 'ternary_operator_spaces' => true, + 'class_definition' => ['single_line' => true], + 'whitespace_after_comma_in_array' => true, + + // phpdoc + 'phpdoc_add_missing_param_annotation' => ['only_untyped' => true], + 'phpdoc_order' => true, + 'phpdoc_types_order' => [ + 'null_adjustment' => 'always_last', + 'sort_algorithm' => 'alpha', + ], + 'phpdoc_no_empty_return' => false, + 'phpdoc_summary' => false, + 'general_phpdoc_annotation_remove' => [ + 'annotations' => [ + 'expectedExceptionMessageRegExp', + 'expectedException', + 'expectedExceptionMessage', + 'author', + ], + ], + ]) + ->setFinder($finder) +; \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index cdbd9ed..e14c89a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,6 @@ { - "editor.fontSize": 14 + "editor.fontSize": 14, + "php-cs-fixer.executablePath": "${workspaceFolder}/vendor/bin/php-cs-fixer", + "php-cs-fixer.onsave": true, // Active l'exécution à la sauvegarde + "php-cs-fixer.rules": null // Null pour utiliser les règles définies dans .php-cs-fixer.dist.php } \ No newline at end of file diff --git a/assets/app.js b/assets/app.js index f9c3dca..6a22e7d 100644 --- a/assets/app.js +++ b/assets/app.js @@ -15,7 +15,8 @@ import '@fortawesome/fontawesome-free/css/all.min.css'; // Datatable import 'datatables.net'; -import 'datatables.net-dt/css/jquery.dataTables.css'; +import 'datatables.net-dt/css/dataTables.dataTables.min.css'; +import './datatables.init.js'; // Local CSS import './styles/bootswatch.min.css' diff --git a/assets/datatables.init.js b/assets/datatables.init.js index 18becb3..4382461 100644 --- a/assets/datatables.init.js +++ b/assets/datatables.init.js @@ -1,3 +1,5 @@ +import $ from 'jquery'; + $(document).ready(function() { $.extend( $.fn.dataTable.defaults, { responsive: true, diff --git a/assets/styles/app.css b/assets/styles/app.css index dd6fe18..f3a38b4 100644 --- a/assets/styles/app.css +++ b/assets/styles/app.css @@ -9,8 +9,10 @@ body { align-items: stretch; } -.form-group { - margin-bottom: 5px; +.avatar{ + border-radius: 100%; + width:40px; + height:40px; } .navbar-brand img { diff --git a/composer.json b/composer.json index 0bc5839..93dfc30 100644 --- a/composer.json +++ b/composer.json @@ -96,6 +96,10 @@ } }, "require-dev": { + "friendsofphp/php-cs-fixer": "^3.65", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-doctrine": "^2.0", + "phpstan/phpstan-symfony": "^2.0", "phpunit/phpunit": "^9.5", "symfony/browser-kit": "7.1.*", "symfony/css-selector": "7.1.*", diff --git a/composer.lock b/composer.lock index 9fa0e39..f9e578e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "bfa3fd6c661ba7df71cffe78211433ff", + "content-hash": "77a13f7382fbf701f9ba3574e31863d7", "packages": [ { "name": "composer/semver", @@ -7566,6 +7566,426 @@ } ], "packages-dev": [ + { + "name": "clue/ndjson-react", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/clue/reactphp-ndjson.git", + "reference": "392dc165fce93b5bb5c637b67e59619223c931b0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/clue/reactphp-ndjson/zipball/392dc165fce93b5bb5c637b67e59619223c931b0", + "reference": "392dc165fce93b5bb5c637b67e59619223c931b0", + "shasum": "" + }, + "require": { + "php": ">=5.3", + "react/stream": "^1.2" + }, + "require-dev": { + "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35", + "react/event-loop": "^1.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Clue\\React\\NDJson\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering" + } + ], + "description": "Streaming newline-delimited JSON (NDJSON) parser and encoder for ReactPHP.", + "homepage": "https://github.com/clue/reactphp-ndjson", + "keywords": [ + "NDJSON", + "json", + "jsonlines", + "newline", + "reactphp", + "streaming" + ], + "support": { + "issues": "https://github.com/clue/reactphp-ndjson/issues", + "source": "https://github.com/clue/reactphp-ndjson/tree/v1.3.0" + }, + "funding": [ + { + "url": "https://clue.engineering/support", + "type": "custom" + }, + { + "url": "https://github.com/clue", + "type": "github" + } + ], + "time": "2022-12-23T10:58:28+00:00" + }, + { + "name": "composer/pcre", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<1.11.10" + }, + "require-dev": { + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", + "phpunit/phpunit": "^8 || ^9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + }, + "phpstan": { + "includes": [ + "extension.neon" + ] + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/3.3.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-11-12T16:29:46+00:00" + }, + { + "name": "composer/xdebug-handler", + "version": "3.0.5", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef", + "shasum": "" + }, + "require": { + "composer/pcre": "^1 || ^2 || ^3", + "php": "^7.2.5 || ^8.0", + "psr/log": "^1 || ^2 || ^3" + }, + "require-dev": { + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1", + "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Composer\\XdebugHandler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without Xdebug.", + "keywords": [ + "Xdebug", + "performance" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/xdebug-handler/issues", + "source": "https://github.com/composer/xdebug-handler/tree/3.0.5" + }, + "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-05-06T16:37:16+00:00" + }, + { + "name": "evenement/evenement", + "version": "v3.0.2", + "source": { + "type": "git", + "url": "https://github.com/igorw/evenement.git", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc", + "shasum": "" + }, + "require": { + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^9 || ^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Evenement\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + } + ], + "description": "Événement is a very simple event dispatching library for PHP", + "keywords": [ + "event-dispatcher", + "event-emitter" + ], + "support": { + "issues": "https://github.com/igorw/evenement/issues", + "source": "https://github.com/igorw/evenement/tree/v3.0.2" + }, + "time": "2023-08-08T05:53:35+00:00" + }, + { + "name": "fidry/cpu-core-counter", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/theofidry/cpu-core-counter.git", + "reference": "8520451a140d3f46ac33042715115e290cf5785f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/8520451a140d3f46ac33042715115e290cf5785f", + "reference": "8520451a140d3f46ac33042715115e290cf5785f", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "fidry/makefile": "^0.2.0", + "fidry/php-cs-fixer-config": "^1.1.2", + "phpstan/extension-installer": "^1.2.0", + "phpstan/phpstan": "^1.9.2", + "phpstan/phpstan-deprecation-rules": "^1.0.0", + "phpstan/phpstan-phpunit": "^1.2.2", + "phpstan/phpstan-strict-rules": "^1.4.4", + "phpunit/phpunit": "^8.5.31 || ^9.5.26", + "webmozarts/strict-phpunit": "^7.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Fidry\\CpuCoreCounter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Théo FIDRY", + "email": "theo.fidry@gmail.com" + } + ], + "description": "Tiny utility to get the number of CPU cores.", + "keywords": [ + "CPU", + "core" + ], + "support": { + "issues": "https://github.com/theofidry/cpu-core-counter/issues", + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.2.0" + }, + "funding": [ + { + "url": "https://github.com/theofidry", + "type": "github" + } + ], + "time": "2024-08-06T10:04:20+00:00" + }, + { + "name": "friendsofphp/php-cs-fixer", + "version": "v3.65.0", + "source": { + "type": "git", + "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", + "reference": "79d4f3e77b250a7d8043d76c6af8f0695e8a469f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/79d4f3e77b250a7d8043d76c6af8f0695e8a469f", + "reference": "79d4f3e77b250a7d8043d76c6af8f0695e8a469f", + "shasum": "" + }, + "require": { + "clue/ndjson-react": "^1.0", + "composer/semver": "^3.4", + "composer/xdebug-handler": "^3.0.3", + "ext-filter": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "fidry/cpu-core-counter": "^1.2", + "php": "^7.4 || ^8.0", + "react/child-process": "^0.6.5", + "react/event-loop": "^1.0", + "react/promise": "^2.0 || ^3.0", + "react/socket": "^1.0", + "react/stream": "^1.0", + "sebastian/diff": "^4.0 || ^5.0 || ^6.0", + "symfony/console": "^5.4 || ^6.0 || ^7.0", + "symfony/event-dispatcher": "^5.4 || ^6.0 || ^7.0", + "symfony/filesystem": "^5.4 || ^6.0 || ^7.0", + "symfony/finder": "^5.4 || ^6.0 || ^7.0", + "symfony/options-resolver": "^5.4 || ^6.0 || ^7.0", + "symfony/polyfill-mbstring": "^1.28", + "symfony/polyfill-php80": "^1.28", + "symfony/polyfill-php81": "^1.28", + "symfony/process": "^5.4 || ^6.0 || ^7.0", + "symfony/stopwatch": "^5.4 || ^6.0 || ^7.0" + }, + "require-dev": { + "facile-it/paraunit": "^1.3.1 || ^2.4", + "infection/infection": "^0.29.8", + "justinrainbow/json-schema": "^5.3 || ^6.0", + "keradus/cli-executor": "^2.1", + "mikey179/vfsstream": "^1.6.12", + "php-coveralls/php-coveralls": "^2.7", + "php-cs-fixer/accessible-object": "^1.1", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.5", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.5", + "phpunit/phpunit": "^9.6.21 || ^10.5.38 || ^11.4.3", + "symfony/var-dumper": "^5.4.47 || ^6.4.15 || ^7.1.8", + "symfony/yaml": "^5.4.45 || ^6.4.13 || ^7.1.6" + }, + "suggest": { + "ext-dom": "For handling output formats in XML", + "ext-mbstring": "For handling non-UTF8 characters." + }, + "bin": [ + "php-cs-fixer" + ], + "type": "application", + "autoload": { + "psr-4": { + "PhpCsFixer\\": "src/" + }, + "exclude-from-classmap": [ + "src/Fixer/Internal/*" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Dariusz Rumiński", + "email": "dariusz.ruminski@gmail.com" + } + ], + "description": "A tool to automatically fix PHP code style", + "keywords": [ + "Static code analysis", + "fixer", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.65.0" + }, + "funding": [ + { + "url": "https://github.com/keradus", + "type": "github" + } + ], + "time": "2024-11-25T00:39:24+00:00" + }, { "name": "masterminds/html5", "version": "2.9.0", @@ -7869,6 +8289,206 @@ }, "time": "2022-02-21T01:04:05+00:00" }, + { + "name": "phpstan/phpstan", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "6c98c7600fc717b2c78c11ef60040d5b1e359c82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/6c98c7600fc717b2c78c11ef60040d5b1e359c82", + "reference": "6c98c7600fc717b2c78c11ef60040d5b1e359c82", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2024-11-17T14:17:00+00:00" + }, + { + "name": "phpstan/phpstan-doctrine", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-doctrine.git", + "reference": "90c42756b2d7c3660b423d328622d4dfa2194487" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/90c42756b2d7c3660b423d328622d4dfa2194487", + "reference": "90c42756b2d7c3660b423d328622d4dfa2194487", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.0" + }, + "conflict": { + "doctrine/collections": "<1.0", + "doctrine/common": "<2.7", + "doctrine/mongodb-odm": "<1.2", + "doctrine/orm": "<2.5", + "doctrine/persistence": "<1.3" + }, + "require-dev": { + "cache/array-adapter": "^1.1", + "composer/semver": "^3.3.2", + "cweagans/composer-patches": "^1.7.3", + "doctrine/annotations": "^2.0", + "doctrine/collections": "^1.6 || ^2.1", + "doctrine/common": "^2.7 || ^3.0", + "doctrine/dbal": "^3.3.8", + "doctrine/lexer": "^2.0 || ^3.0", + "doctrine/mongodb-odm": "^2.4.3", + "doctrine/orm": "^2.16.0", + "doctrine/persistence": "^2.2.1 || ^3.2", + "gedmo/doctrine-extensions": "^3.8", + "nesbot/carbon": "^2.49", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6.20", + "ramsey/uuid": "^4.2", + "symfony/cache": "^5.4" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon", + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Doctrine extensions for PHPStan", + "support": { + "issues": "https://github.com/phpstan/phpstan-doctrine/issues", + "source": "https://github.com/phpstan/phpstan-doctrine/tree/2.0.0" + }, + "time": "2024-11-09T17:34:32+00:00" + }, + { + "name": "phpstan/phpstan-symfony", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-symfony.git", + "reference": "1ef4dce2baabd464c2dd3109d051bad94efa1e79" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/1ef4dce2baabd464c2dd3109d051bad94efa1e79", + "reference": "1ef4dce2baabd464c2dd3109d051bad94efa1e79", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.0" + }, + "conflict": { + "symfony/framework-bundle": "<3.0" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", + "psr/container": "1.0 || 1.1.1", + "symfony/config": "^5.4 || ^6.1", + "symfony/console": "^5.4 || ^6.1", + "symfony/dependency-injection": "^5.4 || ^6.1", + "symfony/form": "^5.4 || ^6.1", + "symfony/framework-bundle": "^5.4 || ^6.1", + "symfony/http-foundation": "^5.4 || ^6.1", + "symfony/messenger": "^5.4", + "symfony/polyfill-php80": "^1.24", + "symfony/serializer": "^5.4", + "symfony/service-contracts": "^2.2.0" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon", + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lukáš Unger", + "email": "looky.msc@gmail.com", + "homepage": "https://lookyman.net" + } + ], + "description": "Symfony Framework extensions and rules for PHPStan", + "support": { + "issues": "https://github.com/phpstan/phpstan-symfony/issues", + "source": "https://github.com/phpstan/phpstan-symfony/tree/2.0.0" + }, + "time": "2024-11-06T10:13:40+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "9.2.32", @@ -8291,6 +8911,536 @@ ], "time": "2024-09-19T10:50:18+00:00" }, + { + "name": "react/cache", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/cache.git", + "reference": "d47c472b64aa5608225f47965a484b75c7817d5b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/cache/zipball/d47c472b64aa5608225f47965a484b75c7817d5b", + "reference": "d47c472b64aa5608225f47965a484b75c7817d5b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/promise": "^3.0 || ^2.0 || ^1.1" + }, + "require-dev": { + "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async, Promise-based cache interface for ReactPHP", + "keywords": [ + "cache", + "caching", + "promise", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/cache/issues", + "source": "https://github.com/reactphp/cache/tree/v1.2.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2022-11-30T15:59:55+00:00" + }, + { + "name": "react/child-process", + "version": "v0.6.5", + "source": { + "type": "git", + "url": "https://github.com/reactphp/child-process.git", + "reference": "e71eb1aa55f057c7a4a0d08d06b0b0a484bead43" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/child-process/zipball/e71eb1aa55f057c7a4a0d08d06b0b0a484bead43", + "reference": "e71eb1aa55f057c7a4a0d08d06b0b0a484bead43", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.0", + "react/event-loop": "^1.2", + "react/stream": "^1.2" + }, + "require-dev": { + "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35", + "react/socket": "^1.8", + "sebastian/environment": "^5.0 || ^3.0 || ^2.0 || ^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\ChildProcess\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Event-driven library for executing child processes with ReactPHP.", + "keywords": [ + "event-driven", + "process", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/child-process/issues", + "source": "https://github.com/reactphp/child-process/tree/v0.6.5" + }, + "funding": [ + { + "url": "https://github.com/WyriHaximus", + "type": "github" + }, + { + "url": "https://github.com/clue", + "type": "github" + } + ], + "time": "2022-09-16T13:41:56+00:00" + }, + { + "name": "react/dns", + "version": "v1.13.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/dns.git", + "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/dns/zipball/eb8ae001b5a455665c89c1df97f6fb682f8fb0f5", + "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/cache": "^1.0 || ^0.6 || ^0.5", + "react/event-loop": "^1.2", + "react/promise": "^3.2 || ^2.7 || ^1.2.1" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4.3 || ^3 || ^2", + "react/promise-timer": "^1.11" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Dns\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async DNS resolver for ReactPHP", + "keywords": [ + "async", + "dns", + "dns-resolver", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/dns/issues", + "source": "https://github.com/reactphp/dns/tree/v1.13.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-06-13T14:18:03+00:00" + }, + { + "name": "react/event-loop", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/event-loop.git", + "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/event-loop/zipball/bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", + "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "suggest": { + "ext-pcntl": "For signal handling support when using the StreamSelectLoop" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\EventLoop\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.", + "keywords": [ + "asynchronous", + "event-loop" + ], + "support": { + "issues": "https://github.com/reactphp/event-loop/issues", + "source": "https://github.com/reactphp/event-loop/tree/v1.5.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2023-11-13T13:48:05+00:00" + }, + { + "name": "react/promise", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "8a164643313c71354582dc850b42b33fa12a4b63" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/8a164643313c71354582dc850b42b33fa12a4b63", + "reference": "8a164643313c71354582dc850b42b33fa12a4b63", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "phpstan/phpstan": "1.10.39 || 1.4.10", + "phpunit/phpunit": "^9.6 || ^7.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "React\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "keywords": [ + "promise", + "promises" + ], + "support": { + "issues": "https://github.com/reactphp/promise/issues", + "source": "https://github.com/reactphp/promise/tree/v3.2.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-05-24T10:39:05+00:00" + }, + { + "name": "react/socket", + "version": "v1.16.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/socket.git", + "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/socket/zipball/23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1", + "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.0", + "react/dns": "^1.13", + "react/event-loop": "^1.2", + "react/promise": "^3.2 || ^2.6 || ^1.2.1", + "react/stream": "^1.4" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4.3 || ^3.3 || ^2", + "react/promise-stream": "^1.4", + "react/promise-timer": "^1.11" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Socket\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP", + "keywords": [ + "Connection", + "Socket", + "async", + "reactphp", + "stream" + ], + "support": { + "issues": "https://github.com/reactphp/socket/issues", + "source": "https://github.com/reactphp/socket/tree/v1.16.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-07-26T10:38:09+00:00" + }, + { + "name": "react/stream", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/stream.git", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.8", + "react/event-loop": "^1.2" + }, + "require-dev": { + "clue/stream-filter": "~1.2", + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Stream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP", + "keywords": [ + "event-driven", + "io", + "non-blocking", + "pipe", + "reactphp", + "readable", + "stream", + "writable" + ], + "support": { + "issues": "https://github.com/reactphp/stream/issues", + "source": "https://github.com/reactphp/stream/tree/v1.4.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-06-11T12:45:25+00:00" + }, { "name": "sebastian/cli-parser", "version": "1.0.2", @@ -9845,5 +10995,5 @@ "ext-iconv": "*" }, "platform-dev": [], - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" } diff --git a/config/packages/twig.yaml b/config/packages/twig.yaml index 245f138..aeb223e 100644 --- a/config/packages/twig.yaml +++ b/config/packages/twig.yaml @@ -1,6 +1,6 @@ twig: file_name_pattern: "*.twig" - + form_themes: ['bootstrap_5_layout.html.twig'] globals: appName: "%appName%" diff --git a/config/services.yaml b/config/services.yaml index 1d754c9..fc181e9 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -7,6 +7,7 @@ parameters: appEnv: "%env(resolve:APP_ENV)%" appSecret: "%env(resolve:APP_SECRET)%" appName: "%env(resolve:APP_NAME)%" + appNoreply: "%env(resolve:APP_NOREPLY)%" services: # default configuration for services in *this* file diff --git a/public/medias/avatar/admin.jpg b/public/medias/avatar/admin.jpg new file mode 100644 index 0000000..0fa3174 Binary files /dev/null and b/public/medias/avatar/admin.jpg differ diff --git a/public/medias/avatar/noavatar.png b/public/medias/avatar/noavatar.png new file mode 100644 index 0000000..2e1ad1f Binary files /dev/null and b/public/medias/avatar/noavatar.png differ diff --git a/src/Command/InitCommand.php b/src/Command/InitCommand.php index 4118c10..f2f38bc 100644 --- a/src/Command/InitCommand.php +++ b/src/Command/InitCommand.php @@ -7,13 +7,10 @@ use App\Entity\User; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; -use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasher; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; #[AsCommand( @@ -26,7 +23,7 @@ class InitCommand extends Command private ParameterBagInterface $params; private UserPasswordHasherInterface $passwordHasher; - public function __construct(EntityManagerInterface $em,ParameterBagInterface $params,UserPasswordHasherInterface $passwordHasher) + public function __construct(EntityManagerInterface $em, ParameterBagInterface $params, UserPasswordHasherInterface $passwordHasher) { $this->em = $em; $this->params = $params; @@ -38,38 +35,41 @@ class InitCommand extends Command protected function execute(InputInterface $input, OutputInterface $output): int { $io = new SymfonyStyle($input, $output); - $io->title("APP:INIT"); - $io->text("Initialisation of the app"); - $io->text(""); - + $io->title('APP:INIT'); + $io->text('Initialisation of the app'); + $io->text(''); + // Création du compte admin - $io->text("> Création du compte admin"); - $user = $this->em->getRepository("App\Entity\User")->findOneBy(["username"=>"admin"]); - if(!$user) { - $user=new User; + $io->text('> Création du compte admin'); + $user = $this->em->getRepository("App\Entity\User")->findOneBy(['username' => 'admin']); + if (!$user) { + $user = new User(); $hashedPassword = $this->passwordHasher->hashPassword( $user, - $this->params->get("appSecret") + $this->params->get('appSecret') ); - $user->setUsername("admin"); + $user->setUsername('admin'); $user->setPassword($hashedPassword); + $user->setAvatar('medias/avatar/admin.jpg'); + $user->setEmail($this->params->get('appNoreply')); $this->em->persist($user); } - $user->setRoles(["ROLE_ADMIN"]); + $user->setRoles(['ROLE_ADMIN']); $this->em->flush(); // Création d'un company par defaut $io->text("> Création d'un company par defaut"); $nbcompanys = $this->em->getRepository("App\Entity\Company")->count([]); - if($nbcompanys==0) { - $company=new Company; - $company->setTitle($this->params->get("appName")); - $company->setLogo("logo.png"); + if (0 == $nbcompanys) { + $company = new Company(); + $company->setTitle($this->params->get('appName')); + $company->setLogo('logo.png'); $this->em->persist($company); - $this->em->flush(); + $this->em->flush(); } + return Command::SUCCESS; } } diff --git a/src/Controller/HomeController.php b/src/Controller/HomeController.php index e838a6c..cfe9670 100644 --- a/src/Controller/HomeController.php +++ b/src/Controller/HomeController.php @@ -14,7 +14,7 @@ class HomeController extends AbstractController return $this->render('home/home.html.twig', [ 'usemenu' => true, 'usesidebar' => false, - ]); + ]); } #[Route('/admin', name: 'app_admin')] @@ -23,6 +23,6 @@ class HomeController extends AbstractController return $this->render('home/home.html.twig', [ 'usemenu' => true, 'usesidebar' => true, - ]); - } + ]); + } } diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php index 962dd80..aae94c3 100644 --- a/src/Controller/UserController.php +++ b/src/Controller/UserController.php @@ -2,44 +2,107 @@ namespace App\Controller; +use App\Entity\User; +use App\Form\UserType; +use App\Repository\UserRepository; +use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; use Symfony\Component\Routing\Attribute\Route; class UserController extends AbstractController { #[Route('/admin/user', name: 'app_admin_user')] - public function list(): Response + public function list(UserRepository $userRepository): Response { + $users = $userRepository->findAll(); + return $this->render('user/list.html.twig', [ 'usemenu' => true, 'usesidebar' => true, 'title' => 'Liste des Utilisateurs', 'routesubmit' => 'app_admin_user_submit', 'routeupdate' => 'app_admin_user_update', + 'users' => $users, ]); } - #[Route('/admin/user', name: 'app_admin_user_submit')] - public function submit(): Response + #[Route('/admin/user/submit', name: 'app_admin_user_submit')] + public function submit(Request $request, UserPasswordHasherInterface $passwordHasher, EntityManagerInterface $em): Response { + $user = new User(); + + $form = $this->createForm(UserType::class, $user, ['mode' => 'submit']); + $form->handleRequest($request); + if ($form->isSubmitted() && $form->isValid()) { + $user = $form->getData(); + $hashedPassword = $passwordHasher->hashPassword( + $user, + $user->getPassword() + ); + $user->setPassword($hashedPassword); + + $em->persist($user); + $em->flush(); + + return $this->redirectToRoute('app_admin_user'); + } + return $this->render('user/edit.html.twig', [ + 'usemenu' => true, + 'usesidebar' => true, 'title' => 'Création Utilisateur', 'routecancel' => 'app_admin_user', 'routedelete' => 'app_admin_user_delete', + 'mode' => 'submit', + 'form' => $form, ]); } - #[Route('/admin/user/update', name: 'app_admin_user_update')] - public function update(): Response + #[Route('/admin/user/update/{id}', name: 'app_admin_user_update')] + public function update(int $id, Request $request, UserPasswordHasherInterface $passwordHasher, EntityManagerInterface $em): Response { + $user = $em->getRepository(User::class)->find($id); + if (!$user) { + return $this->redirectToRoute('app_admin_user'); + } + $form = $this->createForm(UserType::class, $user, ['mode' => 'update']); + $form->handleRequest($request); + if ($form->isSubmitted() && $form->isValid()) { + $user = $form->getData(); + $hashedPassword = $passwordHasher->hashPassword( + $user, + $user->getPassword() + ); + $user->setPassword($hashedPassword); + $em->persist($user); + $em->flush(); + + return $this->redirectToRoute('app_admin_user'); + } + + return $this->render('user/edit.html.twig', [ + 'usemenu' => true, + 'usesidebar' => true, + 'title' => 'Création Utilisateur', + 'routecancel' => 'app_admin_user', + 'routedelete' => 'app_admin_user_delete', + 'mode' => 'update', + 'form' => $form, + ]); } #[Route('/admin/user/delete', name: 'app_admin_user_delete')] public function delete(): Response { + } + #[Route('/user', name: 'app_user_profil')] + public function profil(): Response + { } } diff --git a/src/Entity/Accounting.php b/src/Entity/Accounting.php index 17c9fff..3310a73 100644 --- a/src/Entity/Accounting.php +++ b/src/Entity/Accounting.php @@ -6,8 +6,11 @@ use App\Repository\AccountingRepository; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; #[ORM\Entity(repositoryClass: AccountingRepository::class)] +#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_ACCOUNTING', fields: ['num01', 'num02'])] +#[UniqueEntity(fields: ['num01', 'num02'], message: 'Ce numéro de compte est déjà utilisé.')] class Accounting { #[ORM\Id] diff --git a/src/Entity/Company.php b/src/Entity/Company.php index 7845e7e..6dc566e 100644 --- a/src/Entity/Company.php +++ b/src/Entity/Company.php @@ -7,8 +7,11 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; #[ORM\Entity(repositoryClass: CompanyRepository::class)] +#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_COMPANY', fields: ['title'])] +#[UniqueEntity(fields: ['email'], message: 'Ce nom de companie est déjà utilisé.')] class Company { #[ORM\Id] @@ -16,7 +19,7 @@ class Company #[ORM\Column] private ?int $id = null; - #[ORM\Column(length: 255)] + #[ORM\Column(length: 255, unique: true)] private ?string $title = null; #[ORM\Column(type: Types::TEXT, nullable: true)] @@ -260,5 +263,4 @@ class Company return $this; } - } diff --git a/src/Entity/Operation.php b/src/Entity/Operation.php index c97aae6..a520891 100644 --- a/src/Entity/Operation.php +++ b/src/Entity/Operation.php @@ -95,5 +95,4 @@ class Operation return $this; } - } diff --git a/src/Entity/User.php b/src/Entity/User.php index 5882a7d..4645fee 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -6,11 +6,16 @@ use App\Repository\UserRepository; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\UserInterface; +use Symfony\Component\Validator\Constraints as Assert; #[ORM\Entity(repositoryClass: UserRepository::class)] #[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_USERNAME', fields: ['username'])] +#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_EMAIL', fields: ['email'])] +#[UniqueEntity(fields: ['email'], message: 'Cet email est déjà utilisé.')] +#[UniqueEntity(fields: ['username'], message: 'Ce nom d’utilisateur est déjà pris.')] class User implements UserInterface, PasswordAuthenticatedUserInterface { #[ORM\Id] @@ -18,24 +23,26 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface #[ORM\Column] private ?int $id = null; - #[ORM\Column(length: 180)] + #[ORM\Column(length: 180, unique: true)] private ?string $username = null; - /** - * @var list The user roles - */ #[ORM\Column] private array $roles = []; - /** - * @var string The hashed password - */ #[ORM\Column] + #[Assert\Regex( + pattern: '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\W).{8,}$/', + message: 'Le mot de passe doit contenir au moins 8 caractères, une lettre majuscule, une lettre minuscule et un caractère spécial.' + )] private ?string $password = null; - /** - * @var Collection - */ + #[ORM\Column(length: 255, nullable: true)] + private ?string $avatar = null; + + #[ORM\Column(length: 255, unique: true)] + #[Assert\Email(message: 'Veuillez entrer un email valide.')] + private ?string $email = null; + #[ORM\ManyToMany(targetEntity: Company::class, inversedBy: 'users')] private Collection $companys; @@ -119,6 +126,30 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface // $this->plainPassword = null; } + public function getAvatar(): ?string + { + return $this->avatar ? $this->avatar : 'medias/avatar/noavatar.png'; + } + + public function setAvatar(?string $avatar): static + { + $this->avatar = $avatar; + + return $this; + } + + public function getEmail(): ?string + { + return $this->email; + } + + public function setEmail(string $email): static + { + $this->email = $email; + + return $this; + } + /** * @return Collection */ diff --git a/src/EventSubscriber/CompanySubscriber.php b/src/EventSubscriber/CompanySubscriber.php index 0eab24a..0310f25 100644 --- a/src/EventSubscriber/CompanySubscriber.php +++ b/src/EventSubscriber/CompanySubscriber.php @@ -6,7 +6,6 @@ use App\Entity\Accounting; use App\Entity\Company; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Event\PostPersistEventArgs; -use Doctrine\ORM\Events; class CompanySubscriber { @@ -16,7 +15,7 @@ class CompanySubscriber { $this->em = $em; } - + public function postPersist(PostPersistEventArgs $args): void { $company = $args->getObject(); @@ -27,19 +26,19 @@ class CompanySubscriber $entityManager = $args->getObjectManager(); // Génération des accounting par défaut - $this->insertAccounting($company,"512","000","Banque","actif","fa-building-columns"); - $this->insertAccounting($company,"530","000","Caisse","actif","fa-piggy-bank"); - $this->insertAccounting($company,"600","000","Charge","charge",null); - $this->insertAccounting($company,"700","000","Produit","produit",null); + $this->insertAccounting($company, '512', '000', 'Banque', 'actif', 'fa-building-columns'); + $this->insertAccounting($company, '530', '000', 'Caisse', 'actif', 'fa-piggy-bank'); + $this->insertAccounting($company, '600', '000', 'Charge', 'charge', null); + $this->insertAccounting($company, '700', '000', 'Produit', 'produit', null); // Génération du year par } - private function insertAccounting(Company $company,string $num01, string $num02, string $title, string $category, ?string $icon): void + private function insertAccounting(Company $company, string $num01, string $num02, string $title, string $category, ?string $icon): void { - $accounting=$this->em->getRepository("App\Entity\Accounting")->findOneBy(["company"=>$company,"num01"=>$num01,"num02"=>$num02]); - if(!$accounting) { - $accounting = new Accounting; + $accounting = $this->em->getRepository("App\Entity\Accounting")->findOneBy(['company' => $company, 'num01' => $num01, 'num02' => $num02]); + if (!$accounting) { + $accounting = new Accounting(); $accounting->setCompany($company); $accounting->setNum01($num01); $accounting->setNum02($num02); @@ -48,7 +47,5 @@ class CompanySubscriber $this->em->persist($accounting); $this->em->flush(); } - } - -} \ No newline at end of file +} diff --git a/src/Form/UserType.php b/src/Form/UserType.php new file mode 100644 index 0000000..0c47d93 --- /dev/null +++ b/src/Form/UserType.php @@ -0,0 +1,67 @@ +add('submit', SubmitType::class, [ + 'label' => 'Valider', + 'attr' => ['class' => 'btn btn-success no-print'], + ]) + + ->add('username', TextType::class, [ + 'label' => 'Login', + ]) + + ->add('roles', ChoiceType::class, [ + 'choices' => ['ROLE_ADMIN' => 'ROLE_ADMIN', 'ROLE_USER' => 'ROLE_USER'], + 'multiple' => true, + 'expanded' => true, + ]) + + ->add('password', RepeatedType::class, [ + 'type' => PasswordType::class, + 'required' => ('submit' == $options['mode'] ? true : false), + 'options' => ['always_empty' => true], + 'first_options' => ['label' => 'Mot de Passe', 'attr' => ['class' => 'form-control', 'style' => 'margin-bottom:15px', 'autocomplete' => 'new-password']], + 'second_options' => ['label' => 'Confirmer Mot de Passe', 'attr' => ['class' => 'form-control', 'style' => 'margin-bottom:15px']], + ]) + + ->add('avatar') + + ->add('email', EmailType::class, [ + 'label' => 'Email', + ]) + + ->add('companys', EntityType::class, [ + 'class' => Company::class, + 'choice_label' => 'id', + 'multiple' => true, + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => User::class, + 'mode' => 'submit', + ]); + } +} diff --git a/src/Repository/AccountingRepository.php b/src/Repository/AccountingRepository.php index 5acaff0..e5920e4 100644 --- a/src/Repository/AccountingRepository.php +++ b/src/Repository/AccountingRepository.php @@ -16,28 +16,28 @@ class AccountingRepository extends ServiceEntityRepository parent::__construct($registry, Accounting::class); } -// /** -// * @return Accounting[] Returns an array of Accounting objects -// */ -// public function findByExampleField($value): array -// { -// return $this->createQueryBuilder('a') -// ->andWhere('a.exampleField = :val') -// ->setParameter('val', $value) -// ->orderBy('a.id', 'ASC') -// ->setMaxResults(10) -// ->getQuery() -// ->getResult() -// ; -// } + // /** + // * @return Accounting[] Returns an array of Accounting objects + // */ + // public function findByExampleField($value): array + // { + // return $this->createQueryBuilder('a') + // ->andWhere('a.exampleField = :val') + // ->setParameter('val', $value) + // ->orderBy('a.id', 'ASC') + // ->setMaxResults(10) + // ->getQuery() + // ->getResult() + // ; + // } -// public function findOneBySomeField($value): ?Accounting -// { -// return $this->createQueryBuilder('a') -// ->andWhere('a.exampleField = :val') -// ->setParameter('val', $value) -// ->getQuery() -// ->getOneOrNullResult() -// ; -// } + // public function findOneBySomeField($value): ?Accounting + // { + // return $this->createQueryBuilder('a') + // ->andWhere('a.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } } diff --git a/src/Repository/OperationRepository.php b/src/Repository/OperationRepository.php index cddb38f..2cee301 100644 --- a/src/Repository/OperationRepository.php +++ b/src/Repository/OperationRepository.php @@ -16,28 +16,28 @@ class OperationRepository extends ServiceEntityRepository parent::__construct($registry, Operation::class); } -// /** -// * @return Operation[] Returns an array of Operation objects -// */ -// public function findByExampleField($value): array -// { -// return $this->createQueryBuilder('o') -// ->andWhere('o.exampleField = :val') -// ->setParameter('val', $value) -// ->orderBy('o.id', 'ASC') -// ->setMaxResults(10) -// ->getQuery() -// ->getResult() -// ; -// } + // /** + // * @return Operation[] Returns an array of Operation objects + // */ + // public function findByExampleField($value): array + // { + // return $this->createQueryBuilder('o') + // ->andWhere('o.exampleField = :val') + // ->setParameter('val', $value) + // ->orderBy('o.id', 'ASC') + // ->setMaxResults(10) + // ->getQuery() + // ->getResult() + // ; + // } -// public function findOneBySomeField($value): ?Operation -// { -// return $this->createQueryBuilder('o') -// ->andWhere('o.exampleField = :val') -// ->setParameter('val', $value) -// ->getQuery() -// ->getOneOrNullResult() -// ; -// } + // public function findOneBySomeField($value): ?Operation + // { + // return $this->createQueryBuilder('o') + // ->andWhere('o.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } } diff --git a/symfony.lock b/symfony.lock index 246a271..980c6b3 100644 --- a/symfony.lock +++ b/symfony.lock @@ -26,6 +26,30 @@ "migrations/.gitignore" ] }, + "friendsofphp/php-cs-fixer": { + "version": "3.65", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "3.0", + "ref": "be2103eb4a20942e28a6dd87736669b757132435" + }, + "files": [ + ".php-cs-fixer.dist.php" + ] + }, + "phpstan/phpstan": { + "version": "2.0", + "recipe": { + "repo": "github.com/symfony/recipes-contrib", + "branch": "main", + "version": "1.0", + "ref": "5e490cc197fb6bb1ae22e5abbc531ddc633b6767" + }, + "files": [ + "phpstan.dist.neon" + ] + }, "phpunit/phpunit": { "version": "9.6", "recipe": { diff --git a/templates/user/edit.html.twig b/templates/user/edit.html.twig new file mode 100644 index 0000000..f58b8a7 --- /dev/null +++ b/templates/user/edit.html.twig @@ -0,0 +1,30 @@ +{% extends 'base.html.twig' %} + +{% block title %} = {{title}}{% endblock %} + +{% block body %} +

{{title}}

+ + + {{ form_start(form) }} + {{ form_widget(form.submit) }} + Annuler + +
+
Information
+
+ {{ form_widget(form) }} +
+
+ {{ form_end(form) }} + +{% endblock %} + +{% block localscript %} + +{% endblock %} diff --git a/templates/user/list.html.twig b/templates/user/list.html.twig index 46121ee..ac3f1ae 100644 --- a/templates/user/list.html.twig +++ b/templates/user/list.html.twig @@ -4,5 +4,53 @@ {% block body %}

{{title}}

- Ajouter + Ajouter + +
+ + + + + + + + + + + + {% for user in users %} + + + + + + + + {% endfor %} + +
ActionAvatarLoginRôlesCompagnies
{{user.username}} + {% for role in user.roles %} + {{role}}
+ {% endfor %} +
+ {% for company in user.companys %} + {{company.title}}
+ {% endfor %} +
+
+{% endblock %} + +{% block localscript %} + {% endblock %}