Passed
Push — master ( f71b04...7dcb0c )
by P.R.
12:30
created

RoutineParametersHelper   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 174
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 65
dl 0
loc 174
rs 10
c 0
b 0
f 0
wmc 21

6 Methods

Rating   Name   Duplication   Size   Complexity  
A getParameters() 0 12 2
A enhanceParametersWithAddendum() 0 17 5
A __construct() 0 3 1
A enhanceTypeOfParameters() 0 28 4
A extractParametersAddendum() 0 25 4
A enhanceCharacterSet() 0 19 5
1
<?php
2
declare(strict_types=1);
3
4
namespace SetBased\Stratum\MySql\Loader\Helper;
5
6
use SetBased\Stratum\Common\Exception\RoutineLoaderException;
7
use SetBased\Stratum\Common\Loader\Helper\LoaderContext;
8
use SetBased\Stratum\MySql\MySqlMetadataLayer;
9
10
/**
11
 * Class for handling routine parameters.
12
 */
13
class RoutineParametersHelper
14
{
15
  //--------------------------------------------------------------------------------------------------------------------
16
  /**
17
   * The metadata layer.
18
   *
19
   * @var MySqlMetadataLayer
20
   */
21
  private MySqlMetadataLayer $dl;
22
23
  /**
24
   * The information about the parameters of the stored routine.
25
   *
26
   * @var array[]|null
27
   */
28
  private ?array $parameters = null;
29
30
  /**
31
   * Information about parameters with specific format (string in CSV format etc.).
32
   *
33
   * @var array
34
   */
35
  private array $parametersAddendum = [];
36
37
  //--------------------------------------------------------------------------------------------------------------------
38
  /**
39
   * Object constructor.
40
   *
41
   * @param MySqlMetadataLayer $dl The metadata layer.
42
   *
43
   */
44
  public function __construct(MySqlMetadataLayer $dl)
45
  {
46
    $this->dl = $dl;
47
  }
48
49
  //--------------------------------------------------------------------------------------------------------------------
50
  /**
51
   * Returns the metadata of all parameters.
52
   *
53
   * @param LoaderContext $context The loader context.
54
   */
55
  public function getParameters(LoaderContext $context): array
56
  {
57
    if ($this->parameters===null)
58
    {
59
      $this->parameters = $this->dl->routineParameters($context->storedRoutine->getName());
60
      $this->enhanceTypeOfParameters();
61
      $this->enhanceCharacterSet();
62
      $this->extractParametersAddendum($context);
63
      $this->enhanceParametersWithAddendum();
64
    }
65
66
    return $this->parameters;
67
  }
68
69
  //--------------------------------------------------------------------------------------------------------------------
70
  /**
71
   * Enhances parameters with character data with their character set.
72
   */
73
  private function enhanceCharacterSet(): void
74
  {
75
    foreach ($this->parameters as $key => $parameter)
76
    {
77
      if ($parameter['parameter_name'])
78
      {
79
        $dataTypeDescriptor = $parameter['dtd_identifier'];
80
        if (isset($parameter['character_set_name']))
81
        {
82
          $dataTypeDescriptor .= ' character set '.$parameter['character_set_name'];
83
        }
84
        if (isset($parameter['collation_name']))
85
        {
86
          $dataTypeDescriptor .= ' collation '.$parameter['collation_name'];
87
        }
88
89
        $parameter['dtd_identifier'] = $dataTypeDescriptor;
90
91
        $this->parameters[$key] = $parameter;
92
      }
93
    }
94
  }
95
96
  //--------------------------------------------------------------------------------------------------------------------
97
  /**
98
   * Updates parameters with data from parameter addendum tags.
99
   */
100
  private function enhanceParametersWithAddendum(): void
101
  {
102
    foreach ($this->parametersAddendum as $parameterName => $addendum)
103
    {
104
      $exists = false;
105
      foreach ($this->parameters as $key => $parameter)
106
      {
107
        if ($parameter['parameter_name']===$parameterName)
108
        {
109
          $this->parameters[$key] = array_merge($this->parameters[$key], $addendum);
110
          $exists                 = true;
111
          break;
112
        }
113
      }
114
      if (!$exists)
115
      {
116
        throw new RoutineLoaderException("Specific parameter '%s' does not exist", $parameterName);
117
      }
118
    }
119
  }
120
121
  //--------------------------------------------------------------------------------------------------------------------
122
  /**
123
   */
124
  private function enhanceTypeOfParameters(): void
125
  {
126
    foreach ($this->parameters as $key => $parameter)
127
    {
128
      if ($parameter['data_type']==='TYPE OF')
129
      {
130
        $n = preg_match('/^("(?<schema>[a-zA-Z0-9_]+)"\.)?("(?<table>[a-zA-Z0-9_]+)")\.("(?<column>[a-zA-Z0-9_]+)")%TYPE$/',
131
                        $parameter['dtd_identifier'],
132
                        $matches);
133
        if ($n!==1)
134
        {
135
          throw new RoutineLoaderException('Unable to parse data type description %s of parameter %s.',
136
                                           $parameter['dtd_identifier'],
137
                                           $parameter['parameter_name']);
138
        }
139
140
        $schemaName = $matches['schema'] ?? null;
141
        $tableName  = $matches['table'];
142
        $columnName = $matches['column'];
143
144
        $column = $this->dl->tableColumn($schemaName, $tableName, $columnName);
145
146
        $this->parameters[$key]['data_type']          = $column['data_type'];
147
        $this->parameters[$key]['numeric_precision']  = $column['numeric_precision'];
148
        $this->parameters[$key]['numeric_scale']      = $column['numeric_scale'];
149
        $this->parameters[$key]['character_set_name'] = $column['character_set_name'];
150
        $this->parameters[$key]['collation_name']     = $column['collation_name'];
151
        $this->parameters[$key]['dtd_identifier']     = $column['column_type'];
152
      }
153
    }
154
  }
155
156
  //--------------------------------------------------------------------------------------------------------------------
157
  /**
158
   * Extracts parameter addendum of the routine parameters.
159
   *
160
   * @param LoaderContext $context The loader context.
161
   */
162
  private function extractParametersAddendum(LoaderContext $context): void
163
  {
164
    $tags = $context->docBlock->getTags('paramAddendum');
165
    foreach ($tags as $tag)
166
    {
167
      $n = preg_match('/^(@paramAddendum)\s+(?<name>\w+)\s+(?<type>\w+)\s+(?<delimiter>.)\s+(?<enclosure>.)\s+(?<escape>.)$/s',
168
                      $tag,
169
                      $matches);
170
      if ($n!==1)
171
      {
172
        throw new RoutineLoaderException('Expected: @paramAddendum <name> <type_of_list> <delimiter> <enclosure> <escape>. Found %s',
173
                                         $tag);
174
      }
175
176
      $parameterName = $matches['name'];
177
      if (isset($this->parametersAddendum[$parameterName]))
178
      {
179
        throw new RoutineLoaderException("Duplicate @paramAddendum tag for parameter '%s'", $parameterName);
180
      }
181
182
      $this->parametersAddendum[$parameterName] = ['name'      => $parameterName,
183
                                                   'data_type' => $matches['type'],
184
                                                   'delimiter' => $matches['delimiter'],
185
                                                   'enclosure' => $matches['enclosure'],
186
                                                   'escape'    => $matches['escape']];
187
    }
188
  }
189
190
  //--------------------------------------------------------------------------------------------------------------------
191
}
192
193
//----------------------------------------------------------------------------------------------------------------------
194