Browse Source

Start building the InputRegistry.

Add an interface for ensuring some sanity to inputs, and add a hacky
implementation of a registry.
mark_story 12 years ago
parent
commit
944faaddbb
2 changed files with 167 additions and 0 deletions
  1. 30 0
      src/View/Input/InputInterface.php
  2. 137 0
      src/View/Input/InputRegistry.php

+ 30 - 0
src/View/Input/InputInterface.php

@@ -0,0 +1,30 @@
+<?php
+/**
+ * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
+ * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link          http://cakephp.org CakePHP(tm) Project
+ * @since         CakePHP(tm) v3.0
+ * @license       http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Cake\View\Input;
+
+/**
+ * Interface for input widgets.
+ */
+interface InputInterface {
+
+/**
+ * Converts the $data into one or many HTML elements.
+ *
+ * @param array $data The data to render.
+ * @return string
+ */
+	public function render(array $data);
+
+}

+ 137 - 0
src/View/Input/InputRegistry.php

@@ -0,0 +1,137 @@
+<?php
+/**
+ * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
+ * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link          http://cakephp.org CakePHP(tm) Project
+ * @since         CakePHP(tm) v3.0
+ * @license       http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Cake\View\Input;
+
+use Cake\Core\App;
+use Cake\View\Input\InputInterface;
+use Cake\View\StringTemplate;
+use \ReflectionClass;
+
+/**
+ * A registry/factory for input widgets.
+ *
+ * Can be used by helpers/view logic to build form widgets
+ * and other HTML widgets.
+ *
+ * This class handles the mapping between names and concrete classes.
+ * It also has a basic name based dependency resolver that allows
+ * widgets to depend on each other.
+ *
+ * Each widget should expect a StringTemplate instance as their first
+ * argument. All other dependencies will be included after.
+ */
+class InputRegistry {
+
+/**
+ * Array of widgets + widget configuration.
+ *
+ * @var array
+ */
+	protected $_widgets = [];
+
+/**
+ * Templates to use.
+ *
+ * @var Cake\View\StringTemplate
+ */
+	protected $_templates;
+
+/**
+ * Constructor
+ *
+ * @param StringTemplate $templates Templates instance to use.
+ * @param array $widgets See add() method for more information.
+ */
+	public function __construct(StringTemplate $templates, array $widgets = null) {
+		$this->_templates = $templates;
+		$this->add($widgets);
+	}
+
+/**
+ * Adds or replaces existing widget instances/configuration with new ones.
+ *
+ * Widget arrays can either be descriptions or instances. For example:
+ *
+ * {{{
+ * $registry->add([
+ *   'label' => new MyLabel($templates),
+ *   'checkbox' => ['Fancy.MyCheckbox', 'label']
+ * ]);
+ * }}}
+ *
+ * The above shows how to define widgets as instances or as
+ * descriptions including dependencies. Classes can be defined
+ * with plugin notation, or fully namespaced class names.
+ *
+ * @param array $widgets Array of widgets to use.
+ * @return void
+ */
+	public function add(array $widgets) {
+		$this->_widgets = array_merge($this->_widgets, $widgets);
+	}
+
+/**
+ * Get a widget.
+ *
+ * Will either fetch an already created widget, or create a new instance
+ * if the widget has been defined. If the widget is undefined an instance of
+ * the `_default` widget will be returned. An exception will be thrown if
+ * the `_default` widget is undefined.
+ *
+ * @param string $name The widget name to get.
+ * @return mixed InputInterface widget interface class.
+ * @throws \RuntimeException when widget is undefined.
+ */
+	public function get($name) {
+		if (!isset($this->_widgets[$name]) && empty($this->_widgets['_default'])) {
+			throw new \RuntimeException(sprintf('Unknown widget "%s"', $name));
+		}
+		if (!isset($this->_widgets[$name])) {
+			$name = '_default';
+		}
+		$this->_widgets[$name] = $this->_resolveWidget($this->_widgets[$name]);
+		return $this->_widgets[$name];
+	}
+
+/**
+ * Resolves a widget spec into an instance.
+ *
+ * @param mixed $widget The widget to get
+ * @return InputInterface
+ * @throws \RuntimeException when class cannot be loaded or does not
+ *   implement InputInterface.
+ */
+	protected function _resolveWidget($widget) {
+		if (!is_array($widget)) {
+			return $widget;
+		}
+		$class = array_shift($widget);
+		$className = App::classname($class, 'View/Input');
+		if ($className === false) {
+			throw new \RuntimeException(sprintf('Unable to locate widget class "%s"', $class));
+		}
+		$reflection = new ReflectionClass($className);
+		$arguments = [$this->_templates];
+		foreach ($widget as $requirement) {
+			$arguments[] = $this->get($requirement);
+		}
+		$instance = $reflection->newInstanceArgs($arguments);
+		if (!($instance instanceof InputInterface)) {
+			throw new \RuntimeException(sprintf('"%s" does not implement the InputInterface', $className));
+		}
+		return $instance;
+	}
+
+}