cerbero90 /
enum
| 1 | <?php |
||
| 2 | |||
| 3 | declare(strict_types=1); |
||
| 4 | |||
| 5 | namespace Cerbero\Enum; |
||
| 6 | |||
| 7 | use Generator; |
||
| 8 | |||
| 9 | /** |
||
| 10 | * Yield the content of the given path line by line. |
||
| 11 | * |
||
| 12 | * @return Generator<int, string> |
||
| 13 | */ |
||
| 14 | function yieldLines(string $path): Generator |
||
| 15 | { |
||
| 16 | $stream = fopen($path, 'rb'); |
||
| 17 | |||
| 18 | try { |
||
| 19 | while (($line = fgets($stream, 1024)) !== false) { |
||
| 20 | yield $line; |
||
| 21 | } |
||
| 22 | } finally { |
||
| 23 | is_resource($stream) && fclose($stream); |
||
| 24 | } |
||
| 25 | } |
||
| 26 | |||
| 27 | /** |
||
| 28 | * Retrieve the PSR-4 map of the composer file. |
||
| 29 | * |
||
| 30 | * @return array<string, string> |
||
| 31 | */ |
||
| 32 | function psr4(): array |
||
| 33 | { |
||
| 34 | if (! is_file($path = Enums::basePath('composer.json'))) { |
||
| 35 | return []; |
||
| 36 | } |
||
| 37 | |||
| 38 | $composer = (array) json_decode((string) file_get_contents($path), true); |
||
| 39 | |||
| 40 | /** @var array<string, string> */ |
||
| 41 | return $composer['autoload']['psr-4'] ?? []; |
||
| 42 | } |
||
| 43 | |||
| 44 | /** |
||
| 45 | * Retrieve the traits used by the given target recursively. |
||
| 46 | * |
||
| 47 | * @return array<class-string, class-string> |
||
|
0 ignored issues
–
show
Documentation
Bug
introduced
by
Loading history...
|
|||
| 48 | */ |
||
| 49 | function traitsUsedBy(string $target): array |
||
| 50 | { |
||
| 51 | $traits = class_uses($target) ?: []; |
||
| 52 | |||
| 53 | foreach ($traits as $trait) { |
||
| 54 | $traits += traitsUsedBy($trait); |
||
| 55 | } |
||
| 56 | |||
| 57 | return $traits; |
||
| 58 | } |
||
| 59 | |||
| 60 | /** |
||
| 61 | * Retrieve the given value in snake case. |
||
| 62 | */ |
||
| 63 | function snake(string $value, string $delimiter = '_'): string |
||
| 64 | { |
||
| 65 | $value = preg_replace('/\s+/u', '', ucwords($value)); |
||
| 66 | |||
| 67 | return strtolower(preg_replace('/(.)(?=[A-Z])/u', '$1' . $delimiter, $value)); |
||
| 68 | } |
||
| 69 | |||
| 70 | /** |
||
| 71 | * Retrieve the given value in camel case. |
||
| 72 | */ |
||
| 73 | function camel(string $value): string |
||
| 74 | { |
||
| 75 | $words = explode(' ', str_replace(['-', '_'], ' ', $value)); |
||
| 76 | $studly = array_map('ucfirst', $words); |
||
| 77 | |||
| 78 | return lcfirst(implode($studly)); |
||
| 79 | } |
||
| 80 | |||
| 81 | /** |
||
| 82 | * Parse the given raw string containing the name and value of a case. |
||
| 83 | * |
||
| 84 | * @return array<string, string|int> |
||
| 85 | */ |
||
| 86 | function parseCaseValue(string $raw): array |
||
| 87 | { |
||
| 88 | [$rawName, $rawValue] = explode('=', $raw, limit: 2); |
||
| 89 | $trimmed = trim($rawValue); |
||
| 90 | $value = is_numeric($trimmed) ? (int) $trimmed : $trimmed; |
||
| 91 | |||
| 92 | return [trim($rawName) => $value]; |
||
| 93 | } |
||
| 94 | |||
| 95 | /** |
||
| 96 | * Retrieve the backing type depending on the given value. |
||
| 97 | */ |
||
| 98 | function backingType(mixed $value): ?string |
||
| 99 | { |
||
| 100 | return match (true) { |
||
| 101 | is_int($value) => 'int', |
||
| 102 | is_string($value) => str_contains($value, '<<') ? 'int' : 'string', |
||
| 103 | default => null, |
||
| 104 | }; |
||
| 105 | } |
||
| 106 | |||
| 107 | /** |
||
| 108 | * Retrieve the common type among the given types. |
||
| 109 | */ |
||
| 110 | function commonType(string ...$types): string |
||
| 111 | { |
||
| 112 | $null = ''; |
||
| 113 | $types = array_unique($types); |
||
| 114 | |||
| 115 | if (($index = array_search('null', $types)) !== false) { |
||
| 116 | $null = '?'; |
||
| 117 | |||
| 118 | unset($types[$index]); |
||
| 119 | } |
||
| 120 | |||
| 121 | if (count($types) == 1) { |
||
| 122 | return $null . reset($types); |
||
| 123 | } |
||
| 124 | |||
| 125 | return implode('|', $types) . ($null ? '|null' : ''); |
||
| 126 | } |
||
| 127 | |||
| 128 | /** |
||
| 129 | * Retrieve only the name of the given namespace. |
||
| 130 | */ |
||
| 131 | function className(string $namespace): string |
||
| 132 | { |
||
| 133 | return basename(strtr($namespace, '\\', '/')); |
||
| 134 | } |
||
| 135 | |||
| 136 | /** |
||
| 137 | * Split the given FQCN into namespace and name. |
||
| 138 | * |
||
| 139 | * @param class-string $namespace |
||
|
0 ignored issues
–
show
|
|||
| 140 | * @return list<string> |
||
| 141 | */ |
||
| 142 | function splitNamespace(string $namespace): array |
||
| 143 | { |
||
| 144 | $segments = explode('\\', $namespace); |
||
| 145 | $name = (string) array_pop($segments); |
||
| 146 | |||
| 147 | return [implode('\\', $segments), $name]; |
||
| 148 | } |
||
| 149 | |||
| 150 | /** |
||
| 151 | * Retrieve the absolute path of the given namespace. |
||
| 152 | * |
||
| 153 | * @param class-string $namespace |
||
|
0 ignored issues
–
show
|
|||
| 154 | */ |
||
| 155 | function namespaceToPath(string $namespace): string |
||
| 156 | { |
||
| 157 | $path = Enums::basePath($namespace) . '.php'; |
||
| 158 | |||
| 159 | foreach (psr4() as $root => $relative) { |
||
| 160 | if (str_starts_with($namespace, $root)) { |
||
| 161 | $relative = path($relative) . DIRECTORY_SEPARATOR; |
||
| 162 | |||
| 163 | return strtr($path, [$root => $relative]); |
||
| 164 | } |
||
| 165 | } |
||
| 166 | |||
| 167 | return $path; |
||
| 168 | } |
||
| 169 | |||
| 170 | /** |
||
| 171 | * Retrieve the normalized path. |
||
| 172 | */ |
||
| 173 | function path(string $path): string |
||
| 174 | { |
||
| 175 | $segments = []; |
||
| 176 | $path = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $path); |
||
| 177 | $path = rtrim($path, DIRECTORY_SEPARATOR); |
||
| 178 | $head = str_starts_with($path, DIRECTORY_SEPARATOR) ? DIRECTORY_SEPARATOR : ''; |
||
| 179 | |||
| 180 | foreach (explode(DIRECTORY_SEPARATOR, $path) as $segment) { |
||
| 181 | if ($segment === '..') { |
||
| 182 | array_pop($segments); |
||
| 183 | } elseif ($segment !== '' && $segment !== '.') { |
||
| 184 | $segments[] = $segment; |
||
| 185 | } |
||
| 186 | } |
||
| 187 | |||
| 188 | return $head . implode(DIRECTORY_SEPARATOR, $segments); |
||
| 189 | } |
||
| 190 | |||
| 191 | /** |
||
| 192 | * Create the directory for the given path if missing. |
||
| 193 | */ |
||
| 194 | function ensureParentDirectory(string $path): bool |
||
| 195 | { |
||
| 196 | if (file_exists($directory = dirname($path))) { |
||
| 197 | return true; |
||
| 198 | } |
||
| 199 | |||
| 200 | return mkdir($directory, 0755, recursive: true); |
||
| 201 | } |
||
| 202 |