2013-04-15 4 views
1

Je suis actuellement avoir un problème avec Zend Framework dans la pagination 2.Comment définir sql_mode dans Zend Framework 2?

Ce code

public function findAllByCriteria(CourseSearchInput $input) { 
    $concatDelimiter = self::CONCAT_DELIMITER; 
    $select = new Select(); 
    $where = new Where(); 
    $having = new Having(); 
    $select->columns(array(
     'id', 'title', 'description' 
    )); 
    $select->from($this->tableGateway->getTable()); 
    $select 
     ->join('coursedata', 'courses.id = coursedata.id', array(
      'relevance' => $this->buildRelevanceExpressionFromCriteria($input) 
     )) 
    ; 
    $having 
     ->greaterThanOrEqualTo('relevance', self::RELEVANCE_MIN); 
    ; 
    $select->where($where, Predicate::OP_AND); 
    $select->having($having); 
    $select->group(array('courses.id')); 

    $dbAdapter = $this->tableGateway->getAdapter(); 
    // $dbAdapter->getDriver()->getConnection()->execute('SET sql_mode = "";'); 
    $adapter = new \Zend\Paginator\Adapter\DbSelect($select, $dbAdapter); 
    $paginator = new \Zend\Paginator\Paginator($adapter); 
    return $paginator; 
} 

créer cette SQL:

SELECT 
    `courses`.`id` AS `id`, 
    `courses`.`title` AS `title`, 
    `courses`.`description` AS `description`, 
    MATCH (coursedata.title) AGAINST ('Salsa') * 5 + MATCH (coursedata.description) AGAINST ('Salsa') * 2 AS `relevance` 
FROM `courses` 
INNER JOIN `coursedata` ON `courses`.`id` = `coursedata`.`id` 
GROUP BY `courses`.`id` 
HAVING `relevance` >= '3' 

Il ueses le MySQL Extensions to GROUP BY et ne peut pas être exécuté, si le sql_mode est défini sur ONLY_FULL_GROUP_BY. Donc, j'ai essayé de réinitialiser le sql_mode avant que l'instruction soit exécutée (voir la ligne commentée ci-dessus: $dbAdapter->getDriver()->getConnection()->execute('SET sql_mode = "";');). Mais ça n'a pas marché. Alors, comment puis-je définir le sql_mode afin d'exécuter mon SQL non standard?

+0

Ceci est seulement une hypothèse, que ma connaissance sql est minime, mais vous pourriez peut-être exécuter cette commande sur l'initiation? Dans votre 'driver_options', ajoutez' PDO :: MYSQL_ATTR_INIT_COMMAND => 'set sql_mode = ""' '. – Sam

+0

Il devrait y avoir (aussi) une autre façon de le faire, puisque je peux donc utiliser SET NAMES ou SET sql_mode. En tous cas. J'ai essayé ces deux dehors: '' driver_options '=> tableau (PDO :: MYSQL_ATTR_INIT_COMMAND =>' SET NAMES \ 'UTF8 \' ',' SET SESSION sql_mode = \ '\' '), 'et' 'driver_options' => tableau (PDO :: MYSQL_ATTR_INIT_COMMAND => 'SET SESSION sql_mode = \' \ '',), '. L'erreur SQL, que j'ai l'intention d'éliminer avec 'sql_mode = ''' est toujours là. Mais peut-être que le mode n'a pas été défini? Comment puis-je vérifier les paramètres PDO actuels/'sql_mode'? – automatix

Répondre

1

Cela peut ne pas être la réponse à la question que vous posez, mais je peux voir que vous aurez un problème avec votre requête, même si vous utilisez Paginator.

L'adaptateur DbSelect pour la Paginator n'aime pas la fonction d'agrégation là-bas (Grouper par)

Le Paginator va essayer d'utiliser votre requête pour construire sa propre requête pour calculer le « compte » des articles dans la collection. Ceci est cassé en raison de vous en utilisant un agrégat dans votre requête, tous les groupes, etc. vont casser l'adaptateur.

si vous vérifiez l'implémentation par défaut, vous verrez:

/** 
* Returns the total number of rows in the result set. 
* 
* @return integer 
*/ 
public function count() 
{ 
    if ($this->rowCount !== null) { 
     return $this->rowCount; 
    } 

    $select = clone $this->select; 
    $select->reset(Select::COLUMNS); 
    $select->reset(Select::LIMIT); 
    $select->reset(Select::OFFSET); 

    // This won't work if you've got a Group By in your query 
    $select->columns(array('c' => new Expression('COUNT(1)'))); 

    $statement = $this->sql->prepareStatementForSqlObject($select); 
    $result = $statement->execute(); 
    $row  = $result->current(); 

    $this->rowCount = $row['c']; 

    return $this->rowCount; 
} 

cela n'aime pas lorsque vous utilisez GROUP BY et redonnera des résultats incorrects.

Vous pouvez créer votre propre adataper et étendre le DbSelect existant et remplacer la méthode de comptage lorsque vous prévoyez d'utiliser Group BY;

Du haut de ma tête quelque chose comme ça devrait fonctionner, mais ne peut pas être le moyen le plus efficace de le faire

/** 
* Returns the total number of rows in the result set. 
* 
* @return integer 
*/ 
public function count() 
{ 
    if ($this->rowCount !== null) { 
     return $this->rowCount; 
    } 

    /** 
    * If the query hasn't got 'GROUP BY' just try and use the old method 
    */ 
    $stateGroup = $this->select->getRawState('group'); 
    if(! isset($stateGroup) || empty($stateGroup)) { 
     return parent::count(); 
    } 

    $select = clone $this->select; 
    $select->reset(Select::LIMIT); 
    $select->reset(Select::OFFSET); 

    $statement = $this->sql->prepareStatementForSqlObject($select); 
    $result = $statement->execute(); 

    $this->rowCount = $result->count(); 

    return $this->rowCount; 
} 
+0

Merci un million! Ca marche (dans mon cas)! Mais «GROUP BY» peut parfois affecter/réduire le nombre total de lignes sélectionnées. Cela signifie que lorsque nous l'enlevons de la déclaration, nous risquons d'obtenir un nombre de chiffres supérieur à celui que nous sélectionnons. Droite? Ou ai-je mal compris/négligé quelque chose? – automatix

+0

C'est la raison pour laquelle il y a une vérification, s'il n'y a pas de GROUP dans l'objet select, il utilise simplement l'ancienne méthode de comptage. Je suis sûr que ce n'est pas parfait et que vous pourriez faire un peu de travail mais c'est un exemple pour vous aider à démarrer ;-) – Andrew

+0

C'est même un bon exemple! Merci beaucoup encore une fois pour ça! :) – automatix