From ed17f70713be32d87b8a510382814f92431c03ff Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marko=20Ivan=C4=8Di=C4=87?= <marko.ivancic@srce.hr>
Date: Mon, 13 Jun 2022 16:45:29 +0200
Subject: [PATCH] WIP

---
 .gitignore                                    |  1 +
 composer.json                                 |  5 +++
 config-templates/module_accounting.php        |  4 +-
 phpcs.xml                                     | 17 +++++++
 phpunit.xml                                   | 42 ++++++++++++++++++
 psalm.xml                                     | 39 ++++++++++++++++
 routing/routes/{routes.yaml => routes.yml}    |  0
 routing/services/services.yml                 |  7 +++
 src/Controller/Test.php                       | 14 ++++--
 .../InvalidConfigurationNameException.php     |  7 +++
 src/ModuleConfiguration.php                   | 44 +++++++++++++++++++
 templates/configuration.twig                  |  3 +-
 tests/ModuleConfigurationTest.php             | 20 +++++++++
 .../module_accounting_basic.php               |  5 +++
 14 files changed, 202 insertions(+), 6 deletions(-)
 create mode 100644 phpcs.xml
 create mode 100644 phpunit.xml
 create mode 100644 psalm.xml
 rename routing/routes/{routes.yaml => routes.yml} (100%)
 create mode 100644 routing/services/services.yml
 create mode 100644 src/Exceptions/ModuleConfiguration/InvalidConfigurationNameException.php
 create mode 100644 src/ModuleConfiguration.php
 create mode 100644 tests/ModuleConfigurationTest.php
 create mode 100644 tests/config-templates/module_accounting_basic.php

diff --git a/.gitignore b/.gitignore
index f7f8ac3..c73b3bb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 /.idea/
 /vendor/
+/build/
\ No newline at end of file
diff --git a/composer.json b/composer.json
index b24da28..499865c 100644
--- a/composer.json
+++ b/composer.json
@@ -19,6 +19,11 @@
             "SimpleSAML\\Module\\accounting\\": "src/"
         }
     },
