Ir para conteúdo

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Paulo Freitas Nobrega

Melhores Práticas - PHPOO

Recommended Posts

Fala pessoal! Gostaria da opinião/sugestão de vocês sobre o seguinte caso:

(obs: apenas estudo)

 

Considere a Interface

<?php

/**
 * @author		Paulo Freitas Nobrega
 * @brief		Interface relacionada ao Adaptador PDO
 * @package		Db\Adapter\Pdo\Driver
 */
namespace Db\Adapter\Pdo\Driver;

/**
 * @brief	Interface de Driver 
 * @interface	Driver
 */
interface Driver
{
	/**
	 * Cria o DNS referente ao Driver
	 * @param array $elements Fornece os elementos necessarios para criacao do DNS
	 * @return	string
	 */
	public function createDNS(array $elements);
}

E também sua implementação:

<?php

/**
 * @author		Paulo Freitas Nobrega
 * @brief		Driver relacionado ao Adaptador PDO
 * @package		Db\Adapter\Pdo\Driver
 */
namespace Db\Adapter\Pdo\Driver;
use Db\Adapter\Pdo\Driver\Driver;
use Db\Adapter\Pdo\Driver\ElementLabels;

/**
 * @brief		Driver MySQL
 * @details		Implementa o PDO para o acesso do PHP ao MySQL 3.x, 4.x e 5.x 
 * @class		MySQL
 */
class MySQL implements Driver
{
	/**
	 * Prefixo do Driver
	 */
	const PREFIX = 'mysql';

	/**
	 * Cria o DNS referente ao Driver
	 * @param array $elements Fornece os elementos necessarios para criacao do DNS
	 * @return	string
	 */	
	public function createDNS(array $elements)
	{
		if(!array_key_exists(ElementLabels::HOST,$elements))
		{
			throw new InvalidArgumentException( 'Servidor não informado' );
		}

		if(!array_key_exists(ElementLabels::DBNAME, $elements))
		{
			throw new InvalidArgumentException( 'Banco de dados não informado' );
		}

		$dns = self::PREFIX . ':' . ElementLabels::HOST . '=' . $elements[ElementLabels::HOST] . ';';
		$dns .= ElementLabels::DBNAME . '=' . $elements[ElementLabels::DBNAME] . ';';
		$dns .= array_key_exists(ElementLabels::PORT, $elements) ? ElementLabels::PORT . '=' . $elements[ElementLabels::PORT] . ';' : '';

		return $dns;
	}
} 

Por fim ElementLabels:

<?php

/**
 * @author		Paulo Freitas Nobrega
 * @brief		Classe relacionada ao Adaptador PDO
 * @package		Db\Adapter\Pdo\Driver
 */
namespace Db\Adapter\Pdo\Driver;

/**
 * @brief		Etiquetas dos elementos
 * @details		Os elementos fornecem a base para criação dos DNS's de cada Driver. Suas etiquetas possíveis são:
 * @li host 	- Servidor
 * @li dbname 	- Nome do banco de dados
 * @li port 	- Porta de acesso
 * @li charset 	- Codificação de caracteres
 * @class		ElementLabels
 */
class ElementLabels
{
	/**
	 * Servidor
	 */
	const HOST = 'host';

	/**
	 * Nome do banco de dados
	 */
	const DBNAME = 'dbname';

	/**
	 * Porta de acesso
	 */
	const PORT = 'port';
}

Minha dúvida:

Um Driver PostgreSQL, por exemplo, possuí exatamente os mesmos elementos para gerar o DNS do Driver MySQL, exceto o valor de seu prefixo. Porém um Driver MS SQL Server possuí elementos não comuns a estes citados. O dilema é que a grande maioria dos Driver utilizam os mesmos elementos, porém há exceções.

 

Então segue a pergunta: Como evitar, neste caso, a duplicação de código. Mantendo a flexíbilidade, um código elegante e respeitando a OO?

Compartilhar este post


Link para o post
Compartilhar em outros sites

PDO já é OO. Abstração importante ele já faz pra vc (seria da forma de lidar com as query)!

 

DNS pro PDO não é nada alem de um string constante.(algo que pode ser passado em um arquivo de config)

 

A melhor pratica neste caso seria o "FACTORY"(de uma pesquisada) na minha opinião, seria ideal pro seu caso! (não tenho tempo agora pra implementa algo pra vc como exemplo)

 

Particularmente, e muito volta pra apenas um string!

 

Essa abordagem de "fabrica de conexões", não me agrada kkkkk.

 

Mas é bom pra aprendizagem.

Compartilhar este post


Link para o post
Compartilhar em outros sites

DO já é OO. Abstração importante ele já faz pra você (seria da forma de lidar com as query)!

 

DNS pro PDO não é nada alem de um string constante.(algo que pode ser passado em um arquivo de config)

 

A melhor pratica neste caso seria o "FACTORY"(de uma pesquisada) na minha opinião, seria ideal pro seu caso! (não tenho tempo agora pra implementa algo pra você como exemplo)

 

Particularmente, e muito volta pra apenas um string!

 

Essa abordagem de "fabrica de conexões", não me agrada kkkkk.

 

Mas é bom pra aprendizagem.

 

Legal Luis! Primeiramente obrigado por contribuir.

 

Porém atribuir diretamente o DNS me causa um certo desconforto quanto as atribuições. Digo isso porque uma futura classe responsável pela conexão PDO não deveria ter conhecimento específico sobre o Driver utilizado. A mesma deveria receber um Driver, sem se importar qual, e confiar única e exclusivamente na interface Driver, executando o método createDNS.

 

