Skip to content

Commit

Permalink
Modular config files
Browse files Browse the repository at this point in the history
This change introduces an option to have the configuration split across
several files using standard XInclude tags. This may be useful for more
complex configs, or to include auto-generated parts into a manually
written config file.
  • Loading branch information
weirdan committed Jan 16, 2020
1 parent 7b887ef commit fd58a18
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 7 deletions.
23 changes: 23 additions & 0 deletions docs/running_psalm/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,29 @@ Psalm uses an XML config file (by default, `psalm.xml`). A barebones example loo
</psalm>
```

Configuration file may be split into several files using [XInclude](https://www.w3.org/TR/xinclude/) tags (c.f. previous example):
#### psalm.xml
```xml
<?xml version="1.0"?>
<psalm
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
xmlns:xi="http://www.w3.org/2001/XInclude"
>
<xi:include href="files.xml"/>
</psalm>
```
#### files.xml
```xml
<?xml version="1.0" encoding="UTF-8"?>
<projectFiles xmlns="https://getpsalm.org/schema/config">
<file name="Bar.php" />
<file name="Bat.php" />
</projectFiles>
```


## Optional `<psalm />` attributes

### Coding style
Expand Down
34 changes: 27 additions & 7 deletions src/Psalm/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
use function array_unique;
use function class_exists;
use Composer\Autoload\ClassLoader;
use DOMDocument;

use function count;
use const DIRECTORY_SEPARATOR;
use function dirname;
Expand Down Expand Up @@ -65,6 +67,9 @@
use function trigger_error;
use function unlink;
use function version_compare;
use function getcwd;
use function chdir;
use function simplexml_import_dom;

class Config
{
Expand Down Expand Up @@ -605,25 +610,39 @@ public static function loadFromXML($base_dir, $file_contents, $current_dir = nul
$current_dir = $base_dir;
}

self::validateXmlConfig($file_contents);
self::validateXmlConfig($base_dir, $file_contents);

return self::fromXmlAndPaths($base_dir, $file_contents, $current_dir);
}

private static function loadDomDocument(string $base_dir, string $file_contents): DOMDocument
{
$dom_document = new DOMDocument();

// there's no obvious way to set xml:base for a document when loading it from string
// so instead we're changing the current directory instead to be able to process XIncludes
$oldpwd = getcwd();
chdir($base_dir);

$dom_document->loadXML($file_contents, LIBXML_NONET);
$dom_document->xinclude(LIBXML_NONET);

chdir($oldpwd);
return $dom_document;
}

/**
* @throws ConfigException
*/
private static function validateXmlConfig(string $file_contents): void
private static function validateXmlConfig(string $base_dir, string $file_contents): void
{
$schema_path = dirname(dirname(__DIR__)) . '/config.xsd';

if (!file_exists($schema_path)) {
throw new ConfigException('Cannot locate config schema');
}

$dom_document = new \DOMDocument();
$dom_document->loadXML($file_contents);
$dom_document = self::loadDomDocument($base_dir, $file_contents);

$psalm_nodes = $dom_document->getElementsByTagName('psalm');

Expand All @@ -640,8 +659,7 @@ private static function validateXmlConfig(string $file_contents): void
$psalm_node->setAttribute('xmlns', 'https://getpsalm.org/schema/config');

$old_dom_document = $dom_document;
$dom_document = new \DOMDocument();
$dom_document->loadXML($old_dom_document->saveXML());
$dom_document = self::loadDomDocument($base_dir, $old_dom_document->saveXML());
}

// Enable user error handling
Expand Down Expand Up @@ -674,7 +692,9 @@ private static function fromXmlAndPaths(string $base_dir, string $file_contents,
{
$config = new static();

$config_xml = new SimpleXMLElement($file_contents);
$dom_document = self::loadDomDocument($base_dir, $file_contents);

$config_xml = simplexml_import_dom($dom_document);

$booleanAttributes = [
'useDocblockTypes' => 'use_docblock_types',
Expand Down
14 changes: 14 additions & 0 deletions tests/Config/ConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1195,6 +1195,20 @@ public function testTemplatedFiles()
}
}

/** @return void */
public function testModularConfig()
{
$root = __DIR__ . '/../fixtures/ModularConfig';
$config = Config::loadFromXMLFile($root . '/psalm.xml', $root);
$this->assertEquals(
[
realpath($root . '/Bar.php'),
realpath($root . '/Bat.php')
],
$config->getProjectFiles()
);
}

public function tearDown(): void
{
parent::tearDown();
Expand Down
23 changes: 23 additions & 0 deletions tests/fixtures/ModularConfig/Bar.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php
namespace Vimeo\Test\DummyProject;

class Bar
{
use SomeTrait;

/** @var string */
public $x;

public function __construct()
{
$this->x = 'hello';
}
}

/**
* @return void
*/
function someFunction()
{
echo 'here';
}
13 changes: 13 additions & 0 deletions tests/fixtures/ModularConfig/Bat.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php
namespace Vimeo\Test\DummyProject;

class Bat
{
public function __construct()
{
$a = new Bar();

someFunction();
someOtherFunction();
}
}
14 changes: 14 additions & 0 deletions tests/fixtures/ModularConfig/SomeTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php
namespace Vimeo\Test\DummyProject;

trait SomeTrait
{
}

/**
* @return void
*/
function someOtherFunction()
{
echo 'here';
}
5 changes: 5 additions & 0 deletions tests/fixtures/ModularConfig/files.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectFiles xmlns="https://getpsalm.org/schema/config">
<file name="Bar.php" />
<file name="Bat.php" />
</projectFiles>
10 changes: 10 additions & 0 deletions tests/fixtures/ModularConfig/psalm.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0"?>
<psalm
totallyTyped="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
xmlns:xi="http://www.w3.org/2001/XInclude"
>
<xi:include href="files.xml"/>
</psalm>

0 comments on commit fd58a18

Please sign in to comment.