Passed
Push — master ( 2e64cc...304ce4 )
by P.R.
03:51
created

MySqlRoutineWrapperGeneratorWorker   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 256
Duplicated Lines 0 %

Test Coverage

Coverage 96.34%

Importance

Changes 0
Metric Value
eloc 80
c 0
b 0
f 0
dl 0
loc 256
ccs 79
cts 82
cp 0.9634
rs 10
wmc 20

8 Methods

Rating   Name   Duplication   Size   Complexity  
A storeWrapperClass() 0 4 1
B writeClassHeader() 0 57 7
A execute() 0 10 2
A writeRoutineFunction() 0 6 1
A readRoutineMetadata() 0 5 1
A writeClassTrailer() 0 6 1
A readConfigurationFile() 0 10 2
A generateWrapperClass() 0 41 5
1
<?php
2
declare(strict_types=1);
3
4
namespace SetBased\Stratum\MySql\Backend;
5
6
use SetBased\Exception\RuntimeException;
7
use SetBased\Helper\CodeStore\PhpCodeStore;
8
use SetBased\Stratum\Backend\RoutineWrapperGeneratorWorker;
9
use SetBased\Stratum\Common\Helper\Util;
10
use SetBased\Stratum\Middle\NameMangler\NameMangler;
11
use SetBased\Stratum\MySql\Helper\RoutineLoaderHelper;
12
use SetBased\Stratum\MySql\Helper\StratumMetadata;
13
use SetBased\Stratum\MySql\Wrapper\Wrapper;
14
15
/**
16
 * Command for generating a class with wrapper methods for calling stored routines in a MySQL database.
17
 */