Isso permitiria que a futura classe responsável pela conexão PDO focasse em sua atribuição, deixando para o Driver as responsabilidades de validação/etc dos elementos que compõem o DNS;

 

De fato um DNS é apenas uma string, porém esta string é composta de elementos que devem ser válidos, e a futura classe responsável pela conexão PDO não deve ficar responsável em verificar isso, não é uma atribuição dela.

 

Resumindo a futura classe responsável pela conexão PDO possuirá uma instância de Driver, este atribuido via typeof, e a classe simplesmente vai pegar as configurações recebidas e lançar sobre o Driver através do método createDNS(), confiando que receberá como resposta uma DNS válido. "Ela é egoista, não esta nem ai para quem é o Driver, e muito menos como ele vai gerar o DNS, a única coisa que importa à ela é receber um DNS válido, para que possa cuidar das suas responsabilidades"

Compartilhar este post


Link para o post
Compartilhar em outros sites

Se alguém possuir a mesma dúvida no futuro, segue uma resposta simples:

 

Duplique o código!

 

Segue os exemplos do Doctrine DBAL (Observe o método _constructPdoDsn() em ambos exemplos)

 

Doctrine\DBAL\Driver\PDOMySql

<?php
/*
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * This software consists of voluntary contributions made by many individuals
 * and is licensed under the LGPL. For more information, see
 * <http://www.doctrine-project.org>.
 */

namespace Doctrine\DBAL\Driver\PDOMySql;

use Doctrine\DBAL\Connection;

/**
 * PDO MySql driver.
 *
 * @since 2.0
 */
class Driver implements \Doctrine\DBAL\Driver
{
    /**
     * Attempts to establish a connection with the underlying driver.
     *
     * @param array $params
     * @param string $username
     * @param string $password
     * @param array $driverOptions
     * @return Doctrine\DBAL\Driver\Connection
     */
    public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
    {
        $conn = new \Doctrine\DBAL\Driver\PDOConnection(
            $this->_constructPdoDsn($params),
            $username,
            $password,
            $driverOptions
        );
        return $conn;
    }

    /**
     * Constructs the MySql PDO DSN.
     *
     * @return string  The DSN.
     */
    private function _constructPdoDsn(array $params)
    {
        $dsn = 'mysql:';
        if (isset($params['host']) && $params['host'] != '') {
            $dsn .= 'host=' . $params['host'] . ';';
        }
        if (isset($params['port'])) {
            $dsn .= 'port=' . $params['port'] . ';';
        }
        if (isset($params['dbname'])) {
            $dsn .= 'dbname=' . $params['dbname'] . ';';
        }
        if (isset($params['unix_socket'])) {
            $dsn .= 'unix_socket=' . $params['unix_socket'] . ';';
        }
        if (isset($params['charset'])) {
            $dsn .= 'charset=' . $params['charset'] . ';';
        }

        return $dsn;
    }

    public function getDatabasePlatform()
    {
        return new \Doctrine\DBAL\Platforms\MySqlPlatform();
    }

    public function getSchemaManager(\Doctrine\DBAL\Connection $conn)
    {
        return new \Doctrine\DBAL\Schema\MySqlSchemaManager($conn);
    }

    public function getName()
    {
        return 'pdo_mysql';
    }

    public function getDatabase(\Doctrine\DBAL\Connection $conn)
    {
        $params = $conn->getParams();

        if (isset($params['dbname'])) {
            return $params['dbname'];
        }
        return $conn->query('SELECT DATABASE()')->fetchColumn();
    }
}

Doctrine\DBAL\Driver\PDOPgSql

<?php

namespace Doctrine\DBAL\Driver\PDOPgSql;

use Doctrine\DBAL\Platforms;

/**
 * Driver that connects through pdo_pgsql.
 *
 * @since 2.0
 */
class Driver implements \Doctrine\DBAL\Driver
{
    /**
     * Attempts to connect to the database and returns a driver connection on success.
     *
     * @return Doctrine\DBAL\Driver\Connection
     */
    public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
    {
        return new \Doctrine\DBAL\Driver\PDOConnection(
            $this->_constructPdoDsn($params),
            $username,
            $password,
            $driverOptions
        );
    }

    /**
     * Constructs the Postgres PDO DSN.
     *
     * @return string The DSN.
     */
    private function _constructPdoDsn(array $params)
    {
        $dsn = 'pgsql:';
        if (isset($params['host']) && $params['host'] != '') {
            $dsn .= 'host=' . $params['host'] . ' ';
        }
        if (isset($params['port']) && $params['port'] != '') {
            $dsn .= 'port=' . $params['port'] . ' ';
        }
        if (isset($params['dbname'])) {
            $dsn .= 'dbname=' . $params['dbname'] . ' ';
        }

        return $dsn;
    }

    public function getDatabasePlatform()
    {
        return new \Doctrine\DBAL\Platforms\PostgreSqlPlatform();
    }

    public function getSchemaManager(\Doctrine\DBAL\Connection $conn)
    {
        return new \Doctrine\DBAL\Schema\PostgreSqlSchemaManager($conn);
    }

    public function getName()
    {
        return 'pdo_pgsql';
    }

    public function getDatabase(\Doctrine\DBAL\Connection $conn)
    {
        $params = $conn->getParams();
        return $params['dbname'];
    }
}

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.