+    "autoload-dev": {
+        "psr-4": {
+            "SimpleSAML\\Test\\Module\\accounting\\": "tests/"
+        }
+    },
     "require": {
         "php": "^7.4 || ^8.0",
         "ext-pdo": "*",
diff --git a/config-templates/module_accounting.php b/config-templates/module_accounting.php
index 8efd023..29497c1 100644
--- a/config-templates/module_accounting.php
+++ b/config-templates/module_accounting.php
@@ -1,5 +1,5 @@
 <?php
 
 $config = [
-
-];
\ No newline at end of file
+    'test-config' => 'test-value',
+];
diff --git a/phpcs.xml b/phpcs.xml
new file mode 100644
index 0000000..2ea895d
--- /dev/null
+++ b/phpcs.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<ruleset name="SimpleSAMLphp accounting module ruleset">
+
+    <file>config-templates</file>
+    <file>src</file>
+    <file>tests</file>
+    <file>www</file>
+
+    <!-- Use this to exclude paths. You can have multiple patterns -->
+    <!--<exclude-pattern>*/tests/*</exclude-pattern>-->
+    <!--<exclude-pattern>*/other/*</exclude-pattern>-->
+    <exclude-pattern>www/assets/*</exclude-pattern>
+
+    <!-- This is the rule we inherit from. If you want to exlude some specific rules, see the docs on how to do that -->
+    <rule ref="PSR12"/>
+</ruleset>
+
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000..cd24325
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd"
+         bootstrap="vendor/autoload.php"
+         cacheResultFile="build/.phpunit.cache/test-results"
+         executionOrder="depends,defects"
+         forceCoversAnnotation="true"
+         beStrictAboutCoversAnnotation="true"
+         beStrictAboutOutputDuringTests="true"
+         beStrictAboutTodoAnnotatedTests="true"
+         convertDeprecationsToExceptions="true"
+         failOnRisky="true"
+         failOnWarning="true"
+         verbose="true">
+
+    <testsuites>
+        <testsuite name="default">
+            <directory>tests</directory>
+        </testsuite>
+    </testsuites>
+
+    <coverage cacheDirectory="build/.phpunit.cache/code-coverage"
+              processUncoveredFiles="true">
+        <include>
+            <directory suffix=".php">src</directory>
+        </include>
+
+        <report>
+            <clover outputFile="build/coverage/clover.xml"/>
+            <html outputDirectory="build/coverage/html"/>
+            <text outputFile="php://stdout"/>
+        </report>
+    </coverage>
+
+    <logging>
+        <junit outputFile="build/logs/junit.xml"/>
+    </logging>
+
+    <php>
+        <env name="SIMPLESAMLPHP_CONFIG_DIR" value="tests/config-templates"/>
+    </php>
+</phpunit>
diff --git a/psalm.xml b/psalm.xml
new file mode 100644
index 0000000..d95e939
--- /dev/null
+++ b/psalm.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<psalm
+    errorLevel="1"
+    resolveFromConfigFile="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"
+>
+    <projectFiles>
+        <directory name="src" />
+        <directory name="config-templates" />
+        <directory name="tests" />
+        <directory name="www" />
+
+        <ignoreFiles>
+            <directory name="vendor" />
+        </ignoreFiles>
+    </projectFiles>
+
+    <issueHandlers>
+        <!-- Ignore the fact that $config variable is not used in particular config files. -->
+        <UnusedVariable>
+            <errorLevel type="suppress">
+                <directory name="config-templates" />
+                <directory name="tests/config-templates" />
+            </errorLevel>
+        </UnusedVariable>
+
+        <!--
+        Ignore PropertyNotSetInConstructor for phpunit tests. For example, this will ignore things like
+        "Property SomeTestClass::$backupStaticAttributes is not defined in constructor of SomeTestClass..."
+        -->
+        <PropertyNotSetInConstructor>
+            <errorLevel type="suppress">
+                <directory name="tests" />
+            </errorLevel>
+        </PropertyNotSetInConstructor>
+    </issueHandlers>
+</psalm>
diff --git a/routing/routes/routes.yaml b/routing/routes/routes.yml
similarity index 100%
rename from routing/routes/routes.yaml
rename to routing/routes/routes.yml
diff --git a/routing/services/services.yml b/routing/services/services.yml
new file mode 100644
index 0000000..18958e2
--- /dev/null
+++ b/routing/services/services.yml
@@ -0,0 +1,7 @@
+services:
+  # default configuration for services in *this* file
+  _defaults:
+    public: false
+
+  SimpleSAML\Module\accounting\ModuleConfiguration:
+    class: SimpleSAML\Module\accounting\ModuleConfiguration
\ No newline at end of file
diff --git a/src/Controller/Test.php b/src/Controller/Test.php
index 58ef2fc..ec6d040 100644
--- a/src/Controller/Test.php
+++ b/src/Controller/Test.php
@@ -4,6 +4,7 @@ namespace SimpleSAML\Module\accounting\Controller;
 
 use SimpleSAML\Configuration;
 use SimpleSAML\Locale\Translate;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
 use SimpleSAML\Session;
 use SimpleSAML\XHTML\Template;
 use Symfony\Component\HttpFoundation\Request;
@@ -12,15 +13,21 @@ class Test
 {
     protected Configuration $configuration;
     protected Session $session;
+    protected ModuleConfiguration $moduleConfiguration;
 
     /**
      * @param Configuration $configuration
      * @param Session $session The current user session.
+     * @param ModuleConfiguration $moduleConfiguration
      */
