Skip to content

Commit cc14c27

Browse files
authored
Merge pull request #2391 from flow-php/mago-bridges
Mago bridges
2 parents 89439ac + 2cbd472 commit cc14c27

175 files changed

Lines changed: 4148 additions & 3585 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Justfile

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ lint-actions:
5151
set -uo pipefail
5252
rc=0
5353
actionlint || rc=$?
54-
zizmor .github/workflows || rc=$?
54+
zizmor --offline .github/workflows || rc=$?
5555
exit $rc
5656

5757
# Run static analysis (PHPStan).
@@ -70,7 +70,29 @@ analyze-mago *args:
7070
src/lib/doctrine-dbal-bulk \
7171
src/lib/snappy \
7272
src/lib/parquet \
73-
src/core/etl
73+
src/core/etl \
74+
src/lib/parquet-viewer \
75+
src/bridge/openapi/specification \
76+
src/bridge/psr3/telemetry \
77+
src/bridge/symfony/http-foundation-telemetry \
78+
src/bridge/telemetry/otlp \
79+
src/bridge/filesystem/async-aws \
80+
src/bridge/filesystem/azure \
81+
src/bridge/monolog/http \
82+
src/bridge/monolog/telemetry \
83+
src/bridge/phpunit/postgresql \
84+
src/bridge/phpunit/telemetry \
85+
src/bridge/postgresql/valinor \
86+
src/bridge/psr18/telemetry \
87+
src/bridge/psr7/telemetry \
88+
src/bridge/symfony/filesystem-bundle \
89+
src/bridge/symfony/filesystem-cache \
90+
src/bridge/symfony/http-foundation \
91+
src/bridge/symfony/postgresql-bundle \
92+
src/bridge/symfony/postgresql-cache \
93+
src/bridge/symfony/postgresql-messenger \
94+
src/bridge/symfony/postgresql-session \
95+
src/bridge/symfony/telemetry-bundle
7496

7597
# Auto-fix code style (Mago format + lint --fix) and GitHub Actions findings (zizmor --fix).
7698
fix:

mago.toml

