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

Fermé
mikis69 Messages postés 168 Date d'inscription mardi 26 novembre 2013 Statut Membre Dernière intervention 11 février 2019 - Modifié le 9 févr. 2019 à 18:06
mikis69 Messages postés 168 Date d'inscription mardi 26 novembre 2013 Statut Membre Dernière intervention 11 février 2019 - 11 févr. 2019 à 21:35
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

jordane45 Messages postés 38145 Date d'inscription mercredi 22 octobre 2003 Statut Modérateur Dernière intervention 25 avril 2024 4 650
9 févr. 2019 à 18:13
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
mikis69 Messages postés 168 Date d'inscription mardi 26 novembre 2013 Statut Membre Dernière intervention 11 février 2019
9 févr. 2019 à 19:01
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
mikis69 Messages postés 168 Date d'inscription mardi 26 novembre 2013 Statut Membre Dernière intervention 11 février 2019
11 févr. 2019 à 17:58
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
Utilisateur anonyme
11 févr. 2019 à 20:07
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
mikis69 Messages postés 168 Date d'inscription mardi 26 novembre 2013 Statut Membre Dernière intervention 11 février 2019
11 févr. 2019 à 21:35
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