/** * ><p>**Note:** for use by MacroCall. * * @param string $name * @return false|null|string * @throws ComponentException */ public function getParameterType($name) { $param = $this->getParameter($name); if (isset($param)) { $p = type::getIdOf($param->props->type); if ($p === false) { $s = join('</kbd>, <kbd>', type::getAllNames()); throw new ComponentException($this, "The <kbd>{$name}</kbd> parameter has an invalid type: <kbd>{$param->props->type}</kbd>.<p>Expected values: <kbd>{$s}</kbd>."); } return $p; } return null; }
function render() { // Validate defaultParam's value. $def = $this->getDefaultParam(); if (!empty($def)) { if (!$this->props->defines($def)) { throw new ComponentException($this, "Invalid value for <kbd>defaultParam</kbd> on <b><{$this->props->macro}></b>; parameter <kbd>{$def}</kbd> does not exist"); } // Move children to default parameter. if ($this->hasChildren()) { $type = $this->props->getTypeOf($def); if ($type != type::content && $type != type::metadata) { throw new ComponentException($this, sprintf("The macro's default parameter <kbd>{$def}</kbd> can't hold content because its type is <kbd>%s</kbd>.", type::getNameOf($type))); } $param = new Metadata($this->context, ucfirst($def), $type); $this->props->set($def, $param); $param->attachTo($this); $param->setChildren($this->getChildren()); } } elseif ($this->hasChildren()) { throw new ComponentException($this, 'You may not specify content for this tag because it has no default property'); } parent::render(); }
/** * Converts a value that will be assigned to a property into a type compatible with that * property. * >**Note:** you should call {@see validate()} before calling this method, as the later does not * validate its input. * * @param string $type The property type. * @param mixed $v The value to be converted. * @return bool|float|int|null|string|\Traversable */ public static function typecast($type, $v) { if (isset($v) && $v !== '') { switch ($type) { case type::bool: return type::toBoolean($v); case type::id: return $v; case type::number: return is_float($v) ? floatval($v) : intval($v); case type::string: return strval($v); case type::data: if ($v instanceof \Iterator) { return $v; } if ($v instanceof \IteratorAggregate) { return $v->getIterator(); } return $v; } } return $v; }
/** * Returns the value converted to a the data type required by the specified property. * * @param string $name * @param mixed $v * @return bool|float|int|null|string|\Traversable * @throws ComponentException */ function typecastPropertyValue($name, $v) { if ($this->isScalar($name) && $this->isEnum($name)) { $this->validateEnum($name, $v); } $type = $this->getTypeOf($name); if ($type && !type::validate($type, $v)) { throw new ComponentException($this->component, sprintf("%s is not a valid value for the <kbd>{$name}</kbd> property, which is of type <kbd>%s</kbd>", is_scalar($v) ? sprintf("The %s<kbd>%s</kbd>", typeOf($v), var_export($v, true)) : sprintf("A value of PHP type <kbd>%s</kbd>", typeOf($v)), type::getNameOf($type))); } // A special case for content type properties: // Convert a content property specified as attribute=string to a format equivalent to the one generated by // <subtag>string</subtag> if ($type == type::content && is_string($v)) { $content = new Metadata($this->component->context, $name, type::metadata); $content->setChildren([Text::from($this->component->context, $v)]); return $content; } return type::typecast($type, $v); }