Skip to content

Commit 69e8c76

Browse files
committed
refactor: create dedicated YamlParser class
1 parent 5767f53 commit 69e8c76

4 files changed

Lines changed: 166 additions & 13 deletions

File tree

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of Ymir command-line tool.
7+
*
8+
* (c) Carl Alexander <support@ymirapp.com>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Ymir\Cli\Exception;
15+
16+
class YamlParseException extends RuntimeException
17+
{
18+
}

src/Project/ProjectConfiguration.php

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@
2121
use Ymir\Cli\Exception\ConfigurationException;
2222
use Ymir\Cli\Exception\InvalidArgumentException;
2323
use Ymir\Cli\Exception\Project\UnsupportedProjectException;
24+
use Ymir\Cli\Exception\YamlParseException;
2425
use Ymir\Cli\Project\Configuration\ConfigurationChangeInterface;
2526
use Ymir\Cli\Project\Type\ProjectTypeInterface;
2627
use Ymir\Cli\Resource\Model\Project;
2728
use Ymir\Cli\Support\Arr;
29+
use Ymir\Cli\YamlParser;
2830

2931
class ProjectConfiguration implements Arrayable
3032
{
@@ -49,6 +51,13 @@ class ProjectConfiguration implements Arrayable
4951
*/
5052
private $filesystem;
5153

54+
/**
55+
* The YAML parser.
56+
*
57+
* @var YamlParser
58+
*/
59+
private $parser;
60+
5261
/**
5362
* All supported project types.
5463
*
@@ -59,9 +68,10 @@ class ProjectConfiguration implements Arrayable
5968
/**
6069
* Constructor.
6170
*/
62-
public function __construct(Filesystem $filesystem, iterable $projectTypes, string $configurationFilePath = '')
71+
public function __construct(Filesystem $filesystem, YamlParser $parser, iterable $projectTypes, string $configurationFilePath = '')
6372
{
6473
$this->filesystem = $filesystem;
74+
$this->parser = $parser;
6575

6676
$this->loadConfiguration($configurationFilePath);
6777

@@ -228,18 +238,10 @@ public function hasEnvironment(string $environment): bool
228238
*/
229239
public function loadConfiguration(string $configurationFilePath): void
230240
{
231-
$configuration = [];
232-
233-
if ($this->filesystem->exists($configurationFilePath)) {
234-
try {
235-
$configuration = Yaml::parse((string) file_get_contents($configurationFilePath));
236-
} catch (\Throwable $exception) {
237-
throw new ConfigurationException(sprintf('Error parsing Ymir project configuration file: %s', $exception->getMessage()));
238-
}
239-
}
240-
241-
if (!empty($configuration) && !is_array($configuration)) {
242-
throw new ConfigurationException('Error parsing Ymir project configuration file');
241+
try {
242+
$configuration = $this->parser->parse($configurationFilePath) ?? [];
243+
} catch (YamlParseException $exception) {
244+
throw new ConfigurationException(sprintf('Error parsing Ymir project configuration file: %s', $exception->getMessage()));
243245
}
244246

245247
$this->configuration = $configuration;

src/YamlParser.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of Ymir command-line tool.
7+
*
8+
* (c) Carl Alexander <support@ymirapp.com>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Ymir\Cli;
15+
16+
use Symfony\Component\Yaml\Yaml;
17+
use Ymir\Cli\Exception\YamlParseException;
18+
19+
class YamlParser
20+
{
21+
/**
22+
* Parse the given YAML file.
23+
*/
24+
public function parse(string $filePath): ?array
25+
{
26+
if (!file_exists($filePath)) {
27+
return null;
28+
}
29+
30+
$contents = file_get_contents($filePath);
31+
32+
if (false === $contents) {
33+
throw new YamlParseException(sprintf('Unable to read the YAML file at "%s"', $filePath));
34+
}
35+
36+
try {
37+
$configuration = Yaml::parse($contents);
38+
} catch (\Throwable $exception) {
39+
throw new YamlParseException(sprintf('Error parsing YAML file at "%s": %s', $filePath, $exception->getMessage()));
40+
}
41+
42+
if (null === $configuration) {
43+
return [];
44+
} elseif (!is_array($configuration)) {
45+
throw new YamlParseException(sprintf('Error parsing YAML file at "%s"', $filePath));
46+
}
47+
48+
return $configuration;
49+
}
50+
}

tests/Unit/YamlParserTest.php

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of Ymir command-line tool.
7+
*
8+
* (c) Carl Alexander <support@ymirapp.com>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Ymir\Cli\Tests\Unit;
15+
16+
use Ymir\Cli\Exception\YamlParseException;
17+
use Ymir\Cli\Tests\TestCase;
18+
use Ymir\Cli\YamlParser;
19+
20+
class YamlParserTest extends TestCase
21+
{
22+
/**
23+
* @var string
24+
*/
25+
private $tempFile;
26+
27+
protected function setUp(): void
28+
{
29+
parent::setUp();
30+
31+
$this->tempFile = tempnam(sys_get_temp_dir(), 'ymir-yaml-parser-test');
32+
}
33+
34+
protected function tearDown(): void
35+
{
36+
if (file_exists($this->tempFile)) {
37+
unlink($this->tempFile);
38+
}
39+
40+
parent::tearDown();
41+
}
42+
43+
public function testParseReturnsArray(): void
44+
{
45+
file_put_contents($this->tempFile, "foo: bar\nbaz: 123");
46+
47+
$this->assertSame(['foo' => 'bar', 'baz' => 123], (new YamlParser())->parse($this->tempFile));
48+
}
49+
50+
public function testParseReturnsEmptyArrayWhenFileIsEmpty(): void
51+
{
52+
file_put_contents($this->tempFile, '');
53+
54+
$this->assertSame([], (new YamlParser())->parse($this->tempFile));
55+
}
56+
57+
public function testParseReturnsNullWhenFileDoesNotExist(): void
58+
{
59+
unlink($this->tempFile);
60+
61+
$this->assertNull((new YamlParser())->parse($this->tempFile));
62+
}
63+
64+
public function testParseThrowsExceptionWhenParsedYamlIsNotArray(): void
65+
{
66+
file_put_contents($this->tempFile, 'foo');
67+
68+
$this->expectException(YamlParseException::class);
69+
$this->expectExceptionMessage('Error parsing YAML file at');
70+
71+
(new YamlParser())->parse($this->tempFile);
72+
}
73+
74+
public function testParseThrowsExceptionWhenYamlIsInvalid(): void
75+
{
76+
file_put_contents($this->tempFile, 'invalid yaml: [');
77+
78+
$this->expectException(YamlParseException::class);
79+
$this->expectExceptionMessage('Error parsing YAML file at');
80+
81+
(new YamlParser())->parse($this->tempFile);
82+
}
83+
}

0 commit comments

Comments
 (0)