Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
66.67% covered (warning)
66.67%
2 / 3
CRAP
96.55% covered (success)
96.55%
28 / 29
ReflectedAttribute
0.00% covered (danger)
0.00%
0 / 1
66.67% covered (warning)
66.67%
2 / 3
18
96.55% covered (success)
96.55%
28 / 29
 __construct
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
3 / 3
 get
n/a
0 / 0
1
n/a
0 / 0
 set
n/a
0 / 0
1
n/a
0 / 0
 buildAttributes
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
8 / 8
 factory
0.00% covered (danger)
0.00%
0 / 1
11.02
94.44% covered (success)
94.44%
17 / 18
<?php
declare( strict_types = 1 );
namespace Wikimedia\Dodo;
/**
 * Abstract class for the different attribute types.
 * $element and $attributeName are protected for use in subclasses
 *
 * @author DannyS712
 */
abstract class ReflectedAttribute {
    /** @var Element */
    protected $element;
    /** @var string */
    protected $attributeName;
    /**
     * @param Element $elem
     * @param array $spec
     */
    public function __construct( Element $elem, $spec ) {
        $this->element = $elem;
        $this->attributeName = $spec['name'];
    }
    /**
     * @return mixed
     */
    abstract public function get();
    /**
     * Some of the attribute classes return something here, others don't - why?
     *
     * @param mixed $value
     */
    abstract public function set( $value );
    // Factory methods
    /**
     * Get multiple reflected attributes, based on a spec
     *
     * @param HTMLImgElement $owner
     * @param array $specs
     * @return ReflectedAttribute[]
     */
    final public static function buildAttributes( HTMLImgElement $owner, array $specs ) : array {
        $attribs = [];
        foreach ( $specs as $name => $spec ) {
            if ( !is_array( $spec ) ) {
                $spec = [ 'type' => $spec, 'name' => $name ];
            }
            if ( !isset( $spec['name'] ) ) {
                $spec['name'] = $name;
            }
            $attribs[$name] = self::factory( $owner, $spec );
        }
        return $attribs;
    }
    /******************************************************************************
     * Reflecting content attributes in IDL attributes
     *
     * http://html.spec.whatwg.org/#reflecting-content-attributes-in-idl-attributes
     *
     * From the spec:
     * "Some IDL attributes are defined to reflect a particular content attribute.
     * This means that on getting, the IDL attribute returns the current value of
     * the content attribute, and on setting, the IDL attribute changes the value
     * of the content attribute to the given value."
     *
     * Many HTML Elements have well-defined interfaces expressed as attributes.
     * These attributes may be typed, have an enumerated set of allowed values,
     * have default values, and so on.
     *
     * This family of classes allows us to implement these reflected attributes.
     *
     * USAGE:
     * For each specialized attribute on an Element, build a reflected
     * attribute object and add its access functions to the magic
     * __get() and/or __set() functions.
     *
     * (As of PHP 7 this is the only way to implement implicit accessors,
     * which must be done to comply with spec.)
     *
     * The switch in Element::__get()/Element::__set() will call
     * ReflectedAttr::get or ReflectedAttr::set after looking the
     * object up in a table or as a class member like
     * Element::$__attr_<attrname>.
     *
     * @param HTMLImgElement $owner
     * @param array $spec
     * @return ReflectedAttribute one of the different subclasses
     */
    final public static function factory( $owner, $spec ) {
        if ( is_array( $spec['type'] ) ) {
            return new IDLReflectedAttributeEnumerated( $owner, $spec );
        }
        switch ( $spec['type'] ) {
            case 'CORS':
                return new IDLReflectedAttributeCORS( $owner, $spec );
            case 'URL':
                return new IDLReflectedAttributeURL( $owner, $spec );
            case 'boolean':
                return new IDLReflectedAttributeBoolean( $owner, $spec );
            case 'number':
            case 'long':
            case 'unsigned long':
            case 'limited unsigned long with fallback':
                return new IDLReflectedAttributeNumeric( $owner, $spec );
            case 'function':
                // FIXME IDLReflectedAttributeFunction does not exist
                // @phan-suppress-next-line PhanUndeclaredClassMethod
                return new IDLReflectedAttributeFunction( $owner, $spec );
            case 'string':
            default:
                return new IDLReflectedAttributeString( $owner, $spec );
        }
    }
}