2
\$\begingroup\$

I have attempted to create a view helper class which makes programmatically creating HTML strings less verbose and hopefully simpler.

This is inspired by the tag helpers in Rails. It's compatible with the Symfony2 Templating Component but can be used outside Symfony.

It also has methods for creating tags for stylesheets (link) and script tags using the Symfony\Component\Templating\Helper\AssetsHelper to resolve urls. However, I don't really know how manage different packages without complicating the API. Ideas?

namespace Maxcal\TagHelper;

use Symfony\Component\Templating\Helper\Helper;
use Symfony\Component\Templating\Asset\PackageInterface;
use \DOMDocument, \DOMElement;

/**
 * A Symfony\Component\Templating compatible view helper which creates HTML elements with no string interpolation required.
 * Inspired by the Rails ActionView helpers.
 */
class TagHelper extends Helper {

    /**
     * @var PackageInterface
     */
    protected $assets;

    /**
     * @param PackageInterface $assets
     */
    public function __construct(PackageInterface $assets = null){
        $this->assets = $assets;
    }

    /**
     * @param PackageInterface $assets
     */
    public function setAssetsHelper(PackageInterface $assets){
        $this->assets = $assets;
    }

    /**
     * Returns the canonical name of this helper.
     *
     * @return string The canonical name
     *
     * @api
     */
    public function getName()
    {
        return 'tag';
    }

    /**
     * Low level method to create generic HTML elements
     * @param $tag_name
     * @param $value string | DOMElement - the node value of the created element
     * @param $attibutes array - (optional) attributes to apply to the node
     * @return string
     * @api
     */
    public function createTag($tag_name, $value, $attributes = array()){
        $doc = new DOMDocument();
        $el = $doc->createElement($tag_name, $value);

        foreach ($attributes as $key => $val) {
            $el->setAttribute($key, $val);
        }
        $doc->appendChild($el);
        return trim($doc->saveHTML());
    }

    /**
     * Creates an anchor element
     * @param $text
     * @param $href
     * @param array $attributes
     * @return string
     * @api
     */
    public function link($text, $href, $attributes = array()){
        $attributes['href'] = $href;
        return $this->createTag('a', $text, $attributes);
    }

    /**
     * Create a link element pointing to a style sheet
     * Will use the AssetsHelper to resolve a url if it has been injected
     * @param $name
     * @param array $media
     * @return string
     * @api
     */
    public function stylesheet($name, $media = array('all')){
        $attributes = array();
        $name .= '.css';
        $attributes['href'] = $name;
        $attributes['rel'] = 'stylesheet';

        if ($this->getStylesheetPackage()) {
            $attributes['href'] = $this->getStylesheetPackage()->getUrl($name);
        }

        if (!empty($media)) $attributes['media'] = implode(' ', $media);

        return $this->createTag('link', null, $attributes);
    }

    /**
     * Creates a "empty" script tag with the src set to the
     * @note Does not support "inline" script tags.
     * @note Does not set a "type" attribute since they are deemed "useless" in HTML5.
     * @param string $src
     * @param array $attributes (optional)
     * @return string
     * @api
     */
    public function script($src, $attributes = array()) {
        $attributes['src'] = "$src.js";

        if ($this->getScriptPackage()) {
            $attributes['src'] = $this->getScriptPackage()->getUrl($attributes['src']);
        }

        return $this->createTag('script', null, $attributes);
    }

    /**
     * @return null|PackageInterface
     */
    protected function getStylesheetPackage(){
        return $this->assets;
    }

    /**
     * @return null|PackageInterface
     */
    protected function getScriptPackage(){
        return $this->assets;
    }

}

Examples usages:

<?= $view['tag']->link( $page->title, $page->url ) ?>

In a Decorator:

class PageDecorator {

   // .. injected in some way
   protected $tag;

   public function getLink(){
      return $tag->link( $this->title, $this->url );
   }
}
\$\endgroup\$
  • \$\begingroup\$ @Jamal - your edited title was so a bit too vague. \$\endgroup\$ – papirtiger Mar 1 '15 at 19:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.