Skip to content

Commit 788c3d7

Browse files
authored
Merge pull request #12 from php-etl/feature/generate-csv-without-enclosure
Manage case no enclosure is required to write csv files
2 parents ccce92d + 295fe08 commit 788c3d7

File tree

8 files changed

+189
-15
lines changed

8 files changed

+189
-15
lines changed

src/Builder/Extractor.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ final class Extractor implements StepBuilderInterface
1212
private ?Node\Expr $logger;
1313

1414
public function __construct(
15-
private ?Node\Expr $filePath,
15+
private Node\Expr $filePath,
1616
private ?Node\Expr $delimiter = null,
1717
private ?Node\Expr $enclosure = null,
1818
private ?Node\Expr $escape = null,

src/Builder/Loader.php

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@ final class Loader implements StepBuilderInterface
1212
private ?Node\Expr $logger;
1313

1414
public function __construct(
15-
private ?Node\Expr $filePath,
15+
private Node\Expr $filePath,
1616
private ?Node\Expr $delimiter = null,
1717
private ?Node\Expr $enclosure = null,
1818
private ?Node\Expr $escape = null,
1919
private ?Node\Expr $columns = null,
2020
private bool $safeMode = true,
21+
private bool $withNonStandard = false,
2122
) {
2223
$this->logger = null;
2324
}
@@ -88,12 +89,91 @@ public function withFingersCrossedMode(): self
8889
return $this;
8990
}
9091

