diff --git a/.coderabbit.yaml b/.coderabbit.yaml
new file mode 100644
index 0000000..11bd52f
--- /dev/null
+++ b/.coderabbit.yaml
@@ -0,0 +1,2 @@
+reviews:
+ request_changes_workflow: true
diff --git a/demos/blog-publishing/composer.json b/demos/blog-publishing/composer.json
index 8d1f927..a9c6b1a 100644
--- a/demos/blog-publishing/composer.json
+++ b/demos/blog-publishing/composer.json
@@ -18,13 +18,16 @@
"ray/di": "^2.18"
},
"require-dev": {
+ "be-framework/psalm-plugin": "1.x-dev",
"phpunit/phpunit": "^12"
},
"scripts": {
+ "psalm": "psalm --show-info=false",
"stree": "vendor/bin/stree $(ls -t var/log/*.json | head -1)",
"stree:full": "vendor/bin/stree --full $(ls -t var/log/*.json | head -1)"
},
"scripts-descriptions": {
+ "psalm": "Run static analysis with Psalm + Be Framework plugin.",
"stree": "Render the latest var/log/*.json as a compact tree.",
"stree:full": "Render the latest var/log/*.json as a semantic full tree with full props and close.profile details."
}
diff --git a/demos/blog-publishing/psalm.xml b/demos/blog-publishing/psalm.xml
new file mode 100644
index 0000000..76620e9
--- /dev/null
+++ b/demos/blog-publishing/psalm.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demos/blog-publishing/src/Exception/InvalidAuthorNameException.php b/demos/blog-publishing/src/Exception/InvalidAuthorNameException.php
new file mode 100644
index 0000000..09e4601
--- /dev/null
+++ b/demos/blog-publishing/src/Exception/InvalidAuthorNameException.php
@@ -0,0 +1,16 @@
+ 'Author name cannot be empty.',
+ 'ja' => '著者名は空にできません。'
+])]
+final class InvalidAuthorNameException extends DomainException
+{
+}
diff --git a/demos/blog-publishing/src/Exception/InvalidExcerptException.php b/demos/blog-publishing/src/Exception/InvalidExcerptException.php
new file mode 100644
index 0000000..c1d444d
--- /dev/null
+++ b/demos/blog-publishing/src/Exception/InvalidExcerptException.php
@@ -0,0 +1,16 @@
+ 'Excerpt is too long. Must be 250 characters or fewer.',
+ 'ja' => '抜粋が長すぎます。250文字以下で入力してください。'
+])]
+final class InvalidExcerptException extends DomainException
+{
+}
diff --git a/demos/blog-publishing/src/Exception/InvalidHtmlBodyException.php b/demos/blog-publishing/src/Exception/InvalidHtmlBodyException.php
new file mode 100644
index 0000000..ff31179
--- /dev/null
+++ b/demos/blog-publishing/src/Exception/InvalidHtmlBodyException.php
@@ -0,0 +1,16 @@
+ 'HTML body cannot be empty.',
+ 'ja' => 'HTML本文は空にできません。'
+])]
+final class InvalidHtmlBodyException extends DomainException
+{
+}
diff --git a/demos/blog-publishing/src/Exception/InvalidSlugException.php b/demos/blog-publishing/src/Exception/InvalidSlugException.php
new file mode 100644
index 0000000..db34fa0
--- /dev/null
+++ b/demos/blog-publishing/src/Exception/InvalidSlugException.php
@@ -0,0 +1,16 @@
+ 'Invalid slug format. Use lowercase letters, digits, and hyphens only.',
+ 'ja' => 'スラッグの形式が不正です。小文字・数字・ハイフンのみ使用できます。'
+])]
+final class InvalidSlugException extends DomainException
+{
+}
diff --git a/demos/blog-publishing/src/Semantic/AuthorName.php b/demos/blog-publishing/src/Semantic/AuthorName.php
index f03964c..5d8a52b 100644
--- a/demos/blog-publishing/src/Semantic/AuthorName.php
+++ b/demos/blog-publishing/src/Semantic/AuthorName.php
@@ -5,7 +5,7 @@
namespace Be\Pattern\BlogPublishing\Semantic;
use Be\Framework\Attribute\Validate;
-use InvalidArgumentException;
+use Be\Pattern\BlogPublishing\Exception\InvalidAuthorNameException;
/**
* AuthorName - Semantic validation
@@ -20,7 +20,7 @@ final class AuthorName
public function validate(string $authorName): void
{
if (empty(trim($authorName))) {
- throw new InvalidArgumentException('Author name cannot be empty');
+ throw new InvalidAuthorNameException();
}
}
}
diff --git a/demos/blog-publishing/src/Semantic/Excerpt.php b/demos/blog-publishing/src/Semantic/Excerpt.php
index a28992e..125b05e 100644
--- a/demos/blog-publishing/src/Semantic/Excerpt.php
+++ b/demos/blog-publishing/src/Semantic/Excerpt.php
@@ -5,7 +5,7 @@
namespace Be\Pattern\BlogPublishing\Semantic;
use Be\Framework\Attribute\Validate;
-use InvalidArgumentException;
+use Be\Pattern\BlogPublishing\Exception\InvalidExcerptException;
/**
* Excerpt - Semantic validation
@@ -18,7 +18,7 @@ final class Excerpt
public function validate(string $excerpt): void
{
if (mb_strlen($excerpt) > 250) {
- throw new InvalidArgumentException('Excerpt too long');
+ throw new InvalidExcerptException();
}
}
}
diff --git a/demos/blog-publishing/src/Semantic/HtmlBody.php b/demos/blog-publishing/src/Semantic/HtmlBody.php
index 0e785b4..bc61dce 100644
--- a/demos/blog-publishing/src/Semantic/HtmlBody.php
+++ b/demos/blog-publishing/src/Semantic/HtmlBody.php
@@ -5,7 +5,7 @@
namespace Be\Pattern\BlogPublishing\Semantic;
use Be\Framework\Attribute\Validate;
-use InvalidArgumentException;
+use Be\Pattern\BlogPublishing\Exception\InvalidHtmlBodyException;
/**
* HtmlBody - Semantic validation
@@ -18,7 +18,7 @@ final class HtmlBody
public function validate(string $htmlBody): void
{
if (empty(trim(strip_tags($htmlBody)))) {
- throw new InvalidArgumentException('HTML body cannot be empty');
+ throw new InvalidHtmlBodyException();
}
}
}
diff --git a/demos/blog-publishing/src/Semantic/Slug.php b/demos/blog-publishing/src/Semantic/Slug.php
index e03dd1f..e36754c 100644
--- a/demos/blog-publishing/src/Semantic/Slug.php
+++ b/demos/blog-publishing/src/Semantic/Slug.php
@@ -5,7 +5,7 @@
namespace Be\Pattern\BlogPublishing\Semantic;
use Be\Framework\Attribute\Validate;
-use InvalidArgumentException;
+use Be\Pattern\BlogPublishing\Exception\InvalidSlugException;
/**
* Slug - Semantic validation
@@ -18,7 +18,7 @@ final class Slug
public function validate(string $slug): void
{
if (!preg_match('/^[a-z0-9-]+$/', $slug)) {
- throw new InvalidArgumentException('Invalid slug format');
+ throw new InvalidSlugException();
}
}
}
diff --git a/demos/contact-form/composer.json b/demos/contact-form/composer.json
index ece0256..d4f56ff 100644
--- a/demos/contact-form/composer.json
+++ b/demos/contact-form/composer.json
@@ -18,13 +18,16 @@
"ray/di": "^2.18"
},
"require-dev": {
+ "be-framework/psalm-plugin": "1.x-dev",
"phpunit/phpunit": "^12"
},
"scripts": {
+ "psalm": "psalm --show-info=false",
"stree": "vendor/bin/stree $(ls -t var/log/*.json | head -1)",
"stree:full": "vendor/bin/stree --full $(ls -t var/log/*.json | head -1)"
},
"scripts-descriptions": {
+ "psalm": "Run static analysis with Psalm + Be Framework plugin.",
"stree": "Render the latest var/log/*.json as a compact tree.",
"stree:full": "Render the latest var/log/*.json as a semantic full tree with full props and close.profile details."
}
diff --git a/demos/contact-form/psalm.xml b/demos/contact-form/psalm.xml
new file mode 100644
index 0000000..76620e9
--- /dev/null
+++ b/demos/contact-form/psalm.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demos/hello-world/composer.json b/demos/hello-world/composer.json
index 795c46a..f0b1870 100644
--- a/demos/hello-world/composer.json
+++ b/demos/hello-world/composer.json
@@ -18,17 +18,20 @@
"ray/di": "^2.18"
},
"require-dev": {
+ "be-framework/psalm-plugin": "1.x-dev",
"phpunit/phpunit": "^12"
},
"scripts": {
"dev": "php bin/be.php 'hello?name=World'",
"profile": "XDEBUG_MODE=trace php -d xdebug.use_compression=0 -d extension=xhprof.so bin/be.php 'hello?name=World'",
+ "psalm": "psalm --show-info=false",
"stree": "vendor/bin/stree $(ls -t var/log/*.json | head -1)",
"stree:full": "vendor/bin/stree --full $(ls -t var/log/*.json | head -1)"
},
"scripts-descriptions": {
"dev": "Run the Hello World demo in dev mode; writes a semantic log to var/log/*.json without Xdebug/XHProf profiling.",
"profile": "Run the Hello World demo with semantic profiling; writes a semantic log to var/log/*.json with uncompressed Xdebug trace and xhprof enabled.",
+ "psalm": "Run static analysis with Psalm + Be Framework plugin.",
"stree": "Render the latest var/log/*.json as a compact tree.",
"stree:full": "Render the latest var/log/*.json as a semantic full tree with full props and close.profile details."
}
diff --git a/demos/hello-world/psalm.xml b/demos/hello-world/psalm.xml
new file mode 100644
index 0000000..76620e9
--- /dev/null
+++ b/demos/hello-world/psalm.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demos/insurance-claim/composer.json b/demos/insurance-claim/composer.json
index a629a17..a75b2a4 100644
--- a/demos/insurance-claim/composer.json
+++ b/demos/insurance-claim/composer.json
@@ -17,13 +17,16 @@
"ray/di": "^2.18"
},
"require-dev": {
+ "be-framework/psalm-plugin": "1.x-dev",
"phpunit/phpunit": "^12"
},
"scripts": {
+ "psalm": "psalm --show-info=false",
"stree": "vendor/bin/stree $(ls -t var/log/*.json | head -1)",
"stree:full": "vendor/bin/stree --full $(ls -t var/log/*.json | head -1)"
},
"scripts-descriptions": {
+ "psalm": "Run static analysis with Psalm + Be Framework plugin.",
"stree": "Render the latest var/log/*.json as a compact tree.",
"stree:full": "Render the latest var/log/*.json as a semantic full tree with full props and close.profile details."
}
diff --git a/demos/insurance-claim/psalm.xml b/demos/insurance-claim/psalm.xml
new file mode 100644
index 0000000..76620e9
--- /dev/null
+++ b/demos/insurance-claim/psalm.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demos/loan-application/composer.json b/demos/loan-application/composer.json
index 920056a..b1ecc44 100644
--- a/demos/loan-application/composer.json
+++ b/demos/loan-application/composer.json
@@ -17,13 +17,16 @@
"ray/di": "^2.18"
},
"require-dev": {
+ "be-framework/psalm-plugin": "1.x-dev",
"phpunit/phpunit": "^12"
},
"scripts": {
+ "psalm": "psalm --show-info=false",
"stree": "vendor/bin/stree $(ls -t var/log/*.json | head -1)",
"stree:full": "vendor/bin/stree --full $(ls -t var/log/*.json | head -1)"
},
"scripts-descriptions": {
+ "psalm": "Run static analysis with Psalm + Be Framework plugin.",
"stree": "Render the latest var/log/*.json as a compact tree.",
"stree:full": "Render the latest var/log/*.json as a semantic full tree with full props and close.profile details."
}
diff --git a/demos/loan-application/psalm.xml b/demos/loan-application/psalm.xml
new file mode 100644
index 0000000..76620e9
--- /dev/null
+++ b/demos/loan-application/psalm.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demos/medical-triage/composer.json b/demos/medical-triage/composer.json
index 76028f6..1a5f370 100644
--- a/demos/medical-triage/composer.json
+++ b/demos/medical-triage/composer.json
@@ -17,17 +17,20 @@
"ray/di": "^2.18"
},
"require-dev": {
+ "be-framework/psalm-plugin": "1.x-dev",
"phpunit/phpunit": "^12"
},
"scripts": {
"dev": "php bin/be.php",
"profile": "XDEBUG_MODE=trace php -d xdebug.use_compression=0 -d extension=xhprof.so bin/be.php",
+ "psalm": "psalm --show-info=false",
"stree": "vendor/bin/stree $(ls -t var/log/*.json | head -1)",
"stree:full": "vendor/bin/stree --full $(ls -t var/log/*.json | head -1)"
},
"scripts-descriptions": {
"dev": "Run the Medical Triage demo in dev mode; writes a semantic log to var/log/*.json without Xdebug/XHProf profiling.",
"profile": "Run the Medical Triage demo with semantic profiling; writes a semantic log to var/log/*.json with uncompressed Xdebug trace and xhprof enabled.",
+ "psalm": "Run static analysis with Psalm + Be Framework plugin.",
"stree": "Render the latest var/log/*.json as a compact tree.",
"stree:full": "Render the latest var/log/*.json as a semantic full tree with full props and close.profile details."
}
diff --git a/demos/medical-triage/psalm.xml b/demos/medical-triage/psalm.xml
new file mode 100644
index 0000000..76620e9
--- /dev/null
+++ b/demos/medical-triage/psalm.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demos/order-processing/composer.json b/demos/order-processing/composer.json
index 47fa0a9..6900217 100644
--- a/demos/order-processing/composer.json
+++ b/demos/order-processing/composer.json
@@ -17,17 +17,20 @@
"ray/di": "^2.18"
},
"require-dev": {
+ "be-framework/psalm-plugin": "1.x-dev",
"phpunit/phpunit": "^12"
},
"scripts": {
"dev": "php bin/be.php",
"profile": "XDEBUG_MODE=trace php -d xdebug.use_compression=0 -d extension=xhprof.so bin/be.php",
+ "psalm": "psalm --show-info=false",
"stree": "vendor/bin/stree $(ls -t var/log/*.json | head -1)",
"stree:full": "vendor/bin/stree --full $(ls -t var/log/*.json | head -1)"
},
"scripts-descriptions": {
"dev": "Run the Order Processing demo in dev mode; writes a semantic log to var/log/*.json without Xdebug/XHProf profiling.",
"profile": "Run the Order Processing demo with semantic profiling; writes a semantic log to var/log/*.json with uncompressed Xdebug trace and xhprof enabled.",
+ "psalm": "Run static analysis with Psalm + Be Framework plugin.",
"stree": "Render the latest var/log/*.json as a compact tree.",
"stree:full": "Render the latest var/log/*.json as a semantic full tree with full props and close.profile details."
}
diff --git a/demos/order-processing/psalm.xml b/demos/order-processing/psalm.xml
new file mode 100644
index 0000000..76620e9
--- /dev/null
+++ b/demos/order-processing/psalm.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demos/user-registration/composer.json b/demos/user-registration/composer.json
index 0b77b6b..6c56de4 100644
--- a/demos/user-registration/composer.json
+++ b/demos/user-registration/composer.json
@@ -19,17 +19,20 @@
"ray/di": "^2.18"
},
"require-dev": {
+ "be-framework/psalm-plugin": "1.x-dev",
"phpunit/phpunit": "^12"
},
"scripts": {
"dev": "php bin/be.php",
"profile": "XDEBUG_MODE=trace php -d xdebug.use_compression=0 -d extension=xhprof.so bin/be.php",
+ "psalm": "psalm --show-info=false",
"stree": "vendor/bin/stree $(ls -t var/log/*.json | head -1)",
"stree:full": "vendor/bin/stree --full $(ls -t var/log/*.json | head -1)"
},
"scripts-descriptions": {
"dev": "Run the User Registration demo in dev mode; writes a semantic log to var/log/*.json without Xdebug/XHProf profiling.",
"profile": "Run the User Registration demo with semantic profiling; writes a semantic log to var/log/*.json with uncompressed Xdebug trace and xhprof enabled.",
+ "psalm": "Run static analysis with Psalm + Be Framework plugin.",
"stree": "Render the latest var/log/*.json as a compact tree.",
"stree:full": "Render the latest var/log/*.json as a semantic full tree with full props and close.profile details."
}
diff --git a/demos/user-registration/psalm.xml b/demos/user-registration/psalm.xml
new file mode 100644
index 0000000..76620e9
--- /dev/null
+++ b/demos/user-registration/psalm.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demos/user-registration/src/Exception/InvalidAvatarUrlException.php b/demos/user-registration/src/Exception/InvalidAvatarUrlException.php
new file mode 100644
index 0000000..69ceda2
--- /dev/null
+++ b/demos/user-registration/src/Exception/InvalidAvatarUrlException.php
@@ -0,0 +1,16 @@
+ 'Invalid avatar URL.',
+ 'ja' => 'アバターURLの形式が不正です。'
+])]
+final class InvalidAvatarUrlException extends DomainException
+{
+}
diff --git a/demos/user-registration/src/Exception/InvalidHashedPasswordException.php b/demos/user-registration/src/Exception/InvalidHashedPasswordException.php
new file mode 100644
index 0000000..d861e10
--- /dev/null
+++ b/demos/user-registration/src/Exception/InvalidHashedPasswordException.php
@@ -0,0 +1,16 @@
+ 'Invalid password hash format.',
+ 'ja' => 'パスワードハッシュの形式が不正です。'
+])]
+final class InvalidHashedPasswordException extends DomainException
+{
+}
diff --git a/demos/user-registration/src/Semantic/AvatarUrl.php b/demos/user-registration/src/Semantic/AvatarUrl.php
index 7205b63..be48f92 100644
--- a/demos/user-registration/src/Semantic/AvatarUrl.php
+++ b/demos/user-registration/src/Semantic/AvatarUrl.php
@@ -5,7 +5,7 @@
namespace Be\Pattern\UserRegistration\Semantic;
use Be\Framework\Attribute\Validate;
-use InvalidArgumentException;
+use Be\Pattern\UserRegistration\Exception\InvalidAvatarUrlException;
/**
* AvatarUrl - Semantic validation
@@ -20,7 +20,7 @@ final class AvatarUrl
public function validate(string $avatarUrl): void
{
if (filter_var($avatarUrl, FILTER_VALIDATE_URL) === false) {
- throw new InvalidArgumentException('Invalid avatar URL');
+ throw new InvalidAvatarUrlException();
}
}
}
diff --git a/demos/user-registration/src/Semantic/HashedPassword.php b/demos/user-registration/src/Semantic/HashedPassword.php
index 09d4526..b4174a0 100644
--- a/demos/user-registration/src/Semantic/HashedPassword.php
+++ b/demos/user-registration/src/Semantic/HashedPassword.php
@@ -5,7 +5,7 @@
namespace Be\Pattern\UserRegistration\Semantic;
use Be\Framework\Attribute\Validate;
-use InvalidArgumentException;
+use Be\Pattern\UserRegistration\Exception\InvalidHashedPasswordException;
/**
* HashedPassword - Semantic validation
@@ -19,7 +19,7 @@ public function validate(string $hashedPassword): void
{
// Bcrypt hashes start with $2y$ or $2a$ and are 60 characters
if (!preg_match('/^\$2[aby]\$\d{2}\$.{53}$/', $hashedPassword)) {
- throw new InvalidArgumentException('Invalid password hash format');
+ throw new InvalidHashedPasswordException();
}
}
}