18
class MySqlRoutineWrapperGeneratorWorker extends MySqlWorker implements RoutineWrapperGeneratorWorker
19
{
20
  //--------------------------------------------------------------------------------------------------------------------
21
  /**
22
   * Store php code with indention.
23
   *
24
   * @var PhpCodeStore
25
   */
26
  private $codeStore;
27
28
  /**
29
   * Array with fully qualified names that must be imported.
30
   *
31
   * @var array
32
   */
33
  private $imports = [];
34
35
  /**
36
   * The filename of the file with the metadata of all stored procedures.
37
   *
38
   * @var string
39
   */
40
  private $metadataFilename;
41
42
  /**
43
   * Class name for mangling routine and parameter names.
44
   *
45
   * @var string
46
   */
47
  private $nameMangler;
48
49
  /**
50
   * The class name (including namespace) of the parent class of the routine wrapper.
51
   *
52
   * @var string
53
   */
54
  private $parentClassName;
55
56
  /**
57
   * If true wrapper must declare strict types.
58
   *
59
   * @var bool
60
   */
61
  private $strictTypes;
62
63
  /**
64
   * The class name (including namespace) of the routine wrapper.
65
   *
66
   * @var string
67
   */
68
  private $wrapperClassName;
69
70
  /**
71
   * The filename where the generated wrapper class must be stored
72
   *
73
   * @var string
74
   */
75
  private $wrapperFilename;
76
77
  //--------------------------------------------------------------------------------------------------------------------
78
  /**
79
   * @inheritdoc
80
   *
81
   * @throws RuntimeException
82
   */
83 1
  public function execute(): int
84
  {
85 1
    $this->readConfigurationFile();
86
87 1
    if ($this->wrapperClassName!==null)
88
    {
89 1
      $this->generateWrapperClass();
90
    }
91
92 1
    return 0;
93
  }
94
95
  //--------------------------------------------------------------------------------------------------------------------
96
  /**
97
   * Generates the wrapper class.
98
   *
99
   * @throws RuntimeException
100
   */
101 1
  private function generateWrapperClass(): void
102
  {
103 1
    $this->io->title('PhpStratum: MySql Wrapper');
104
105 1
    $this->codeStore = new PhpCodeStore();
106
107
    /** @var NameMangler $mangler */
108 1
    $mangler  = new $this->nameMangler();
109 1
    $routines = $this->readRoutineMetadata();
110
111 1
    if (!empty($routines))
112
    {
113
      // Sort routines by their wrapper method name.
114 1
      $sortedRoutines = [];
115 1
      foreach ($routines as $routine)
116
      {
117 1
        $methodName                  = $mangler->getMethodName($routine['routine_name']);
118 1
        $sortedRoutines[$methodName] = $routine;
119
      }
120 1
      ksort($sortedRoutines);
121
122
      // Write methods for each stored routine.
123 1
      foreach ($sortedRoutines as $methodName => $routine)
124
      {
125 1
        if ($routine['designation']!=='hidden')
126
        {
127 1
          $this->writeRoutineFunction($routine, $mangler);
128
        }
129
      }
130
    }
131
    else
132
    {
133
      echo "No files with stored routines found.\n";
134
    }
135
136 1
    $wrappers        = $this->codeStore->getRawCode();
137 1
    $this->codeStore = new PhpCodeStore();
138 1
    $this->writeClassHeader();
139 1
    $this->codeStore->append($wrappers, false);
140 1
    $this->writeClassTrailer();
141 1
    $this->storeWrapperClass();
142 1
  }
143
144
  //--------------------------------------------------------------------------------------------------------------------
145
  /**
146
   * Reads parameters from the configuration file.
147
   */
148 1
  private function readConfigurationFile(): void
149
  {
150 1
    $this->wrapperClassName = $this->settings->optString('wrapper.wrapper_class');
151 1
    if ($this->wrapperClassName!==null)
152
    {
153 1
      $this->parentClassName  = $this->settings->manString('wrapper.parent_class');
154 1
      $this->nameMangler      = $this->settings->manString('wrapper.mangler_class');
155 1
      $this->wrapperFilename  = $this->settings->manString('wrapper.wrapper_file');
156 1
      $this->metadataFilename = $this->settings->manString('loader.metadata');
157 1
      $this->strictTypes      = $this->settings->manBool('wrapper.strict_types', true);
158
    }
159 1
  }
160
161
  //--------------------------------------------------------------------------------------------------------------------
162
  /**
163
   * Returns the metadata of stored routines.
164
   *
165
   * @return array
166
   *
167
   * @throws RuntimeException
168
   */
169 1
  private function readRoutineMetadata(): array
170
  {
171 1
    $stratumMetadata = new StratumMetadata($this->metadataFilename, RoutineLoaderHelper::METADATA_REVISION);
172
173 1
    return $stratumMetadata->getAllMetadata();
174
  }
175
176
  //--------------------------------------------------------------------------------------------------------------------
177
  /**
178
   * Writes the wrapper class to the filesystem.
179
   */
180 1
  private function storeWrapperClass(): void
181
  {
182 1
    $code = $this->codeStore->getCode();
183 1
    Util::writeTwoPhases($this->wrapperFilename, $code, $this->io);
184 1
  }
185
186
  //--------------------------------------------------------------------------------------------------------------------
187
  /**
188
   * Generate a class header for stored routine wrapper.
189
   */
190 1
  private function writeClassHeader(): void
191
  {
192 1
    $p = strrpos($this->wrapperClassName, '\\');
193 1
    if ($p!==false)
194
    {
195 1
      $namespace = ltrim(substr($this->wrapperClassName, 0, $p), '\\');
196 1
      $className = substr($this->wrapperClassName, $p + 1);
197
    }
198
    else
199
    {
200
      $namespace = null;
201
      $className = $this->wrapperClassName;
202
    }
203
204
    // Write PHP tag.
205 1
    $this->codeStore->append('<?php');
206
207
    // Write strict types.
208 1
    if ($this->strictTypes)
209
    {
210 1
      $this->codeStore->append('declare(strict_types=1);');
211
    }
212
213
    // Write name space of the wrapper class.
214 1
    if ($namespace!==null)
215
    {
216 1
      $this->codeStore->append('');
217 1
      $this->codeStore->append(sprintf('namespace %s;', $namespace));
218 1
      $this->codeStore->append('');
219
    }
220
221
    // If the child class and parent class have different names import the parent class. Otherwise use the fully
222
    // qualified parent class name.
223 1
    $parentClassName = substr($this->parentClassName, strrpos($this->parentClassName, '\\') + 1);
224 1
    if ($className!==$parentClassName)
225
    {
226 1
      $this->imports[]       = $this->parentClassName;
227 1
      $this->parentClassName = $parentClassName;
228
    }
229
230
    // Write use statements.
231 1
    if (!empty($this->imports))
232
    {
233 1
      $this->imports = array_unique($this->imports, SORT_REGULAR);
234 1
      foreach ($this->imports as $import)
235
      {
236 1
        $this->codeStore->append(sprintf('use %s;', $import));
237
      }
238 1
      $this->codeStore->append('');
239
    }
240
241
    // Write class name.
242 1
    $this->codeStore->append('/**');
243 1
    $this->codeStore->append(' * The data layer.', false);
244 1
    $this->codeStore->append(' */', false);
245 1
    $this->codeStore->append(sprintf('class %s extends %s', $className, $this->parentClassName));
246 1
    $this->codeStore->append('{');
247 1
  }
248
249
  //--------------------------------------------------------------------------------------------------------------------
250
  /**
251
   * Generate a class trailer for stored routine wrapper.
252
   */
253 1
  private function writeClassTrailer(): void
254
  {
255 1
    $this->codeStore->appendSeparator();
256 1
    $this->codeStore->append('}');
257 1
    $this->codeStore->append('');
258 1
    $this->codeStore->appendSeparator();
259 1
  }
260
261
  //--------------------------------------------------------------------------------------------------------------------
262
  /**
263
   * Generates a complete wrapper method for a stored routine.
264
   *
265
   * @param array       $routine     The metadata of the stored routine.
266
   * @param NameMangler $nameMangler The mangler for wrapper and parameter names.
267
   */
268 1
  private function writeRoutineFunction(array $routine, NameMangler $nameMangler): void
269
  {
270 1
    $wrapper = Wrapper::createRoutineWrapper($routine, $this->codeStore, $nameMangler);
271 1
    $wrapper->writeRoutineFunction();
272
273 1
    $this->imports = array_merge($this->imports, $wrapper->getImports());
274 1
  }
275
276
  //--------------------------------------------------------------------------------------------------------------------
277
}
278
279
//----------------------------------------------------------------------------------------------------------------------
280