Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d29877d953 | |||
| 245b88bf31 | |||
| 7e0c084ebe |
23
.gitea/PULL_REQUEST_TEMPLATE.md
Normal file
23
.gitea/PULL_REQUEST_TEMPLATE.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
name: "Merge Request"
|
||||||
|
about: "Template de MR"
|
||||||
|
title: "[#NUMERO_TICKET] TITRE TICKET"
|
||||||
|
ref: "main"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
| Numéro du ticket | Titre du ticket |
|
||||||
|
|------------------|-----------------|
|
||||||
|
| | |
|
||||||
|
|
||||||
|
## Description de la PR
|
||||||
|
|
||||||
|
## Modification du .env
|
||||||
|
|
||||||
|
## Check list
|
||||||
|
|
||||||
|
- [ ] Pas de régression
|
||||||
|
- [ ] TU/TI/TF rédigée
|
||||||
|
- [ ] TU/TI/TF OK
|
||||||
|
- [ ] CHANGELOG modifié
|
||||||
45
.gitea/workflows/auto-tag-develop.yml
Normal file
45
.gitea/workflows/auto-tag-develop.yml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
name: Auto Tag Develop
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
tag:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
persist-credentials: true
|
||||||
|
|
||||||
|
- name: Create next tag v0.0.X
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Skip if current commit already has a v0.0.* tag
|
||||||
|
if git tag --points-at HEAD | grep -qE '^v0\.0\.'; then
|
||||||
|
echo "Tag already exists on this commit. Skipping."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
last_tag="$(git tag -l 'v0.0.*' --sort=-v:refname | head -n1 || true)"
|
||||||
|
if [ -z "$last_tag" ]; then
|
||||||
|
next_tag="v0.0.1"
|
||||||
|
else
|
||||||
|
patch="${last_tag##v0.0.}"
|
||||||
|
if ! [[ "$patch" =~ ^[0-9]+$ ]]; then
|
||||||
|
echo "Unexpected tag format: $last_tag" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
next_tag="v0.0.$((patch + 1))"
|
||||||
|
fi
|
||||||
|
|
||||||
|
git config user.name "gitea-actions"
|
||||||
|
git config user.email "gitea-actions@local"
|
||||||
|
git tag "$next_tag"
|
||||||
|
git push origin "$next_tag"
|
||||||
43
.gitea/workflows/release-artefact.yml
Normal file
43
.gitea/workflows/release-artefact.yml
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
name: Build Release Artefact
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "v0.0.*"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: "8.4"
|
||||||
|
extensions: mbstring, intl, xml, curl, zip
|
||||||
|
|
||||||
|
- name: Install backend deps (prod)
|
||||||
|
env:
|
||||||
|
APP_ENV: prod
|
||||||
|
APP_DEBUG: "0"
|
||||||
|
run: composer install --no-dev --optimize-autoloader --no-interaction --no-scripts
|
||||||
|
|
||||||
|
- name: Build artefact
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
mkdir -p release
|
||||||
|
tar --exclude=.git --exclude=.gitea -czf "release/ednotif-bundle-${GITHUB_REF_NAME}.tar.gz" \
|
||||||
|
.
|
||||||
|
|
||||||
|
- name: Create Release
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
files: release/ednotif-bundle-${{ github.ref_name }}.tar.gz
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
20
.idea/Soap-bundle.iml
generated
20
.idea/Soap-bundle.iml
generated
@@ -56,6 +56,26 @@
|
|||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/var-dumper" />
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/var-dumper" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/var-exporter" />
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/var-exporter" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/theseer/tokenizer" />
|
<excludeFolder url="file://$MODULE_DIR$/vendor/theseer/tokenizer" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/clue/ndjson-react" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/evenement/evenement" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/fidry/cpu-core-counter" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/friendsofphp/php-cs-fixer" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/react/cache" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/react/child-process" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/react/dns" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/react/event-loop" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/react/promise" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/react/socket" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/react/stream" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/console" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-grapheme" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-normalizer" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php80" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php81" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php84" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/process" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/stopwatch" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/string" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
|||||||
116
.idea/php.xml
generated
116
.idea/php.xml
generated
@@ -12,58 +12,78 @@
|
|||||||
</component>
|
</component>
|
||||||
<component name="PhpIncludePathManager">
|
<component name="PhpIncludePathManager">
|
||||||
<include_path>
|
<include_path>
|
||||||
<path value="$PROJECT_DIR$/vendor/psr/container" />
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" />
|
||||||
<path value="$PROJECT_DIR$/vendor/psr/cache" />
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-timer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-invoker" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/string" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/var-dumper" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-normalizer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/cache-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/finder" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/service-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/dependency-injection" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/http-foundation" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-ctype" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/process" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/stopwatch" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/config" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/options-resolver" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/cache" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/phpunit-bridge" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/framework-bundle" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/error-handler" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php85" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/filesystem" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/console" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php80" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php84" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/var-exporter" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/http-kernel" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php81" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-grapheme" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/routing" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/evenement/evenement" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/complexity" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/comparator" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/cli-parser" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/global-state" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/exporter" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/type" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/environment" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/diff" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/lines-of-code" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/friendsofphp/php-cs-fixer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/version" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/composer" />
|
||||||
<path value="$PROJECT_DIR$/vendor/psr/event-dispatcher" />
|
<path value="$PROJECT_DIR$/vendor/psr/event-dispatcher" />
|
||||||
<path value="$PROJECT_DIR$/vendor/psr/log" />
|
<path value="$PROJECT_DIR$/vendor/psr/log" />
|
||||||
<path value="$PROJECT_DIR$/vendor/phar-io/manifest" />
|
<path value="$PROJECT_DIR$/vendor/psr/container" />
|
||||||
<path value="$PROJECT_DIR$/vendor/phar-io/version" />
|
<path value="$PROJECT_DIR$/vendor/psr/cache" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/fidry/cpu-core-counter" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/clue/ndjson-react" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/react/dns" />
|
||||||
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
|
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
|
||||||
<path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
|
<path value="$PROJECT_DIR$/vendor/react/socket" />
|
||||||
<path value="$PROJECT_DIR$/vendor/staabm/side-effects-detector" />
|
<path value="$PROJECT_DIR$/vendor/react/child-process" />
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" />
|
<path value="$PROJECT_DIR$/vendor/react/event-loop" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/react/promise" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/react/cache" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/react/stream" />
|
||||||
<path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" />
|
<path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" />
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/cache" />
|
<path value="$PROJECT_DIR$/vendor/staabm/side-effects-detector" />
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/framework-bundle" />
|
<path value="$PROJECT_DIR$/vendor/phar-io/version" />
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/dependency-injection" />
|
<path value="$PROJECT_DIR$/vendor/phar-io/manifest" />
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/service-contracts" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/options-resolver" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/complexity" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/var-dumper" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/global-state" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php85" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/http-kernel" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/phpunit-bridge" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/cli-parser" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/filesystem" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/finder" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/lines-of-code" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/routing" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/diff" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/version" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/error-handler" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/type" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-ctype" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/exporter" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/comparator" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/cache-contracts" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher-contracts" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/environment" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-timer" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/http-foundation" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/config" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-invoker" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/var-exporter" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/composer" />
|
|
||||||
</include_path>
|
</include_path>
|
||||||
</component>
|
</component>
|
||||||
<component name="PhpProjectSharedConfiguration" php_language_level="8.4" />
|
<component name="PhpProjectSharedConfiguration" php_language_level="8.4" />
|
||||||
|
|||||||
56
.php-cs-fixer.dist.php
Normal file
56
.php-cs-fixer.dist.php
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use PhpCsFixer\Config;
|
||||||
|
use PhpCsFixer\Finder;
|
||||||
|
|
||||||
|
$finder = Finder::create()
|
||||||
|
->in('src')
|
||||||
|
->notName('Kernel.php')
|
||||||
|
;
|
||||||
|
|
||||||
|
$rules = [
|
||||||
|
'@Symfony' => true,
|
||||||
|
'@PSR12' => true,
|
||||||
|
'@PHP84Migration' => true,
|
||||||
|
'@PER-CS' => true,
|
||||||
|
'@PhpCsFixer' => true,
|
||||||
|
'strict_param' => true,
|
||||||
|
'strict_comparison' => true,
|
||||||
|
'no_useless_else' => true,
|
||||||
|
'no_useless_return' => true,
|
||||||
|
'binary_operator_spaces' => [
|
||||||
|
'operators' => [
|
||||||
|
'=' => 'align_single_space_minimal',
|
||||||
|
'||' => 'align_single_space_minimal',
|
||||||
|
'=>' => 'align_single_space_minimal',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'global_namespace_import' => [
|
||||||
|
'import_classes' => true,
|
||||||
|
'import_constants' => true,
|
||||||
|
'import_functions' => true,
|
||||||
|
],
|
||||||
|
'modernize_strpos' => true, // needs PHP 8+ or polyfill
|
||||||
|
'no_superfluous_phpdoc_tags' => true,
|
||||||
|
'echo_tag_syntax' => true,
|
||||||
|
'semicolon_after_instruction' => true,
|
||||||
|
'combine_consecutive_unsets' => true,
|
||||||
|
'ternary_to_null_coalescing' => true,
|
||||||
|
'declare_strict_types' => true,
|
||||||
|
'operator_linebreak' => [
|
||||||
|
'position' => 'beginning',
|
||||||
|
],
|
||||||
|
'no_unused_imports' => true,
|
||||||
|
'single_line_throw' => false,
|
||||||
|
'php_unit_test_class_requires_covers' => false,
|
||||||
|
];
|
||||||
|
|
||||||
|
$config = new Config();
|
||||||
|
|
||||||
|
return $config
|
||||||
|
->setRiskyAllowed(true)
|
||||||
|
->setRules($rules)
|
||||||
|
->setFinder($finder)
|
||||||
|
;
|
||||||
35
README.md
Normal file
35
README.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Bundle Malio ednotif
|
||||||
|
|
||||||
|
## Installation prod
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"repositories": [
|
||||||
|
{
|
||||||
|
"type": "vcs",
|
||||||
|
"url": "https://gitea.malio.fr/MALIO-DEV/ednotif-bundle"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
## Utilisation en dev
|
||||||
|
Pour le développement, vous pouvez utiliser une configuration de type "path" dans votre fichier `composer.json` plutôt que de configurer le dépôt Git. Cette approche est plus pratique pour tester des modifications locales :
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"repositories": [
|
||||||
|
{
|
||||||
|
"type": "path",
|
||||||
|
"url": "../soap-generator-bundle",
|
||||||
|
"options": {
|
||||||
|
"symlink": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Dans le docker-composer.yaml
|
||||||
|
```yaml
|
||||||
|
volumes:
|
||||||
|
- ../ednotif-bundle:/var/www/html/ednotif-bundle
|
||||||
|
```
|
||||||
31
commit-msg
Normal file
31
commit-msg
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
MSG_FILE="${1}"
|
||||||
|
FIRST_LINE="$(head -n 1 "$MSG_FILE" | tr -d '\r')"
|
||||||
|
|
||||||
|
# Autoriser commits auto-générés par git
|
||||||
|
if [[ "$FIRST_LINE" =~ ^Merge\ ]]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Types autorisés (MINUSCULES uniquement)
|
||||||
|
# Optionnel: scope => feat(auth) : ...
|
||||||
|
REGEX='^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\([a-z0-9._-]+\))?\ :\ .+'
|
||||||
|
|
||||||
|
if [[ ! "$FIRST_LINE" =~ $REGEX ]]; then
|
||||||
|
echo "❌ Message de commit invalide."
|
||||||
|
echo ""
|
||||||
|
echo "➡️ Format attendu : <type>(<scope optionnel>) : <message>"
|
||||||
|
echo "➡️ Types autorisés (minuscules uniquement) :"
|
||||||
|
echo " build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test"
|
||||||
|
echo ""
|
||||||
|
echo "✅ Exemples :"
|
||||||
|
echo " feat : add login page"
|
||||||
|
echo " fix(auth) : prevent null token crash"
|
||||||
|
echo " docs : update README"
|
||||||
|
echo ""
|
||||||
|
echo "❌ Exemple refusé :"
|
||||||
|
echo " Feat : add login page"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "Malio/ednotif-bundle",
|
"name": "malio/ednotif-bundle",
|
||||||
"description": "Client EDNOTIF (Guichet + wsIpBNotif) pour Symfony",
|
"description": "Client EDNOTIF (Guichet + wsIpBNotif) pour Symfony",
|
||||||
"type": "symfony-bundle",
|
"type": "symfony-bundle",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
"friendsofphp/php-cs-fixer": "^3.92",
|
||||||
"phpunit/phpunit": "^12.0",
|
"phpunit/phpunit": "^12.0",
|
||||||
"symfony/phpunit-bridge": "^8.0"
|
"symfony/phpunit-bridge": "^8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
1748
composer.lock
generated
1748
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -2,49 +2,60 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
use Malio\EdnotifBundle\Api\BovinApi;
|
|
||||||
use Malio\EdnotifBundle\Api\BovinApiInterface;
|
|
||||||
use Malio\EdnotifBundle\Auth\TokenProvider;
|
use Malio\EdnotifBundle\Auth\TokenProvider;
|
||||||
use Malio\EdnotifBundle\Soap\SoapClientFactory;
|
use Malio\EdnotifBundle\Bovin\Api\BovinApi;
|
||||||
|
use Malio\EdnotifBundle\Bovin\Api\BovinApiInterface;
|
||||||
|
use Malio\EdnotifBundle\Bovin\Mapper\AnimalFileMapper;
|
||||||
|
use Malio\EdnotifBundle\Shared\Soap\SoapClientFactory;
|
||||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||||
|
|
||||||
use function Symfony\Component\DependencyInjection\Loader\Configurator\service;
|
use function Symfony\Component\DependencyInjection\Loader\Configurator\service;
|
||||||
|
|
||||||
return static function (ContainerConfigurator $container): void {
|
return static function (ContainerConfigurator $container): void {
|
||||||
$services = $container->services()
|
$services = $container->services()
|
||||||
->defaults()
|
->defaults()
|
||||||
->autowire()
|
->autowire()
|
||||||
->autoconfigure();
|
->autoconfigure()
|
||||||
|
;
|
||||||
|
|
||||||
$services->set(SoapClientFactory::class)
|
$services->set(SoapClientFactory::class)
|
||||||
->arg('$soapOptions', '%ednotif.soap_options%');
|
->arg('$soapOptions', '%ednotif.soap_options%')
|
||||||
|
;
|
||||||
|
|
||||||
// SoapClient Guichet
|
|
||||||
$services->set('ednotif.soap.guichet', SoapClient::class)
|
$services->set('ednotif.soap.guichet', SoapClient::class)
|
||||||
->factory([service(SoapClientFactory::class), 'create'])
|
->factory([service(SoapClientFactory::class), 'create'])
|
||||||
->args(['%ednotif.guichet_wsdl%']);
|
->args(['%ednotif.guichet_wsdl%'])
|
||||||
|
;
|
||||||
|
|
||||||
// SoapClient Métier
|
$services->set('ednotif.soap.business', SoapClient::class)
|
||||||
$services->set('ednotif.soap.metier', SoapClient::class)
|
|
||||||
->factory([service(SoapClientFactory::class), 'create'])
|
->factory([service(SoapClientFactory::class), 'create'])
|
||||||
->args(['%ednotif.metier_wsdl%']);
|
->args(['%ednotif.metier_wsdl%'])
|
||||||
|
;
|
||||||
|
|
||||||
|
$services->set(AnimalFileMapper::class);
|
||||||
|
|
||||||
$services->set(TokenProvider::class)
|
$services->set(TokenProvider::class)
|
||||||
->args([
|
->args([
|
||||||
service('ednotif.soap.guichet'),
|
service('ednotif.soap.guichet'),
|
||||||
'%ednotif.entreprise%',
|
'%ednotif.exploitation_code%',
|
||||||
'%ednotif.zone%',
|
'%ednotif.zone%',
|
||||||
'%ednotif.application%',
|
'%ednotif.application%',
|
||||||
'%ednotif.login%',
|
'%ednotif.login%',
|
||||||
'%ednotif.password%',
|
'%ednotif.password%',
|
||||||
'%ednotif.token_ttl_seconds%',
|
'%ednotif.token_ttl_seconds%',
|
||||||
service('cache.app'),
|
service('cache.app'),
|
||||||
]);
|
])
|
||||||
|
;
|
||||||
|
|
||||||
$services->set(BovinApi::class)
|
$services->set(BovinApi::class)
|
||||||
->args([
|
->args([
|
||||||
service(TokenProvider::class),
|
service(TokenProvider::class),
|
||||||
service('ednotif.soap.metier'),
|
service('ednotif.soap.business'),
|
||||||
]);
|
service(AnimalFileMapper::class),
|
||||||
|
'%ednotif.exploitation_country_code%',
|
||||||
|
'%ednotif.exploitation_number%',
|
||||||
|
])
|
||||||
|
;
|
||||||
|
|
||||||
$services->alias(BovinApiInterface::class, BovinApi::class)->public();
|
$services->alias(BovinApiInterface::class, BovinApi::class)->public();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,10 +6,14 @@ services:
|
|||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
args:
|
args:
|
||||||
DOCKER_PHP_VERSION: ${DOCKER_PHP_VERSION}
|
DOCKER_PHP_VERSION: ${DOCKER_PHP_VERSION}
|
||||||
|
CURRENT_UID: ${CURRENT_UID}
|
||||||
|
CURRENT_GID: ${CURRENT_GID}
|
||||||
environment:
|
environment:
|
||||||
PHP_IDE_CONFIG: serverName=${DOCKER_APP_NAME}-docker
|
PHP_IDE_CONFIG: serverName=${DOCKER_APP_NAME}-docker
|
||||||
|
XDEBUG_CLIENT_HOST: ${XDEBUG_CLIENT_HOST:-host.docker.internal}
|
||||||
|
XDEBUG_CONFIG: client_host=${XDEBUG_CLIENT_HOST:-host.docker.internal} client_port=9003
|
||||||
extra_hosts:
|
extra_hosts:
|
||||||
- "host.docker.internal:${CLIENT_HOST:-0.0.0.0}"
|
- "host.docker.internal:${CLIENT_HOST:-0.0.0.0}"
|
||||||
volumes:
|
volumes:
|
||||||
- ./:/app
|
- ./:/var/www/html
|
||||||
- ./docker/php/config/docker-php-ext-xdebug.ini:/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
|
- ./docker/php/config/docker-php-ext-xdebug.ini:/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
|
||||||
@@ -14,12 +14,26 @@ RUN apt-get update && apt-get install -y \
|
|||||||
&& docker-php-ext-install soap \
|
&& docker-php-ext-install soap \
|
||||||
&& docker-php-ext-install dom
|
&& docker-php-ext-install dom
|
||||||
|
|
||||||
# Install Composer
|
# installation de composer
|
||||||
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
|
RUN rm -rf /var/cache/apk/* && rm -rf /tmp/* && \
|
||||||
|
curl --insecure https://getcomposer.org/composer.phar -o /usr/bin/composer && chmod +x /usr/bin/composer
|
||||||
|
|
||||||
# install Symfony Flex in the CI environment
|
# install Symfony Flex in the CI environment
|
||||||
RUN composer global config --no-plugins allow-plugins.symfony/flex true
|
RUN composer global config --no-plugins allow-plugins.symfony/flex true
|
||||||
RUN composer global require --no-progress --no-scripts --no-plugins symfony/flex
|
RUN composer global require --no-progress --no-scripts --no-plugins symfony/flex
|
||||||
|
|
||||||
# Set working directory
|
###> User ###
|
||||||
WORKDIR /app
|
ARG CURRENT_UID
|
||||||
|
ARG CURRENT_GID
|
||||||
|
# mapping du user host avec www-data
|
||||||
|
RUN usermod -o -u ${CURRENT_UID} www-data && groupmod -o -g ${CURRENT_GID} www-data
|
||||||
|
RUN chown www-data:www-data -R /var/www/*
|
||||||
|
RUN chown www-data:www-data -R /var/www/.*
|
||||||
|
###< User ###
|
||||||
|
|
||||||
|
RUN rm -rf \
|
||||||
|
/var/lib/apt/lists/* \
|
||||||
|
/tmp/* \
|
||||||
|
/var/tmp/*
|
||||||
|
|
||||||
|
WORKDIR /var/www/html
|
||||||
20
makefile
20
makefile
@@ -40,11 +40,17 @@ restart: env-init
|
|||||||
$(DOCKER_COMPOSE) down
|
$(DOCKER_COMPOSE) down
|
||||||
CURRENT_UID=$(shell id -u) CURRENT_GID=$(shell id -g) $(DOCKER_COMPOSE) up -d
|
CURRENT_UID=$(shell id -u) CURRENT_GID=$(shell id -g) $(DOCKER_COMPOSE) up -d
|
||||||
|
|
||||||
install: composer-install
|
install: copy-git-hook composer-install
|
||||||
|
|
||||||
# Supprime tout est réinstalle tout (Attention ça supprime la bdd aussi)
|
# Supprime tout est réinstalle tout (Attention ça supprime la bdd aussi)
|
||||||
reset: delete_built_dir remove_orphans build-without-cache start wait install
|
reset: delete_built_dir remove_orphans build-without-cache start wait install
|
||||||
|
|
||||||
|
copy-git-hook:
|
||||||
|
$(EXEC_PHP) cp pre-commit .git/hooks/
|
||||||
|
$(EXEC_PHP) cp commit-msg .git/hooks/
|
||||||
|
$(EXEC_PHP) chmod a+x .git/hooks/pre-commit
|
||||||
|
$(EXEC_PHP) chmod a+x .git/hooks/commit-msg
|
||||||
|
|
||||||
composer-install:
|
composer-install:
|
||||||
$(EXEC_PHP) composer install
|
$(EXEC_PHP) composer install
|
||||||
|
|
||||||
@@ -67,5 +73,17 @@ build-without-cache:
|
|||||||
shell:
|
shell:
|
||||||
$(EXEC_PHP_INTERACTIVE) bash
|
$(EXEC_PHP_INTERACTIVE) bash
|
||||||
|
|
||||||
|
shell-root:
|
||||||
|
$(EXEC_PHP_INTERACTIVE_ROOT) bash
|
||||||
|
|
||||||
|
# Lance php fixer
|
||||||
|
php-cs-fixer-all:
|
||||||
|
$(EXEC_PHP) php vendor/bin/php-cs-fixer fix
|
||||||
|
|
||||||
|
# Utilisé par le pre-commit pour fix les fichiers modifiés
|
||||||
|
php-cs-fixer-allow-risky:
|
||||||
|
@echo "Fixing files: $(FILES)"
|
||||||
|
$(EXEC_PHP_CS_FIXER) fix --config=.php-cs-fixer.dist.php --allow-risky=yes $(FILES)
|
||||||
|
|
||||||
wait:
|
wait:
|
||||||
sleep 10
|
sleep 10
|
||||||
28
pre-commit
Normal file
28
pre-commit
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo "######### Pre-commit hook start #############"
|
||||||
|
echo "--- php-cs-fixer pre commit hook start ---"
|
||||||
|
|
||||||
|
FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.php$')
|
||||||
|
# Vérifier s'il y a des fichiers PHP modifiés
|
||||||
|
if [ -n "$FILES" ]; then
|
||||||
|
echo "Running PHP CS Fixer on staged PHP files..."
|
||||||
|
|
||||||
|
# Convertir la liste des fichiers en une chaîne séparée par des espaces
|
||||||
|
FILES_LIST=""
|
||||||
|
for FILE in $FILES; do
|
||||||
|
FILES_LIST="$FILES_LIST $FILE"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Exécuter la cible make pour PHP CS Fixer
|
||||||
|
make php-cs-fixer-allow-risky FILES="$FILES_LIST"
|
||||||
|
|
||||||
|
# Ajouter les fichiers corrigés au commit
|
||||||
|
git add $FILES
|
||||||
|
else
|
||||||
|
echo "No PHP files to fix."
|
||||||
|
fi
|
||||||
|
echo "--- php-cs-fixer pre commit hook finish---"
|
||||||
|
|
||||||
|
echo "All checks passed. Proceeding with commit."
|
||||||
|
exit 0
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Malio\EdnotifBundle\Api;
|
|
||||||
|
|
||||||
use Malio\EdnotifBundle\Auth\TokenProvider;
|
|
||||||
use Malio\EdnotifBundle\Dto\DossierAnimalDto;
|
|
||||||
use Malio\EdnotifBundle\Exception\EdnotifException;
|
|
||||||
use SoapClient;
|
|
||||||
use SoapFault;
|
|
||||||
|
|
||||||
final class BovinApi implements BovinApiInterface
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private TokenProvider $tokenProvider,
|
|
||||||
private SoapClient $metierClient,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDossierAnimal(string $exploitationNumero, string $numeroNational, string $codePays = 'FR'): DossierAnimalDto
|
|
||||||
{
|
|
||||||
$token = $this->tokenProvider->getToken();
|
|
||||||
|
|
||||||
$payload = [[
|
|
||||||
'JetonAuthentification' => $token,
|
|
||||||
'Exploitation' => [
|
|
||||||
'CodePays' => $codePays,
|
|
||||||
'NumeroExploitation' => $exploitationNumero,
|
|
||||||
],
|
|
||||||
'Bovin' => [
|
|
||||||
'CodePays' => $codePays,
|
|
||||||
'NumeroNational' => $numeroNational,
|
|
||||||
],
|
|
||||||
]];
|
|
||||||
|
|
||||||
try {
|
|
||||||
/** @var object $response */
|
|
||||||
$response = $this->metierClient->__soapCall('IpBGetDossierAnimal', $payload);
|
|
||||||
} catch (SoapFault $e) {
|
|
||||||
// Si c’est un souci de jeton, tu peux invalider et retenter une fois (optionnel)
|
|
||||||
throw new \RuntimeException('SOAP Fault lors de IpBGetDossierAnimal: ' . $e->getMessage(), 0, $e);
|
|
||||||
}
|
|
||||||
|
|
||||||
$rs = $response->ReponseStandard ?? null;
|
|
||||||
$ok = is_object($rs) && (($rs->Resultat ?? false) === true);
|
|
||||||
|
|
||||||
if (!$ok) {
|
|
||||||
$anom = $rs->Anomalie ?? null;
|
|
||||||
$code = (string)($anom->Code ?? 'UNKNOWN');
|
|
||||||
$sev = (int)($anom->Severite ?? 1);
|
|
||||||
$msg = (string)($anom->Message ?? 'Appel EDNOTIF refusé');
|
|
||||||
throw new EdnotifException($code, $sev, $msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
$identite = [];
|
|
||||||
$periodes = [];
|
|
||||||
|
|
||||||
$bovinNode = $response->ReponseSpecifique->Bovin ?? null;
|
|
||||||
if (is_object($bovinNode)) {
|
|
||||||
$identiteObj = $bovinNode->IdentiteBovin ?? null;
|
|
||||||
if (is_object($identiteObj)) {
|
|
||||||
$identite = $this->objectToArray($identiteObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
$pp = $bovinNode->PeriodesPresences->PeriodePresence ?? null;
|
|
||||||
foreach ($this->normalizeList($pp) as $periode) {
|
|
||||||
if (!is_object($periode)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$entree = is_object($periode->Entree ?? null) ? $this->objectToArray($periode->Entree) : [];
|
|
||||||
$sortie = is_object($periode->Sortie ?? null) ? $this->objectToArray($periode->Sortie) : null;
|
|
||||||
|
|
||||||
$row = ['entree' => $entree];
|
|
||||||
if ($sortie !== null) {
|
|
||||||
$row['sortie'] = $sortie;
|
|
||||||
}
|
|
||||||
$periodes[] = $row;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new DossierAnimalDto(
|
|
||||||
numeroNational: $numeroNational,
|
|
||||||
identiteBovin: $identite,
|
|
||||||
periodesPresence: $periodes,
|
|
||||||
rawResponse: $response,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return list<mixed>
|
|
||||||
*/
|
|
||||||
private function normalizeList(mixed $value): array
|
|
||||||
{
|
|
||||||
if ($value === null) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
if (is_array($value)) {
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
return [$value];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array<string,mixed>
|
|
||||||
*/
|
|
||||||
private function objectToArray(object $obj): array
|
|
||||||
{
|
|
||||||
// conversion simple (suffisante pour démarrer)
|
|
||||||
return json_decode(json_encode($obj, JSON_THROW_ON_ERROR), true, 512, JSON_THROW_ON_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Malio\EdnotifBundle\Api;
|
|
||||||
|
|
||||||
use Malio\EdnotifBundle\Dto\DossierAnimalDto;
|
|
||||||
|
|
||||||
interface BovinApiInterface
|
|
||||||
{
|
|
||||||
public function getDossierAnimal(
|
|
||||||
string $exploitationNumero,
|
|
||||||
string $numeroNational,
|
|
||||||
string $codePays = 'FR'
|
|
||||||
): DossierAnimalDto;
|
|
||||||
}
|
|
||||||
@@ -4,33 +4,37 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Malio\EdnotifBundle\Auth;
|
namespace Malio\EdnotifBundle\Auth;
|
||||||
|
|
||||||
use Malio\EdnotifBundle\Exception\EdnotifException;
|
use Malio\EdnotifBundle\Shared\Exception\EdnotifException;
|
||||||
use Psr\Cache\CacheItemPoolInterface;
|
use Psr\Cache\CacheItemPoolInterface;
|
||||||
|
use Psr\Cache\InvalidArgumentException;
|
||||||
|
use RuntimeException;
|
||||||
use SoapClient;
|
use SoapClient;
|
||||||
use SoapFault;
|
use SoapFault;
|
||||||
|
|
||||||
final class TokenProvider
|
final readonly class TokenProvider
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private SoapClient $guichetClient,
|
private SoapClient $guichetClient,
|
||||||
private string $entreprise,
|
private string $exploitationCode,
|
||||||
private ?string $zone,
|
private ?string $zone,
|
||||||
private ?string $application,
|
private ?string $application,
|
||||||
private string $login,
|
private string $login,
|
||||||
private string $password,
|
private string $password,
|
||||||
private int $tokenTtlSeconds,
|
private int $tokenTtlSeconds,
|
||||||
private CacheItemPoolInterface $cachePool,
|
private CacheItemPoolInterface $cachePool,
|
||||||
) {
|
) {}
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
*/
|
||||||
public function getToken(): string
|
public function getToken(): string
|
||||||
{
|
{
|
||||||
$cacheKey = $this->getCacheKey();
|
$cacheKey = $this->getCacheKey();
|
||||||
$item = $this->cachePool->getItem($cacheKey);
|
$item = $this->cachePool->getItem($cacheKey);
|
||||||
|
|
||||||
if ($item->isHit()) {
|
if ($item->isHit()) {
|
||||||
$token = $item->get();
|
$token = $item->get();
|
||||||
if (is_string($token) && $token !== '') {
|
if (is_string($token) && '' !== $token) {
|
||||||
return $token;
|
return $token;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -44,6 +48,9 @@ final class TokenProvider
|
|||||||
return $token;
|
return $token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
*/
|
||||||
public function invalidateToken(): void
|
public function invalidateToken(): void
|
||||||
{
|
{
|
||||||
$this->cachePool->deleteItem($this->getCacheKey());
|
$this->cachePool->deleteItem($this->getCacheKey());
|
||||||
@@ -52,16 +59,16 @@ final class TokenProvider
|
|||||||
private function createToken(): string
|
private function createToken(): string
|
||||||
{
|
{
|
||||||
$profil = array_filter([
|
$profil = array_filter([
|
||||||
'Entreprise' => $this->entreprise,
|
'Entreprise' => $this->exploitationCode,
|
||||||
'Zone' => $this->zone,
|
'Zone' => $this->zone,
|
||||||
'Application' => $this->application,
|
'Application' => $this->application,
|
||||||
], static fn ($v) => $v !== null && $v !== '');
|
], static fn ($v) => null !== $v && '' !== $v);
|
||||||
|
|
||||||
$payload = [
|
$payload = [
|
||||||
'Identification' => [
|
'Identification' => [
|
||||||
'UserId' => $this->login,
|
'UserId' => $this->login,
|
||||||
'Password' => $this->password,
|
'Password' => $this->password,
|
||||||
'Profil' => $profil,
|
'Profil' => $profil,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -69,7 +76,7 @@ final class TokenProvider
|
|||||||
/** @var object $response */
|
/** @var object $response */
|
||||||
$response = $this->guichetClient->__soapCall('tkCreateIdentification', [$payload]);
|
$response = $this->guichetClient->__soapCall('tkCreateIdentification', [$payload]);
|
||||||
} catch (SoapFault $e) {
|
} catch (SoapFault $e) {
|
||||||
throw new \RuntimeException('SOAP Fault lors de tkCreateIdentification: ' . $e->getMessage(), 0, $e);
|
throw new RuntimeException('SOAP Fault lors de tkCreateIdentification: '.$e->getMessage(), 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
$rs = $response->ReponseStandard ?? null;
|
$rs = $response->ReponseStandard ?? null;
|
||||||
@@ -77,15 +84,16 @@ final class TokenProvider
|
|||||||
|
|
||||||
if (!$ok) {
|
if (!$ok) {
|
||||||
$anom = $rs->Anomalie ?? null;
|
$anom = $rs->Anomalie ?? null;
|
||||||
$code = (string)($anom->Code ?? 'UNKNOWN');
|
$code = (string) ($anom->Code ?? 'UNKNOWN');
|
||||||
$sev = (int)($anom->Severite ?? 1);
|
$sev = (int) ($anom->Severite ?? 1);
|
||||||
$msg = (string)($anom->Message ?? 'Authentification refusée');
|
$msg = (string) ($anom->Message ?? 'Authentification refusée');
|
||||||
|
|
||||||
throw new EdnotifException($code, $sev, $msg);
|
throw new EdnotifException($code, $sev, $msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
$token = $response->Jeton ?? null;
|
$token = $response->Jeton ?? null;
|
||||||
if (!is_string($token) || $token === '') {
|
if (!is_string($token) || '' === $token) {
|
||||||
throw new \RuntimeException('Guichet: réponse OK mais Jeton absent.');
|
throw new RuntimeException('Guichet: réponse OK mais Jeton absent.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $token;
|
return $token;
|
||||||
@@ -93,6 +101,6 @@ final class TokenProvider
|
|||||||
|
|
||||||
private function getCacheKey(): string
|
private function getCacheKey(): string
|
||||||
{
|
{
|
||||||
return 'ednotif.token.' . hash('sha256', $this->entreprise . '|' . $this->login);
|
return 'ednotif.token.'.hash('sha256', $this->exploitationCode.'|'.$this->login);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
64
src/Bovin/Api/BovinApi.php
Normal file
64
src/Bovin/Api/BovinApi.php
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Malio\EdnotifBundle\Bovin\Api;
|
||||||
|
|
||||||
|
use Malio\EdnotifBundle\Auth\TokenProvider;
|
||||||
|
use Malio\EdnotifBundle\Bovin\Dto\AnimalFileDto;
|
||||||
|
use Malio\EdnotifBundle\Bovin\Mapper\AnimalFileMapper;
|
||||||
|
use Malio\EdnotifBundle\Shared\Exception\EdnotifException;
|
||||||
|
use RuntimeException;
|
||||||
|
use SoapClient;
|
||||||
|
use SoapFault;
|
||||||
|
|
||||||
|
final readonly class BovinApi implements BovinApiInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private TokenProvider $tokenProvider,
|
||||||
|
private SoapClient $businessClient,
|
||||||
|
private AnimalFileMapper $bovinDossierMapper,
|
||||||
|
private string $exploitationCountryCode,
|
||||||
|
private string $exploitationNumber,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function getAnimalFile(string $nationalNumber, string $countryCode = 'FR'): AnimalFileDto
|
||||||
|
{
|
||||||
|
$token = $this->tokenProvider->getToken();
|
||||||
|
|
||||||
|
$requestPayload = [[
|
||||||
|
'JetonAuthentification' => $token,
|
||||||
|
'Exploitation' => [
|
||||||
|
'CodePays' => $this->exploitationCountryCode,
|
||||||
|
'NumeroExploitation' => $this->exploitationNumber,
|
||||||
|
],
|
||||||
|
'Bovin' => [
|
||||||
|
'CodePays' => $countryCode,
|
||||||
|
'NumeroNational' => $nationalNumber,
|
||||||
|
],
|
||||||
|
]];
|
||||||
|
|
||||||
|
try {
|
||||||
|
/** @var object $soapResponse */
|
||||||
|
$soapResponse = $this->businessClient->__soapCall('IpBGetDossierAnimal', $requestPayload);
|
||||||
|
} catch (SoapFault $soapFault) {
|
||||||
|
throw new RuntimeException('SOAP Fault on IpBGetDossierAnimal: '.$soapFault->getMessage(), 0, $soapFault);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throw uniquement si Resultat=false (erreur métier)
|
||||||
|
$standardResponseNode = $soapResponse->ReponseStandard ?? null;
|
||||||
|
$isOk = is_object($standardResponseNode) && (($standardResponseNode->Resultat ?? false) === true);
|
||||||
|
|
||||||
|
if (!$isOk) {
|
||||||
|
$anomalyNode = is_object($standardResponseNode) ? ($standardResponseNode->Anomalie ?? null) : null;
|
||||||
|
|
||||||
|
throw new EdnotifException(
|
||||||
|
codeAnomalie: (string) ($anomalyNode->Code ?? 'UNKNOWN'),
|
||||||
|
severite: (int) ($anomalyNode->Severite ?? 1),
|
||||||
|
message: (string) ($anomalyNode->Message ?? 'EDNOTIF error')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->bovinDossierMapper->map($soapResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/Bovin/Api/BovinApiInterface.php
Normal file
12
src/Bovin/Api/BovinApiInterface.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Malio\EdnotifBundle\Bovin\Api;
|
||||||
|
|
||||||
|
use Malio\EdnotifBundle\Bovin\Dto\AnimalFileDto;
|
||||||
|
|
||||||
|
interface BovinApiInterface
|
||||||
|
{
|
||||||
|
public function getAnimalFile(string $nationalNumber, string $countryCode = 'FR'): AnimalFileDto;
|
||||||
|
}
|
||||||
20
src/Bovin/Dto/AnimalFileDto.php
Normal file
20
src/Bovin/Dto/AnimalFileDto.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Malio\EdnotifBundle\Bovin\Dto;
|
||||||
|
|
||||||
|
use Malio\EdnotifBundle\Shared\Dto\StandardResponseDto;
|
||||||
|
|
||||||
|
final readonly class AnimalFileDto
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param list<PresencePeriodDto> $presencePeriods
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
public StandardResponseDto $standardResponse,
|
||||||
|
public ?BovinIdentificationDto $identification,
|
||||||
|
public array $presencePeriods,
|
||||||
|
public ?object $rawSoapResponse, // pour garder 100% des data
|
||||||
|
) {}
|
||||||
|
}
|
||||||
20
src/Bovin/Dto/BovinIdentificationDto.php
Normal file
20
src/Bovin/Dto/BovinIdentificationDto.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Malio\EdnotifBundle\Bovin\Dto;
|
||||||
|
|
||||||
|
final readonly class BovinIdentificationDto
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ?BovinRef $bovin,
|
||||||
|
public ?string $sex,
|
||||||
|
public ?string $breedType,
|
||||||
|
public ?DateValueDto $birthDate,
|
||||||
|
public ?string $workNumber,
|
||||||
|
public ?bool $isFilie,
|
||||||
|
public ?ParentInfoDto $motherCarrier,
|
||||||
|
public ?ParentInfoDto $fatherIpg,
|
||||||
|
public ?ExploitationRef $birthExploitation,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
13
src/Bovin/Dto/BovinRef.php
Normal file
13
src/Bovin/Dto/BovinRef.php
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Malio\EdnotifBundle\Bovin\Dto;
|
||||||
|
|
||||||
|
final readonly class BovinRef
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ?string $countryCode,
|
||||||
|
public ?string $nationalNumber,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
15
src/Bovin/Dto/DateValueDto.php
Normal file
15
src/Bovin/Dto/DateValueDto.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Malio\EdnotifBundle\Bovin\Dto;
|
||||||
|
|
||||||
|
use DateTimeImmutable;
|
||||||
|
|
||||||
|
final readonly class DateValueDto
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ?DateTimeImmutable $date,
|
||||||
|
public ?string $completenessFlag,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace Malio\EdnotifBundle\Dto;
|
namespace Malio\EdnotifBundle\Bovin\Dto;
|
||||||
|
|
||||||
final readonly class DossierAnimalDto
|
final readonly class DossierAnimalDto
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param array<string,mixed> $identiteBovin
|
* @param array<string,mixed> $identiteBovin
|
||||||
* @param list<array{entree: array<string,mixed>, sortie?: array<string,mixed>}> $periodesPresence
|
* @param list<array{entree: array<string,mixed>, sortie?: array<string,mixed>}> $periodesPresence
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
@@ -15,6 +15,5 @@ final readonly class DossierAnimalDto
|
|||||||
public array $identiteBovin,
|
public array $identiteBovin,
|
||||||
public array $periodesPresence,
|
public array $periodesPresence,
|
||||||
public object $rawResponse,
|
public object $rawResponse,
|
||||||
) {
|
) {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
13
src/Bovin/Dto/ExploitationRef.php
Normal file
13
src/Bovin/Dto/ExploitationRef.php
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Malio\EdnotifBundle\Bovin\Dto;
|
||||||
|
|
||||||
|
final readonly class ExploitationRef
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ?string $countryCode,
|
||||||
|
public ?string $exploitationNumber,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
16
src/Bovin/Dto/MovementDto.php
Normal file
16
src/Bovin/Dto/MovementDto.php
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Malio\EdnotifBundle\Bovin\Dto;
|
||||||
|
|
||||||
|
use DateTimeImmutable;
|
||||||
|
|
||||||
|
final readonly class MovementDto
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ?DateTimeImmutable $date,
|
||||||
|
public ?string $cause,
|
||||||
|
public ?ExploitationRef $exploitation,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
13
src/Bovin/Dto/ParentInfoDto.php
Normal file
13
src/Bovin/Dto/ParentInfoDto.php
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Malio\EdnotifBundle\Bovin\Dto;
|
||||||
|
|
||||||
|
final readonly class ParentInfoDto
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ?BovinRef $bovin,
|
||||||
|
public ?string $breedType,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
13
src/Bovin/Dto/PresencePeriodDto.php
Normal file
13
src/Bovin/Dto/PresencePeriodDto.php
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Malio\EdnotifBundle\Bovin\Dto;
|
||||||
|
|
||||||
|
final readonly class PresencePeriodDto
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ?MovementDto $entry,
|
||||||
|
public ?MovementDto $exit,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
235
src/Bovin/Mapper/AnimalFileMapper.php
Normal file
235
src/Bovin/Mapper/AnimalFileMapper.php
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Malio\EdnotifBundle\Bovin\Mapper;
|
||||||
|
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use Malio\EdnotifBundle\Bovin\Dto\AnimalFileDto;
|
||||||
|
use Malio\EdnotifBundle\Bovin\Dto\BovinIdentificationDto;
|
||||||
|
use Malio\EdnotifBundle\Bovin\Dto\BovinRef;
|
||||||
|
use Malio\EdnotifBundle\Bovin\Dto\DateValueDto;
|
||||||
|
use Malio\EdnotifBundle\Bovin\Dto\ExploitationRef;
|
||||||
|
use Malio\EdnotifBundle\Bovin\Dto\MovementDto;
|
||||||
|
use Malio\EdnotifBundle\Bovin\Dto\ParentInfoDto;
|
||||||
|
use Malio\EdnotifBundle\Bovin\Dto\PresencePeriodDto;
|
||||||
|
use Malio\EdnotifBundle\Shared\Dto\AnomalyDto;
|
||||||
|
use Malio\EdnotifBundle\Shared\Dto\StandardResponseDto;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
final class AnimalFileMapper
|
||||||
|
{
|
||||||
|
public function map(object $soapResponse): AnimalFileDto
|
||||||
|
{
|
||||||
|
$standardResponse = $this->mapStandardResponse($soapResponse->ReponseStandard ?? null);
|
||||||
|
|
||||||
|
$specificResponseNode = $soapResponse->ReponseSpecifique ?? null;
|
||||||
|
$bovinNode = is_object($specificResponseNode) ? ($specificResponseNode->Bovin ?? null) : null;
|
||||||
|
|
||||||
|
$identification = null;
|
||||||
|
$presencePeriods = [];
|
||||||
|
|
||||||
|
if (is_object($bovinNode)) {
|
||||||
|
$identificationNode = $bovinNode->IdentiteBovin ?? null;
|
||||||
|
if (is_object($identificationNode)) {
|
||||||
|
$identification = $this->mapIdentification($identificationNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
$presencePeriodsNode = $bovinNode->PeriodesPresences->PeriodePresence ?? null;
|
||||||
|
foreach ($this->normalizeToList($presencePeriodsNode) as $presencePeriodNode) {
|
||||||
|
if (!is_object($presencePeriodNode)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$presencePeriods[] = $this->mapPresencePeriod($presencePeriodNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AnimalFileDto(
|
||||||
|
standardResponse: $standardResponse,
|
||||||
|
identification: $identification,
|
||||||
|
presencePeriods: $presencePeriods,
|
||||||
|
rawSoapResponse: $soapResponse
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function mapStandardResponse(mixed $standardResponseNode): StandardResponseDto
|
||||||
|
{
|
||||||
|
$result = (bool) ($standardResponseNode->Resultat ?? false);
|
||||||
|
|
||||||
|
$anomalyNode = $standardResponseNode->Anomalie ?? null;
|
||||||
|
$anomaly = null;
|
||||||
|
|
||||||
|
if (is_object($anomalyNode)) {
|
||||||
|
$anomaly = new AnomalyDto(
|
||||||
|
code: $this->toNullableString($anomalyNode->Code ?? null),
|
||||||
|
severity: $this->toNullableInt($anomalyNode->Severite ?? null),
|
||||||
|
message: $this->toNullableString($anomalyNode->Message ?? null),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new StandardResponseDto($result, $anomaly);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function mapIdentification(object $identificationNode): BovinIdentificationDto
|
||||||
|
{
|
||||||
|
$bovinRef = $this->mapBovinRef($identificationNode->Bovin ?? null);
|
||||||
|
|
||||||
|
$birthDate = null;
|
||||||
|
$birthDateNode = $identificationNode->DateNaissance ?? null;
|
||||||
|
if (is_object($birthDateNode)) {
|
||||||
|
$birthDate = new DateValueDto(
|
||||||
|
date: $this->toNullableDate($birthDateNode->Date ?? null),
|
||||||
|
completenessFlag: $this->toNullableString($birthDateNode->TemoinCompletude ?? null),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$motherCarrier = $this->mapParentInfo($identificationNode->MerePorteuse ?? null);
|
||||||
|
$fatherIpg = $this->mapParentInfo($identificationNode->PereIPG ?? null);
|
||||||
|
$birthExploitation = $this->mapExploitationRef($identificationNode->ExploitationNaissance ?? null);
|
||||||
|
|
||||||
|
return new BovinIdentificationDto(
|
||||||
|
bovin: $bovinRef,
|
||||||
|
sex: $this->toNullableString($identificationNode->Sexe ?? null),
|
||||||
|
breedType: $this->toNullableString($identificationNode->TypeRacial ?? null),
|
||||||
|
birthDate: $birthDate,
|
||||||
|
workNumber: $this->toNullableString($identificationNode->NumeroTravail ?? null),
|
||||||
|
isFilie: $this->toNullableBool($identificationNode->StatutFilie ?? null),
|
||||||
|
motherCarrier: $motherCarrier,
|
||||||
|
fatherIpg: $fatherIpg,
|
||||||
|
birthExploitation: $birthExploitation,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function mapPresencePeriod(object $presencePeriodNode): PresencePeriodDto
|
||||||
|
{
|
||||||
|
$entryNode = $presencePeriodNode->Entree ?? null;
|
||||||
|
$exitNode = $presencePeriodNode->Sortie ?? null;
|
||||||
|
|
||||||
|
$entryMovement = is_object($entryNode) ? $this->mapMovement($entryNode, 'entry') : null;
|
||||||
|
$exitMovement = is_object($exitNode) ? $this->mapMovement($exitNode, 'exit') : null;
|
||||||
|
|
||||||
|
return new PresencePeriodDto(
|
||||||
|
entry: $entryMovement,
|
||||||
|
exit: $exitMovement,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function mapMovement(object $movementNode, string $direction): MovementDto
|
||||||
|
{
|
||||||
|
$dateValue = null;
|
||||||
|
$causeValue = null;
|
||||||
|
|
||||||
|
if ('entry' === $direction) {
|
||||||
|
// SOAP: DateEntree / CauseEntree
|
||||||
|
$dateValue = $movementNode->DateEntree ?? ($movementNode->Date ?? ($movementNode->DateMouvement ?? null));
|
||||||
|
$causeValue = $movementNode->CauseEntree ?? null;
|
||||||
|
} else {
|
||||||
|
// SOAP (souvent): DateSortie / CauseSortie
|
||||||
|
$dateValue = $movementNode->DateSortie ?? ($movementNode->Date ?? ($movementNode->DateMouvement ?? null));
|
||||||
|
$causeValue = $movementNode->CauseSortie ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$exploitationRef = $this->mapExploitationRef($movementNode->Exploitation ?? null);
|
||||||
|
|
||||||
|
return new MovementDto(
|
||||||
|
date: $this->toNullableDate($dateValue),
|
||||||
|
cause: $this->toNullableString($causeValue),
|
||||||
|
exploitation: $exploitationRef,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function mapParentInfo(mixed $parentNode): ?ParentInfoDto
|
||||||
|
{
|
||||||
|
if (!is_object($parentNode)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$bovinRef = $this->mapBovinRef($parentNode->Bovin ?? null);
|
||||||
|
|
||||||
|
return new ParentInfoDto(
|
||||||
|
bovin: $bovinRef,
|
||||||
|
breedType: $this->toNullableString($parentNode->TypeRacial ?? null),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function mapBovinRef(mixed $bovinNode): ?BovinRef
|
||||||
|
{
|
||||||
|
if (!is_object($bovinNode)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BovinRef(
|
||||||
|
countryCode: $this->toNullableString($bovinNode->CodePays ?? null),
|
||||||
|
nationalNumber: $this->toNullableString($bovinNode->NumeroNational ?? null),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function mapExploitationRef(mixed $exploitationNode): ?ExploitationRef
|
||||||
|
{
|
||||||
|
if (!is_object($exploitationNode)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ExploitationRef(
|
||||||
|
countryCode: $this->toNullableString($exploitationNode->CodePays ?? null),
|
||||||
|
exploitationNumber: $this->toNullableString($exploitationNode->NumeroExploitation ?? null),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return list<mixed> */
|
||||||
|
private function normalizeToList(mixed $value): array
|
||||||
|
{
|
||||||
|
if (null === $value) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_array($value) ? $value : [$value];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function toNullableString(mixed $value): ?string
|
||||||
|
{
|
||||||
|
if (null === $value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$stringValue = trim((string) $value);
|
||||||
|
|
||||||
|
return '' === $stringValue ? null : $stringValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function toNullableInt(mixed $value): ?int
|
||||||
|
{
|
||||||
|
if (null === $value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (is_int($value)) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
if (is_numeric($value)) {
|
||||||
|
return (int) $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function toNullableBool(mixed $value): ?bool
|
||||||
|
{
|
||||||
|
if (null === $value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (bool) $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function toNullableDate(mixed $value): ?DateTimeImmutable
|
||||||
|
{
|
||||||
|
if (!is_string($value) || '' === trim($value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new DateTimeImmutable($value);
|
||||||
|
} catch (Throwable) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,9 @@ namespace Malio\EdnotifBundle\DependencyInjection;
|
|||||||
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
||||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||||
|
|
||||||
|
use const SOAP_SINGLE_ELEMENT_ARRAYS;
|
||||||
|
use const WSDL_CACHE_BOTH;
|
||||||
|
|
||||||
final class Configuration implements ConfigurationInterface
|
final class Configuration implements ConfigurationInterface
|
||||||
{
|
{
|
||||||
public function getConfigTreeBuilder(): TreeBuilder
|
public function getConfigTreeBuilder(): TreeBuilder
|
||||||
@@ -19,13 +22,16 @@ final class Configuration implements ConfigurationInterface
|
|||||||
->scalarNode('guichet_wsdl')->cannotBeEmpty()->isRequired()->end()
|
->scalarNode('guichet_wsdl')->cannotBeEmpty()->isRequired()->end()
|
||||||
->scalarNode('metier_wsdl')->cannotBeEmpty()->isRequired()->end()
|
->scalarNode('metier_wsdl')->cannotBeEmpty()->isRequired()->end()
|
||||||
|
|
||||||
->scalarNode('entreprise')->cannotBeEmpty()->isRequired()->end()
|
->scalarNode('exploitation_code')->cannotBeEmpty()->isRequired()->end()
|
||||||
->scalarNode('zone')->defaultNull()->end()
|
->scalarNode('zone')->defaultNull()->end()
|
||||||
->scalarNode('application')->defaultNull()->end()
|
->scalarNode('application')->defaultNull()->end()
|
||||||
|
|
||||||
->scalarNode('login')->cannotBeEmpty()->isRequired()->end()
|
->scalarNode('login')->cannotBeEmpty()->isRequired()->end()
|
||||||
->scalarNode('password')->cannotBeEmpty()->isRequired()->end()
|
->scalarNode('password')->cannotBeEmpty()->isRequired()->end()
|
||||||
|
|
||||||
|
->scalarNode('exploitation_number')->cannotBeEmpty()->isRequired()->end()
|
||||||
|
->scalarNode('exploitation_country_code')->defaultValue('FR')->end()
|
||||||
|
|
||||||
->integerNode('token_ttl_seconds')->min(30)->defaultValue(900)->end()
|
->integerNode('token_ttl_seconds')->min(30)->defaultValue(900)->end()
|
||||||
|
|
||||||
->arrayNode('soap_options')
|
->arrayNode('soap_options')
|
||||||
@@ -34,11 +40,12 @@ final class Configuration implements ConfigurationInterface
|
|||||||
->booleanNode('trace')->defaultFalse()->end()
|
->booleanNode('trace')->defaultFalse()->end()
|
||||||
->booleanNode('exceptions')->defaultTrue()->end()
|
->booleanNode('exceptions')->defaultTrue()->end()
|
||||||
->integerNode('connection_timeout')->min(1)->defaultValue(15)->end()
|
->integerNode('connection_timeout')->min(1)->defaultValue(15)->end()
|
||||||
->integerNode('cache_wsdl')->defaultValue(\WSDL_CACHE_BOTH)->end()
|
->integerNode('cache_wsdl')->defaultValue(WSDL_CACHE_BOTH)->end()
|
||||||
->integerNode('features')->defaultValue(\SOAP_SINGLE_ELEMENT_ARRAYS)->end()
|
->integerNode('features')->defaultValue(SOAP_SINGLE_ELEMENT_ARRAYS)->end()
|
||||||
->end()
|
->end()
|
||||||
->end()
|
->end()
|
||||||
->end();
|
->end()
|
||||||
|
;
|
||||||
|
|
||||||
return $treeBuilder;
|
return $treeBuilder;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,10 +14,11 @@ final class EdnotifExtension extends Extension
|
|||||||
public function load(array $configs, ContainerBuilder $container): void
|
public function load(array $configs, ContainerBuilder $container): void
|
||||||
{
|
{
|
||||||
$configuration = new Configuration();
|
$configuration = new Configuration();
|
||||||
|
|
||||||
/** @var array{
|
/** @var array{
|
||||||
* guichet_wsdl:string,
|
* guichet_wsdl:string,
|
||||||
* metier_wsdl:string,
|
* metier_wsdl:string,
|
||||||
* entreprise:string,
|
* exploitation_code:string,
|
||||||
* zone:?string,
|
* zone:?string,
|
||||||
* application:?string,
|
* application:?string,
|
||||||
* login:string,
|
* login:string,
|
||||||
@@ -31,17 +32,20 @@ final class EdnotifExtension extends Extension
|
|||||||
$container->setParameter('ednotif.guichet_wsdl', $config['guichet_wsdl']);
|
$container->setParameter('ednotif.guichet_wsdl', $config['guichet_wsdl']);
|
||||||
$container->setParameter('ednotif.metier_wsdl', $config['metier_wsdl']);
|
$container->setParameter('ednotif.metier_wsdl', $config['metier_wsdl']);
|
||||||
|
|
||||||
$container->setParameter('ednotif.entreprise', $config['entreprise']);
|
$container->setParameter('ednotif.exploitation_code', $config['exploitation_code']);
|
||||||
$container->setParameter('ednotif.zone', $config['zone']);
|
$container->setParameter('ednotif.zone', $config['zone']);
|
||||||
$container->setParameter('ednotif.application', $config['application']);
|
$container->setParameter('ednotif.application', $config['application']);
|
||||||
|
|
||||||
|
$container->setParameter('ednotif.exploitation_number', $config['exploitation_number']);
|
||||||
|
$container->setParameter('ednotif.exploitation_country_code', $config['exploitation_country_code']);
|
||||||
|
|
||||||
$container->setParameter('ednotif.login', $config['login']);
|
$container->setParameter('ednotif.login', $config['login']);
|
||||||
$container->setParameter('ednotif.password', $config['password']);
|
$container->setParameter('ednotif.password', $config['password']);
|
||||||
|
|
||||||
$container->setParameter('ednotif.token_ttl_seconds', $config['token_ttl_seconds']);
|
$container->setParameter('ednotif.token_ttl_seconds', $config['token_ttl_seconds']);
|
||||||
$container->setParameter('ednotif.soap_options', $config['soap_options']);
|
$container->setParameter('ednotif.soap_options', $config['soap_options']);
|
||||||
|
|
||||||
$loader = new PhpFileLoader($container, new FileLocator(__DIR__ . '/../../config'));
|
$loader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../../config'));
|
||||||
$loader->load('services.php');
|
$loader->load('services.php');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,4 @@ namespace Malio\EdnotifBundle;
|
|||||||
|
|
||||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||||
|
|
||||||
final class EdnotifBundle extends Bundle
|
final class EdnotifBundle extends Bundle {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|||||||
14
src/Shared/Dto/AnomalyDto.php
Normal file
14
src/Shared/Dto/AnomalyDto.php
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Malio\EdnotifBundle\Shared\Dto;
|
||||||
|
|
||||||
|
final readonly class AnomalyDto
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ?string $code,
|
||||||
|
public ?int $severity,
|
||||||
|
public ?string $message,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
13
src/Shared/Dto/StandardResponseDto.php
Normal file
13
src/Shared/Dto/StandardResponseDto.php
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Malio\EdnotifBundle\Shared\Dto;
|
||||||
|
|
||||||
|
final readonly class StandardResponseDto
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public bool $result,
|
||||||
|
public ?AnomalyDto $anomaly,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace Malio\EdnotifBundle\Exception;
|
namespace Malio\EdnotifBundle\Shared\Exception;
|
||||||
|
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace Malio\EdnotifBundle\Soap;
|
namespace Malio\EdnotifBundle\Shared\Soap;
|
||||||
|
|
||||||
use SoapClient;
|
use SoapClient;
|
||||||
|
|
||||||
@@ -11,9 +11,7 @@ final class SoapClientFactory
|
|||||||
/**
|
/**
|
||||||
* @param array<string,mixed> $soapOptions
|
* @param array<string,mixed> $soapOptions
|
||||||
*/
|
*/
|
||||||
public function __construct(private array $soapOptions = [])
|
public function __construct(private array $soapOptions = []) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function create(string $wsdl): SoapClient
|
public function create(string $wsdl): SoapClient
|
||||||
{
|
{
|
||||||
Reference in New Issue
Block a user