{"id":176,"date":"2017-10-05T07:58:15","date_gmt":"2017-10-05T10:58:15","guid":{"rendered":"http:\/\/hackerzone.com.br\/blog\/?p=176"},"modified":"2022-08-13T00:20:34","modified_gmt":"2022-08-13T03:20:34","slug":"zend-framework-3-doctrine-getscalarresult-form-objectselect","status":"publish","type":"post","link":"http:\/\/hackerzone.com.br\/blog\/zend-framework-3-doctrine-getscalarresult-form-objectselect\/","title":{"rendered":"Zend Framework 3 &#8211; Doctrine getScalarResult + Form ObjectSelect"},"content":{"rendered":"<p>Se voc\u00ea esta utilizando Zend Framework 3 com Doctrine provavelmente j\u00e1 se deparou com algumas situa\u00e7\u00f5es complicadas relacionadas aos formul\u00e1rios, no meu caso eu utilizo uma combo para trazer os valores e para isso eu sempre utilizava o ObjectSelect do Doctrine localizado em &#8220;\\DoctrineModule\\Form\\Element\\ObjectSelect&#8221;, mas surgiu a necessidade de construir uma consulta totalmente personalizada com relacionamentos de tabelas e que seus resultados s\u00e3o retornados em forma de array, geralmente pra isso utilizamos o retorno <strong>getScalarResult()<\/strong>.<\/p>\n<p>Pelo que andei mexendo nas classes ainda n\u00e3o existe o recurso para tornar poss\u00edvel essa combina\u00e7\u00e3o, pois na hora de exibir os resultados dentro da combo at\u00e9 \u00e9 poss\u00edvel exibir o texto vis\u00edvel pela op\u00e7\u00e3o &#8220;label_generator&#8221;, mas \u00e9 apresentado um erro e o valor do elemento n\u00e3o \u00e9 preenchido com o ID.<\/p>\n<p>Caso seja poss\u00edvel utilizar esse recurso sem a adapta\u00e7\u00e3o que eu criei, por favor, ignore meu erro e me informe a respeito, simplesmente me deparei com essa situa\u00e7\u00e3o e em modo de emerg\u00eancia criei este recurso.<\/p>\n<p>Agora vamos ao meu m\u00e9todo:<br \/>\nMODRastreador\\Entity\\RastreadorRepository<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n&lt;?php\r\n\r\nnamespace MODRastreador\\Entity;\r\n\r\nuse Doctrine\\ORM\\EntityRepository;\r\nuse Zend\\Authentication\\AuthenticationService;\r\nuse Zend\\Authentication\\Storage\\Session as SessionStorage;\r\nuse \\Doctrine\\ORM\\Query\\Expr;\r\n\r\nclass RastreadorRepository extends EntityRepository {\r\n\r\n    protected $admIdentity = null;\r\n\r\n    public function buscaRastreadoresDisponiveis() {\r\n\r\n        $em = $this-&gt;getEntityManager();\r\n\r\n        $rastreador = $em-&gt;createQueryBuilder('a');\r\n        $rastreadores = $rastreador-&gt;select(array('r', 'rm'))\r\n                -&gt;from(\\MODRastreador\\Entity\\Rastreador::class, 'r')\r\n                -&gt;leftJoin(\\MODRastreamento\\Entity\\Rastreamento::class, 'rm', Expr\\Join::WITH, 'r.id &lt;&gt; rm.idRastreador')\r\n                -&gt;where('r.ativo = ?1')\r\n                -&gt;andWhere('r.idEmpresa = ?2')\r\n                -&gt;andWhere('rm.idEmpresa = ?3')\r\n                -&gt;groupBy('r.imei')\r\n                -&gt;orderBy('r.imei', 'ASC')\r\n                -&gt;setParameter(1, true)\r\n                -&gt;setParameter(2, $this-&gt;getIdentityUser()-&gt;getId())\r\n                -&gt;setParameter(3, $this-&gt;getIdentityUser()-&gt;getId())\r\n                -&gt;getQuery()\r\n                -&gt;getScalarResult();\r\n\r\n        return $rastreadores;\r\n    }\r\n}\r\n<\/pre>\n<p>N\u00e3o vou postar o c\u00f3digo do formul\u00e1rio completo, pois n\u00e3o h\u00e1 necessidade, se voc\u00ea chegou at\u00e9 este ponto \u00e9 porque voc\u00ea j\u00e1 sabe criar formul\u00e1rios no Zend Framework e n\u00e3o \u00e9 o meu objetivo ensinar isso agora.<br \/>\n\\MODRastreamento\\Form\\Rastreamento<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n        \/\/ *** OBSERVE O CAMINHO DIFERENTE PARA O OBJECTSELECT\r\n\r\n        $id_rastreador = new \\MODRastreador\\Form\\Element\\ObjectSelect('idRastreador');\r\n        $id_rastreador-&gt;setLabel('Rastreador p\/ Transferir');\r\n        $id_rastreador-&gt;setOptions(array(\r\n                    'object_manager' =&gt; $objectManager,\r\n                    'target_class' =&gt; \\MODRastreador\\Entity\\Rastreador::class,\r\n                    'label_generator' =&gt; function($target) {\r\n                        return $target['r_imei'];\r\n                    },\r\n                    'value_generator' =&gt; function($target) {\r\n                        return $target['r_id'];                                \r\n                    },\r\n                    'is_method' =&gt; true,\r\n                    'find_method' =&gt; [\r\n                        'name' =&gt; 'buscaRastreadoresDisponiveis',\r\n                    ],\r\n                    'display_empty_item' =&gt; true,\r\n                    'empty_item_label' =&gt; 'Selecione o Rastreador.',\r\n                ))\r\n                -&gt;setAttribute('class', 'form-control select2')\r\n                -&gt;setAttribute('required', true);\r\n        $this-&gt;add($id_rastreador);\r\n<\/pre>\n<p>Veja estou criando um elemento ObjectSelect no qual eu aponto um m\u00e9todo para consulta chamado &#8220;buscaRastreadoresDisponiveis&#8221; estou passando tamb\u00e9m minha op\u00e7\u00e3o de &#8220;label_generator&#8221; onde at\u00e9 aqui tudo normal, voc\u00ea conseguiria fazer isso no ObjectSelect original.<\/p>\n<p>Mas observe que eu criei uma op\u00e7\u00e3o a mais chamada de &#8220;value_generator&#8221; na qual eu passo atrav\u00e9s de um m\u00e9todo qual valor do meu array ser\u00e1 o id da minha combo. Obviamente voc\u00ea j\u00e1 deve ter reparado que eu n\u00e3o chamei o ObjectSelect nativo do Doctrine, pois eu criei um ObjectSelect personalizado. Basicamente essa classe trabalha com a classe Proxy que \u00e9 onde toda a m\u00e1gica acontece.<\/p>\n<p>Ent\u00e3o dentro da minha pasta Form, eu criei uma pasta chamada Element e dentro coloquei minhas duas classes ObjectSelect e Proxy e quando vou criar chamo eles e n\u00e3o o nativo do Doctrine. (Os meus s\u00e3o apenas uma c\u00f3pia do original com algumas modifica\u00e7\u00f5es). Por mais que o Doctrine atualize duvido que ter\u00e1 grandes modifica\u00e7\u00f5es ao ponto de n\u00e3o conseguir utilizar essas classes ou ent\u00e3o que utilizando essas classes deixar\u00e1 de utilizar recursos novos futuros, at\u00e9 mesmo porque at\u00e9 l\u00e1 se surgir algo de especial eu estarei alterando este artigo.<\/p>\n<p>Siga minhas classes para <a href=\"http:\/\/hackerzone.com.br\/blog\/wp-content\/uploads\/2017\/10\/Element.zip\">Download<\/a><\/p>\n<p>Vou postar tamb\u00e9m o c\u00f3digo das duas aqui, mas como ser\u00e1 grande de mais vale mais a pena baixar:<br \/>\nObjectSelect<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n&lt;?php\r\n\/*\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r\n * &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\r\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n *\r\n * This software consists of voluntary contributions made by many individuals\r\n * and is licensed under the MIT license. For more information, see\r\n * &lt;http:\/\/www.doctrine-project.org&gt;.\r\n *\/\r\n\r\nnamespace MODRastreador\\Form\\Element;\r\n\r\nuse MODRastreador\\Form\\Element\\Proxy;\r\nuse Zend\\Form\\Element\\Select as SelectElement;\r\nuse Zend\\Form\\Form;\r\nuse Zend\\Stdlib\\ArrayUtils;\r\n\r\nclass ObjectSelect extends SelectElement\r\n{\r\n    \/**\r\n     * @var Proxy\r\n     *\/\r\n    protected $proxy;\r\n\r\n    \/**\r\n     * @return Proxy\r\n     *\/\r\n    public function getProxy()\r\n    {\r\n        if (null === $this-&gt;proxy) {\r\n            $this-&gt;proxy = new Proxy();\r\n        }\r\n        return $this-&gt;proxy;\r\n    }\r\n\r\n    \/**\r\n     * @param  array|\\Traversable $options\r\n     * @return self\r\n     *\/\r\n    public function setOptions($options)\r\n    {\r\n        $this-&gt;getProxy()-&gt;setOptions($options);\r\n        return parent::setOptions($options);\r\n    }\r\n\r\n    \/**\r\n     * @param string $key\r\n     * @param mixed $value\r\n     * @return self\r\n     *\/\r\n    public function setOption($key, $value)\r\n    {\r\n        $this-&gt;getProxy()-&gt;setOptions(array($key =&gt; $value));\r\n        return parent::setOption($key, $value);\r\n    }\r\n\r\n    \/**\r\n     * {@inheritDoc}\r\n     *\/\r\n    public function setValue($value)\r\n    {\r\n        $multiple = $this-&gt;getAttribute('multiple');\r\n\r\n        if (true === $multiple || 'multiple' === $multiple) {\r\n            if ($value instanceof \\Traversable) {\r\n                $value = ArrayUtils::iteratorToArray($value);\r\n            } elseif ($value == null) {\r\n                return parent::setValue(array());\r\n            } elseif (!is_array($value)) {\r\n                $value = (array) $value;\r\n            }\r\n\r\n            return parent::setValue(array_map(array($this-&gt;getProxy(), 'getValue'), $value));\r\n        }\r\n\r\n        return parent::setValue($this-&gt;getProxy()-&gt;getValue($value));\r\n    }\r\n\r\n    \/**\r\n     * {@inheritDoc}\r\n     *\/\r\n    public function getValueOptions()\r\n    {\r\n        if (! empty($this-&gt;valueOptions)) {\r\n            return $this-&gt;valueOptions;\r\n        }\r\n\r\n        $proxyValueOptions = $this-&gt;getProxy()-&gt;getValueOptions();\r\n\r\n        if (! empty($proxyValueOptions)) {\r\n            $this-&gt;setValueOptions($proxyValueOptions);\r\n        }\r\n\r\n        return $this-&gt;valueOptions;\r\n    }\r\n}\r\n\r\n<\/pre>\n<p>Proxy<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n&lt;?php\r\n\r\n\/*\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r\n * &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\r\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n *\r\n * This software consists of voluntary contributions made by many individuals\r\n * and is licensed under the MIT license. For more information, see\r\n * &lt;http:\/\/www.doctrine-project.org&gt;.\r\n *\/\r\n\r\nnamespace MODRastreador\\Form\\Element;\r\n\r\nuse Doctrine\\Common\\Collections\\Collection;\r\nuse Doctrine\\Common\\Persistence\\ObjectManager;\r\nuse DoctrineModule\\Persistence\\ObjectManagerAwareInterface;\r\nuse InvalidArgumentException;\r\nuse ReflectionMethod;\r\nuse RuntimeException;\r\nuse Traversable;\r\nuse Zend\\Stdlib\\Guard\\ArrayOrTraversableGuardTrait;\r\n\r\nclass Proxy implements ObjectManagerAwareInterface {\r\n\r\n    use ArrayOrTraversableGuardTrait;\r\n\r\n    \/**\r\n     * @var array|Traversable\r\n     *\/\r\n    protected $objects;\r\n\r\n    \/**\r\n     * @var string\r\n     *\/\r\n    protected $targetClass;\r\n\r\n    \/**\r\n     * @var array\r\n     *\/\r\n    protected $valueOptions = array();\r\n\r\n    \/**\r\n     * @var array\r\n     *\/\r\n    protected $findMethod = array();\r\n\r\n    \/**\r\n     * @var\r\n     *\/\r\n    protected $property;\r\n\r\n    \/**\r\n     * @var array\r\n     *\/\r\n    protected $option_attributes = array();\r\n\r\n    \/**\r\n     * @var callable $labelGenerator A callable used to create a label based on an item in the collection an Entity\r\n     *\/\r\n    protected $labelGenerator;\r\n\r\n    \/**\r\n     * @var callable $value Generator Um chamado usado para criar um valor com base em um item na cole\u00e7\u00e3o uma Entidade\r\n     *\/\r\n    protected $valueGenerator;\r\n\r\n    \/**\r\n     * @var bool|null\r\n     *\/\r\n    protected $isMethod;\r\n\r\n    \/**\r\n     * @var ObjectManager\r\n     *\/\r\n    protected $objectManager;\r\n\r\n    \/**\r\n     * @var bool\r\n     *\/\r\n    protected $displayEmptyItem = false;\r\n\r\n    \/**\r\n     * @var string\r\n     *\/\r\n    protected $emptyItemLabel = '';\r\n\r\n    \/**\r\n     * @var string|null\r\n     *\/\r\n    protected $optgroupIdentifier;\r\n\r\n    \/**\r\n     * @var string|null\r\n     *\/\r\n    protected $optgroupDefault;\r\n\r\n    public function setOptions($options) {\r\n        if (isset($options['object_manager'])) {\r\n            $this-&gt;setObjectManager($options['object_manager']);\r\n        }\r\n\r\n        if (isset($options['target_class'])) {\r\n            $this-&gt;setTargetClass($options['target_class']);\r\n        }\r\n\r\n        if (isset($options['property'])) {\r\n            $this-&gt;setProperty($options['property']);\r\n        }\r\n\r\n        if (isset($options['label_generator'])) {\r\n            $this-&gt;setLabelGenerator($options['label_generator']);\r\n        }\r\n\r\n        if (isset($options['value_generator'])) {\r\n            $this-&gt;setValueGenerator($options['value_generator']);\r\n        }\r\n\r\n        if (isset($options['find_method'])) {\r\n            $this-&gt;setFindMethod($options['find_method']);\r\n        }\r\n\r\n        if (isset($options['is_method'])) {\r\n            $this-&gt;setIsMethod($options['is_method']);\r\n        }\r\n\r\n        if (isset($options['display_empty_item'])) {\r\n            $this-&gt;setDisplayEmptyItem($options['display_empty_item']);\r\n        }\r\n\r\n        if (isset($options['empty_item_label'])) {\r\n            $this-&gt;setEmptyItemLabel($options['empty_item_label']);\r\n        }\r\n\r\n        if (isset($options['option_attributes'])) {\r\n            $this-&gt;setOptionAttributes($options['option_attributes']);\r\n        }\r\n\r\n        if (isset($options['optgroup_identifier'])) {\r\n            $this-&gt;setOptgroupIdentifier($options['optgroup_identifier']);\r\n        }\r\n\r\n        if (isset($options['optgroup_default'])) {\r\n            $this-&gt;setOptgroupDefault($options['optgroup_default']);\r\n        }\r\n    }\r\n\r\n    public function getValueOptions() {\r\n        if (empty($this-&gt;valueOptions)) {\r\n            $this-&gt;loadValueOptions();\r\n        }\r\n\r\n        return $this-&gt;valueOptions;\r\n    }\r\n\r\n    \/**\r\n     * @return array|Traversable\r\n     *\/\r\n    public function getObjects() {\r\n        $this-&gt;loadObjects();\r\n\r\n        return $this-&gt;objects;\r\n    }\r\n\r\n    \/**\r\n     * Set the label for the empty option\r\n     *\r\n     * @param string $emptyItemLabel\r\n     *\r\n     * @return Proxy\r\n     *\/\r\n    public function setEmptyItemLabel($emptyItemLabel) {\r\n        $this-&gt;emptyItemLabel = $emptyItemLabel;\r\n\r\n        return $this;\r\n    }\r\n\r\n    \/**\r\n     * @return string\r\n     *\/\r\n    public function getEmptyItemLabel() {\r\n        return $this-&gt;emptyItemLabel;\r\n    }\r\n\r\n    \/**\r\n     * @return array\r\n     *\/\r\n    public function getOptionAttributes() {\r\n        return $this-&gt;option_attributes;\r\n    }\r\n\r\n    \/**\r\n     * @param array $option_attributes\r\n     *\/\r\n    public function setOptionAttributes(array $option_attributes) {\r\n        $this-&gt;option_attributes = $option_attributes;\r\n    }\r\n\r\n    \/**\r\n     * Set a flag, whether to include the empty option at the beginning or not\r\n     *\r\n     * @param boolean $displayEmptyItem\r\n     *\r\n     * @return Proxy\r\n     *\/\r\n    public function setDisplayEmptyItem($displayEmptyItem) {\r\n        $this-&gt;displayEmptyItem = $displayEmptyItem;\r\n\r\n        return $this;\r\n    }\r\n\r\n    \/**\r\n     * @return boolean\r\n     *\/\r\n    public function getDisplayEmptyItem() {\r\n        return $this-&gt;displayEmptyItem;\r\n    }\r\n\r\n    \/**\r\n     * Set the object manager\r\n     *\r\n     * @param  ObjectManager $objectManager\r\n     *\r\n     * @return Proxy\r\n     *\/\r\n    public function setObjectManager(ObjectManager $objectManager) {\r\n        $this-&gt;objectManager = $objectManager;\r\n\r\n        return $this;\r\n    }\r\n\r\n    \/**\r\n     * Get the object manager\r\n     *\r\n     * @return ObjectManager\r\n     *\/\r\n    public function getObjectManager() {\r\n        return $this-&gt;objectManager;\r\n    }\r\n\r\n    \/**\r\n     * Set the FQCN of the target object\r\n     *\r\n     * @param  string $targetClass\r\n     *\r\n     * @return Proxy\r\n     *\/\r\n    public function setTargetClass($targetClass) {\r\n        $this-&gt;targetClass = $targetClass;\r\n\r\n        return $this;\r\n    }\r\n\r\n    \/**\r\n     * Get the target class\r\n     *\r\n     * @return string\r\n     *\/\r\n    public function getTargetClass() {\r\n        return $this-&gt;targetClass;\r\n    }\r\n\r\n    \/**\r\n     * Set the property to use as the label in the options\r\n     *\r\n     * @param  string $property\r\n     *\r\n     * @return Proxy\r\n     *\/\r\n    public function setProperty($property) {\r\n        $this-&gt;property = $property;\r\n\r\n        return $this;\r\n    }\r\n\r\n    \/**\r\n     * @return mixed\r\n     *\/\r\n    public function getProperty() {\r\n        return $this-&gt;property;\r\n    }\r\n\r\n    \/**\r\n     * Set the label generator callable that is responsible for generating labels for the items in the collection\r\n     *\r\n     * @param callable $callable A callable used to create a label based off of an Entity\r\n     *\r\n     * @throws InvalidArgumentException\r\n     *\r\n     * @return void\r\n     *\/\r\n    public function setLabelGenerator($callable) {\r\n        if (!is_callable($callable)) {\r\n            throw new InvalidArgumentException(\r\n            'Property &quot;label_generator&quot; needs to be a callable function or a \\Closure'\r\n            );\r\n        }\r\n\r\n        $this-&gt;labelGenerator = $callable;\r\n    }\r\n\r\n    \/**\r\n     * Defina o gerador de valores que pode ser chamado para gerar valor para os itens da cole\u00e7\u00e3o\r\n     *\r\n     * @param callable $callable Usado para criar um valor com base em uma Entidade\r\n     *\r\n     * @throws InvalidArgumentException\r\n     *\r\n     * @return void\r\n     *\/\r\n    public function setValueGenerator($callable) {\r\n        if (!is_callable($callable)) {\r\n            throw new InvalidArgumentException(\r\n            'Property &quot;value_generator&quot; needs to be a callable function or a \\Closure'\r\n            );\r\n        }\r\n\r\n        $this-&gt;valueGenerator = $callable;\r\n    }\r\n\r\n    \/**\r\n     * @return callable|null\r\n     *\/\r\n    public function getLabelGenerator() {\r\n        return $this-&gt;labelGenerator;\r\n    }\r\n\r\n    \/**\r\n     * @return callable||null\r\n     *\/\r\n    public function getValueGenerator() {\r\n        return $this-&gt;valueGenerator;\r\n    }\r\n\r\n    \/**\r\n     * @return string|null\r\n     *\/\r\n    public function getOptgroupIdentifier() {\r\n        return $this-&gt;optgroupIdentifier;\r\n    }\r\n\r\n    \/**\r\n     * @param string $optgroupIdentifier\r\n     *\/\r\n    public function setOptgroupIdentifier($optgroupIdentifier) {\r\n        $this-&gt;optgroupIdentifier = (string) $optgroupIdentifier;\r\n    }\r\n\r\n    \/**\r\n     * @return string|null\r\n     *\/\r\n    public function getOptgroupDefault() {\r\n        return $this-&gt;optgroupDefault;\r\n    }\r\n\r\n    \/**\r\n     * @param string $optgroupDefault\r\n     *\/\r\n    public function setOptgroupDefault($optgroupDefault) {\r\n        $this-&gt;optgroupDefault = (string) $optgroupDefault;\r\n    }\r\n\r\n    \/**\r\n     * Set if the property is a method to use as the label in the options\r\n     *\r\n     * @param  boolean $method\r\n     *\r\n     * @return Proxy\r\n     *\/\r\n    public function setIsMethod($method) {\r\n        $this-&gt;isMethod = (bool) $method;\r\n\r\n        return $this;\r\n    }\r\n\r\n    \/**\r\n     * @return mixed\r\n     *\/\r\n    public function getIsMethod() {\r\n        return $this-&gt;isMethod;\r\n    }\r\n\r\n    \/** Set the findMethod property to specify the method to use on repository\r\n     *\r\n     * @param array $findMethod\r\n     *\r\n     * @return Proxy\r\n     *\/\r\n    public function setFindMethod($findMethod) {\r\n        $this-&gt;findMethod = $findMethod;\r\n\r\n        return $this;\r\n    }\r\n\r\n    \/**\r\n     * Get findMethod definition\r\n     *\r\n     * @return array\r\n     *\/\r\n    public function getFindMethod() {\r\n        return $this-&gt;findMethod;\r\n    }\r\n\r\n    \/**\r\n     * @param $targetEntity\r\n     *\r\n     * @return string|null\r\n     *\/\r\n    protected function generateLabel($targetEntity) {\r\n        if (null === ($labelGenerator = $this-&gt;getLabelGenerator())) {\r\n            return null;\r\n        }\r\n\r\n        return call_user_func($labelGenerator, $targetEntity);\r\n    }\r\n\r\n    \/**\r\n     * @param $targetEntity\r\n     * \r\n     * @return value|null\r\n     *\/\r\n    protected function generateValue($targetEntity) {\r\n        if (null == ($valueGenerator = $this-&gt;getValueGenerator())) {\r\n            return null;\r\n        }\r\n\r\n        return call_user_func($valueGenerator, $targetEntity);\r\n    }\r\n\r\n    \/**\r\n     * @param  $value\r\n     *\r\n     * @return array|mixed|object\r\n     * @throws RuntimeException\r\n     *\/\r\n    public function getValue($value) {\r\n        if (!($om = $this-&gt;getObjectManager())) {\r\n            throw new RuntimeException('No object manager was set');\r\n        }\r\n\r\n        if (!($targetClass = $this-&gt;getTargetClass())) {\r\n            throw new RuntimeException('No target class was set');\r\n        }\r\n\r\n        $metadata = $om-&gt;getClassMetadata($targetClass);\r\n\r\n        if (is_object($value)) {\r\n            if ($value instanceof Collection) {\r\n                $data = array();\r\n\r\n                foreach ($value as $object) {\r\n                    $values = $metadata-&gt;getIdentifierValues($object);\r\n                    $data[] = array_shift($values);\r\n                }\r\n\r\n                $value = $data;\r\n            } else {\r\n                $metadata = $om-&gt;getClassMetadata(get_class($value));\r\n                $identifier = $metadata-&gt;getIdentifierFieldNames();\r\n\r\n                \/\/ TODO: handle composite (multiple) identifiers\r\n                if (count($identifier) &gt; 1) {\r\n                    \/\/$value = $key;\r\n                } else {\r\n                    $value = current($metadata-&gt;getIdentifierValues($value));\r\n                }\r\n            }\r\n        }\r\n\r\n        return $value;\r\n    }\r\n\r\n    \/**\r\n     * Load objects\r\n     *\r\n     * @throws RuntimeException\r\n     * @throws Exception\\InvalidRepositoryResultException\r\n     * @return void\r\n     *\/\r\n    protected function loadObjects() {\r\n        if (!empty($this-&gt;objects)) {\r\n            return;\r\n        }\r\n\r\n        $findMethod = (array) $this-&gt;getFindMethod();\r\n\r\n        if (!$findMethod) {\r\n            $findMethodName = 'findAll';\r\n            $repository = $this-&gt;objectManager-&gt;getRepository($this-&gt;targetClass);\r\n            $objects = $repository-&gt;findAll();\r\n        } else {\r\n            if (!isset($findMethod['name'])) {\r\n                throw new RuntimeException('No method name was set');\r\n            }\r\n            $findMethodName = $findMethod['name'];\r\n            $findMethodParams = isset($findMethod['params']) ? array_change_key_case($findMethod['params']) : array();\r\n            $repository = $this-&gt;objectManager-&gt;getRepository($this-&gt;targetClass);\r\n\r\n            if (!method_exists($repository, $findMethodName)) {\r\n                throw new RuntimeException(\r\n                sprintf(\r\n                        'Method &quot;%s&quot; could not be found in repository &quot;%s&quot;', $findMethodName, get_class($repository)\r\n                )\r\n                );\r\n            }\r\n\r\n            $r = new ReflectionMethod($repository, $findMethodName);\r\n            $args = array();\r\n\r\n            foreach ($r-&gt;getParameters() as $param) {\r\n                if (array_key_exists(strtolower($param-&gt;getName()), $findMethodParams)) {\r\n                    $args[] = $findMethodParams[strtolower($param-&gt;getName())];\r\n                } elseif ($param-&gt;isDefaultValueAvailable()) {\r\n                    $args[] = $param-&gt;getDefaultValue();\r\n                } elseif (!$param-&gt;isOptional()) {\r\n                    throw new RuntimeException(\r\n                    sprintf(\r\n                            'Required parameter &quot;%s&quot; with no default value for method &quot;%s&quot; in repository &quot;%s&quot;'\r\n                            . ' was not provided', $param-&gt;getName(), $findMethodName, get_class($repository)\r\n                    )\r\n                    );\r\n                }\r\n            }\r\n            $objects = $r-&gt;invokeArgs($repository, $args);\r\n        }\r\n\r\n        $this-&gt;guardForArrayOrTraversable(\r\n                $objects, sprintf('%s::%s() return value', get_class($repository), $findMethodName), 'DoctrineModule\\Form\\Element\\Exception\\InvalidRepositoryResultException'\r\n        );\r\n\r\n        $this-&gt;objects = $objects;\r\n    }\r\n\r\n    \/**\r\n     * Load value options\r\n     *\r\n     * @throws RuntimeException\r\n     * @return void\r\n     *\/\r\n    protected function loadValueOptions() {\r\n        if (!($om = $this-&gt;objectManager)) {\r\n            throw new RuntimeException('No object manager was set');\r\n        }\r\n\r\n        if (!($targetClass = $this-&gt;targetClass)) {\r\n            throw new RuntimeException('No target class was set');\r\n        }\r\n\r\n        $metadata = $om-&gt;getClassMetadata($targetClass);\r\n        $identifier = $metadata-&gt;getIdentifierFieldNames();\r\n        $objects = $this-&gt;getObjects();\r\n        $options = array();\r\n        $optionAttributes = array();\r\n\r\n        if ($this-&gt;displayEmptyItem) {\r\n            $options[''] = $this-&gt;getEmptyItemLabel();\r\n        }\r\n\r\n        foreach ($objects as $key =&gt; $object) {\r\n            if (null !== ($generatedLabel = $this-&gt;generateLabel($object))) {\r\n                $label = $generatedLabel;\r\n            } elseif ($property = $this-&gt;property) {\r\n                if ($this-&gt;isMethod == false &amp;&amp; !$metadata-&gt;hasField($property)) {\r\n                    throw new RuntimeException(\r\n                    sprintf(\r\n                            'Property &quot;%s&quot; could not be found in object &quot;%s&quot;', $property, $targetClass\r\n                    )\r\n                    );\r\n                }\r\n\r\n                $getter = 'get' . ucfirst($property);\r\n\r\n                if (!is_callable(array($object, $getter))) {\r\n                    throw new RuntimeException(\r\n                    sprintf('Method &quot;%s::%s&quot; is not callable', $this-&gt;targetClass, $getter)\r\n                    );\r\n                }\r\n\r\n                $label = $object-&gt;{$getter}();\r\n            } else {\r\n                if (!is_callable(array($object, '__toString'))) {\r\n                    throw new RuntimeException(\r\n                    sprintf(\r\n                            '%s must have a &quot;__toString()&quot; method defined if you have not set a property'\r\n                            . ' or method to use.', $targetClass\r\n                    )\r\n                    );\r\n                }\r\n\r\n                $label = (string) $object;\r\n            }\r\n\r\n            \/\/ AQUI ESTA O PONTO CHAVE\r\n            if (!$this-&gt;getValueGenerator()) {\r\n                if (count($identifier) &gt; 1) {\r\n                    $value = $key;\r\n                } else {\r\n                    $value = current($metadata-&gt;getIdentifierValues($object));\r\n                }\r\n            } else {\r\n\r\n                if (null !== ($generatedValue = $this-&gt;generateValue($object))) {\r\n                    $value = $generatedValue;\r\n                }\r\n            }\r\n\r\n            foreach ($this-&gt;getOptionAttributes() as $optionKey =&gt; $optionValue) {\r\n                if (is_string($optionValue)) {\r\n                    $optionAttributes[$optionKey] = $optionValue;\r\n\r\n                    continue;\r\n                }\r\n\r\n                if (is_callable($optionValue)) {\r\n                    $callableValue = call_user_func($optionValue, $object);\r\n                    $optionAttributes[$optionKey] = (string) $callableValue;\r\n\r\n                    continue;\r\n                }\r\n\r\n                throw new RuntimeException(\r\n                sprintf(\r\n                        'Parameter &quot;option_attributes&quot; expects an array of key =&gt; value where value is of type'\r\n                        . '&quot;string&quot; or &quot;callable&quot;. Value of type &quot;%s&quot; found.', gettype($optionValue)\r\n                )\r\n                );\r\n            }\r\n\r\n            \/\/ If no optgroup_identifier has been configured, apply default handling and continue\r\n            if (is_null($this-&gt;getOptgroupIdentifier())) {\r\n                $options[] = array('label' =&gt; $label, 'value' =&gt; $value, 'attributes' =&gt; $optionAttributes);\r\n\r\n                continue;\r\n            }\r\n\r\n            \/\/ optgroup_identifier found, handle grouping\r\n            $optgroupGetter = 'get' . ucfirst($this-&gt;getOptgroupIdentifier());\r\n\r\n            if (!is_callable(array($object, $optgroupGetter))) {\r\n                throw new RuntimeException(\r\n                sprintf('Method &quot;%s::%s&quot; is not callable', $this-&gt;targetClass, $optgroupGetter)\r\n                );\r\n            }\r\n\r\n            $optgroup = $object-&gt;{$optgroupGetter}();\r\n\r\n            \/\/ optgroup_identifier contains a valid group-name. Handle default grouping.\r\n            if (false === is_null($optgroup) &amp;&amp; trim($optgroup) !== '') {\r\n                $options[$optgroup]['label'] = $optgroup;\r\n                $options[$optgroup]['options'][] = array(\r\n                    'label' =&gt; $label,\r\n                    'value' =&gt; $value,\r\n                    'attributes' =&gt; $optionAttributes\r\n                );\r\n\r\n                continue;\r\n            }\r\n\r\n            $optgroupDefault = $this-&gt;getOptgroupDefault();\r\n\r\n            \/\/ No optgroup_default has been provided. Line up without a group\r\n            if (is_null($optgroupDefault)) {\r\n                $options[] = array('label' =&gt; $label, 'value' =&gt; $value, 'attributes' =&gt; $optionAttributes);\r\n\r\n                continue;\r\n            }\r\n\r\n            \/\/ Line up entry with optgroup_default\r\n            $options[$optgroupDefault]['label'] = $optgroupDefault;\r\n            $options[$optgroupDefault]['options'][] = array(\r\n                'label' =&gt; $label,\r\n                'value' =&gt; $value,\r\n                'attributes' =&gt; $optionAttributes\r\n            );\r\n        }\r\n\r\n        $this-&gt;valueOptions = $options;\r\n    }\r\n\r\n}\r\n\r\n\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Se voc\u00ea esta utilizando Zend Framework 3 com Doctrine provavelmente j\u00e1 se deparou com algumas situa\u00e7\u00f5es complicadas relacionadas aos formul\u00e1rios, no meu caso eu utilizo uma combo para trazer os valores e para isso eu sempre utilizava o ObjectSelect do Doctrine localizado em &#8220;\\DoctrineModule\\Form\\Element\\ObjectSelect&#8221;, mas surgiu a necessidade de construir uma consulta totalmente personalizada com [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":459,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[14,12,13],"tags":[16,81,80,18,19],"class_list":["post-176","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-doctrine","category-php","category-zend-framework-3","tag-doctrine","tag-getscalarresult","tag-objectselect","tag-zend-framework-3","tag-zf3","cat-14-id","cat-12-id","cat-13-id","has_thumb"],"_links":{"self":[{"href":"http:\/\/hackerzone.com.br\/blog\/wp-json\/wp\/v2\/posts\/176","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/hackerzone.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/hackerzone.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/hackerzone.com.br\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/hackerzone.com.br\/blog\/wp-json\/wp\/v2\/comments?post=176"}],"version-history":[{"count":1,"href":"http:\/\/hackerzone.com.br\/blog\/wp-json\/wp\/v2\/posts\/176\/revisions"}],"predecessor-version":[{"id":178,"href":"http:\/\/hackerzone.com.br\/blog\/wp-json\/wp\/v2\/posts\/176\/revisions\/178"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/hackerzone.com.br\/blog\/wp-json\/wp\/v2\/media\/459"}],"wp:attachment":[{"href":"http:\/\/hackerzone.com.br\/blog\/wp-json\/wp\/v2\/media?parent=176"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/hackerzone.com.br\/blog\/wp-json\/wp\/v2\/categories?post=176"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/hackerzone.com.br\/blog\/wp-json\/wp\/v2\/tags?post=176"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}