Skip to content

Commit 96c2027

Browse files
Add config validation for xml configurations
On every run the xml configuration is validated against the .xsd file. Every validation error will be echoed as warning.
1 parent d39c729 commit 96c2027

File tree

5 files changed

+90
-5
lines changed

5 files changed

+90
-5
lines changed

build.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@
8989

9090
<exec executable="${basedir}/build/phar-manifest.php" output="${basedir}/build/phar/manifest.txt"/>
9191

92+
<!-- Copy .xsd for config validation -->
93+
<copy file="${basedir}/phpbu.xsd" tofile="${basedir}/build/phar/phpbu.xsd"/>
94+
9295
<!-- SF/CLI -->
9396
<copy file="${basedir}/vendor/sebastianfeldmann/cli/LICENSE" tofile="${basedir}/build/phar/lib/sf-cli/LICENSE"/>
9497
<copy todir="${basedir}/build/phar/lib/sf-cli">

src/Cmd.php

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,11 +186,25 @@ protected function findConfiguration() : string
186186
* @return \phpbu\App\Configuration
187187
* @throws \phpbu\App\Exception
188188
*/
189-
protected function createConfiguration(string $configurationFile, Factory $factory)
189+
protected function createConfiguration(string $configurationFile, Factory $factory) : Configuration
190190
{
191191
// setup bootstrapper with --bootstrap option that has precedence over the config file value
192192
$bootstrapper = new Bootstrapper(Arr::getValue($this->arguments, 'bootstrap', ''));
193193
$configLoader = Configuration\Loader\Factory::createLoader($configurationFile, $bootstrapper);
194+
195+
if ($configLoader->hasValidationErrors()) {
196+
echo " Warning - The configuration file did not pass validation!" . \PHP_EOL .
197+
" The following problems have been detected:" . \PHP_EOL;
198+
199+
foreach ($configLoader->getValidationErrors() as $line => $errors) {
200+
echo \sprintf("\n Line %d:\n", $line);
201+
foreach ($errors as $msg) {
202+
echo \sprintf(" - %s\n", $msg);
203+
}
204+
}
205+
echo \PHP_EOL;
206+
}
207+
194208
$configuration = $configLoader->getConfiguration($factory);
195209

196210
// command line arguments overrule the config file settings
@@ -265,7 +279,7 @@ protected function handleSelfUpdate()
265279
unset($phar);
266280
// replace current phar with the new one
267281
rename($tempFilename, $localFilename);
268-
} catch (Exception $e) {
282+
} catch (\Exception $e) {
269283
// cleanup crappy phar
270284
unlink($tempFilename);
271285
echo 'failed' . PHP_EOL . $e->getMessage() . PHP_EOL;

src/Configuration/Loader.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?php
22
namespace phpbu\App\Configuration;
33

4+
use phpbu\App\Configuration;
45
use phpbu\App\Factory;
56

67
/**
@@ -22,5 +23,19 @@ interface Loader
2223
* @param \phpbu\App\Factory $factory
2324
* @return \phpbu\App\Configuration
2425
*/
25-
public function getConfiguration(Factory $factory);
26+
public function getConfiguration(Factory $factory) : Configuration;
27+
28+
/**
29+
* Is the configuration valid
30+
*
31+
* @return bool
32+
*/
33+
public function hasValidationErrors() : bool;
34+
35+
/**
36+
* Return a list of all validation errors
37+
*
38+
* @return array
39+
*/
40+
public function getValidationErrors() : array;
2641
}

src/Configuration/Loader/File.php

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ abstract class File
4141
*/
4242
protected $bootstrapper;
4343

44+
/**
45+
* List of validation errors
46+
*
47+
* @var array
48+
*/
49+
protected $errors = [];
50+
4451
/**
4552
* File constructor
4653
*
@@ -53,14 +60,34 @@ public function __construct(string $file, Configuration\Bootstrapper $bootstrapp
5360
$this->bootstrapper = $bootstrapper;
5461
}
5562

63+
/**
64+
* Is the configuration valid
65+
*
66+
* @return bool
67+
*/
68+
public function hasValidationErrors(): bool
69+
{
70+
return \count($this->errors) > 0;
71+
}
72+
73+
/**
74+
* Return a list of all validation errors
75+
*
76+
* @return array
77+
*/
78+
public function getValidationErrors(): array
79+
{
80+
return $this->errors;
81+
}
82+
5683
/**
5784
* Returns the phpbu Configuration
5885
*
5986
* @param \phpbu\App\Factory $factory
6087
* @return \phpbu\App\Configuration
6188
* @throws \phpbu\App\Exception
6289
*/
63-
public function getConfiguration(AppFactory $factory)
90+
public function getConfiguration(AppFactory $factory) : Configuration
6491
{
6592
// create configuration first so the working directory is available for all adapters
6693
$configuration = new Configuration();

src/Configuration/Loader/Xml.php

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ public function __construct(string $file, Configuration\Bootstrapper $bootstrapp
9292
parent::__construct($file, $bootstrapper);
9393
$this->document = $this->loadXmlFile($file);
9494
$this->xpath = new DOMXPath($this->document);
95+
96+
$this->validateConfigurationAgainstSchema();
9597
}
9698

9799
/**
@@ -344,8 +346,9 @@ protected function setCleanup(Configuration\Backup $backup, DOMElement $node)
344346
/**
345347
* Extracts all option tags.
346348
*
347-
* @param DOMElement $node
349+
* @param \DOMElement $node
348350
* @return array
351+
* @throws \phpbu\App\Exception
349352
*/
350353
protected function getOptions(DOMElement $node)
351354
{
@@ -395,4 +398,27 @@ private function loadXmlFile($filename)
395398
}
396399
return $document;
397400
}
401+
402+
/**
403+
* Validate xml configuration against phpbu.xsd schema
404+
*
405+
* @return void
406+
*/
407+
private function validateConfigurationAgainstSchema() : void
408+
{
409+
$original = \libxml_use_internal_errors(true);
410+
$xsdFilename = __DIR__ . '/../../../phpbu.xsd';
411+
if (\defined('__PHPBU_PHAR_ROOT__')) {
412+
$xsdFilename = __PHPBU_PHAR_ROOT__ . '/phpbu.xsd';
413+
}
414+
$this->document->schemaValidate($xsdFilename);
415+
foreach (\libxml_get_errors() as $error) {
416+
if (!isset($this->errors[$error->line])) {
417+
$this->errors[$error->line] = [];
418+
}
419+
$this->errors[$error->line][] = \trim($error->message);
420+
}
421+
\libxml_clear_errors();
422+
\libxml_use_internal_errors($original);
423+
}
398424
}

0 commit comments

Comments
 (0)