['Cake\View\Input\Checkbox'], 'label' => ['Cake\View\Input\Label'], 'multicheckbox' => ['Cake\View\Input\MultiCheckbox', 'label'], 'radio' => ['Cake\View\Input\Radio', 'label'], 'select' => ['Cake\View\Input\SelectBox'], '_default' => ['Cake\View\Input\Basic'], ]; /** * 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 = []) { $this->_templates = $templates; if (!empty($widgets)) { $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 = $widgets + $this->_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]; } /** * Clear the registry and reset the widgets. * * @return void */ public function clear() { $this->_widgets = []; } /** * 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_object($widget)) { return $widget; } $class = array_shift($widget); $className = App::classname($class, 'View/Input'); if ($className === false || !class_exists($className)) { throw new \RuntimeException(sprintf('Unable to locate widget class "%s"', $class)); } if (count($widget)) { $reflection = new ReflectionClass($className); $arguments = [$this->_templates]; foreach ($widget as $requirement) { $arguments[] = $this->get($requirement); } $instance = $reflection->newInstanceArgs($arguments); } else { $instance = new $className($this->_templates); } if (!($instance instanceof InputInterface)) { throw new \RuntimeException(sprintf('"%s" does not implement the InputInterface', $className)); } return $instance; } }