Adapter class usage example - production code

In my earlier post about my ClassDecorator class I’ve only briefly mentioned its main use to decorate a class that only implements PHP magic methods.
The case is raised when using the Functions adapter class (see it on GitHub in an early but pretty faithful actual incarnation) in my production code.

An example from the codex

Taking a look into WordPress Codex definition of the add_filter function I can see that one class method from a plugin might very well include the code

// file 'MyFilter.php'

class MyFilter{

    // this method, called at __construct time, will add the filter 
    public function __construct(){
        add_filter('img_caption_shortcode', array($this,'imgCaptionShortcodeFilter'),10,3);
    }

    // this is the method that gets called each time
    public function imgCaptionShortcodeFilter ($val, $attr, $content = null){
        extract(shortcode_atts(array(
            'id'    => '',
            'align' => '',
            'width' => '',
            'caption' => ''
        ), $attr));

        if ( 1 > (int) $width || empty($caption) )
            return $val;

        $capid = '';
        if ( $id ) {
            $id = esc_attr($id);
            $capid = 'id="figcaption_'. $id . '" ';
            $id = 'id="' . $id . '" aria-labelledby="figcaption_' . $id . '" ';
        }

        return '<figure ' . $id . 'class="wp-caption ' . esc_attr($align) . '" style="width: '
        . (10 + (int) $width) . 'px">' . do_shortcode( $content ) . '<figcaption ' . $capid 
        . 'class="wp-caption-text">' . $caption . '</figcaption></figure>'; 
    }
}   

And all would be fine. Except that the function imgCaptionShortcodeFilter can’t be tested in isolation.

The problem

To call the method imgCaptionShortcodeFilter the functions

  • add_filter - called in __construct()
  • shortcode_atts()
  • esc_attr()
  • do_shortcode()

all need to be defined in the global namespace.

$filter = new MyFilter();

will generate an error when called outside of a WordPress session.

Modify the code to use the adapter class

I will use the Functions adapter class to wrap WordPress methods and be able, in test, to mock them without issuing errors.

// file 'MyTestableFilter.php'

class MyTestableFilter{

    protected $functions = null;

    // this method, called at __construct time, will add the filter 
    public function __construct(){

        // get an instance of the Functions adapter class
        $this->functions = Functions::getInstance();
        // add the filter
        $this->functions->add_filter('img_caption_shortcode', array($this,'imgCaptionShortcodeFilter'),10,3);
    }

    // this is the method that gets called each time
    public function imgCaptionShortcodeFilter ($val, $attr, $content = null){
        extract($this->functions->shortcode_atts(array(
            'id'    => '',
            'align' => '',
            'width' => '',
            'caption' => ''
        ), $attr));

        if ( 1 > (int) $width || empty($caption) )
            return $val;

        $capid = '';
        if ( $id ) {
            $id = $this->functions->esc_attr($id);
            $capid = 'id="figcaption_'. $id . '" ';
            $id = 'id="' . $id . '" aria-labelledby="figcaption_' . $id . '" ';
        }

        return '<figure ' . $id . 'class="wp-caption ' . $this->functions->esc_attr($align) . '" style="width: '
        . (10 + (int) $width) . 'px">' . $this->functions->do_shortcode( $content ) . '<figcaption ' . $capid 
        . 'class="wp-caption-text">' . $caption . '</figcaption></figure>'; 
    }
}   

Aside for some prefixing of well known WordPress methods the code is not much different.