1<?php
2/**
3 * Zend Framework (http://framework.zend.com/)
4 *
5 * @link      http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license   http://framework.zend.com/license/new-bsd New BSD License
8 */
9
10namespace Zend\View;
11
12use Zend\I18n\Translator\TranslatorAwareInterface;
13use Zend\ServiceManager\AbstractPluginManager;
14use Zend\ServiceManager\ConfigInterface;
15
16/**
17 * Plugin manager implementation for view helpers
18 *
19 * Enforces that helpers retrieved are instances of
20 * Helper\HelperInterface. Additionally, it registers a number of default
21 * helpers.
22 */
23class HelperPluginManager extends AbstractPluginManager
24{
25    /**
26     * Default set of helpers factories
27     *
28     * @var array
29     */
30    protected $factories = array(
31        'flashmessenger' => 'Zend\View\Helper\Service\FlashMessengerFactory',
32        'identity'       => 'Zend\View\Helper\Service\IdentityFactory',
33    );
34
35    /**
36     * Default set of helpers
37     *
38     * @var array
39     */
40    protected $invokableClasses = array(
41        // basepath, doctype, and url are set up as factories in the ViewHelperManagerFactory.
42        // basepath and url are not very useful without their factories, however the doctype
43        // helper works fine as an invokable. The factory for doctype simply checks for the
44        // config value from the merged config.
45        'basepath'            => 'Zend\View\Helper\BasePath',
46        'cycle'               => 'Zend\View\Helper\Cycle',
47        'declarevars'         => 'Zend\View\Helper\DeclareVars',
48        'doctype'             => 'Zend\View\Helper\Doctype', // overridden by a factory in ViewHelperManagerFactory
49        'escapehtml'          => 'Zend\View\Helper\EscapeHtml',
50        'escapehtmlattr'      => 'Zend\View\Helper\EscapeHtmlAttr',
51        'escapejs'            => 'Zend\View\Helper\EscapeJs',
52        'escapecss'           => 'Zend\View\Helper\EscapeCss',
53        'escapeurl'           => 'Zend\View\Helper\EscapeUrl',
54        'gravatar'            => 'Zend\View\Helper\Gravatar',
55        'htmltag'             => 'Zend\View\Helper\HtmlTag',
56        'headlink'            => 'Zend\View\Helper\HeadLink',
57        'headmeta'            => 'Zend\View\Helper\HeadMeta',
58        'headscript'          => 'Zend\View\Helper\HeadScript',
59        'headstyle'           => 'Zend\View\Helper\HeadStyle',
60        'headtitle'           => 'Zend\View\Helper\HeadTitle',
61        'htmlflash'           => 'Zend\View\Helper\HtmlFlash',
62        'htmllist'            => 'Zend\View\Helper\HtmlList',
63        'htmlobject'          => 'Zend\View\Helper\HtmlObject',
64        'htmlpage'            => 'Zend\View\Helper\HtmlPage',
65        'htmlquicktime'       => 'Zend\View\Helper\HtmlQuicktime',
66        'inlinescript'        => 'Zend\View\Helper\InlineScript',
67        'json'                => 'Zend\View\Helper\Json',
68        'layout'              => 'Zend\View\Helper\Layout',
69        'paginationcontrol'   => 'Zend\View\Helper\PaginationControl',
70        'partialloop'         => 'Zend\View\Helper\PartialLoop',
71        'partial'             => 'Zend\View\Helper\Partial',
72        'placeholder'         => 'Zend\View\Helper\Placeholder',
73        'renderchildmodel'    => 'Zend\View\Helper\RenderChildModel',
74        'rendertoplaceholder' => 'Zend\View\Helper\RenderToPlaceholder',
75        'serverurl'           => 'Zend\View\Helper\ServerUrl',
76        'url'                 => 'Zend\View\Helper\Url',
77        'viewmodel'           => 'Zend\View\Helper\ViewModel',
78    );
79
80    /**
81     * @var Renderer\RendererInterface
82     */
83    protected $renderer;
84
85    /**
86     * Constructor
87     *
88     * After invoking parent constructor, add an initializer to inject the
89     * attached renderer and translator, if any, to the currently requested helper.
90     *
91     * @param null|ConfigInterface $configuration
92     */
93    public function __construct(ConfigInterface $configuration = null)
94    {
95        parent::__construct($configuration);
96
97        $this->addInitializer(array($this, 'injectRenderer'))
98             ->addInitializer(array($this, 'injectTranslator'));
99    }
100
101    /**
102     * Set renderer
103     *
104     * @param  Renderer\RendererInterface $renderer
105     * @return HelperPluginManager
106     */
107    public function setRenderer(Renderer\RendererInterface $renderer)
108    {
109        $this->renderer = $renderer;
110
111        return $this;
112    }
113
114    /**
115     * Retrieve renderer instance
116     *
117     * @return null|Renderer\RendererInterface
118     */
119    public function getRenderer()
120    {
121        return $this->renderer;
122    }
123
124    /**
125     * Inject a helper instance with the registered renderer
126     *
127     * @param  Helper\HelperInterface $helper
128     * @return void
129     */
130    public function injectRenderer($helper)
131    {
132        $renderer = $this->getRenderer();
133        if (null === $renderer) {
134            return;
135        }
136        $helper->setView($renderer);
137    }
138
139    /**
140     * Inject a helper instance with the registered translator
141     *
142     * @param  Helper\HelperInterface $helper
143     * @return void
144     */
145    public function injectTranslator($helper)
146    {
147        if (!$helper instanceof TranslatorAwareInterface) {
148            return;
149        }
150
151        $locator = $this->getServiceLocator();
152
153        if (!$locator) {
154            return;
155        }
156
157        if ($locator->has('MvcTranslator')) {
158            $helper->setTranslator($locator->get('MvcTranslator'));
159            return;
160        }
161
162        if ($locator->has('Zend\I18n\Translator\TranslatorInterface')) {
163            $helper->setTranslator($locator->get('Zend\I18n\Translator\TranslatorInterface'));
164            return;
165        }
166
167        if ($locator->has('Translator')) {
168            $helper->setTranslator($locator->get('Translator'));
169            return;
170        }
171    }
172
173    /**
174     * Validate the plugin
175     *
176     * Checks that the helper loaded is an instance of Helper\HelperInterface.
177     *
178     * @param  mixed                            $plugin
179     * @return void
180     * @throws Exception\InvalidHelperException if invalid
181     */
182    public function validatePlugin($plugin)
183    {
184        if ($plugin instanceof Helper\HelperInterface) {
185            // we're okay
186            return;
187        }
188
189        throw new Exception\InvalidHelperException(sprintf(
190            'Plugin of type %s is invalid; must implement %s\Helper\HelperInterface',
191            (is_object($plugin) ? get_class($plugin) : gettype($plugin)),
192            __NAMESPACE__
193        ));
194    }
195}
196