Compare commits
No commits in common. "6246f29135a7612bcf7119d26e0bcf4b0930afdb" and "77ce2c3043114eae5d1c3f0fc94e3af84912a240" have entirely different histories.
6246f29135
...
77ce2c3043
18
CLAUDE.md
18
CLAUDE.md
@ -80,24 +80,6 @@ php bin/console cache:clear
|
|||||||
APP_ENV=prod php bin/console cache:warmup
|
APP_ENV=prod php bin/console cache:warmup
|
||||||
```
|
```
|
||||||
|
|
||||||
### Module Management (Plugin System)
|
|
||||||
```bash
|
|
||||||
# List all installed modules with license status
|
|
||||||
php bin/console app:module:list
|
|
||||||
|
|
||||||
# Register/manage module license
|
|
||||||
php bin/console app:module:license billing # Interactive
|
|
||||||
php bin/console app:module:license billing <license-key> # Direct
|
|
||||||
php bin/console app:module:license billing --validate # Validate
|
|
||||||
php bin/console app:module:license billing --revoke # Revoke
|
|
||||||
|
|
||||||
# Remove a module safely
|
|
||||||
php bin/console app:module:remove billing # Interactive
|
|
||||||
php bin/console app:module:remove billing --force # No confirmation
|
|
||||||
php bin/console app:module:remove billing --keep-license # Keep license
|
|
||||||
php bin/console app:module:remove billing --keep-db-entry # Keep DB entry
|
|
||||||
```
|
|
||||||
|
|
||||||
## Architecture Overview
|
## Architecture Overview
|
||||||
|
|
||||||
### Security System (6 Layers)
|
### Security System (6 Layers)
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
"knpuniversity/oauth2-client-bundle": "*",
|
"knpuniversity/oauth2-client-bundle": "*",
|
||||||
"league/oauth2-client": "*",
|
"league/oauth2-client": "*",
|
||||||
"mycrm/billing-module": "^1.0",
|
"mycrm/billing-module": "^1.0",
|
||||||
|
"mycrm/test-module": "*",
|
||||||
"nelmio/cors-bundle": "^2.6",
|
"nelmio/cors-bundle": "^2.6",
|
||||||
"phpdocumentor/reflection-docblock": "^5.6",
|
"phpdocumentor/reflection-docblock": "^5.6",
|
||||||
"phpstan/phpdoc-parser": "^2.3",
|
"phpstan/phpdoc-parser": "^2.3",
|
||||||
|
|||||||
120
composer.lock
generated
120
composer.lock
generated
@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "f89ce01cc8bcb7810af77472d2437dd0",
|
"content-hash": "ac7d8a38f7c8dd8a8f2760177304dcb4",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "api-platform/core",
|
"name": "api-platform/core",
|
||||||
@ -3259,6 +3259,42 @@
|
|||||||
"description": "Ausgangsrechnungsverwaltung für myCRM",
|
"description": "Ausgangsrechnungsverwaltung für myCRM",
|
||||||
"time": "2025-12-05T10:24:44+00:00"
|
"time": "2025-12-05T10:24:44+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "mycrm/test-module",
|
||||||
|
"version": "v1.0.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.osdata-home.de/mycrm/mycrm-test-module",
|
||||||
|
"reference": "0630a840ffdca475208b51f7807196468e44c27c"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.2",
|
||||||
|
"symfony/framework-bundle": "^7.0"
|
||||||
|
},
|
||||||
|
"type": "symfony-bundle",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "1.0-dev",
|
||||||
|
"stable": "v1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"MyCRM\\TestModule\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"license": [
|
||||||
|
"proprietary"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Your Name",
|
||||||
|
"email": "your.email@example.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Test Module for myCRM - Demonstrates the plugin system",
|
||||||
|
"time": "2025-12-03T15:57:07+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "nelmio/cors-bundle",
|
"name": "nelmio/cors-bundle",
|
||||||
"version": "2.6.0",
|
"version": "2.6.0",
|
||||||
@ -6542,16 +6578,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/monolog-bundle",
|
"name": "symfony/monolog-bundle",
|
||||||
"version": "v3.11.1",
|
"version": "v3.11.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/monolog-bundle.git",
|
"url": "https://github.com/symfony/monolog-bundle.git",
|
||||||
"reference": "0e675a6e08f791ef960dc9c7e392787111a3f0c1"
|
"reference": "e12eb92655b234cd50c21cda648088847a7ec777"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/0e675a6e08f791ef960dc9c7e392787111a3f0c1",
|
"url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/e12eb92655b234cd50c21cda648088847a7ec777",
|
||||||
"reference": "0e675a6e08f791ef960dc9c7e392787111a3f0c1",
|
"reference": "e12eb92655b234cd50c21cda648088847a7ec777",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -6598,7 +6634,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/symfony/monolog-bundle/issues",
|
"issues": "https://github.com/symfony/monolog-bundle/issues",
|
||||||
"source": "https://github.com/symfony/monolog-bundle/tree/v3.11.1"
|
"source": "https://github.com/symfony/monolog-bundle/tree/v3.11.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -6618,7 +6654,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2025-12-08T07:58:26+00:00"
|
"time": "2025-11-27T09:16:19+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/notifier",
|
"name": "symfony/notifier",
|
||||||
@ -9761,16 +9797,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "twig/extra-bundle",
|
"name": "twig/extra-bundle",
|
||||||
"version": "v3.22.2",
|
"version": "v3.22.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/twigphp/twig-extra-bundle.git",
|
"url": "https://github.com/twigphp/twig-extra-bundle.git",
|
||||||
"reference": "09de9be7f6c0d19ede7b5a1dbfcfb2e9d1e0ea9e"
|
"reference": "b6534bc925bec930004facca92fccebd0c809247"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/09de9be7f6c0d19ede7b5a1dbfcfb2e9d1e0ea9e",
|
"url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/b6534bc925bec930004facca92fccebd0c809247",
|
||||||
"reference": "09de9be7f6c0d19ede7b5a1dbfcfb2e9d1e0ea9e",
|
"reference": "b6534bc925bec930004facca92fccebd0c809247",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -9819,7 +9855,7 @@
|
|||||||
"twig"
|
"twig"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.22.2"
|
"source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.22.1"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -9831,7 +9867,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2025-12-05T08:51:53+00:00"
|
"time": "2025-11-02T11:00:49+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "twig/twig",
|
"name": "twig/twig",
|
||||||
@ -10326,16 +10362,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "nikic/php-parser",
|
"name": "nikic/php-parser",
|
||||||
"version": "v5.7.0",
|
"version": "v5.6.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||||
"reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82"
|
"reference": "3a454ca033b9e06b63282ce19562e892747449bb"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82",
|
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb",
|
||||||
"reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82",
|
"reference": "3a454ca033b9e06b63282ce19562e892747449bb",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -10378,9 +10414,9 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||||
"source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0"
|
"source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2"
|
||||||
},
|
},
|
||||||
"time": "2025-12-06T11:56:16+00:00"
|
"time": "2025-10-21T19:32:17+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phar-io/manifest",
|
"name": "phar-io/manifest",
|
||||||
@ -10502,23 +10538,23 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-code-coverage",
|
"name": "phpunit/php-code-coverage",
|
||||||
"version": "12.5.1",
|
"version": "12.5.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||||
"reference": "c467c59a4f6e04b942be422844e7a6352fa01b57"
|
"reference": "bca180c050dd3ae15f87c26d25cabb34fe1a0a5a"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c467c59a4f6e04b942be422844e7a6352fa01b57",
|
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/bca180c050dd3ae15f87c26d25cabb34fe1a0a5a",
|
||||||
"reference": "c467c59a4f6e04b942be422844e7a6352fa01b57",
|
"reference": "bca180c050dd3ae15f87c26d25cabb34fe1a0a5a",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"ext-dom": "*",
|
"ext-dom": "*",
|
||||||
"ext-libxml": "*",
|
"ext-libxml": "*",
|
||||||
"ext-xmlwriter": "*",
|
"ext-xmlwriter": "*",
|
||||||
"nikic/php-parser": "^5.7.0",
|
"nikic/php-parser": "^5.6.2",
|
||||||
"php": ">=8.3",
|
"php": ">=8.3",
|
||||||
"phpunit/php-file-iterator": "^6.0",
|
"phpunit/php-file-iterator": "^6.0",
|
||||||
"phpunit/php-text-template": "^5.0",
|
"phpunit/php-text-template": "^5.0",
|
||||||
@ -10526,10 +10562,10 @@
|
|||||||
"sebastian/environment": "^8.0.3",
|
"sebastian/environment": "^8.0.3",
|
||||||
"sebastian/lines-of-code": "^4.0",
|
"sebastian/lines-of-code": "^4.0",
|
||||||
"sebastian/version": "^6.0",
|
"sebastian/version": "^6.0",
|
||||||
"theseer/tokenizer": "^2.0"
|
"theseer/tokenizer": "^1.3.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^12.5.1"
|
"phpunit/phpunit": "^12.4.4"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-pcov": "PHP extension that provides line coverage",
|
"ext-pcov": "PHP extension that provides line coverage",
|
||||||
@ -10567,7 +10603,7 @@
|
|||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||||
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
||||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.5.1"
|
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.5.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -10587,7 +10623,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2025-12-08T07:17:58+00:00"
|
"time": "2025-11-29T07:15:54+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-file-iterator",
|
"name": "phpunit/php-file-iterator",
|
||||||
@ -10836,16 +10872,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/phpunit",
|
"name": "phpunit/phpunit",
|
||||||
"version": "12.5.3",
|
"version": "12.5.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||||
"reference": "6dc2e076d09960efbb0c1272aa9bc156fc80955e"
|
"reference": "fef037fe50d20ce826cdbd741b7a2afcdec5f45b"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6dc2e076d09960efbb0c1272aa9bc156fc80955e",
|
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fef037fe50d20ce826cdbd741b7a2afcdec5f45b",
|
||||||
"reference": "6dc2e076d09960efbb0c1272aa9bc156fc80955e",
|
"reference": "fef037fe50d20ce826cdbd741b7a2afcdec5f45b",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -10859,7 +10895,7 @@
|
|||||||
"phar-io/manifest": "^2.0.4",
|
"phar-io/manifest": "^2.0.4",
|
||||||
"phar-io/version": "^3.2.1",
|
"phar-io/version": "^3.2.1",
|
||||||
"php": ">=8.3",
|
"php": ">=8.3",
|
||||||
"phpunit/php-code-coverage": "^12.5.1",
|
"phpunit/php-code-coverage": "^12.5.0",
|
||||||
"phpunit/php-file-iterator": "^6.0.0",
|
"phpunit/php-file-iterator": "^6.0.0",
|
||||||
"phpunit/php-invoker": "^6.0.0",
|
"phpunit/php-invoker": "^6.0.0",
|
||||||
"phpunit/php-text-template": "^5.0.0",
|
"phpunit/php-text-template": "^5.0.0",
|
||||||
@ -10913,7 +10949,7 @@
|
|||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/12.5.3"
|
"source": "https://github.com/sebastianbergmann/phpunit/tree/12.5.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -10937,7 +10973,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2025-12-11T08:52:59+00:00"
|
"time": "2025-12-05T04:59:40+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/cli-parser",
|
"name": "sebastian/cli-parser",
|
||||||
@ -12343,23 +12379,23 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "theseer/tokenizer",
|
"name": "theseer/tokenizer",
|
||||||
"version": "2.0.1",
|
"version": "1.3.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/theseer/tokenizer.git",
|
"url": "https://github.com/theseer/tokenizer.git",
|
||||||
"reference": "7989e43bf381af0eac72e4f0ca5bcbfa81658be4"
|
"reference": "b7489ce515e168639d17feec34b8847c326b0b3c"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/7989e43bf381af0eac72e4f0ca5bcbfa81658be4",
|
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c",
|
||||||
"reference": "7989e43bf381af0eac72e4f0ca5bcbfa81658be4",
|
"reference": "b7489ce515e168639d17feec34b8847c326b0b3c",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"ext-dom": "*",
|
"ext-dom": "*",
|
||||||
"ext-tokenizer": "*",
|
"ext-tokenizer": "*",
|
||||||
"ext-xmlwriter": "*",
|
"ext-xmlwriter": "*",
|
||||||
"php": "^8.1"
|
"php": "^7.2 || ^8.0"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@ -12381,7 +12417,7 @@
|
|||||||
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
|
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/theseer/tokenizer/issues",
|
"issues": "https://github.com/theseer/tokenizer/issues",
|
||||||
"source": "https://github.com/theseer/tokenizer/tree/2.0.1"
|
"source": "https://github.com/theseer/tokenizer/tree/1.3.1"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -12389,7 +12425,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2025-12-08T11:19:18+00:00"
|
"time": "2025-11-17T20:03:58+00:00"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
|
|||||||
@ -18,5 +18,6 @@ return [
|
|||||||
Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
|
Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
|
||||||
Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
|
Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
|
||||||
KnpU\OAuth2ClientBundle\KnpUOAuth2ClientBundle::class => ['all' => true],
|
KnpU\OAuth2ClientBundle\KnpUOAuth2ClientBundle::class => ['all' => true],
|
||||||
|
MyCRM\TestModule\TestModuleBundle::class => ['all' => true],
|
||||||
MyCRM\BillingModule\BillingModuleBundle::class => ['all' => true],
|
MyCRM\BillingModule\BillingModuleBundle::class => ['all' => true],
|
||||||
];
|
];
|
||||||
|
|||||||
@ -223,132 +223,6 @@ Navigiere zu: `http://localhost:8000/admin/modules`
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🗑️ Modul entfernen
|
|
||||||
|
|
||||||
### Option A: CLI (empfohlen)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Interaktiv mit Bestätigung
|
|
||||||
php bin/console app:module:remove billing
|
|
||||||
|
|
||||||
# Ohne Bestätigung (force)
|
|
||||||
php bin/console app:module:remove billing --force
|
|
||||||
|
|
||||||
# Lizenz behalten
|
|
||||||
php bin/console app:module:remove billing --keep-license
|
|
||||||
|
|
||||||
# Permission-Datenbank-Eintrag behalten
|
|
||||||
php bin/console app:module:remove billing --keep-db-entry
|
|
||||||
```
|
|
||||||
|
|
||||||
Der Command führt folgende Schritte durch:
|
|
||||||
|
|
||||||
1. ✓ **Modul-Informationen anzeigen** (Plugin + Datenbank)
|
|
||||||
2. ✓ **Bestätigung einholen** (außer mit `--force`)
|
|
||||||
3. ✓ **Lizenz widerrufen** (außer mit `--keep-license`)
|
|
||||||
4. ✓ **Datenbank-Eintrag löschen** (außer mit `--keep-db-entry`)
|
|
||||||
5. → **Composer-Command vorschlagen**
|
|
||||||
|
|
||||||
### Manuelle Schritte nach app:module:remove
|
|
||||||
|
|
||||||
Der Command zeigt dir die nötigen manuellen Schritte:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Composer-Package entfernen
|
|
||||||
composer remove mycrm/billing-module
|
|
||||||
|
|
||||||
# 2. Bundle aus config/bundles.php entfernen (falls vorhanden)
|
|
||||||
# Öffne config/bundles.php und entferne die Zeile:
|
|
||||||
# MyCRM\BillingModule\BillingBundle::class => ['all' => true],
|
|
||||||
|
|
||||||
# 3. Optional: Migrationen zurückrollen (falls benötigt)
|
|
||||||
php bin/console doctrine:migrations:migrate prev
|
|
||||||
|
|
||||||
# 4. Cache leeren
|
|
||||||
php bin/console cache:clear
|
|
||||||
```
|
|
||||||
|
|
||||||
### Option B: Vollständig manuell
|
|
||||||
|
|
||||||
Falls du den Command nicht nutzen möchtest:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Lizenz widerrufen
|
|
||||||
php bin/console app:module:license billing --revoke
|
|
||||||
|
|
||||||
# 2. Composer-Package entfernen
|
|
||||||
composer remove mycrm/billing-module
|
|
||||||
|
|
||||||
# 3. Bundle aus config/bundles.php entfernen (manuell editieren)
|
|
||||||
|
|
||||||
# 4. Optional: Module-Entity aus DB löschen
|
|
||||||
# Nur nötig, wenn das Modul auch im Permission-System registriert ist
|
|
||||||
# VORSICHT: Löscht auch verknüpfte RolePermissions!
|
|
||||||
|
|
||||||
# 5. Cache leeren
|
|
||||||
php bin/console cache:clear
|
|
||||||
```
|
|
||||||
|
|
||||||
### Beispiel-Ausgabe
|
|
||||||
|
|
||||||
```
|
|
||||||
Modul "billing" entfernen
|
|
||||||
=========================
|
|
||||||
|
|
||||||
Modul-Informationen
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
Eigenschaft Wert
|
|
||||||
Plugin-Informationen
|
|
||||||
Name Rechnungsmodul
|
|
||||||
Version 1.0.0
|
|
||||||
Beschreibung Rechnungsverwaltung für myCRM
|
|
||||||
Lizenziert ✓ Ja
|
|
||||||
Aktiv ✓ Ja
|
|
||||||
|
|
||||||
Datenbank-Informationen (Permission-System)
|
|
||||||
Name Rechnungen
|
|
||||||
Code billing
|
|
||||||
Aktiv ✓ Ja
|
|
||||||
Permissions 3
|
|
||||||
|
|
||||||
! [NOTE] Möchten Sie dieses Modul wirklich entfernen? (yes/no) [no]:
|
|
||||||
> yes
|
|
||||||
|
|
||||||
Entferne Modul
|
|
||||||
--------------
|
|
||||||
|
|
||||||
⏳ Widerrufe Lizenz...
|
|
||||||
[OK] ✓ Lizenz erfolgreich widerrufen
|
|
||||||
|
|
||||||
⏳ Entferne Datenbank-Eintrag (Permission-System)...
|
|
||||||
! [WARNING] ACHTUNG: Dieses Modul hat 3 verknüpfte Permission(s). Diese werden ebenfalls gelöscht!
|
|
||||||
! [NOTE] Trotzdem fortfahren? (yes/no) [no]:
|
|
||||||
> yes
|
|
||||||
[OK] ✓ Datenbank-Eintrag erfolgreich entfernt
|
|
||||||
|
|
||||||
Zusammenfassung
|
|
||||||
---------------
|
|
||||||
|
|
||||||
* ✓ Lizenz widerrufen
|
|
||||||
* ✓ Datenbank-Eintrag gelöscht
|
|
||||||
|
|
||||||
Nächste Schritte (manuell)
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
* 1. Composer-Package entfernen: composer remove mycrm/billing-module
|
|
||||||
* 2. Bundle aus config/bundles.php entfernen (falls vorhanden)
|
|
||||||
* 3. Optional: Migrationen zurückrollen (falls benötigt)
|
|
||||||
php bin/console doctrine:migrations:migrate prev
|
|
||||||
* 4. Cache leeren: php bin/console cache:clear
|
|
||||||
|
|
||||||
[OK] Modul "billing" wurde vorbereitet zum Entfernen. Führen Sie die obigen Schritte manuell aus.
|
|
||||||
```
|
|
||||||
|
|
||||||
✅ **Modul sicher entfernt!**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔧 Troubleshooting
|
## 🔧 Troubleshooting
|
||||||
|
|
||||||
### Problem: "Modul wird nicht erkannt"
|
### Problem: "Modul wird nicht erkannt"
|
||||||
|
|||||||
@ -1,203 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Command;
|
|
||||||
|
|
||||||
use App\Entity\Module;
|
|
||||||
use App\Plugin\LicenseValidatorInterface;
|
|
||||||
use App\Plugin\ModuleRegistry;
|
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CLI-Command zum sicheren Entfernen von Modulen
|
|
||||||
*/
|
|
||||||
#[AsCommand(
|
|
||||||
name: 'app:module:remove',
|
|
||||||
description: 'Entfernt ein Modul sicher aus dem System',
|
|
||||||
)]
|
|
||||||
class ModuleRemoveCommand extends Command
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private readonly ModuleRegistry $moduleRegistry,
|
|
||||||
private readonly LicenseValidatorInterface $licenseValidator,
|
|
||||||
private readonly EntityManagerInterface $entityManager
|
|
||||||
) {
|
|
||||||
parent::__construct();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function configure(): void
|
|
||||||
{
|
|
||||||
$this
|
|
||||||
->addArgument('module', InputArgument::REQUIRED, 'Modul-Identifier (z.B. "billing")')
|
|
||||||
->addOption('keep-license', null, InputOption::VALUE_NONE, 'Lizenz behalten (nicht widerrufen)')
|
|
||||||
->addOption('keep-db-entry', null, InputOption::VALUE_NONE, 'Datenbank-Eintrag behalten (Permission-System)')
|
|
||||||
->addOption('force', 'f', InputOption::VALUE_NONE, 'Keine Bestätigung erforderlich')
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
|
||||||
{
|
|
||||||
$io = new SymfonyStyle($input, $output);
|
|
||||||
$moduleIdentifier = $input->getArgument('module');
|
|
||||||
$keepLicense = $input->getOption('keep-license');
|
|
||||||
$keepDbEntry = $input->getOption('keep-db-entry');
|
|
||||||
$force = $input->getOption('force');
|
|
||||||
|
|
||||||
$io->title(sprintf('Modul "%s" entfernen', $moduleIdentifier));
|
|
||||||
|
|
||||||
// 1. Modul-Informationen sammeln
|
|
||||||
$modulePlugin = $this->moduleRegistry->getModule($moduleIdentifier);
|
|
||||||
$moduleEntity = $this->findModuleEntity($moduleIdentifier);
|
|
||||||
|
|
||||||
if (!$modulePlugin && !$moduleEntity) {
|
|
||||||
$io->error(sprintf('Modul "%s" wurde nicht gefunden (weder als Plugin noch in der Datenbank).', $moduleIdentifier));
|
|
||||||
return Command::FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Informationen anzeigen
|
|
||||||
$this->displayModuleInfo($io, $modulePlugin, $moduleEntity);
|
|
||||||
|
|
||||||
// 3. Bestätigung einholen
|
|
||||||
if (!$force && !$io->confirm('Möchten Sie dieses Modul wirklich entfernen?', false)) {
|
|
||||||
$io->info('Abgebrochen.');
|
|
||||||
return Command::SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
$io->section('Entferne Modul');
|
|
||||||
|
|
||||||
$steps = [];
|
|
||||||
|
|
||||||
// 4. Lizenz widerrufen
|
|
||||||
if (!$keepLicense && $modulePlugin && $modulePlugin->isLicensed()) {
|
|
||||||
$io->text('⏳ Widerrufe Lizenz...');
|
|
||||||
try {
|
|
||||||
$this->licenseValidator->revokeLicense($moduleIdentifier);
|
|
||||||
$io->success('✓ Lizenz erfolgreich widerrufen');
|
|
||||||
$steps[] = '✓ Lizenz widerrufen';
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$io->warning(sprintf('Lizenz konnte nicht widerrufen werden: %s', $e->getMessage()));
|
|
||||||
$steps[] = '⚠ Lizenz-Widerruf fehlgeschlagen';
|
|
||||||
}
|
|
||||||
} elseif ($keepLicense) {
|
|
||||||
$io->text('⏭ Lizenz wird behalten (--keep-license)');
|
|
||||||
$steps[] = '⏭ Lizenz behalten';
|
|
||||||
} else {
|
|
||||||
$io->text('⏭ Keine Lizenz vorhanden');
|
|
||||||
$steps[] = '⏭ Keine Lizenz';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. Datenbank-Eintrag entfernen
|
|
||||||
if (!$keepDbEntry && $moduleEntity) {
|
|
||||||
$io->text('⏳ Entferne Datenbank-Eintrag (Permission-System)...');
|
|
||||||
|
|
||||||
// Warnung, wenn Permissions existieren
|
|
||||||
$permissionCount = $moduleEntity->getPermissions()->count();
|
|
||||||
if ($permissionCount > 0) {
|
|
||||||
$io->warning(sprintf(
|
|
||||||
'ACHTUNG: Dieses Modul hat %d verknüpfte Permission(s). Diese werden ebenfalls gelöscht!',
|
|
||||||
$permissionCount
|
|
||||||
));
|
|
||||||
|
|
||||||
if (!$force && !$io->confirm('Trotzdem fortfahren?', false)) {
|
|
||||||
$io->info('Abgebrochen.');
|
|
||||||
return Command::SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->entityManager->remove($moduleEntity);
|
|
||||||
$this->entityManager->flush();
|
|
||||||
$io->success('✓ Datenbank-Eintrag erfolgreich entfernt');
|
|
||||||
$steps[] = '✓ Datenbank-Eintrag gelöscht';
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$io->error(sprintf('Datenbank-Eintrag konnte nicht entfernt werden: %s', $e->getMessage()));
|
|
||||||
$steps[] = '✗ Datenbank-Eintrag Fehler';
|
|
||||||
return Command::FAILURE;
|
|
||||||
}
|
|
||||||
} elseif ($keepDbEntry) {
|
|
||||||
$io->text('⏭ Datenbank-Eintrag wird behalten (--keep-db-entry)');
|
|
||||||
$steps[] = '⏭ DB-Eintrag behalten';
|
|
||||||
} else {
|
|
||||||
$io->text('⏭ Kein Datenbank-Eintrag vorhanden');
|
|
||||||
$steps[] = '⏭ Kein DB-Eintrag';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6. Nächste Schritte anzeigen
|
|
||||||
$io->section('Zusammenfassung');
|
|
||||||
$io->listing($steps);
|
|
||||||
|
|
||||||
$io->section('Nächste Schritte (manuell)');
|
|
||||||
|
|
||||||
$nextSteps = [];
|
|
||||||
|
|
||||||
// Composer-Package entfernen
|
|
||||||
if ($modulePlugin) {
|
|
||||||
$packageName = $this->guessPackageName($moduleIdentifier);
|
|
||||||
$nextSteps[] = sprintf('1. Composer-Package entfernen: <comment>composer remove %s</comment>', $packageName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bundle aus config/bundles.php entfernen
|
|
||||||
$nextSteps[] = '2. Bundle aus <comment>config/bundles.php</comment> entfernen (falls vorhanden)';
|
|
||||||
|
|
||||||
// Migrationen
|
|
||||||
$nextSteps[] = '3. Optional: Migrationen zurückrollen (falls benötigt)';
|
|
||||||
$nextSteps[] = ' <comment>php bin/console doctrine:migrations:migrate prev</comment>';
|
|
||||||
|
|
||||||
// Cache leeren
|
|
||||||
$nextSteps[] = '4. Cache leeren: <comment>php bin/console cache:clear</comment>';
|
|
||||||
|
|
||||||
$io->listing($nextSteps);
|
|
||||||
|
|
||||||
$io->success(sprintf('Modul "%s" wurde vorbereitet zum Entfernen. Führen Sie die obigen Schritte manuell aus.', $moduleIdentifier));
|
|
||||||
|
|
||||||
return Command::SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function displayModuleInfo(SymfonyStyle $io, $modulePlugin, ?Module $moduleEntity): void
|
|
||||||
{
|
|
||||||
$io->section('Modul-Informationen');
|
|
||||||
|
|
||||||
$rows = [];
|
|
||||||
|
|
||||||
if ($modulePlugin) {
|
|
||||||
$rows[] = ['<info>Plugin-Informationen</info>', ''];
|
|
||||||
$rows[] = [' Name', $modulePlugin->getDisplayName()];
|
|
||||||
$rows[] = [' Version', $modulePlugin->getVersion()];
|
|
||||||
$rows[] = [' Beschreibung', $modulePlugin->getDescription()];
|
|
||||||
$rows[] = [' Lizenziert', $modulePlugin->isLicensed() ? '✓ Ja' : '✗ Nein'];
|
|
||||||
$rows[] = [' Aktiv', $this->moduleRegistry->isModuleActive($modulePlugin->getIdentifier()) ? '✓ Ja' : '✗ Nein'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($moduleEntity) {
|
|
||||||
if (!empty($rows)) {
|
|
||||||
$rows[] = ['', ''];
|
|
||||||
}
|
|
||||||
$rows[] = ['<info>Datenbank-Informationen (Permission-System)</info>', ''];
|
|
||||||
$rows[] = [' Name', $moduleEntity->getName()];
|
|
||||||
$rows[] = [' Code', $moduleEntity->getCode()];
|
|
||||||
$rows[] = [' Aktiv', $moduleEntity->isActive() ? '✓ Ja' : '✗ Nein'];
|
|
||||||
$rows[] = [' Permissions', (string)$moduleEntity->getPermissions()->count()];
|
|
||||||
}
|
|
||||||
|
|
||||||
$io->table(['Eigenschaft', 'Wert'], $rows);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function findModuleEntity(string $identifier): ?Module
|
|
||||||
{
|
|
||||||
return $this->entityManager
|
|
||||||
->getRepository(Module::class)
|
|
||||||
->findOneBy(['code' => $identifier]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function guessPackageName(string $identifier): string
|
|
||||||
{
|
|
||||||
// Versuche Package-Name zu erraten (z.B. billing -> mycrm/billing-module)
|
|
||||||
return sprintf('mycrm/%s-module', $identifier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -90,6 +90,9 @@
|
|||||||
"mycrm/billing-module": {
|
"mycrm/billing-module": {
|
||||||
"version": "dev-main"
|
"version": "dev-main"
|
||||||
},
|
},
|
||||||
|
"mycrm/test-module": {
|
||||||
|
"version": "dev-main"
|
||||||
|
},
|
||||||
"nelmio/cors-bundle": {
|
"nelmio/cors-bundle": {
|
||||||
"version": "2.6",
|
"version": "2.6",
|
||||||
"recipe": {
|
"recipe": {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user