Query MYSQL interprété différemment par PHP ?

mikis69 Messages postés 174 Statut Membre -  
mikis69 Messages postés 174 Statut Membre -
Bonjour la communauté,

Je viens chercher un peu d'aide auprès de vous car il y a quelque chose qui me perturbe. Je développe actuellement un site e-commerce en PHP et MYSQL. Dans le cadre de la gestion des commandes et par conséquent des numéros de facture, je bloque un petit peu :

Un numéro de facture est de ce format 2019_001W, 2019_002W, ... 2019_999W, 2019_1000W, ...
(où 2019 est l'année courante).

J'ai donc une query (elle fonctionne très bien) qui me permet de récupérer le prochain numéro de facture :

select 
   concat('',
    year(sysdate()), 
    '_',
    case when length(max(substr(factureNbr, 6) + 1)) is null then
     '001'
    else
     case when length(max(substr(factureNbr, 6) + 1)) < 3 then
      LPAD(max(substr(factureNbr, 6) + 1), 3, '0')
     else 
      max(substr(factureNbr, 6) + 1)
     end
    end,
    'W'
   )
  from orders 
  where year(sysdate()) = substr(factureNbr, 1, 4);


Donc quand j'exécute cette query via MYSQL, je reçois bien le prochain numéro de facture.

Maintenant, je vais vous expliquer mon problème : j'utilise cette query dans une fonction MYSQL pour mettre à jour ma table 'orders'. Cette fonction MYSQL est appelé depuis PHP.

CREATE DEFINER=`root`@`localhost` FUNCTION `FINALIZEORDER`(`Nid` INT) RETURNS int(11)
BEGIN 
declare NfactureNbr varchar(20) DEFAULT null;
    
    if Nstatus = 'Payé' then
  select 
   concat('',
    year(sysdate()), 
    '_',
    case when length(max(substr(factureNbr, 6) + 1)) is null then
     '001'
    else
     case when length(max(substr(factureNbr, 6) + 1)) < 3 then
      LPAD(max(substr(factureNbr, 6) + 1), 3, '0')
     else 
      max(substr(factureNbr, 6) + 1)
     end
    end,
    'W'
   )
  into NfactureNbr
  from orders 
  where year(sysdate()) = substr(factureNbr, 1, 4);
    end if;

    update orders
    set factureNbr = NfactureNbr
    where id = Nid;
  
    return 1;
END


$query = "select finalizeorder (:fkOrder) as retour";

  try {
   $statement = $this->_db->prepare($query);   
   $statement->bindValue(":fkOrder", $fkOrder, PDO::PARAM_INT);
   $statement->execute();
   return true;
  } catch (PDOException $e) {
   return false;
  }


Donc tout fonctionne bien.. SAUF que lorsque ma table 'orders' est mise à jour (avec le prochain numéro de facture), ce n'est pas le prochain numéro de facture. C'est le prochain prochain. (presqu'à chaque fois, il saute un numéro..).


J'ai une piste, lorsque j'enlève du CONCAT la partie year(sysdate()), tout fonctionne absolument comme voulu. Est-ce que lorsque PHP interprète le CONCAT avec l'année courante, il ne l'interprète pas comme MYSQL ?

J'espère avoir été clair.. Sinon, je suis à votre disposition pour donner plus d'informations !

Merci à tous,

Mikis

EDIT : Correction des balises de code

3 réponses

  1. jordane45 Messages postés 30427 Date d'inscription   Statut Modérateur Dernière intervention   4 832
     
    Bonjour,,
    PHP n’interprétè rien du tout.... il ne fait que lancer la requête... qui est exécutée par ta bdd... exactement de la même manière que lorsque tu passes par phpmyadmin ou n'importe quelle autre interface pour manipuler ta bdd

    Dans ta procédure.. tu commence par vérifier la variable Nstatus ... d'où vient elle ??
    As tu testé ta procédure directement dans ta bdd pour voir si le comportement n'était pas le même ??
    0
    1. mikis69 Messages postés 174 Statut Membre
       
      Merci pour ta réponse,

      Oui j'ai pas mis toute la procédure mais la variable Nstatus vient du même endroit que Nid.

      J'ai testé ma procédure sur MYSQL et elle fonctionne de la bonne manière. Il n y a que lorsque je passe par mon site internet que cela ne fonctionne pas.

      Si par exemple dans le concat, je remplace year(sysdate()) par '2019' cela va fonctionner.. Je ne sais pas si tu vois le problème ?

      La procédure s'exécute bien et sans aucunes erreurs. Juste la valeur dans la colonne après l update qui n est pas bonne.
      0
  2. mikis69 Messages postés 174 Statut Membre
     
    Après une recherche très approfondie dans mon code, j'ai remarqué en ajoutant un insert dans ma procédure que cette dernière est exécutée deux fois (car deux inserts dans la table).

    Pour régler mon soucis, j'ai mis un garde fou en début de procédure pour éviter de mettre à jour deux fois la ligne de la table 'orders' :

    CREATE DEFINER=`root`@`localhost` FUNCTION `FINALIZEORDER`(`NpayId` VARCHAR(200), `Nstatus` VARCHAR(50), `Nid` INT) RETURNS int(11)
    BEGIN 
    	declare NfactureNbr varchar(20) DEFAULT null;
        declare nbr int;
        
        select count(*) into nbr from orders where id = Nid and finalized = 1;
        
        if nbr = 0 then
    		if Nstatus = 'Payé' then
    			select 
    				concat_ws('_',
    					year(sysdate()), 
    					case when length(max(substr(factureNbr, 6) + 1)) is null then
    						'001'
    					else
    						case when length(max(substr(factureNbr, 6) + 1)) < 3 then
    							LPAD(max(substr(factureNbr, 6) + 1), 3, '0')
    						else 
    							max(substr(factureNbr, 6) + 1)
    						end
    					end,
    					'W'
    				)
    			into NfactureNbr
    			from orders 
    			where year(sysdate()) = substr(factureNbr, 1, 4);
    		end if;
    			
    		update orders
    		set createdOn = curdate(), paidOn = curdate(), status = Nstatus, finalized = 1,
    		paymentReference = NpayId,
    		factureNbr = NfactureNbr
    		where id = Nid;
    	end if;
        
    	return 1;
    END


    Cela résout en effet mon problème mais est-ce que quelqu'un sait pourquoi PHP exécute deux fois ma procédure MYSQL ?

    public function finalizeOrder($payid, $status, $fkOrder) {
    		$query = "select finalizeorder (:paymentreference, :status, :fkOrder) as retour";
    
    		try {
    			$statement = $this->_db->prepare($query);			
    			$statement->bindValue(":paymentreference", $payid, PDO::PARAM_STR);
    			$statement->bindValue(":status", $status, PDO::PARAM_STR);
    			$statement->bindValue(":fkOrder", $fkOrder, PDO::PARAM_INT);
    			$statement->execute();
    			$data = $statement->fetch();
    			return true;
    		} catch (PDOException $e) {
    			// Logguer le fait que la commande n'a pas pu être finalisé
    			return false;
    		}
    	}
    


    et cette fonction est appelé à un seul endroit du code :

    		$finalized = $mg->finalizeOrder($payid, $statusOrder, $orderid);	
    


    -> j'appelle cette fonction lorsque la page 'acceptedPayment' est chargée. J'ai également un RewriteRule sur cette page..

    Voilà toutes les informations que je possède.. J'aimerai réglé le soucis plus proprement donc si quelqu'un a une idée :p
    0
  3. Utilisateur anonyme
     
    Bonsoir

    Il n'y a aucun doute : si PHP exécute deux fois ta procédure, c'est que tu l'appelles deux fois. Montre le code de la page qui appelle finalizeOrder.
    0
    1. mikis69 Messages postés 174 Statut Membre
       
      Je posterai le code demain matin. J'ai mis des var_dump partout et ils ne sont affichés qu'une seule fois.

      C'est comme ci, la page se chargeait une premiere fois et ensuite se re-charger une deuxième fois.. (d'où le fait que je ne le vois pas avec les var_dump et que je le vois avec des inserts)

      Merci pour ta réponse, je poste le code complet demain en edit sur ma précédente réponse.
      0