Skip to content

Commit 1a196db

Browse files
committed
Merge branch 'cleanup'
2 parents b4a3104 + 0c21b0b commit 1a196db

File tree

14 files changed

+381
-132
lines changed

14 files changed

+381
-132
lines changed

CHANGELOG.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,94 @@ The format is based on [Keep a Changelog][], and this project adheres to
1212
[Keep a Changelog]: https://keepachangelog.com/en/1.1.0/
1313
[Semantic Versioning]: https://semver.org/spec/v2.0.0.html
1414

15+
## [v0.21.18] - 2023-12-29
16+
17+
### Added
18+
19+
- Add `File::guessIndentation()`
20+
- Add `File::isSeekable()`
21+
- Add `Str::toStream()`
22+
- Add `Sys::getUserId()`
23+
24+
### Changed
25+
26+
- Refactor `File::realpath()`
27+
- Remove file descriptor handling
28+
- **Throw an exception if the file doesn't exist**
29+
- Resolve Phar URIs when a Phar is not running
30+
- Refactor `File::relativeToParent()`
31+
- Require `$parentDir`
32+
- Add `$fallback` (`null` by default) and return it if `$filename` does not belong to `$parentDir`
33+
- Refactor `File::writeCsv()`
34+
- **Make `$resource` a required parameter**
35+
- **Swap `$data` and `$resource` parameters**
36+
- **Change return type to `void`**
37+
- Remove UTF-16LE filters applied to streams provided by the caller
38+
- Apply `Arr::toScalars()` to each row of data
39+
- Refactor `Sys::getProgramBasename()`
40+
- Only remove the first matched `$suffix`
41+
- Rename `Stream::fromContents()` to `Stream::fromString()`
42+
- Rename environment variable `CONSOLE_OUTPUT` to `CONSOLE_TARGET`
43+
- Add optional `$null` parameter to `Arr::toScalars()`
44+
- Adopt `Str::lower()` and `Str::upper()` for case comparison
45+
- Make `File::fputcsv()` public
46+
47+
### Fixed
48+
49+
- Fix `File::realpath()` issue where `//../` segments in Phar URIs are not resolved correctly
50+
- Fix `ErrorHandler::silencePath()` issue where files and directories that start with the same name as a silenced file are inadvertently silenced
51+
52+
## [v0.21.17] - 2023-12-25
53+
54+
### Added
55+
56+
- Add `Arr::flatten()`
57+
- Add `HttpFactory` (implements PSR-17 factory interfaces)
58+
59+
### Changed
60+
61+
- **Return `null` instead of `false` when `FluentIteratorInterface::nextWithValue()` finds no matching value**
62+
- Pass value AND key to `FluentIteratorInterface::forEach()` callback
63+
- In `HttpRequest`, preserve the original case of the HTTP method
64+
- In `HttpHeaders`, throw an exception when a header with no values is given
65+
- In `Uri`, do not resolve dot segments if the URI is a relative reference
66+
- In `Arr::toScalars()`, preserve `null` values
67+
- In `Arr::trim()`, remove keys from the array if removing empty values
68+
- Optionally preserve keys in `Arr::unique()`
69+
- Rename `Arr::sameValues()` to `same()`
70+
- Accept `iterable` where possible in `Arr` methods
71+
- Add `Arr::keyOffset()`, deprecating `Convert::arrayKeyToOffset()`
72+
- Add `Arr::toMap()`, deprecating `Convert::listToMap()`
73+
- Add `Arr::toScalars()`, deprecating `Convert::toScalarArray()`
74+
- Add `Get::array()`, deprecating `Convert::iterableToArray()`
75+
76+
### Deprecated
77+
78+
- Deprecate (see above):
79+
- `Convert::arrayKeyToOffset()`
80+
- `Convert::listToMap()`
81+
- `Convert::toScalarArray()`
82+
- `Convert::iterableToArray()`
83+
84+
### Removed
85+
86+
- Remove unused/redundant methods:
87+
- `Arr::forEach()`
88+
- `Convert::columnsToUnique()`
89+
- `Convert::iterableToItem()`
90+
- `Convert::iterableToIterator()`
91+
- `Convert::scalarToString()`
92+
- `Convert::stringsToUnique()`
93+
- `Convert::stringsToUniqueList()`
94+
- `Convert::valueAtKey()`
95+
- `Convert::walkRecursive()`
96+
- `FluentIteratorInterface::forEachWhile()`
97+
- `FluentIteratorTrait::forEachWhile()`
98+
99+
### Fixed
100+
101+
- Fix bug in `Arr::sortDesc()` where keys are not preserved correctly
102+
15103
## [v0.21.16] - 2023-12-21
16104

17105
### Fixed
@@ -1159,6 +1247,8 @@ The format is based on [Keep a Changelog][], and this project adheres to
11591247

11601248
- Allow `CliOption` value names to contain arbitrary characters
11611249

