Issues (82)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

tests/integration/QueueWorkflowTest.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Maketok\DataMigration\IntegrationTest;
4
5
use Faker\Generator;
6
use Faker\Provider\Address;
7
use Faker\Provider\Base;
8
use Faker\Provider\Internet;
9
use Faker\Provider\Lorem;
10
use Faker\Provider\Person;
11
use Maketok\DataMigration\Action\ConfigInterface;
12
use Maketok\DataMigration\Action\Type\AssembleInput;
13
use Maketok\DataMigration\Action\Type\CreateTmpFiles;
14
use Maketok\DataMigration\Action\Type\Delete;
15
use Maketok\DataMigration\Action\Type\Dump;
16
use Maketok\DataMigration\Action\Type\Generate;
17
use Maketok\DataMigration\Action\Type\Load;
18
use Maketok\DataMigration\Action\Type\Move;
19
use Maketok\DataMigration\Action\Type\ReverseMove;
20
use Maketok\DataMigration\ArrayMap;
21
use Maketok\DataMigration\Expression\HelperExpressionsProvider;
22
use Maketok\DataMigration\Expression\LanguageAdapter;
23
use Maketok\DataMigration\Hashmap\ArrayHashmap;
24
use Maketok\DataMigration\Input\Csv;
25
use Maketok\DataMigration\Input\Shaper\Processor\Duplicates;
26
use Maketok\DataMigration\Input\Shaper\Processor\Nulls;
27
use Maketok\DataMigration\QueueWorkflow;
28
use Maketok\DataMigration\Storage\Db\DBALMysqlResource;
29
use Maketok\DataMigration\Storage\Db\DBALMysqlResourceHelper;
30
use Maketok\DataMigration\Unit\SimpleBag;
31
use Maketok\DataMigration\Unit\Type\Unit;
32
use Maketok\DataMigration\Workflow\Result;
33
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
34
35
class QueueWorkflowTest extends \PHPUnit_Extensions_Database_TestCase
0 ignored issues
show
The class QueueWorkflowTest has a coupling between objects value of 40. Consider to reduce the number of dependencies under 13.
Loading history...
36
{
37
    /**
38
     * @var ConfigInterface
39
     */
40
    private $config;
41
    /**
42
     * @var DBALMysqlResource
43
     */
44
    private $resource;
45
    /**
46
     * @var \PDO
47
     */
48
    private $pdo;
49
50
    /**
51
     * {@inheritdoc}
52
     */
53
    protected function setUp()
54
    {
55
        $config = include __DIR__ . '/Storage/Db/assets/config.php';
56
        if (isset($config) && $config instanceof ConfigInterface) {
57
            $this->config = $config;
58
            $this->config['tmp_folder'] = __DIR__ . '/assets';
59
            $this->config['tmp_file_mask'] = 'tmp%2$s/%1$s.csv';
60
            $this->config['tmp_table_mask'] = 'tmp_%1$s_%2$s';
61
            $this->config['local_infile'] = true;
62
            $this->resource = new DBALMysqlResource($this->config);
63
            $ref1 = new \ReflectionProperty(get_class($this->resource->getConnection()), '_conn');
64
            $ref1->setAccessible(true);
65
            $this->pdo = $ref1->getValue($this->resource->getConnection());
66
        } else {
67
            throw new \Exception("Can't find config file.");
68
        }
69
70
        parent::setUp();
71
72
        // assert that 2 pdo's are same
73
        $pdo1 = $this->getConnection()->getConnection();
74
        $pdo2 = $ref1->getValue($this->resource->getConnection());
75
76
        $this->assertSame($pdo1, $pdo2);
77
    }
78
79
    protected function tearDown()
80
    {
81
        parent::tearDown();
82
        $this->resource->close();
83
    }
84
85
    /**
86
     * Set Up Schema
87
     */
88
    public static function setUpBeforeClass()
89
    {
90
        require_once __DIR__ . '/bootstrap.php';
91
    }
92
93
    /**
94
     * {@inheritdoc}
95
     */
96
    protected function getConnection()
97
    {
98
        if (isset($this->pdo)) {
99
            return $this->createDefaultDBConnection($this->pdo);
100
        }
101
        throw new \Exception("Can't find pdo in config.");
102
    }
103
104
    /**
105
     * {@inheritdoc}
106
     */
107
    protected function getTearDownOperation()
108
    {
109
        if ($this->config['db_debug']) {
110
            return \PHPUnit_Extensions_Database_Operation_Factory::NONE();
111
        }
112
        return \PHPUnit_Extensions_Database_Operation_Factory::TRUNCATE();
113
    }
114
115
    /**
116
     * {@inheritdoc}
117
     */
118
    protected function getDataSet()
119
    {
120
        return $this->createXMLDataSet(__DIR__ . '/assets/initialStructure.xml');
121
    }
122
123
    /**
124
     * @return LanguageAdapter
125
     */
126
    public function getLanguageAdapter()
127
    {
128
        $language = new ExpressionLanguage();
129
        $language->registerProvider(new HelperExpressionsProvider());
130
        return new LanguageAdapter($language);
131
    }
132
133
    /**
134
     * @return Unit
135
     * @throws \Doctrine\DBAL\DBALException
136
     */
137
    public function prepareCustomerImportUnit()
138
    {
139
        $customerUnit = new Unit('customers');
140
        $customerUnit->setTable('customers');
141
        $hashMap = new ArrayHashmap('email-id');
142
        $hashMap->load($this->resource->getConnection()
143
            ->executeQuery("SELECT email,id FROM customers")
144
            ->fetchAll(\PDO::FETCH_KEY_PAIR));
145
        $customerUnit->addHashmap($hashMap);
146
        $contribution1 = <<<CONTRIBUTION
147
map.offsetSet(
148
    'customer_id',
149
    (isset(hashmaps['email-id'][trim(map.email)]) ?
150
        hashmaps['email-id'][trim(map.email)] :
151
        map.frozenIncr('new_customer_id', 3))
152
)
153
CONTRIBUTION;
154
        $customerUnit->addContribution($contribution1);
155
        $contribution2 = <<<CONTRIBUTION
156
map.offsetSet(
157
    'complexName',
158
    explode(' ', map.name)
159
)
160
CONTRIBUTION;
161
        $customerUnit->addContribution($contribution2);
162
        $contribution3 = <<<CONTRIBUTION
163
map.offsetSet(
164
    'firstname',
165
    (count(map.complexName) >= 2 && isset(map.complexName[0]) ? map.complexName[0] : map.name)
166
)
167
CONTRIBUTION;
168
        $customerUnit->addContribution($contribution3);
169
        $contribution4 = <<<CONTRIBUTION
170
map.offsetSet(
171
    'lastname',
172
    (count(map.complexName) >= 2 && isset(map.complexName[1]) ? map.complexName[1] : '')
173
)
174
CONTRIBUTION;
175
        $customerUnit->addContribution($contribution4);
176
        $customerUnit->setMapping([
177
            'id' => 'map.customer_id',
178
            'firstname' => 'map.firstname',
179
            'lastname' => 'map.lastname',
180
            'age' => 'map.age',
181
            'email' => 'trim(map.email)',
182
        ]);
183
        $customerUnit->setIsEntityCondition("trim(map.email) != trim(oldmap.email)");
184
        return $customerUnit;
185
    }
186
187
    /**
188
     * @return Unit
189
     */
190
    public function prepareAddressImportUnit()
191
    {
192
        $addressUnit = new Unit("addresses");
193
        $addressUnit->setTable('addresses');
194
        $addressUnit->setMapping([
195
            'id' => 'map.incr("address_id", 4)',
196
            'street' => 'map.street',
197
            'city' => 'map.city',
198
            'parent_id' => 'map.customer_id',
199
        ]);
200
        return $addressUnit;
201
    }
202
203
    /**
204
     * @test
205
     * @throws \Doctrine\DBAL\DBALException
206
     */
207
    public function testSimpleImport()
208
    {
209
        // SET THESE TO TRUE TO DEBUG
210
        $this->config['db_debug'] = false;
211
        $this->config['file_debug'] = false;
212
        //=====================================================================
213
        $customerUnit = $this->prepareCustomerImportUnit();
214
        $addressUnit = $this->prepareAddressImportUnit();
215
        $addressUnit->setParent($customerUnit);
216
        //=====================================================================
217
        $bag = new SimpleBag();
218
        // order matters ;)
219
        $bag->add($customerUnit);
220
        $bag->add($addressUnit);
221
        //=====================================================================
222
        $input = new Csv(__DIR__ . '/assets/customers_1.csv', 'r', new Duplicates(
223
            $bag,
224
            new ArrayMap(),
225
            $this->getLanguageAdapter())
226
        );
227
        $createTmpFiles = new CreateTmpFiles($bag, $this->config, $this->getLanguageAdapter(),
228
            $input, new ArrayMap(), new DBALMysqlResourceHelper($this->resource));
229
        $load = new Load($bag, $this->config, $this->resource);
230
        $move = new Move($bag, $this->config, $this->resource);
231
        //=====================================================================
232
        $result = new Result();
233
        $workflow = new QueueWorkflow($this->config, $result);
234
        $workflow->add($createTmpFiles);
235
        $workflow->add($load);
236
        $workflow->add($move);
237
        $workflow->execute();
238
        //=====================================================================
239
        // time to assert things
240
241
        // assert schema
242
        $expected = $this->createXMLDataSet(__DIR__ . '/assets/afterSimpleImportStructure.xml');
243
        $actual = $this->getConnection()->createDataSet(['customers', 'addresses']);
244
        $this->assertDataSetsEqual($expected, $actual);
245
    }
246
247
    /**
248
     * @test
249
     * @throws \Doctrine\DBAL\DBALException
250
     */
251
    public function testSimpleImport2Nulls()
252
    {
253
        // SET THESE TO TRUE TO DEBUG
254
        $this->config['db_debug'] = false;
255
        $this->config['file_debug'] = false;
256
        //=====================================================================
257
        $customerUnit = $this->prepareCustomerImportUnit();
258
        $addressUnit = $this->prepareAddressImportUnit();
259
        $addressUnit->setParent($customerUnit);
260
        //=====================================================================
261
        $bag = new SimpleBag();
262
        // order matters ;)
263
        $bag->add($customerUnit);
264
        $bag->add($addressUnit);
265
        //=====================================================================
266
        $input = new Csv(__DIR__ . '/assets/customers_2_nulls.csv', 'r', new Nulls(
267
            $bag,
268
            new ArrayMap(),
269
            $this->getLanguageAdapter())
270
        );
271
        $createTmpFiles = new CreateTmpFiles($bag, $this->config, $this->getLanguageAdapter(),
272
            $input, new ArrayMap(), new DBALMysqlResourceHelper($this->resource));
273
        $load = new Load($bag, $this->config, $this->resource);
274
        $move = new Move($bag, $this->config, $this->resource);
275
        //=====================================================================
276
        $result = new Result();
277
        $workflow = new QueueWorkflow($this->config, $result);
278
        $workflow->add($createTmpFiles);
279
        $workflow->add($load);
280
        $workflow->add($move);
281
        $workflow->execute();
282
        //=====================================================================
283
        // time to assert things
284
285
        // assert schema
286
        $expected = $this->createXMLDataSet(__DIR__ . '/assets/afterSimpleImportStructure.xml');
287
        $actual = $this->getConnection()->createDataSet(['customers', 'addresses']);
288
        $this->assertDataSetsEqual($expected, $actual);
289
    }
290
291
    /**
292
     * @test
293
     */
294
    public function testImportWithExisting()
295
    {
296
        // SET THESE TO TRUE TO DEBUG
297
        $this->config['db_debug'] = false;
298
        $this->config['file_debug'] = false;
299
        //=====================================================================
300
        $customerUnit = $this->prepareCustomerImportUnit();
301
        $addressUnit = $this->prepareAddressImportUnit();
302
        $addressUnit->setParent($customerUnit);
303
        //=====================================================================
304
        // order matters ;)
305
        $bag = new SimpleBag();
306
        $bag->add($customerUnit);
307
        $bag->add($addressUnit);
308
        //=====================================================================
309
        $input = new Csv(__DIR__ . '/assets/customers_2.csv', 'r', new Duplicates(
310
            $bag,
311
            new ArrayMap(),
312
            $this->getLanguageAdapter())
313
        );
314
        $createTmpFiles = new CreateTmpFiles($bag, $this->config, $this->getLanguageAdapter(),
315
            $input, new ArrayMap(), new DBALMysqlResourceHelper($this->resource));
316
        $load = new Load($bag, $this->config, $this->resource);
317
        $move = new Move($bag, $this->config, $this->resource);
318
        //=====================================================================
319
        $result = new Result();
320
        $workflow = new QueueWorkflow($this->config, $result);
321
        $workflow->add($createTmpFiles);
322
        $workflow->add($load);
323
        $workflow->add($move);
324
        $workflow->execute();
325
        //=====================================================================
326
        // time to assert things
327
328
        // assert schema
329
        $expected = $this->createXMLDataSet(__DIR__ . '/assets/afterImportWithExistingStructure.xml');
330
        $actual = $this->getConnection()->createDataSet(['customers', 'addresses']);
331
        $this->assertDataSetsEqual($expected, $actual);
332
    }
333
334
    /**
335
     * @test
336
     */
337
    public function testImportDeleteAddresses()
338
    {
339
        // SET THESE TO TRUE TO DEBUG
340
        $this->config['db_debug'] = false;
341
        $this->config['file_debug'] = false;
342
        //=====================================================================
343
        $customerUnit = $this->prepareCustomerImportUnit();
344
        $addressUnit = $this->prepareAddressImportUnit();
345
        $addressUnit->setParent($customerUnit);
346
        //=====================================================================
347
        // order matters ;)
348
        $bag = new SimpleBag();
349
        $bag->add($customerUnit);
350
        $bag->add($addressUnit);
351
        //=====================================================================
352
        $input = new Csv(__DIR__ . '/assets/customers_2.csv', 'r', new Duplicates(
353
            $bag,
354
            new ArrayMap(),
355
            $this->getLanguageAdapter())
356
        );
357
        $createTmpFiles = new CreateTmpFiles($bag, $this->config, $this->getLanguageAdapter(),
358
            $input, new ArrayMap(), new DBALMysqlResourceHelper($this->resource));
359
        $load = new Load($bag, $this->config, $this->resource);
360
        $move = new Move($bag, $this->config, $this->resource);
361
        //=====================================================================
362
        $deleteAddressUnit = new Unit('deleteAddress');
363
        $deleteAddressUnit->setTable('addresses');
364
        $deleteAddressUnit->addWriteCondition("isset(map.address_id)");
365
        $contribution = <<<CONTRIBUTION
366
map.offsetSet(
367
    'address_id',
368
    (isset(hashmaps['email-address'][trim(map.email)]) ?
369
        hashmaps['email-address'][trim(map.email)] :
370
        null)
371
)
372
CONTRIBUTION;
373
374
        $deleteAddressUnit->addContribution($contribution);
375
        $deleteAddressUnit->setMapping(['id' => 'explode(",", map.address_id)']);
376
377
        $hashMap = new ArrayHashmap('email-address');
378
        $sql = <<<MYSQL
379
SELECT c.email,GROUP_CONCAT(a.id) FROM customers c
380
LEFT JOIN addresses a ON a.parent_id = c.id
381
GROUP BY c.email
382
MYSQL;
383
384
        $hashMap->load($this->resource->getConnection()
385
            ->executeQuery($sql)
386
            ->fetchAll(\PDO::FETCH_KEY_PAIR));
387
        $deleteAddressUnit->addHashmap($hashMap);
388
        $deleteAddressUnit->setPk('id');
389
390
        $deleteBag = new SimpleBag();
391
        $deleteBag->add($deleteAddressUnit);
392
393
        $delCreateTmpFiles = new CreateTmpFiles($deleteBag, $this->config, $this->getLanguageAdapter(),
394
            $input, new ArrayMap(), new DBALMysqlResourceHelper($this->resource));
395
        $delLoad = new Load($deleteBag, $this->config, $this->resource);
396
        $delete = new Delete($deleteBag, $this->config, $this->resource);
397
        //=====================================================================
398
        $result = new Result();
399
        $workflow = new QueueWorkflow($this->config, $result);
400
        $workflow->add($createTmpFiles);
401
        $workflow->add($load);
402
        $workflow->add($delCreateTmpFiles);
403
        $workflow->add($delLoad);
404
        $workflow->add($delete);
405
        $workflow->add($move);
406
        try {
407
            $this->resource->startTransaction();
408
            $workflow->execute();
409
            $this->resource->commit();
410
        } catch (\Exception $e) {
411
            $this->resource->rollback();
412
            throw $e;
413
        }
414
        //=====================================================================
415
        // time to assert things
416
417
        // assert schema
418
        $expected = $this->createXMLDataSet(__DIR__ . '/assets/afterImportDeleteAddressStructure.xml');
419
        $actual = $this->getConnection()->createDataSet(['customers', 'addresses']);
420
        $this->assertDataSetsEqual($expected, $actual);
421
    }
422
423
    /**
424
     * @test
425
     * @throws \Doctrine\DBAL\DBALException
426
     * @throws \Exception
427
     */
428
    public function testImportGenerate()
429
    {
430
        // SET THESE TO TRUE TO DEBUG
431
        $this->config['db_debug'] = false;
432
        $this->config['file_debug'] = false;
433
        //=====================================================================
434
        $bag = new SimpleBag();
435
        $cu = $this->getGenerateCustomerUnit();
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $cu. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
436
        $au = $this->getGenerateAddressUnit();
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $au. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
437
        $au->setParent($cu);
438
        $bag->add($cu);
439
        $bag->add($au);
440
441
        $generator = new Generator();
442
        $generator->addProvider(new Base($generator));
443
        $generator->addProvider(new Lorem($generator));
444
        $generator->addProvider(new Person($generator));
445
        $generator->addProvider(new Address($generator));
446
        $generator->addProvider(new Internet($generator));
447
448
        // truncate all info beforehand to not run into issue with duplicate email
449
        $this->resource->getConnection()->executeUpdate("DELETE FROM customers");
450
451
        $generate = new Generate($bag, $this->config, $this->getLanguageAdapter(),
452
            $generator, 100, new ArrayMap(), new DBALMysqlResourceHelper($this->resource));
453
        $load = new Load($bag, $this->config, $this->resource);
454
        $move = new Move($bag, $this->config, $this->resource);
455
456
        $result = new Result();
457
        $workflow = new QueueWorkflow($this->config, $result);
458
        $workflow->add($generate);
459
        $workflow->add($load);
460
        $workflow->add($move);
461
        try {
462
            $this->resource->startTransaction();
463
            $workflow->execute();
464
            $this->resource->commit();
465
        } catch (\Exception $e) {
466
            $this->resource->rollback();
467
            throw $e;
468
        }
469
470
        $this->assertTableRowCount('customers', 100);
471
    }
472
473
    /**
474
     * @return Unit
475
     */
476
    protected function getGenerateCustomerUnit()
477
    {
478
        $customerUnit = new Unit('customers');
479
        $customerUnit->setGeneratorMapping([
480
            'id' => 'map.frozenIncr("customer_id", resource.getLastIncrement("customers"))',
481
            'firstname' => 'generator.firstName',
482
            'lastname' => 'generator.lastName',
483
            'age' => 'generator.numberBetween(10, 60)',
484
            'email' => 'generator.unique().email',
485
        ]);
486
        $customerUnit->setMapping([
487
            'id' => "",
488
            'firstname' => "",
489
            'lastname' => "",
490
            'age' => "",
491
            'email' => "",
492
        ]);
493
        $customerUnit->setTable("customers");
494
        return $customerUnit;
495
    }
496
497
    protected function getGenerateAddressUnit()
498
    {
499
        $addressUnit = new Unit('addresses');
500
        $seed = new \SplFixedArray(2);
501
        $seed[0] = 4;
502
        $seed[1] = 1;
503
        $addressUnit->setGenerationSeed($seed);
504
        $addressUnit->setGeneratorMapping([
505
            'id' => 'map.incr("address_id", resource.getLastIncrement("addresses"))',
506
            'parent_id' => 'map.customer_id',
507
            'street' => 'generator.streetAddress',
508
            'city' => 'generator.city',
509
        ]);
510
        $addressUnit->setMapping([
511
            'id' => '',
512
            'parent_id' => '',
513
            'street' => '',
514
            'city' => '',
515
        ]);
516
        $addressUnit->setTable('addresses');
517
        return $addressUnit;
518
    }
519
520
    /**
521
     * @test
522
     */
523
    public function testGenerateExport()
524
    {
525
        // SET THESE TO TRUE TO DEBUG
526
        $this->config['db_debug'] = false;
527
        $this->config['file_debug'] = false;
528
        //=====================================================================
529
        $cUnit = $this->getGenerateCustomerUnit();
530
        $cUnit->setReversedConnection([
531
            'customer_id' => 'id',
532
        ]);
533
        $cUnit->setReversedMapping([
534
            'email' => 'map.email',
535
            'name' => 'map.firstname ~ " " ~ map.lastname',
536
            'age' => 'map.age',
537
        ]);
538
        $aUnit = $this->getGenerateAddressUnit();
539
        $aUnit->setReversedConnection([
540
            'customer_id' => 'parent_id',
541
        ]);
542
        $aUnit->setReversedMapping([
543
            'street' => 'map.street',
544
            'city' => 'map.city',
545
        ]);
546
        $aUnit->setParent($cUnit);
547
548
        $bag = new SimpleBag();
549
        $bag->add($cUnit);
550
        $bag->add($aUnit);
551
552
        $generator = new Generator();
553
        $generator->addProvider(new Base($generator));
554
        $generator->addProvider(new Lorem($generator));
555
        $generator->addProvider(new Person($generator));
556
        $generator->addProvider(new Address($generator));
557
        $generator->addProvider(new Internet($generator));
558
559
        // truncate all info beforehand to not run into issue with duplicate email
560
        $this->resource->getConnection()->executeUpdate("DELETE FROM customers");
561
562
        $fname = __DIR__ . '/assets/results/customers_generated.csv';
563
        $input = new Csv($fname, 'w', new Duplicates($bag, new ArrayMap(), $this->getLanguageAdapter()));
564
565
        $generate = new Generate($bag, $this->config, $this->getLanguageAdapter(),
566
            $generator, 100, new ArrayMap(), new DBALMysqlResourceHelper($this->resource));
567
        $assemble = new AssembleInput($bag, $this->config, $this->getLanguageAdapter(), $input, new ArrayMap());
568
569
        $result = new Result();
570
        $workflow = new QueueWorkflow($this->config, $result);
571
        $workflow->add($generate);
572
        $workflow->add($assemble);
573
574
        $workflow->execute();
575
        //=====================================================================
576
        // assert that customers are in the file
577
578
        $this->assertFileExists($fname);
579
        $this->assertGreaterThan(100, $this->getNumberOfLines($fname));
580
    }
581
582
    /**
583
     * @test
584
     */
585
    public function testGenerateExport2Branches()
586
    {
587
        // SET THESE TO TRUE TO DEBUG
588
        $this->config['db_debug'] = false;
589
        $this->config['file_debug'] = false;
590
        //=====================================================================
591
        $cUnit = $this->getGenerateCustomerUnit();
592
        $cUnit->setReversedConnection([
593
            'customer_id' => 'id',
594
        ]);
595
        $cUnit->setReversedMapping([
596
            'email' => 'map.email',
597
            'age' => 'map.age',
598
        ]);
599
        $cdUnit = new Unit('customer_data');
600
        $seed = new \SplFixedArray(2);
601
        $seed[0] = 1;
602
        $seed[1] = 1;
603
        $cdUnit->setGenerationSeed($seed);
604
        $cdUnit->setGeneratorMapping([
605
            'id' => 'map.incr("gen_id", 1)',
606
            'parent_id' => 'map.customer_id',
607
            'firstname' => 'generator.firstName',
608
            'lastname' => 'generator.lastName',
609
        ]);
610
        $cdUnit->setMapping([
611
            'id' => '',
612
            'parent_id' => '',
613
            'firstname' => '',
614
            'lastname' => '',
615
        ]);
616
        $cdUnit->setTable('customers');
617
        $cdUnit->setReversedConnection([
618
            'customer_id' => 'parent_id',
619
        ]);
620
        $cdUnit->setReversedMapping([
621
            'name' => 'map.firstname ~ " " ~ map.lastname',
622
        ]);
623
        $cdUnit->addSibling($cUnit);
624
625
        $bag = new SimpleBag();
626
        $bag->add($cUnit);
627
        $bag->add($cdUnit);
628
629
        $generator = new Generator();
630
        $generator->addProvider(new Base($generator));
631
        $generator->addProvider(new Lorem($generator));
632
        $generator->addProvider(new Person($generator));
633
        $generator->addProvider(new Address($generator));
634
        $generator->addProvider(new Internet($generator));
635
636
        // truncate all info beforehand to not run into issue with duplicate email
637
        $this->resource->getConnection()->executeUpdate("DELETE FROM customers");
638
639
        $fname = __DIR__ . '/assets/results/customers_data_generated.csv';
640
        $input = new Csv($fname, 'w', new Duplicates($bag, new ArrayMap(), $this->getLanguageAdapter()));
641
642
        $generate = new Generate($bag, $this->config, $this->getLanguageAdapter(),
643
            $generator, 100, new ArrayMap(), new DBALMysqlResourceHelper($this->resource));
644
        $assemble = new AssembleInput($bag, $this->config, $this->getLanguageAdapter(), $input, new ArrayMap());
645
646
        $result = new Result();
647
        $workflow = new QueueWorkflow($this->config, $result);
648
        $workflow->add($generate);
649
        $workflow->add($assemble);
650
651
        $workflow->execute();
652
        //=====================================================================
653
        // assert that customers are in the file
654
655
        $this->assertFileExists($fname);
656
        $this->assertEquals(101, $this->getNumberOfLines($fname));
657
    }
658
659
    /**
660
     * @test
661
     */
662
    public function testSimpleExport()
663
    {
664
        // SET THESE TO TRUE TO DEBUG
665
        $this->config['db_debug'] = false;
666
        $this->config['file_debug'] = false;
667
        //=====================================================================
668
        $this->config['dump_limit'] = 100;
669
670
        $cUnit = new Unit('customers');
671
        $aUnit = new Unit('addresses');
672
        //=====================================================================
673
        $cUnit->setTable('customers');
674
        $aUnit->setTable('addresses');
675
        $cUnit->setReverseMoveOrder(['id']);
676
        $cUnit->setReverseMoveDirection('asc');
677
        $aUnit->setReverseMoveOrder(['parent_id']);
678
        $aUnit->setReverseMoveDirection('asc');
679
        //=====================================================================
680
        $cUnit->setMapping([
681
            'id' => "",
682
            'firstname' => "",
683
            'lastname' => "",
684
            'age' => "",
685
            'email' => "",
686
        ]);
687
        $aUnit->setMapping([
688
            'id' => '',
689
            'parent_id' => '',
690
            'street' => '',
691
            'city' => '',
692
        ]);
693
        $cUnit->setReversedConnection([
694
            'customer_id' => 'id',
695
        ]);
696
        $cUnit->setReversedMapping([
697
            'email' => 'map.email',
698
            'name' => 'map.firstname ~ " " ~ map.lastname',
699
            'age' => 'map.age',
700
        ]);
701
        $aUnit->setReversedConnection([
702
            'customer_id' => 'parent_id',
703
        ]);
704
        $aUnit->setReversedMapping([
705
            'street' => 'map.street',
706
            'city' => 'map.city',
707
        ]);
708
        $aUnit->setParent($cUnit);
709
        //=====================================================================
710
        $bag = new SimpleBag();
711
        $bag->addSet([$cUnit, $aUnit]);
712
713
        $fname = __DIR__ . '/assets/results/customers_data_exported.csv';
714
        $input = new Csv($fname, 'w', new Duplicates($bag, new ArrayMap(), $this->getLanguageAdapter()));
715
716
        $reverseMove = new ReverseMove($bag, $this->config, $this->resource);
717
        $dump = new Dump($bag, $this->config, $this->resource);
718
        $assemble = new AssembleInput($bag, $this->config, $this->getLanguageAdapter(), $input, new ArrayMap());
719
720
        $result = new Result();
721
        $workflow = new QueueWorkflow($this->config, $result);
722
        $workflow->add($reverseMove);
723
        $workflow->add($dump);
724
        $workflow->add($assemble);
725
726
        $workflow->execute();
727
        //=====================================================================
728
        // assert that customers are in the file
729
730
        $this->assertFileExists($fname);
731
        $this->assertEquals(4, $this->getNumberOfLines($fname));
732
    }
733
734
    public function testExportNull()
735
    {
736
        // SET THESE TO TRUE TO DEBUG
737
        $this->config['db_debug'] = false;
738
        $this->config['file_debug'] = false;
739
        //=====================================================================
740
        $this->config['dump_limit'] = 100;
741
742
        $cUnit = new Unit('customers');
743
        //=====================================================================
744
        $cUnit->setTable('customers');
745
        $cUnit->setReverseMoveOrder(['id']);
746
        $cUnit->setReverseMoveDirection('asc');
747
        //=====================================================================
748
        $cUnit->setMapping([
749
            'id' => "",
750
            'firstname' => "",
751
            'lastname' => "",
752
            'age' => "",
753
            'email' => "",
754
        ]);
755
        $cUnit->setReversedConnection([
756
            'customer_id' => 'id',
757
        ]);
758
        $cUnit->setReversedMapping([
759
            'email' => 'map.email',
760
            'name' => 'map.firstname ~ " " ~ map.lastname',
761
            'age' => 'map.age',
762
        ]);
763
        //=====================================================================
764
        $bag = new SimpleBag();
765
        $bag->add($cUnit);
766
767
        // truncate all info beforehand to not run into issue with duplicate email
768
        $this->resource->getConnection()->executeUpdate("DELETE FROM customers");
769
        $this->resource->getConnection()->insert('customers', [
770
            'id' => 1,
771
            'firstname' => 'test1',
772
            'lastname' => 'test1',
773
            'age' => null,
774
            'email' => '[email protected]',
775
        ]);
776
777
        $fname = __DIR__ . '/assets/results/customers_data_exported_with_nulls.csv';
778
        $input = new Csv($fname, 'w', new Duplicates($bag, new ArrayMap(), $this->getLanguageAdapter()));
779
780
        $reverseMove = new ReverseMove($bag, $this->config, $this->resource);
781
        $dump = new Dump($bag, $this->config, $this->resource);
782
        $assemble = new AssembleInput($bag, $this->config, $this->getLanguageAdapter(), $input, new ArrayMap());
783
784
        $result = new Result();
785
        $workflow = new QueueWorkflow($this->config, $result);
786
        $workflow->add($reverseMove);
787
        $workflow->add($dump);
788
        $workflow->add($assemble);
789
790
        $workflow->execute();
791
        //=====================================================================
792
        // assert that customers are in the file
793
794
        $this->assertFileExists($fname);
795
        $this->assertEquals(2, $this->getNumberOfLines($fname));
796
        $csvObject = new \SplFileObject($fname, 'r');
797
        $csvObject->fgetcsv();
798
        $actual = $csvObject->fgetcsv();
799
        $this->assertEquals([
800
            '[email protected]',
801
            'test1 test1',
802
            '\N',
803
        ], $actual);
804
    }
805
806
    /**
807
     * @param string $fname
808
     * @return int
809
     */
810
    public function getNumberOfLines($fname)
811
    {
812
        $fileObject = new \SplFileObject($fname, 'r');
813
        $i = 0;
814
        while (!$fileObject->eof()) {
815
            $fileObject->next();
816
            $current = $fileObject->current();
817
            if (!empty($current)) {
818
                $i++;
819
            }
820
        }
821
        return $i;
822
    }
823
}
824