Lines changed: 15 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ includes = [
1515
"src/lib/postgresql/src/Flow/PostgreSql/Protobuf",
1616
# Generated by Thrift
1717
"src/lib/parquet/src/Flow/Parquet/ThriftModel",
18+
# Generated by protoc (OTLP protocol definitions)
19+
"src/bridge/telemetry/otlp/src/Opentelemetry",
20+
"src/bridge/telemetry/otlp/src/GPBMetadata",
21+
# Symfony
22+
"src/bridge/symfony/filesystem-bundle/src/Flow/Bridge/Symfony/FilesystemBundle/FlowFilesystemBundle.php",
23+
"src/bridge/symfony/postgresql-bundle/src/Flow/Bridge/Symfony/PostgreSqlBundle/FlowPostgreSqlBundle.php",
24+
"src/bridge/symfony/telemetry-bundle/src/Flow/Bridge/Symfony/TelemetryBundle/FlowTelemetryBundle.php",
1825
]
1926
excludes = [
2027
"src/**/vendor/**",
@@ -30,23 +37,14 @@ enable-short-tags = false
3037
plugins = ["flow-php"]
3138
excludes = [
3239
"**/Flow/Types/PHPStan/**",
40+
# Symfony bundle/config tests accessing deeply-nested processConfiguration() arrays (all mixed-array-access)
41+
"src/bridge/symfony/filesystem-bundle/tests/Flow/Bridge/Symfony/FilesystemBundle/Tests/Unit/FlowFilesystemBundleTest.php",
42+
"src/bridge/symfony/filesystem-bundle/tests/Flow/Bridge/Symfony/FilesystemBundle/Tests/Unit/ConfigurationTest.php",
43+
"src/bridge/symfony/postgresql-bundle/tests/Flow/Bridge/Symfony/PostgreSqlBundle/Tests/Unit/DependencyInjection/ConfigurationTest.php",
44+
"src/bridge/symfony/postgresql-bundle/tests/Flow/Bridge/Symfony/PostgreSqlBundle/Tests/Integration/FlowPostgreSqlExtensionTest.php",
45+
"src/bridge/symfony/telemetry-bundle/tests/Flow/Bridge/Symfony/TelemetryBundle/Tests/Unit/DependencyInjection/ConfigurationTest.php",
3346
]
34-
ignore = [
35-
{ code = "redundant-docblock-type", in = [
36-
"src/lib/postgresql/src/Flow/PostgreSql/DSL/client.php",
37-
] },
38-
{ code = "unavailable-method", in = [
39-
"src/lib/types/src/Flow/Types/Type/Logical/HTMLElementType.php",
40-
"src/lib/types/src/Flow/Types/Type/Logical/HTMLType.php",
41-
"src/lib/types/src/Flow/Types/Type/Native/StringType.php",
42-
"src/lib/types/tests/Flow/Types/Tests/Unit/Type/Logical/HTMLElementTypeTest.php",
43-
"src/lib/types/tests/Flow/Types/Tests/Unit/Type/Logical/HTMLTypeTest.php",
44-
"src/lib/types/tests/Flow/Types/Tests/Unit/Type/Native/StringTypeTest.php",
45-
"src/lib/types/tests/Flow/Types/Tests/Unit/Type/TypeDetectorTest.php",
46-
"src/core/etl/src/Flow/ETL/Row/Entry/HTMLEntry.php",
47-
"src/core/etl/src/Flow/ETL/Row/Entry/HTMLElementEntry.php",
48-
] },
49-
]
47+
ignore = []
5048

5149
[linter]
5250
integrations = ["symfony", "phpunit"]
@@ -113,23 +111,7 @@ no-sprintf-concat = { enabled = false }
113111
no-global = { enabled = false }
114112
no-redundant-method-override = { enabled = false }
115113
no-redundant-else = { enabled = true, level = "warning" }
116-
# Bug in Mago 1.28.0 - false positives on $this when passed as a call/constructor argument.
117-
# Minimal repro: https://mago.carthage.software/1.27.1/en/playground/#019e3f91-7e6d-75d3-6c51-f9dae0ed72f8
118-
# Revisit when fixed upstream.
119-
no-redundant-variable = { enabled = true, level = "warning", exclude = [
120-
"**/Flow/ETL/Function/ScalarFunctionChain.php",
121-
"**/Flow/ETL/DataFrame.php",
122-
"**/Flow/ETL/Row/EntryReference.php",
123-
"**/Flow/ETL/Sort/SortAlgorithms.php",
124-
"**/Flow/PostgreSql/QueryBuilder/**",
125-
"**/Flow/PostgreSql/Tests/Unit/QueryBuilder/Expression/MockExpression.php",
126-
"**/Flow/PostgreSql/Explain/Plan/PlanNodeType.php",
127-
"**/Flow/Filesystem/Path.php",
128-
"**/CacheSpyClient.php",
129-
"**/Tests/Unit/ObjectExtractorTest.php",
130-
"**/array-dot/src/Flow/ArrayDot/array_dot.php",
131-
"**/TracableHttpClientTest.php",
132-
] }
114+
no-redundant-variable = { enabled = true, level = "warning" }
133115
strict-types = { enabled = true, level = "error" }
134116
no-fully-qualified-global-function = { enabled = true, level = "error" }
135117
no-fully-qualified-global-class-like = { enabled = true, level = "error" }

phpstan.neon

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -144,26 +144,29 @@ parameters:
144144
message: '#Dom\\(CharacterData|HTMLDocument|HTMLElement|Element)#i'
145145
identifier: class.notFound
146146
-
147-
path: src/bridge/symfony/telemetry-bundle/src/Flow/Bridge/Symfony/TelemetryBundle/DependencyInjection/FlowTelemetryExtension.php
148-
identifier: argument.type
149-
-
150-
path: src/bridge/symfony/telemetry-bundle/src/Flow/Bridge/Symfony/TelemetryBundle/DependencyInjection/FlowTelemetryExtension.php
147+
path: src/bridge/symfony/telemetry-bundle/src/Flow/Bridge/Symfony/TelemetryBundle/FlowTelemetryBundle.php
151148
identifier: offsetAccess.nonOffsetAccessible
152149
-
153-
path: src/bridge/symfony/telemetry-bundle/src/Flow/Bridge/Symfony/TelemetryBundle/DependencyInjection/FlowTelemetryExtension.php
150+
path: src/bridge/symfony/telemetry-bundle/src/Flow/Bridge/Symfony/TelemetryBundle/FlowTelemetryBundle.php
151+
identifier: cast.string
152+
-
153+
path: src/bridge/symfony/filesystem-cache/src/Flow/Bridge/Symfony/FilesystemCache/FlowFilesystemCacheAdapter.php
154154
identifier: cast.string
155155
-
156-
path: src/bridge/symfony/telemetry-bundle/src/Flow/Bridge/Symfony/TelemetryBundle/DependencyInjection/FlowTelemetryExtension.php
157-
identifier: foreach.nonIterable
156+
path: src/bridge/symfony/telemetry-bundle/src/Flow/Bridge/Symfony/TelemetryBundle/Instrumentation/HttpKernel/HttpKernelSpanSubscriber.php
157+
identifier: encapsedStringPart.nonString
158158
-
159-
path: src/bridge/symfony/telemetry-bundle/src/Flow/Bridge/Symfony/TelemetryBundle/DependencyInjection/FlowTelemetryExtension.php
160-
identifier: binaryOp.invalid
159+
path: src/bridge/symfony/postgresql-messenger/tests/Flow/Bridge/Symfony/PostgreSQLMessenger/Tests/Integration/FlowPostgreSqlTransportTest.php
160+
identifier: cast.string
161161
-
162162
path: src/bridge/symfony/telemetry-bundle/src/Flow/Bridge/Symfony/TelemetryBundle/DependencyInjection/Compiler/DBALTelemetryPass.php
163163
identifier: cast.int
164164
-
165-
path: src/bridge/symfony/telemetry-bundle/src/Flow/Bridge/Symfony/TelemetryBundle/Instrumentation/Doctrine/DBAL/TracingMiddleware.php
166-
identifier: return.type
165+
path: src/bridge/symfony/filesystem-cache/tests/Flow/Bridge/Symfony/FilesystemCache/Tests/Unit/Double/SpyMarshaller.php
166+
identifier: parameterByRef.unusedType
167+
-
168+
path: src/bridge/symfony/postgresql-cache/tests/Flow/Bridge/Symfony/PostgreSQLCache/Tests/Unit/Double/SpyMarshaller.php
169+
identifier: parameterByRef.unusedType
167170
# brick/math 0.12-0.14 vs 0.15+ compatibility shim — branches differ per installed version
168171
-
169172
path: src/core/etl/src/Flow/Calculator/Calculator.php

src/bridge/filesystem/async-aws/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"require": {
1717
"php": "~8.3.0 || ~8.4.0 || ~8.5.0",
1818
"flow-php/filesystem": "self.version",
19+
"flow-php/types": "self.version",
1920
"async-aws/s3": "^2.6 || ^3.0"
2021
},
2122
"config": {

src/bridge/filesystem/async-aws/src/Flow/Filesystem/Bridge/AsyncAWS/AsyncAWSS3DesintationStream/AsyncAWSS3BlockLifecycle.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
use function fclose;
1515
use function fopen;
16-
use function is_resource;
1716
use function unlink;
1817

1918
final readonly class AsyncAWSS3BlockLifecycle implements BlockLifecycle
@@ -47,9 +46,7 @@ public function filled(Block $block): void
4746
*/
4847
$etag = $uploadPartResponse->getETag();
4948

50-
if (is_resource($handle)) {
51-
fclose($handle);
52-
}
49+
fclose($handle);
5350

5451
unlink($block->path()->path());
5552

src/bridge/filesystem/async-aws/src/Flow/Filesystem/Bridge/AsyncAWS/AsyncAWSS3DestinationStream.php

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,6 @@ public static function openAppend(
5050
BlockFactory $blockFactory = new NativeLocalFileBlocksFactory(),
5151
int $blockSize = 1024 * 1024 * 4,
5252
): self {
53-
if ($blockSize < 1) {
54-
throw new InvalidArgumentException('Block size must be greater than 0');
55-
}
56-
5753
try {
5854
$objectHead = $s3Client->headObject([
5955
'Bucket' => $bucket,
@@ -79,7 +75,9 @@ public static function openAppend(
7975
* and append to it. We need to read the file to memory and append it to the new file.
8076
* S3 allows only the last part to be smaller than 5Mb, all other parts needs to be 5Mb+.
8177
*/
82-
if ($objectHead->getContentLength() < SizeUnits::mbToBytes(5)) {
78+
$contentLength = $objectHead->getContentLength() ?? 0;
79+
80+
if ($contentLength < SizeUnits::mbToBytes(5)) {
8381
$blocks = new Blocks(
8482
$blockSize,
8583
$blockFactory,
@@ -140,10 +138,6 @@ public static function openBlank(
140138
BlockFactory $blockFactory = new NativeLocalFileBlocksFactory(),
141139
int $blockSize = 1024 * 1024 * 4,
142140
): self {
143-
if ($blockSize < 1) {
144-
throw new InvalidArgumentException('Block size must be greater than 0');
145-
}
146-
147141
$response = $s3Client->createMultipartUpload(new CreateMultipartUploadRequest([
148142
'Bucket' => $bucket,
149143
'Key' => ltrim($path->path(), '/'),

src/bridge/filesystem/async-aws/src/Flow/Filesystem/Bridge/AsyncAWS/AsyncAWSS3Filesystem.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ public function getSystemTmpDir(): Path
5959
return $this->options->tmpDir();
6060
}
6161

62+
/**
63+
* @return \Generator<FileStatus>
64+
*/
6265
public function list(Path $path, Filter $pathFilter = new KeepAll()): Generator
6366
{
6467
$this->mount->supports($path) || throw new InvalidSchemeException($path->protocol(), $this->mount->protocol);

src/bridge/filesystem/async-aws/src/Flow/Filesystem/Bridge/AsyncAWS/AsyncAWSS3SourceStream.php

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ public function isOpen(): bool
4949

5050
public function iterate(int $length = 1): Generator
5151
{
52-
for ($offset = 0; $offset < $this->size(); $offset += $length) {
52+
$size = $this->size() ?? 0;
53+
54+
for ($offset = 0; $offset < $size; $offset += $length) {
5355
yield $this->read($length, $offset);
5456
}
5557
}
@@ -74,8 +76,9 @@ public function readLines(string $separator = "\n", ?int $length = null): Genera
7476
{
7577
$offset = 0;
7678
$content = '';
79+
$size = $this->size() ?? 0;
7780

78-
while ($offset < $this->size()) {
81+
while ($offset < $size) {
7982
// Read a chunk of the file
8083
$chunk = $this->read($length ?? (1024 * 1024 * 9), $offset);
8184
$offset += strlen($chunk);
@@ -98,12 +101,12 @@ public function readLines(string $separator = "\n", ?int $length = null): Genera
98101

99102
$content = $lines[$lastIndex];
100103
} elseif (substr_count($content, $separator) === 1) {
101-
// Split the content by the separator
102-
/**
103-
* @phpstan-ignore-next-line
104-
*/
105-
yield substr($content, 0, strpos($content, $separator));
106-
$content = substr($content, strpos($content, $separator) + 1);
104+
$pos = strpos($content, $separator);
105+
106+
if ($pos !== false) {
107+
yield substr($content, 0, $pos);
108+
$content = substr($content, $pos + 1);
109+
}
107110
}
108111
}
109112

src/bridge/filesystem/async-aws/src/Flow/Filesystem/Bridge/AsyncAWS/DSL/functions.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Flow\Filesystem\Bridge\AsyncAWS\DSL;
66

7+
use AsyncAws\Core\Configuration;
78
use AsyncAws\S3\S3Client;
89
use Flow\ETL\Attribute\DocumentationDSL;
910
use Flow\ETL\Attribute\Module;
@@ -13,12 +14,11 @@
1314
use Flow\Filesystem\Mount;
1415

1516
/**
16-
* @param array<string, mixed> $configuration - for details please see https://async-aws.com/clients/s3.html
17+
* @param array<Configuration::OPTION_*, null|string> $configuration - for details please see https://async-aws.com/clients/s3.html
1718
*/
1819
#[DocumentationDSL(module: Module::S3_FILESYSTEM, type: Type::HELPER)]
1920
function aws_s3_client(array $configuration): S3Client
2021
{
21-
/** @phpstan-ignore-next-line */
2222
return new S3Client($configuration);
2323
}
2424

src/bridge/filesystem/async-aws/tests/Flow/Filesystem/Bridge/AsyncAWS/Tests/Integration/AsyncAWSS3DestinationStreamTest.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ public function test_writing_content_from_resource(): void
3030
$stream->fromResource($resource);
3131
$stream->close();
3232

33-
static::assertTrue($fs->status(path('aws-s3://orders.csv'))?->isFile());
34-
static::assertFalse($fs->status(path('aws-s3://orders.csv'))->isDirectory());
33+
$status = $fs->status(path('aws-s3://orders.csv'));
34+
static::assertNotNull($status);
35+
static::assertTrue($status->isFile());
36+
static::assertFalse($status->isDirectory());
3537
static::assertSame(
3638
file_get_contents(__DIR__ . '/Fixtures/orders.csv'),
3739
$fs->readFrom(path('aws-s3://orders.csv'))->content(),
@@ -48,8 +50,10 @@ public function test_writing_content_smaller_than_block_size_to_s3(): void
4850
$stream->append('Hello, World!');
4951
$stream->close();
5052

51-
static::assertTrue($fs->status(path('aws-s3://file.txt'))?->isFile());
52-
static::assertFalse($fs->status(path('aws-s3://file.txt'))->isDirectory());
53+
$status = $fs->status(path('aws-s3://file.txt'));
54+
static::assertNotNull($status);
55+
static::assertTrue($status->isFile());
56+
static::assertFalse($status->isDirectory());
5357
static::assertSame('Hello, World!', $fs->readFrom(path('aws-s3://file.txt'))->content());
5458

5559
$fs->rm(path('aws-s3://file.txt'));

0 commit comments

Comments
 (0)