Files
michaelschiemer/src/Framework/Core/ValueObjects/City.php
Michael Schiemer 5050c7d73a docs: consolidate documentation into organized structure
- Move 12 markdown files from root to docs/ subdirectories
- Organize documentation by category:
  • docs/troubleshooting/ (1 file)  - Technical troubleshooting guides
  • docs/deployment/      (4 files) - Deployment and security documentation
  • docs/guides/          (3 files) - Feature-specific guides
  • docs/planning/        (4 files) - Planning and improvement proposals

Root directory cleanup:
- Reduced from 16 to 4 markdown files in root
- Only essential project files remain:
  • CLAUDE.md (AI instructions)
  • README.md (Main project readme)
  • CLEANUP_PLAN.md (Current cleanup plan)
  • SRC_STRUCTURE_IMPROVEMENTS.md (Structure improvements)

This improves:
 Documentation discoverability
 Logical organization by purpose
 Clean root directory
 Better maintainability
2025-10-05 11:05:04 +02:00

124 lines
3.1 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Framework\Core\ValueObjects;
use InvalidArgumentException;
/**
* Represents a city name with optional state/province
* Immutable value object for address handling
*/
final readonly class City
{
public function __construct(
public string $name,
public ?string $state = null,
public ?CountryCode $country = null
) {
if (trim($name) === '') {
throw new InvalidArgumentException('City name cannot be empty');
}
}
public static function create(string $name, ?string $state = null, ?CountryCode $country = null): self
{
return new self($name, $state, $country);
}
public function withState(string $state): self
{
return new self($this->name, $state, $this->country);
}
public function withCountry(CountryCode $country): self
{
return new self($this->name, $this->state, $country);
}
public function withoutState(): self
{
return new self($this->name, null, $this->country);
}
public function format(bool $includeState = true, bool $includeCountry = false): string
{
$formatted = $this->name;
if ($includeState && $this->state !== null && trim($this->state) !== '') {
$formatted .= ', ' . $this->state;
}
if ($includeCountry && $this->country !== null) {
$formatted .= ', ' . ($this->country->getCountryName() ?? $this->country->value);
}
return $formatted;
}
public function getDisplayName(): string
{
return $this->format(true, false);
}
public function getFullName(): string
{
return $this->format(true, true);
}
public function hasState(): bool
{
return $this->state !== null && trim($this->state) !== '';
}
public function hasCountry(): bool
{
return $this->country !== null;
}
public function equals(self $other): bool
{
return $this->name === $other->name
&& $this->state === $other->state
&& (
($this->country === null && $other->country === null) ||
($this->country !== null && $other->country !== null && $this->country->value === $other->country->value)
);
}
public function toString(): string
{
return $this->getDisplayName();
}
public function __toString(): string
{
return $this->getDisplayName();
}
public function toArray(): array
{
return [
'name' => $this->name,
'state' => $this->state,
'country' => $this->country?->value,
'display_name' => $this->getDisplayName(),
'full_name' => $this->getFullName(),
];
}
public static function fromArray(array $data): self
{
$country = isset($data['country'])
? CountryCode::fromString($data['country'])
: null;
return new self(
$data['name'],
$data['state'] ?? null,
$country
);
}
}