1250+
[v0.21.18]: https://github.com/lkrms/php-util/compare/v0.21.17...v0.21.18
1251+
[v0.21.17]: https://github.com/lkrms/php-util/compare/v0.21.16...v0.21.17
11621252
[v0.21.16]: https://github.com/lkrms/php-util/compare/v0.21.15...v0.21.16
11631253
[v0.21.15]: https://github.com/lkrms/php-util/compare/v0.21.14...v0.21.15
11641254
[v0.21.14]: https://github.com/lkrms/php-util/compare/v0.21.13...v0.21.14

src/Container/Application.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ final public function startCache()
428428

429429
if (Cache::isLoaded()) {
430430
$file = Cache::getFilename();
431-
if (File::is($cacheDb, $file)) {
431+
if (File::same($cacheDb, $file)) {
432432
return $this;
433433
}
434434
throw new LogicException(sprintf('Cache store already started: %s', $file));
@@ -455,7 +455,7 @@ final public function resumeCache()
455455
final public function stopCache()
456456
{
457457
if (!Cache::isLoaded() ||
458-
!File::is($this->getCacheDb(false), Cache::getFilename())) {
458+
!File::same($this->getCacheDb(false), Cache::getFilename())) {
459459
return $this;
460460
}
461461
Cache::close();
@@ -496,7 +496,7 @@ final public function startSync(?string $command = null, ?array $arguments = nul
496496

497497
if (Sync::isLoaded()) {
498498
$file = Sync::getFilename();
499-
if (File::is($syncDb, $file)) {
499+
if (File::same($syncDb, $file)) {
500500
return $this;
501501
}
502502
throw new LogicException(sprintf('Entity store already started: %s', $file));
@@ -536,7 +536,7 @@ final public function syncNamespace(string $prefix, string $uri, string $namespa
536536
final public function stopSync()
537537
{
538538
if (!Sync::isLoaded() ||
539-
!File::is($this->getSyncDb(false), Sync::getFilename())) {
539+
!File::same($this->getSyncDb(false), Sync::getFilename())) {
540540
return $this;
541541
}
542542
Sync::close();

src/Utility/File.php

Lines changed: 52 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -126,18 +126,30 @@ public static function tell($stream, $uri = null): int
126126
}
127127

128128
/**
129-
* Get the file status of a stream
129+
* Get the status of a file or stream
130130
*
131+
* @see stat()
131132
* @see fstat()
132-
* @param resource $stream
133+
* @param Stringable|string|resource $resource
133134
* @param Stringable|string|null $uri
134135
* @return int[]
135136
* @throws FilesystemErrorException on failure.
136137
*/
137-
public static function stat($stream, $uri = null): array
138+
public static function stat($resource, $uri = null): array
138139
{
139-
$result = @fstat($stream);
140-
return self::throwOnFailure($result, 'Error getting file status of stream: %s', $uri, $stream);
140+
if (is_resource($resource)) {
141+
self::assertResourceIsStream($resource);
142+
$result = @fstat($resource);
143+
return self::throwOnFailure($result, 'Error getting status of stream: %s', $uri, $resource);
144+
}
145+
146+
if (!Test::isStringable($resource)) {
147+
throw new InvalidArgumentTypeException(1, 'resource', 'Stringable|string|resource', $resource);
148+
}
149+
150+
$resource = (string) $resource;
151+
$result = @stat($resource);
152+
return self::throwOnFailure($result, 'Error getting file status: %s', $resource);
141153
}
142154

143155
/**
@@ -181,8 +193,7 @@ public static function closePipe($pipe, ?string $command = null): int
181193
}
182194

183195
/**
184-
* Get the entire contents of a file or the remaining contents of an open
185-
* stream
196+
* Get the entire contents of a file or the remaining contents of a stream
186197
*
187198
* @see file_get_contents()
188199
* @see stream_get_contents()
@@ -233,7 +244,7 @@ public static function find(): RecursiveFilesystemIterator
233244
}
234245

235246
/**
236-
* Get the end-of-line sequence used in a file
247+
* Get the end-of-line sequence used in a file or stream
237248
*
238249
* Recognised line endings are LF (`"\n"`), CRLF (`"\r\n"`) and CR (`"\r"`).
239250
*
@@ -247,17 +258,7 @@ public static function find(): RecursiveFilesystemIterator
247258
*/
248259
public static function getEol($resource, $uri = null): ?string
249260
{
250-
$close = false;
251-
if (is_resource($resource)) {
252-
self::assertResourceIsStream($resource);
253-
$handle = $resource;
254-
} elseif (Test::isStringable($resource)) {
255-
$uri = (string) $resource;
256-
$handle = self::open($uri, 'r');
257-
$close = true;
258-
} else {
259-
throw new InvalidArgumentTypeException(1, 'resource', 'Stringable|string|resource', $resource);
260-
}
261+
$handle = self::getStream($resource, 'r', $close, $uri);
261262

262263
$line = fgets($handle);
263264

@@ -283,7 +284,7 @@ public static function getEol($resource, $uri = null): ?string
283284
}
284285

285286
/**
286-
* Guess the indentation used in a file
287+
* Guess the indentation used in a file or stream
287288
*
288289
* Derived from VS Code's `indentationGuesser`.
289290
*
@@ -298,17 +299,7 @@ public static function guessIndentation(
298299
bool $alwaysGuessTabSize = false,
299300
$uri = null
300301
): Indentation {
301-
$close = false;
302-
if (is_resource($resource)) {
303-
self::assertResourceIsStream($resource);
304-
$handle = $resource;
305-
} elseif (Test::isStringable($resource)) {
306-
$uri = (string) $resource;
307-
$handle = self::open($uri, 'r');
308-
$close = true;
309-
} else {
310-
throw new InvalidArgumentTypeException(1, 'resource', 'Stringable|string|resource', $resource);
311-
}
302+
$handle = self::getStream($resource, 'r', $close, $uri);
312303

313304
$lines = 0;
314305
$linesWithTabs = 0;
@@ -401,8 +392,7 @@ public static function guessIndentation(
401392
$lineSpaces - 1 < strlen($_prevLine) &&
402393
$_line[$lineSpaces] !== ' ' &&
403394
$_prevLine[$lineSpaces - 1] === ' ' &&
404-
$_prevLine[-1] === ',' &&
405-
!(
395+
$_prevLine[-1] === ',' && !(
406396
$default &&
407397
$default->InsertSpaces &&
408398
$default->TabSize === $diffSpaces
@@ -450,14 +440,16 @@ public static function guessIndentation(
450440
/**
451441
* True if two paths refer to the same filesystem entry
452442
*/
453-
public static function is(string $filename1, string $filename2): bool
443+
public static function same(string $filename1, string $filename2): bool
454444
{
455445
if (!file_exists($filename1) || !file_exists($filename2)) {
456446
return false;
457447
}
458-
$inode = fileinode($filename1);
459-
return $inode !== false &&
460-
fileinode($filename2) === $inode;
448+
$stat1 = self::stat($filename1);
449+
$stat2 = self::stat($filename2);
450+
return
451+
$stat1['dev'] === $stat2['dev'] &&
452+
$stat1['ino'] === $stat2['ino'];
461453
}
462454

463455
/**
@@ -814,17 +806,7 @@ public static function writeCsv(
814806
bool $bom = true,
815807
$uri = null
816808
): void {
817-
$close = false;
818-
if (is_resource($resource)) {
819-
self::assertResourceIsStream($resource);
820-
$handle = $resource;
821-
} elseif (Test::isStringable($resource)) {
822-
$uri = (string) $resource;
823-
$handle = self::open($uri, 'wb');
824-
$close = true;
825-
} else {
826-
throw new InvalidArgumentTypeException(1, 'resource', 'Stringable|string|resource', $resource);
827-
}
809+
$handle = self::getStream($resource, 'wb', $close, $uri);
828810

829811
if ($utf16le) {
830812
if (!extension_loaded('iconv')) {
@@ -900,6 +882,28 @@ public static function fputcsv(
900882
);
901883
}
902884

885+
/**
886+
* @param Stringable|string|resource $resource
887+
* @param Stringable|string|null $uri
888+
* @param-out bool $close
889+
* @param-out Stringable|string|null $uri
890+
* @return resource
891+
*/
892+
private static function getStream($resource, string $mode, ?bool &$close, &$uri)
893+
{
894+
$close = false;
895+
if (is_resource($resource)) {
896+
self::assertResourceIsStream($resource);
897+
return $resource;
898+
}
899+
if (Test::isStringable($resource)) {
900+
$uri = (string) $resource;
901+
$close = true;
902+
return self::open($uri, $mode);
903+
}
904+
throw new InvalidArgumentTypeException(1, 'resource', 'Stringable|string|resource', $resource);
905+
}
906+
903907
/**
904908
* @param resource $resource
905909
*/

src/Utility/Test.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,12 @@ public static function isAbsolutePath(string $path): bool
100100
}
101101

102102
/**
103-
* @deprecated Use {@see File::is()} instead
103+
* @deprecated Use {@see File::same()} instead
104104
* @codeCoverageIgnore
105105
*/
106106
public static function areSameFile(string $path1, string $path2): bool
107107
{
108-
return File::is($path1, $path2);
108+
return File::same($path1, $path2);
109109
}
110110

111111
/**
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
does_not_exist
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dir/file

tests/legacy/file

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ print_r([
3131
'STDOUT' => File::getStreamUri(\STDOUT),
3232
'STDERR' => File::getStreamUri(\STDERR),
3333
'areSame' => array_map(
34-
function ($f) { return array_merge($f, [File::is($f[0], $f[1])]); },
34+
function ($f) { return array_merge($f, [File::same($f[0], $f[1])]); },
3535
$compare
3636
)
3737
]);

0 commit comments

Comments
 (0)