Files
michaelschiemer/src/Framework/Core/ValueObjects/PhpNamespace.php
Michael Schiemer fc3d7e6357 feat(Production): Complete production deployment infrastructure
- Add comprehensive health check system with multiple endpoints
- Add Prometheus metrics endpoint
- Add production logging configurations (5 strategies)
- Add complete deployment documentation suite:
  * QUICKSTART.md - 30-minute deployment guide
  * DEPLOYMENT_CHECKLIST.md - Printable verification checklist
  * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle
  * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference
  * production-logging.md - Logging configuration guide
  * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation
  * README.md - Navigation hub
  * DEPLOYMENT_SUMMARY.md - Executive summary
- Add deployment scripts and automation
- Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment
- Update README with production-ready features

All production infrastructure is now complete and ready for deployment.
2025-10-25 19:18:37 +02:00

236 lines
5.2 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Framework\Core\ValueObjects;
use InvalidArgumentException;
/**
* Immutable PHP namespace value object with validation and operations
*/
final readonly class PhpNamespace
{
private string $namespace;
private function __construct(string $namespace)
{
// Empty namespace is valid (global namespace)
if ($namespace === '') {
$this->namespace = '';
return;
}
// Remove leading/trailing backslashes
$namespace = trim($namespace, '\\');
if (! $this->isValidNamespace($namespace)) {
throw new InvalidArgumentException("Invalid namespace: {$namespace}");
}
$this->namespace = $namespace;
}
/**
* Create from namespace string
*/
public static function fromString(string $namespace): self
{
return new self($namespace);
}
/**
* Create from class name
*/
public static function fromClass(string $className): self
{
$className = ltrim($className, '\\');
$lastBackslash = strrpos($className, '\\');
if ($lastBackslash === false) {
return new self(''); // Global namespace
}
return new self(substr($className, 0, $lastBackslash));
}
/**
* Create from namespace parts
* @param array<string> $parts
*/
public static function fromParts(array $parts): self
{
return new self(implode('\\', $parts));
}
/**
* Create global namespace
*/
public static function global(): self
{
return new self('');
}
/**
* Get namespace as string
*/
public function toString(): string
{
return $this->namespace;
}
/**
* Get namespace parts
* @return array<string>
*/
public function parts(): array
{
if ($this->namespace === '') {
return [];
}
return explode('\\', $this->namespace);
}
/**
* Get namespace depth (number of levels)
*/
public function depth(): int
{
if ($this->namespace === '') {
return 0;
}
return count($this->parts());
}
/**
* Check if this is the global namespace
*/
public function isGlobal(): bool
{
return $this->namespace === '';
}
/**
* Get parent namespace
*/
public function parent(): ?self
{
$parts = $this->parts();
if (count($parts) <= 1) {
return null; // No parent or already at global namespace
}
array_pop($parts);
return self::fromParts($parts);
}
/**
* Append namespace segment
*/
public function append(string $segment): self
{
if ($this->namespace === '') {
return new self($segment);
}
return new self($this->namespace . '\\' . ltrim($segment, '\\'));
}
/**
* Check if namespace starts with given prefix
*/
public function startsWith(string|self $prefix): bool
{
$prefixStr = $prefix instanceof self ? $prefix->toString() : $prefix;
$prefixStr = trim($prefixStr, '\\');
if ($prefixStr === '') {
return true; // All namespaces start with global namespace
}
return str_starts_with($this->namespace, $prefixStr);
}
/**
* Check if namespace ends with given suffix
*/
public function endsWith(string|self $suffix): bool
{
$suffixStr = $suffix instanceof self ? $suffix->toString() : $suffix;
$suffixStr = trim($suffixStr, '\\');
if ($suffixStr === '') {
return true;
}
return str_ends_with($this->namespace, $suffixStr);
}
/**
* Compare for equality
*/
public function equals(self $other): bool
{
return $this->namespace === $other->namespace;
}
/**
* Convert to a fully qualified class name (with leading backslash)
*/
public function toFqcn(string $className): string
{
if ($this->namespace === '') {
return '\\' . $className;
}
return '\\' . $this->namespace . '\\' . $className;
}
/**
* Convert to file path (for PSR-4 autoloading)
*/
public function toPath(): string
{
if ($this->namespace === '') {
return '';
}
return str_replace('\\', '/', $this->namespace);
}
/**
* String representation
*/
public function __toString(): string
{
return $this->namespace;
}
/**
* Validate namespace format
*/
private function isValidNamespace(string $namespace): bool
{
// Empty namespace is valid (global namespace)
if ($namespace === '') {
return true;
}
// Each part must be a valid PHP identifier
$parts = explode('\\', $namespace);
foreach ($parts as $part) {
// Must start with letter or underscore, followed by letters, numbers, or underscores
if (! preg_match('/^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$/', $part)) {
return false;
}
}
return true;
}
}