0, 'dynfilters' => false, 'summarize' => false, 'rownumbers' => false, 'sepbyheaders' => false, 'target' => '', 'align' => [], 'headers' => [], 'cols' => [], 'widths' => [], 'filter' => [], 'schemas' => [], 'sort' => [], 'csv' => true, 'nesting' => 0, 'index' => 0, 'classes' => [] ]; /** * Parser constructor. * * parses the given configuration lines * * @param $lines */ public function __construct($lines) { /** @var \helper_plugin_struct_config $helper */ $helper = plugin_load('helper', 'struct_config'); // parse info foreach ($lines as $line) { [$key, $val] = $this->splitLine($line); if (!$key) continue; $logic = 'OR'; // handle line commands (we allow various aliases here) switch ($key) { case 'from': case 'schema': case 'tables': $this->config['schemas'] = array_merge($this->config['schemas'], $this->parseSchema($val)); break; case 'select': case 'cols': case 'field': case 'col': $this->config['cols'] = $this->parseValues($val); break; case 'sepbyheaders': $this->config['sepbyheaders'] = (bool)$val; break; case 'head': case 'header': case 'headers': $this->config['headers'] = $this->parseValues($val); break; case 'align': $this->config['align'] = $this->parseAlignments($val); break; case 'width': case 'widths': $this->config['widths'] = $this->parseWidths($val); break; case 'min': $this->config['min'] = abs((int)$val); break; case 'limit': case 'max': $this->config['limit'] = abs((int)$val); break; case 'order': case 'sort': $sorts = $this->parseValues($val); $sorts = array_map([$helper, 'parseSort'], $sorts); $this->config['sort'] = array_merge($this->config['sort'], $sorts); break; case 'where': case 'filter': case 'filterand': // phpcs:ignore PSR2.ControlStructures.SwitchDeclaration.TerminatingComment /** @noinspection PhpMissingBreakStatementInspection */ case 'and': // phpcs:ignore PSR2.ControlStructures.SwitchDeclaration.TerminatingComment $logic = 'AND'; case 'filteror': case 'or': $flt = $helper->parseFilterLine($logic, $val); if ($flt) { $this->config['filter'][] = $flt; } break; case 'dynfilters': $this->config['dynfilters'] = (bool)$val; break; case 'rownumbers': $this->config['rownumbers'] = (bool)$val; break; case 'summarize': $this->config['summarize'] = (bool)$val; break; case 'csv': $this->config['csv'] = (bool)$val; break; case 'target': case 'page': $this->config['target'] = cleanID($val); break; case 'nesting': case 'nest': $this->config['nesting'] = (int) $val; break; case 'index': $this->config['index'] = (int) $val; break; case 'class': case 'classes': $this->config['classes'] = $this->parseClasses($val); break; default: $data = ['config' => &$this->config, 'key' => $key, 'val' => $val]; $ev = new Event('PLUGIN_STRUCT_CONFIGPARSER_UNKNOWNKEY', $data); if ($ev->advise_before()) { throw new StructException("unknown option '%s'", hsc($key)); } $ev->advise_after(); } } // fill up headers - a NULL signifies that the column label is wanted $this->config['headers'] = (array)$this->config['headers']; $cnth = count($this->config['headers']); $cntf = count($this->config['cols']); for ($i = $cnth; $i < $cntf; $i++) { $this->config['headers'][] = null; } // fill up alignments $cnta = count($this->config['align']); for ($i = $cnta; $i < $cntf; $i++) { $this->config['align'][] = null; } } /** * Get the parsed configuration * * @return array */ public function getConfig() { return $this->config; } /** * Splits the given line into key and value * * @param $line * @return array returns ['',''] if the line is empty */ protected function splitLine($line) { // ignore comments $line = preg_replace('/(? 0) { $values[] = trim($value); } return $values; } /** * Ensure custom classes are valid and don't clash * * @param string $line * @return string[] */ protected function parseClasses($line) { $classes = $this->parseValues($line); $classes = array_map(function ($class) { $class = str_replace(' ', '_', $class); $class = preg_replace('/[^a-zA-Z0-9_]/', '', $class); return 'struct-custom-' . $class; }, $classes); return $classes; } }