92+
public function withNonStandard(): self
93+
{
94+
$this->withNonStandard = true;
95+
96+
return $this;
97+
}
98+
9199
public function getNode(): Node
92100
{
93101
$arguments = [
94102
new Node\Arg(
95103
value: new Node\Expr\New_(
96-
class: new Node\Name\FullyQualified('SplFileObject'),
104+
class: true === $this->withNonStandard ?
105+
new Node\Stmt\Class_(
106+
name: 'SplFileObject',
107+
subNodes: [
108+
'extends' => new Node\Name\FullyQualified('SplFileObject'),
109+
'stmts' => [
110+
new Node\Stmt\ClassMethod(
111+
name: 'fputcsv',
112+
subNodes: [
113+
'type' => Node\Stmt\Class_::MODIFIER_PUBLIC,
114+
'params' => [
115+
new Node\Param(
116+
var: new Node\Expr\Variable('fields'),
117+
type: 'array',
118+
),
119+
new Node\Param(
120+
var: new Node\Expr\Variable('separator'),
121+
default: new Node\Scalar\String_(','),
122+
type: 'string',
123+
),
124+
new Node\Param(
125+
var: new Node\Expr\Variable('enclosure'),
126+
default: new Node\Scalar\String_('"'),
127+
type: 'string',
128+
),
129+
new Node\Param(
130+
var: new Node\Expr\Variable('escape'),
131+
default: new Node\Scalar\String_('\\'),
132+
type: 'string',
133+
),
134+
new Node\Param(
135+
var: new Node\Expr\Variable('eol'),
136+
default: new Node\Expr\ConstFetch(new Node\Name('PHP_EOL')),
137+
type: 'string',
138+
),
139+
],
140+
'returnType' => new Node\UnionType(
141+
types: [
142+
new Node\Name('int'),
143+
new Node\Name('false'),
144+
],
145+
),
146+
'stmts' => [
147+
new Node\Stmt\Return_(
148+
expr: new Node\Expr\MethodCall(
149+
var: new Node\Expr\Variable('this'),
150+
name: 'fwrite',
151+
args: [
152+
new Node\Arg(
153+
value: new Node\Expr\BinaryOp\Concat(
154+
left: new Node\Expr\FuncCall(
155+
name: new Node\Name('implode'),
156+
args: [
157+
new Node\Arg(
158+
value: new Node\Expr\Variable('separator')
159+
),
160+
new Node\Arg(
161+
value: new Node\Expr\Variable('fields')
162+
),
163+
],
164+
),
165+
right: new Node\Expr\Variable('eol')
166+
),
167+
),
168+
],
169+
),
170+
),
171+
],
172+
],
173+
),
174+
],
175+
],
176+
) : new Node\Name\FullyQualified('SplFileObject'),
97177
args: [
98178
new Node\Arg($this->filePath),
99179
new Node\Arg(new Node\Scalar\String_('w')),

src/Builder/MultipleFilesLoader.php

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@ final class MultipleFilesLoader implements StepBuilderInterface
1212
private ?Node\Expr $logger;
1313

1414
public function __construct(
15-
private ?Node\Expr $filePath,
16-
private ?Node\Expr $maxLines,
15+
private Node\Expr $filePath,
16+
private Node\Expr $maxLines,
1717
private ?Node\Expr $delimiter = null,
1818
private ?Node\Expr $enclosure = null,
1919
private ?Node\Expr $escape = null,
2020
private ?Node\Expr $columns = null,
2121
private bool $safeMode = true,
22+
private bool $withNonStandard = false,
2223
) {
2324
$this->logger = null;
2425
}
@@ -89,6 +90,13 @@ public function withSafeMode(): self
8990
return $this;
9091
}
9192

93+
public function withNonStandard(): self
94+
{
95+
$this->withNonStandard = true;
96+
97+
return $this;
98+
}
99+
92100
public function withFingersCrossedMode(): self
93101
{
94102
$this->safeMode = false;
@@ -101,7 +109,78 @@ public function getNode(): Node
101109
$arguments = [
102110
new Node\Arg(
103111
value: new Node\Expr\New_(
104-
class: new Node\Name\FullyQualified('SplFileObject'),
112+
class: $this->withNonStandard ? new Node\Stmt\Class_(
113+
name: 'SplFileObject',
114+
subNodes: [
115+
'extends' => new Node\Name\FullyQualified('SplFileObject'),
116+
'stmts' => [
117+
new Node\Stmt\ClassMethod(
118+
name: 'fputcsv',
119+
subNodes: [
120+
'type' => Node\Stmt\Class_::MODIFIER_PUBLIC,
121+
'params' => [
122+
new Node\Param(
123+
var: new Node\Expr\Variable('fields'),
124+
type: 'array',
125+
),
126+
new Node\Param(
127+
var: new Node\Expr\Variable('separator'),
128+
default: new Node\Scalar\String_(','),
129+
type: 'string',
130+
),
131+
new Node\Param(
132+
var: new Node\Expr\Variable('enclosure'),
133+
default: new Node\Scalar\String_('"'),
134+
type: 'string',
135+
),
136+
new Node\Param(
137+
var: new Node\Expr\Variable('escape'),
138+
default: new Node\Scalar\String_('\\'),
139+
type: 'string',
140+
),
141+
new Node\Param(
142+
var: new Node\Expr\Variable('eol'),
143+
default: new Node\Expr\ConstFetch(new Node\Name('PHP_EOL')),
144+
type: 'string',
145+
),
146+
],
147+
'returnType' => new Node\UnionType(
148+
types: [
149+
new Node\Name('int'),
150+
new Node\Name('false'),
151+
],
152+
),
153+
'stmts' => [
154+
new Node\Stmt\Return_(
155+
expr: new Node\Expr\MethodCall(
156+
var: new Node\Expr\Variable('this'),
157+
name: 'fwrite',
158+
args: [
159+
new Node\Arg(
160+
value: new Node\Expr\BinaryOp\Concat(
161+
left: new Node\Expr\FuncCall(
162+
name: new Node\Name('implode'),
163+
args: [
164+
new Node\Arg(
165+
value: new Node\Expr\Variable('separator')
166+
),
167+
new Node\Arg(
168+
value: new Node\Expr\Variable('fields')
169+
),
170+
],
171+
),
172+
right: new Node\Expr\Variable('eol')
173+
),
174+
),
175+
],
176+
),
177+
),
178+
],
179+
],
180+
),
181+
],
182+
],
183+
) : new Node\Name\FullyQualified('SplFileObject'),
105184
args: [
106185
new Node\Arg(
107186
value: $this->filePath
@@ -174,7 +253,7 @@ class: new Node\Name\FullyQualified('SplFileObject'),
174253
var: new Node\Expr\Variable('coroutine'),
175254
expr: new Node\Expr\MethodCall(
176255
var: new Node\Expr\Variable('this'),
177-
name: new Node\Name('coroutineFactory'),
256+
name: 'coroutineFactory',
178257
args: [
179258
new Node\Arg(
180259
value: new Node\Expr\Assign(

src/Configuration/Extractor.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44

55
namespace Kiboko\Plugin\CSV\Configuration;
66

7-
use function Kiboko\Component\SatelliteToolbox\Configuration\asExpression;
8-
use function Kiboko\Component\SatelliteToolbox\Configuration\isExpression;
97
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
108
use Symfony\Component\Config\Definition\ConfigurationInterface;
119

10+
use function Kiboko\Component\SatelliteToolbox\Configuration\asExpression;
11+
use function Kiboko\Component\SatelliteToolbox\Configuration\isExpression;
12+
1213
final class Extractor implements ConfigurationInterface
1314
{
1415
public function getConfigTreeBuilder(): TreeBuilder

src/Configuration/Loader.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44

55
namespace Kiboko\Plugin\CSV\Configuration;
66

7-
use function Kiboko\Component\SatelliteToolbox\Configuration\asExpression;
8-
use function Kiboko\Component\SatelliteToolbox\Configuration\isExpression;
97
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
108
use Symfony\Component\Config\Definition\ConfigurationInterface;
119

10+
use function Kiboko\Component\SatelliteToolbox\Configuration\asExpression;
11+
use function Kiboko\Component\SatelliteToolbox\Configuration\isExpression;
12+
use function Kiboko\Component\SatelliteToolbox\Configuration\mutuallyExclusiveFields;
13+
1214
final class Loader implements ConfigurationInterface
1315
{
1416
public function getConfigTreeBuilder(): TreeBuilder
@@ -17,6 +19,9 @@ public function getConfigTreeBuilder(): TreeBuilder
1719

1820
/* @phpstan-ignore-next-line */
1921
$builder->getRootNode()
22+
->beforeNormalization()
23+
->always(mutuallyExclusiveFields('nonstandard', 'enclosure', 'escape'))
24+
->end()
2025
->children()
2126
->scalarNode('file_path')
2227
->isRequired()
@@ -61,6 +66,7 @@ public function getConfigTreeBuilder(): TreeBuilder
6166
->thenInvalid('Value cannot be null')
6267
->end()
6368
->end()
69+
->booleanNode('nonstandard')->end()
6470
->end()
6571
;
6672

src/Factory/Extractor.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@
44

55
namespace Kiboko\Plugin\CSV\Factory;
66

7-
use function Kiboko\Component\SatelliteToolbox\Configuration\compileValue;
8-
use function Kiboko\Component\SatelliteToolbox\Configuration\compileValueWhenExpression;
97
use Kiboko\Contract\Configurator;
108
use Kiboko\Plugin\CSV;
119
use Symfony\Component\Config\Definition\ConfigurationInterface;
1210
use Symfony\Component\Config\Definition\Exception as Symfony;
1311
use Symfony\Component\Config\Definition\Processor;
1412
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
1513

14+
use function Kiboko\Component\SatelliteToolbox\Configuration\compileValue;
15+
use function Kiboko\Component\SatelliteToolbox\Configuration\compileValueWhenExpression;
16+
1617
final class Extractor implements Configurator\FactoryInterface
1718
{
1819
private Processor $processor;

src/Factory/Loader.php

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

55
namespace Kiboko\Plugin\CSV\Factory;
66

7-
use function Kiboko\Component\SatelliteToolbox\Configuration\compileValue;
8-
use function Kiboko\Component\SatelliteToolbox\Configuration\compileValueWhenExpression;
97
use Kiboko\Contract\Configurator;
108
use Kiboko\Plugin\CSV;
119
use Symfony\Component\Config\Definition\ConfigurationInterface;
1210
use Symfony\Component\Config\Definition\Exception as Symfony;
1311
use Symfony\Component\Config\Definition\Processor;
1412
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
1513

14+
use function Kiboko\Component\SatelliteToolbox\Configuration\compileValue;
15+
use function Kiboko\Component\SatelliteToolbox\Configuration\compileValueWhenExpression;
16+
1617
final class Loader implements Configurator\FactoryInterface
1718
{
1819
private Processor $processor;
@@ -81,6 +82,10 @@ public function compile(array $config): Repository\Loader
8182
}
8283
}
8384

85+
if (\array_key_exists('nonstandard', $config) && true === $config['nonstandard']) {
86+
$loader->withNonStandard();
87+
}
88+
8489
return new Repository\Loader($loader);
8590
}
8691
}

src/Service.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Kiboko\Contract\Configurator;
88
use Symfony\Component\Config\Definition\Exception as Symfony;
99
use Symfony\Component\Config\Definition\Processor;
10+
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
1011
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
1112

1213
#[Configurator\Pipeline(
@@ -69,6 +70,7 @@ public function compile(array $config): Configurator\RepositoryInterface
6970
&& \count($config['expression_language'])
7071
) {
7172
foreach ($config['expression_language'] as $provider) {
73+
/* @var ExpressionFunctionProviderInterface $provider */
7274
$interpreter->registerProvider(new $provider());
7375
}
7476
}

0 commit comments

Comments
 (0)