Skip to content

Commit 618d7c1

Browse files
author
Martin Dostál
committed
Merge branch 'v1.7.0' into 'master'
V1.7.0 See merge request redbitcz/composer/utils!30
2 parents 9aad280 + 85e6621 commit 618d7c1

File tree

9 files changed

+398
-19
lines changed

9 files changed

+398
-19
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,12 @@ $variations = BitwiseVariator::create(0b1011)->mustNot(0b0010)->variate();
203203
| `1000` |
204204
| `1001` |
205205

206+
Be aware to use more than 8 variated bits, because it proceed huge of variants:
207+
208+
![Table with count of variants for every variated bits](https://user-images.githubusercontent.com/1657322/153865836-174cbe67-3216-4e47-954b-bec50e8d2c26.png)
209+
210+
(source: [Spreadseed Bitwise Variator counts](https://drive.google.com/open?id=1J4M0PyoQFTDgKk84fVjzhtil_Af0_gVZX0BdPlD5uFg))
211+
206212
## License
207213
The MIT License (MIT). Please see [License File](LICENSE) for more information.
208214

src/IO/IBufferWriter.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Redbitcz\Utils\IO;
6+
7+
interface IBufferWriter extends IOutStream
8+
{
9+
public function hasOutputContent(): bool;
10+
11+
public function getOutputContent(): string;
12+
13+
public function hasErrorContent(): bool;
14+
15+
public function getErrorContent(): string;
16+
}

src/IO/LazyStreamWriter.php

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Redbitcz\Utils\IO;
6+
7+
use LogicException;
8+
9+
/**
10+
* Same as `FileWriter`, but is opening file descriptors only on first write them
11+
*/
12+
class LazyStreamWriter implements IOutStream
13+
{
14+
/** @var callable */
15+
private $outputStreamFactory;
16+
/** @var callable */
17+
private $errorStreamFactory;
18+
/** @var resource|null */
19+
private $outputStream;
20+
/** @var resource|null */
21+
private $errorStream;
22+
23+
/**
24+
* @param callable $outputStreamFactory Callback which return writable stream handler resource
25+
* @param callable $errorStreamFactory Callback which return writable stream handler resource
26+
*/
27+
public function __construct(callable $outputStreamFactory, callable $errorStreamFactory)
28+
{
29+
$this->outputStreamFactory = $outputStreamFactory;
30+
$this->errorStreamFactory = $errorStreamFactory;
31+
}
32+
33+
public function write(string $string): void
34+
{
35+
if ($this->outputStream === null) {
36+
$this->outputStream = $this->createStream($this->outputStreamFactory);
37+
}
38+
39+
fwrite($this->outputStream, $string);
40+
}
41+
42+
public function error(string $string): void
43+
{
44+
if ($this->errorStream === null) {
45+
$this->errorStream = $this->createStream($this->errorStreamFactory);
46+
}
47+
48+
fwrite($this->errorStream, $string);
49+
}
50+
51+
/**
52+
* @return resource
53+
*/
54+
private function createStream(callable $factory)
55+
{
56+
$stream = $factory();
57+
58+
if (is_resource($stream) === false) {
59+
$type = is_object($stream) ? get_class($stream) : gettype($stream);
60+
throw new LogicException(
61+
"Stream factory callback must returns valid stream handler resource, {$type} returned"
62+
);
63+
}
64+
65+
return $stream;
66+
}
67+
}

src/IO/MemoryWriter.php

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Redbitcz\Utils\IO;
6+
7+
use Closure;
8+
use RuntimeException;
9+
10+
class MemoryWriter implements IBufferWriter
11+
{
12+
/** @var resource|null */
13+
private $outputStream;
14+
15+
/** @var resource|null */
16+
private $errorStream;
17+
18+
/** @var LazyStreamWriter */
19+
private $writer;
20+
21+
public function __construct()
22+
{
23+
$this->writer = new LazyStreamWriter(
24+
Closure::fromCallable([$this, 'createOutputStream']),
25+
Closure::fromCallable([$this, 'createErrorStream']),
26+
);
27+
}
28+
29+
public function __destruct()
30+
{
31+
if ($this->hasOutputContent()) {
32+
fclose($this->outputStream);
33+
}
34+
35+
if ($this->hasErrorContent()) {
36+
fclose($this->errorStream);
37+
}
38+
}
39+
40+
public function write(string $string): void
41+
{
42+
$this->writer->write($string);
43+
}
44+
45+
public function error(string $string): void
46+
{
47+
$this->writer->error($string);
48+
}
49+
50+
/**
51+
* @return resource
52+
*/
53+
private function createOutputStream()
54+
{
55+
return $this->outputStream = $this->createMemoryStream();
56+
}
57+
58+
/**
59+
* @return resource
60+
*/
61+
private function createErrorStream()
62+
{
63+
return $this->errorStream = $this->createMemoryStream();
64+
}
65+
66+
public function hasOutputContent(): bool
67+
{
68+
return isset($this->outputStream);
69+
}
70+
71+
public function getOutputContent(): string
72+
{
73+
return $this->hasOutputContent() ? $this->getStreamContent($this->outputStream) : '';
74+
}
75+
76+
public function hasErrorContent(): bool
77+
{
78+
return isset($this->errorStream);
79+
}
80+
81+
public function getErrorContent(): string
82+
{
83+
return $this->hasErrorContent() ? $this->getStreamContent($this->errorStream) : '';
84+
}
85+
86+
/**
87+
* @return resource
88+
*/
89+
private function createMemoryStream()
90+
{
91+
$fileHandler = fopen('php://memory', 'wb+');
92+
93+
if ($fileHandler === false) {
94+
throw new RuntimeException("Unable to create Memory stream (php://memory)");
95+
}
96+
97+
return $fileHandler;
98+
}
99+
100+
/**
101+
* @param resource $fileHandler
102+
* @return string
103+
*/
104+
private function getStreamContent($fileHandler): string
105+
{
106+
return stream_get_contents($fileHandler, -1, 0);
107+
}
108+
}

src/Log/Logger.php

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,57 @@ class Logger implements LoggerInterface, SectionLoggerInterface
1313
use LoggerInterpolator;
1414
use LoggerTrait;
1515

16+
public const STANDARD_ERROR_LEVELS = [
17+
'emergency',
18+
'alert',
19+
'critical',
20+
'error',
21+
];
22+
1623
/** @var IOutStream */
1724
protected $writer;
25+
/** @var array<string, bool> */
26+
protected $errorLevels = [];
1827

19-
public function __construct(IOutStream $writer)
28+
/**
29+
* @param string[] $errorLevels
30+
*/
31+
public function __construct(IOutStream $writer, array $errorLevels = [])
2032
{
2133
$this->writer = $writer;
34+
foreach ($errorLevels as $level) {
35+
$this->addErrorLevel($level);
36+
}
2237
}
2338

2439
public function log($level, $message, array $context = []): void
2540
{
26-
$this->writer->write(
27-
sprintf(
28-
"[%s] %s: %s\n",
29-
date('Y-m-d H:i:s'),
30-
strtoupper((string)$level),
31-
$this->interpolate($message, $context)
32-
)
41+
$interpolatedMessage = sprintf(
42+
"[%s] %s: %s\n",
43+
date('Y-m-d H:i:s'),
44+
strtoupper((string)$level),
45+
$this->interpolate($message, $context)
3346
);
47+
48+
if (isset($this->errorLevels[$level])) {
49+
$this->writer->error($interpolatedMessage);
50+
} else {
51+
$this->writer->write($interpolatedMessage);
52+
}
53+
}
54+
55+
public function withStandardErrorLevels(): self
56+
{
57+
return new self($this->writer, self::STANDARD_ERROR_LEVELS);
58+
}
59+
60+
protected function addErrorLevel(string $level): void
61+
{
62+
$this->errorLevels[$level] = true;
3463
}
3564

3665
public function section(string $section, string $separator = '/'): SectionLoggerInterface
3766
{
38-
return new SectionLogger($this->writer, $section, $separator);
67+
return new SectionLogger($this->writer, $section, $separator, array_keys($this->errorLevels));
3968
}
4069
}

src/Log/SectionLogger.php

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,39 @@ class SectionLogger extends Logger
1414
/** @var string */
1515
private $separator;
1616

17-
public function __construct(IOutStream $writer, string $section, string $separator = '/')
17+
/**
18+
* @param string[] $errorLevels
19+
*/
20+
public function __construct(IOutStream $writer, string $section, string $separator = '/', array $errorLevels = [])
1821
{
19-
parent::__construct($writer);
22+
parent::__construct($writer, $errorLevels);
2023
$this->section = $section;
2124
$this->separator = $separator;
2225
}
2326

2427
public function log($level, $message, array $context = []): void
2528
{
26-
$this->writer->write(
27-
sprintf(
28-
"[%s] %s: {%s} %s\n",
29-
date('Y-m-d H:i:s'),
30-
strtoupper((string)$level),
31-
$this->section,
32-
$this->interpolate($message, $context)
33-
)
29+
$interpolatedMessage = sprintf(
30+
"[%s] %s: {%s} %s\n",
31+
date('Y-m-d H:i:s'),
32+
strtoupper((string)$level),
33+
$this->section,
34+
$this->interpolate($message, $context)
3435
);
36+
37+
if (isset($this->errorLevels[$level])) {
38+
$this->writer->error($interpolatedMessage);
39+
} else {
40+
$this->writer->write($interpolatedMessage);
41+
}
42+
}
43+
44+
/**
45+
* @todo PHP 7.4 return type -> self
46+
*/
47+
public function withStandardErrorLevels(): Logger
48+
{
49+
return new self($this->writer, $this->section, $this->separator, self::STANDARD_ERROR_LEVELS);
3550
}
3651

3752
public function section(string $section, string $separator = null): SectionLoggerInterface

tests/IO/LazyStreamWriterTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
/** @testCase */
3+
4+
declare(strict_types=1);
5+
6+
namespace Tests\IO;
7+
8+
use LogicException;
9+
use Redbitcz\Utils\IO\LazyStreamWriter;
10+
use Tester\Assert;
11+
use Tester\TestCase;
12+
13+
require __DIR__ . '/../../vendor/autoload.php';
14+
15+
class LazyStreamWriterTest extends TestCase
16+
{
17+
public function testInvalidCallback(): void
18+
{
19+
Assert::exception(static function () {
20+
$writer = new LazyStreamWriter(function() {return null;}, function() {return null;});
21+
$writer->write('foo');
22+
}, LogicException::class);
23+
24+
Assert::exception(static function () {
25+
$writer = new LazyStreamWriter(function() {return null;}, function() {return null;});
26+
$writer->error('foo');
27+
}, LogicException::class);
28+
}
29+
}
30+
31+
(new LazyStreamWriterTest)->run();

0 commit comments

Comments
 (0)