-    public function __construct(Configuration $configuration, Session $session)
-    {
+    public function __construct(
+        Configuration $configuration,
+        Session $session,
+        ModuleConfiguration $moduleConfiguration
+    ) {
         $this->configuration = $configuration;
         $this->session = $session;
+        $this->moduleConfiguration = $moduleConfiguration;
     }
 
     /**
@@ -30,10 +37,11 @@ class Test
      */
     public function test(Request $request): Template
     {
-        $template = new Template(Configuration::getConfig(), 'accounting:configuration.twig');
+        $template = new Template($this->configuration, 'accounting:configuration.twig');
 
         $template->data = [
             'test' => Translate::noop('Accounting'),
+            'test_config' => $this->moduleConfiguration->getConfiguration()->getString('test_config'),
         ];
 
         return $template;
diff --git a/src/Exceptions/ModuleConfiguration/InvalidConfigurationNameException.php b/src/Exceptions/ModuleConfiguration/InvalidConfigurationNameException.php
new file mode 100644
index 0000000..46e091d
--- /dev/null
+++ b/src/Exceptions/ModuleConfiguration/InvalidConfigurationNameException.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace SimpleSAML\Module\accounting\Exceptions;
+
+class InvalidConfigurationNameException extends \InvalidArgumentException
+{
+}
diff --git a/src/ModuleConfiguration.php b/src/ModuleConfiguration.php
new file mode 100644
index 0000000..528ec94
--- /dev/null
+++ b/src/ModuleConfiguration.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace SimpleSAML\Module\accounting;
+
+use SimpleSAML\Configuration;
+use SimpleSAML\Module\accounting\Exceptions\InvalidConfigurationNameException;
+
+class ModuleConfiguration
+{
+    protected Configuration $configuration;
+
+    public const FILE_NAME = 'module_accounting.php';
+
+    /**
+     * @throws \Exception
+     */
+    public function __construct(string $fileName = null)
+    {
+        $fileName = $fileName ?? self::FILE_NAME;
+
+        $this->configuration = Configuration::getConfig($fileName);
+    }
+
+    /**
+     * @param string $name
+     * @return mixed
+     */
+    public function getValue(string $name)
+    {
+        if (! $this->configuration->hasValue($name)) {
+            throw new InvalidConfigurationNameException(sprintf('Config name does not exist (%s).', $name));
+        }
+
+        return $this->configuration->getValue($name);
+    }
+
+    /**
+     * @return Configuration
+     */
+    public function getConfiguration(): Configuration
+    {
+        return $this->configuration;
+    }
+}
diff --git a/templates/configuration.twig b/templates/configuration.twig
index 645af5a..78db9bd 100644
--- a/templates/configuration.twig
+++ b/templates/configuration.twig
@@ -12,7 +12,8 @@
     <h2>{{ pagetitle }} </h2>
 
     <p>
-        {{ test }}
+        {{ test }}, <br>
+        {{ test_config }}
     </p>
 
 {% endblock %}
diff --git a/tests/ModuleConfigurationTest.php b/tests/ModuleConfigurationTest.php
new file mode 100644
index 0000000..6184e79
--- /dev/null
+++ b/tests/ModuleConfigurationTest.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace SimpleSAML\Test\Module\accounting;
+
+use PHPUnit\Framework\TestCase;
+use SimpleSAML\Configuration;
+use SimpleSAML\Module\accounting\ModuleConfiguration;
+
+/**
+ * @covers \SimpleSAML\Module\accounting\ModuleConfiguration
+ */
+class ModuleConfigurationTest extends TestCase
+{
+    public function testSample(): void
+    {
+        $moduleConfiguration = new ModuleConfiguration('module_accounting_basic.php');
+
+        $this->assertInstanceOf(Configuration::class, $moduleConfiguration->getConfiguration());
+    }
+}
diff --git a/tests/config-templates/module_accounting_basic.php b/tests/config-templates/module_accounting_basic.php
new file mode 100644
index 0000000..29497c1
--- /dev/null
+++ b/tests/config-templates/module_accounting_basic.php
@@ -0,0 +1,5 @@
+<?php
+
+$config = [
+    'test-config' => 'test-value',
+];
-- 
GitLab