Skip to content

Commit 72b8519

Browse files
committed
Add StringFileName type with validation for file names, methods for extracting name and extension, and usage example.
1 parent e13320f commit 72b8519

File tree

2 files changed

+132
-4
lines changed

2 files changed

+132
-4
lines changed

src/String/StringFileName.php

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpTypedValues\String;
6+
7+
use const PATHINFO_EXTENSION;
8+
use const PATHINFO_FILENAME;
9+
10+
use PhpTypedValues\Exception\FileNameStringTypeException;
11+
use PhpTypedValues\Exception\TypeException;
12+
use PhpTypedValues\Internal\Primitive\String\StrType;
13+
use PhpTypedValues\Undefined\Alias\Undefined;
14+
15+
use function pathinfo;
16+
use function preg_match;
17+
use function sprintf;
18+
19+
/**
20+
* File name string.
21+
*
22+
* Validates that the string is a valid file name (not a path).
23+
* Rejects path separators and characters that are typically invalid in file names
24+
* across major operating systems.
25+
*
26+
* Example
27+
* - $f = StringFileName::fromString('image.jpg');
28+
* $f->getFileNameOnly(); // "image"
29+
* $f->getExtension(); // "jpg"
30+
*
31+
* @psalm-immutable
32+
*/
33+
readonly class StringFileName extends StrType
34+
{
35+
/** @var non-empty-string */
36+
protected string $value;
37+
38+
/**
39+
* @throws FileNameStringTypeException
40+
*/
41+
public function __construct(string $value)
42+
{
43+
if ($value === '') {
44+
throw new FileNameStringTypeException('Expected non-empty file name');
45+
}
46+
47+
// Basic validation for common invalid characters in filenames: / \ ? % * : | " < > and null byte
48+
if (preg_match('/[\/\x00-\x1f\x7f\\\?%*:|"<>]/', $value)) {
49+
throw new FileNameStringTypeException(sprintf('Expected valid file name, got "%s"', $value));
50+
}
51+
52+
$this->value = $value;
53+
}
54+
55+
public static function tryFromMixed(mixed $value): static|Undefined
56+
{
57+
try {
58+
return static::fromString(
59+
static::convertMixedToString($value)
60+
);
61+
} catch (TypeException) {
62+
return Undefined::create();
63+
}
64+
}
65+
66+
/**
67+
* @throws FileNameStringTypeException
68+
*/
69+
public static function fromString(string $value): static
70+
{
71+
return new static($value);
72+
}
73+
74+
public static function tryFromString(string $value): static|Undefined
75+
{
76+
try {
77+
return static::fromString($value);
78+
} catch (TypeException) {
79+
return Undefined::create();
80+
}
81+
}
82+
83+
/**
84+
* Returns the name of the file without the extension.
85+
*/
86+
public function getFileNameOnly(): string
87+
{
88+
return pathinfo($this->value, PATHINFO_FILENAME);
89+
}
90+
91+
/**
92+
* Returns the file extension or an empty string if none exists.
93+
*/
94+
public function getExtension(): string
95+
{
96+
return pathinfo($this->value, PATHINFO_EXTENSION);
97+
}
98+
99+
/** @return non-empty-string */
100+
public function value(): string
101+
{
102+
return $this->value;
103+
}
104+
105+
public function jsonSerialize(): string
106+
{
107+
return $this->toString();
108+
}
109+
110+
public function toString(): string
111+
{
112+
return $this->value();
113+
}
114+
115+
public function __toString(): string
116+
{
117+
return $this->toString();
118+
}
119+
120+
public function isEmpty(): bool
121+
{
122+
return false;
123+
}
124+
125+
public function isUndefined(): bool
126+
{
127+
return false;
128+
}
129+
}

src/Usage/Primitive/String.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
use PhpTypedValues\String\MariaDb\StringVarChar255;
2727
use PhpTypedValues\String\StringCountryCode;
2828
use PhpTypedValues\String\StringEmail;
29+
use PhpTypedValues\String\StringFileName;
2930
use PhpTypedValues\String\StringNonBlank;
3031
use PhpTypedValues\String\StringNonEmpty;
3132
use PhpTypedValues\String\StringStandard;
@@ -52,10 +53,8 @@
5253
echo NonBlank::fromString(' hi ')->toString() . PHP_EOL;
5354
echo StringNonBlank::fromString(' hi ')->toString() . PHP_EOL;
5455

55-
// $nb = StringNonBlank::tryFromString(' ');
56-
// if (!($nb instanceof Undefined)) {
57-
// echo $nb->toString() . \PHP_EOL;
58-
// }
56+
$file = StringFileName::fromString('file.name');
57+
echo $file->toString() . ' ' . $file->getFileNameOnly() . ' ' . $file->getExtension() . PHP_EOL;
5958

6059
echo UuidV4::tryFromString('550e8400-e29b-41d4-a716-446655440000')->toString() . PHP_EOL;
6160

0 commit comments

Comments
 (0)