Completed
Push — master ( 86b2cd...b16d12 )
by Richard
03:26
created

Report::template_path()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 20
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 14
nc 8
nop 1
dl 0
loc 20
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
namespace Lechimp\Dicto\Report;
4
5
/**
6
 * Base class for reports.
7
 */
8
abstract class Report {
9
    /**
10
     * @var Config
11
     */
12
    protected $config;
13
14
    /**
15
     * @var Queries 
16
     */
17
    protected $queries;
18
19
    public function __construct(Queries $queries, Config $config) {
20
        $this->queries = $queries;
21
        $this->config = $config;
22
    }
23
24
    /**
25
     * Get the default template for the report.
26
     *
27
     * This could be:
28
     *   - a filename, which is then assumed to be in templates-directory of
29
     *     dicto or in the current working directory, if not found in dicto
30
     *     templates
31
     *   - an absolute path
32
     *
33
     * @return string
34
     */
35
    abstract protected function default_template();
36
37
    /**
38
     * Get the name of the template.
39
     *
40
     * Uses config["template"] or falls back to default template.
41
     *
42
     * @return string
43
     */
44
    protected function template() {
45
        if (isset($this->config->config()["template"])) {
46
            return $this->config->config()["template"];
47
        }
48
        return $this->default_template();
49
    }
50
51
    /**
52
     * Get the absolute path for a template.
53
     *
54
     * Does only realpath(..) if an absolute path is given. Searches dicto-templates
55
     * directory, config-directory and current working directory otherwise.
56
     *
57
     * @throws  \InvalidArgumentException if none of the strategies leads to an
58
     *                                    existing file.
59
     * @param   string  $name
60
     * @return  string
61
     */
62
    protected function template_path($name) {
63
        $path = $name;
64
        if (substr($name, 0, 1) !== "/") {
65
            $candidates =
66
                [ __DIR__."/../../templates/{$name}.php"
67
                , __DIR__."/../../templates/{$name}"
68
                , $this->config->path()."/{$name}"
69
                ];
70
            foreach ($candidates as $candidate) {
71
                if (file_exists($candidate)) {
72
                    $path = $candidate;
73
                    break;
74
                }
75
            }
76
        }
77
        if (!file_exists($path)) {
78
            throw new \InvalidArgumentException("Can't find path to template '$name'.");
79
        }
80
        return realpath($path);
81
    }
82
83
    /**
84
     * Load a template from a path.
85
     *
86
     * Expects the file to contain a function with the same name as the file
87
     * (minus postfix) prefixed with template_, that writes to stdout.
88
     *
89
     * @param   string  $template_path
90
     * @return  \Closure    array -> null
91
     */
92
    protected function load_template($template_path) {
93
        $tpl_fct_name = $this->template_function_name($template_path);
94
        require_once($template_path);
95
        return function (array $report) use ($tpl_fct_name) {
96
            ob_start();
97
            $tpl_fct_name($report);
98
            return ob_get_clean();
99
        };
100
    }
101
102
    /**
103
     * Derive the name of the template function from a filename.
104
     *
105
     * @param   string  $path
106
     * @return  string
107
     */
108
    protected function template_function_name($path) {
109
        $matches = [];
110
        if (!preg_match("%(.*/)?([^./]+)[.]php%i", $path, $matches)) {
111
            throw new \RuntimeException("Path '$path' seems not to point to a template.");
112
        }
113
        return "template_".$matches[2];
114
    }
115
116
    /**
117
     * Generate the report.
118
     *
119
     * Should return a structured array containing the information in the report.
120
     *
121
     * @return array 
122
     */
123
    abstract public function generate();
124
125
    /**
126
     * Write the report to some handle using a template.
127
     *
128
     * @param   resource    $handle
129
     * @return  null
130
     */
131
    public function write($handle) {
132
        assert('is_resource($handle)');
133
        $template_path = $this->template_path($this->template());
134
        $template = $this->load_template($template_path);
135
        $report = $this->generate();
136
        $printed_report = $template($report);
137
        fputs($handle, $printed_report);
138
    }
139
}
140