schema icon indicating copy to clipboard operation
schema copied to clipboard

Allow recursive schema validation in tree structure

Open foxycode opened this issue 4 years ago • 0 comments

I'm trying to solve recursive schema validation in menu library when you have tree structure of menu (submenu items).

Here's what I did as temporary solution:

final class MenuExtension extends CompilerExtension
{

	public function getConfigSchema(): Schema
	{
		return Expect::arrayOf(Expect::structure([
			'loader' => Expect::string(DefaultMenuLoader::class),
			'items' => Expect::array()->required(),
		]));
	}

	public function getItemSchema(): Schema
	{
		return Expect::structure([
			'title' => Expect::string(),
			'link' => Expect::string(),
			'items' => Expect::array(),
		]);
	}

	public function loadConfiguration(): void
	{
		$config = $this->getConfig();
		$builder = $this->getContainerBuilder();
		$processor = new Processor;

		foreach ($config as $menuName => $menu) {
			$container->addSetup('addMenu', [
				$this->loadMenuConfiguration($builder, $processor, $menuName, $menu),
			]);
		}
	}

	private function loadMenuConfiguration(
		ContainerBuilder $builder,
		Processor $processor,
		string $menuName,
		stdClass $config
	): ServiceDefinition {
		$loader = $config->loader;

		if (!Strings::startsWith($config->loader, '@')) {
			$loader = $builder->addDefinition($this->prefix('menu.'. $menuName. '.loader'))
				->setType($config->loader)
				->setAutowired(false);
		}

		if ($loader->getType() === DefaultMenuLoader::class) {
			$loader->setArguments([$this->normalizeMenuItems($processor, $config->items)]);
		}
	}

	private function normalizeMenuItems(Processor $processor, array $items): array
	{
		array_walk($items, function(array &$item, string $key) use ($processor): void {
			$item = $processor->process($this->getItemSchema(), $item);

			if ($item->title === null) {
				$item->title = $key;
			}

			$item->items = $this->normalizeMenuItems($processor, $item->items);
		});

		return $items;
	}

}

Full file is here

  • It would be nice if I could use something like Expect::schemaFactory([$this, 'getItemSchema']) so function getItemSchema() could be called recursively as long as submenu's are present.
  • It would be nice if I could get Processor in CompilerExtension so I don't need to create one when I have custom config.

foxycode avatar Feb 17 '21 13:02 foxycode