'audit', '' => 'index' ]; /** * @var array */ private static $allowed_actions = [ 'index', 'audit', ]; /** * Note: config() method is already defined, so let's just use index() * * @return string|HTTPResponse */ public function index() { $body = ''; $subtitle = "Config manifest"; if (Director::is_cli()) { $body .= sprintf("\n%s\n\n", strtoupper($subtitle ?? '')); $body .= Yaml::dump(Config::inst()->getAll(), 99, 2, Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE); } else { $renderer = DebugView::create(); $body .= $renderer->renderHeader(); $body .= $renderer->renderInfo("Configuration", Director::absoluteBaseURL()); $body .= "
"; $body .= sprintf("

%s

", $subtitle); $body .= "
";
            $body .= Yaml::dump(Config::inst()->getAll(), 99, 2, Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE);
            $body .= "
"; $body .= "
"; $body .= $renderer->renderFooter(); } return $this->getResponse()->setBody($body); } /** * Output the extraneous config properties which are defined in .yaml but not in a corresponding class * * @return string|HTTPResponse */ public function audit() { $body = ''; $missing = []; $subtitle = "Missing Config property definitions"; foreach ($this->array_keys_recursive(Config::inst()->getAll(), 2) as $className => $props) { $props = array_keys($props ?? []); if (!count($props ?? [])) { // We can skip this entry continue; } if ($className == strtolower(Injector::class)) { // We don't want to check the injector config continue; } foreach ($props as $prop) { $defined = false; // Check ancestry (private properties don't inherit natively) foreach (ClassInfo::ancestry($className) as $cn) { if (property_exists($cn, $prop ?? '')) { $defined = true; break; } } if ($defined) { // No need to record this property continue; } $missing[] = sprintf("%s::$%s\n", $className, $prop); } } $output = count($missing ?? []) ? implode("\n", $missing) : "All configured properties are defined\n"; if (Director::is_cli()) { $body .= sprintf("\n%s\n\n", strtoupper($subtitle ?? '')); $body .= $output; } else { $renderer = DebugView::create(); $body .= $renderer->renderHeader(); $body .= $renderer->renderInfo( "Configuration", Director::absoluteBaseURL(), "Config properties that are not defined (or inherited) by their respective classes" ); $body .= "
"; $body .= sprintf("

%s

", $subtitle); $body .= sprintf("
%s
", $output); $body .= "
"; $body .= $renderer->renderFooter(); } return $this->getResponse()->setBody($body); } /** * Returns all the keys of a multi-dimensional array while maintining any nested structure * * @param array $array * @param int $maxdepth * @param int $depth * @param array $arrayKeys * @return array */ private function array_keys_recursive($array, $maxdepth = 20, $depth = 0, $arrayKeys = []) { if ($depth < $maxdepth) { $depth++; $keys = array_keys($array ?? []); foreach ($keys as $key) { if (!is_array($array[$key])) { continue; } $arrayKeys[$key] = $this->array_keys_recursive($array[$key], $maxdepth, $depth); } } return $arrayKeys; } }