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.