I recently changed my website from shared hosting to a dedicated server (major upgrade..), and some things didn't work out of the box. One of these things was the INSERTs. I was used to code INSERTS without bothering about having all the columns values in my statement. The missing columns were automatically filled with 0s and threw basic warning I ignored.
I thought it was normal MySQL\MariaDB behaviour. With my new dedicated server (not hosted locally), the database sends an error and refuses to insert the line if all the columns values are not declared in the INSERT statement. This is a problem. I add columns, from time to time, in many tables, as I improve the site's functionalities. I don't want to be revising all the INSERTS in the thousands of lines in my PHP scripts every time I add a column to a table.
So, instead, I created this insert function.
Basically:
Call the function, send an array with table name and key+values I want to insert
Function reads the table name, selects one line, and list the columns name
Function prepares an INSERT with the passed key+values, and generates bulk (depending on the types) values for the columns without values passed
Proceed to INSERT
Now the questions:
Is there a simpler way of doing this?
Am I breaching something?
Is it a recurrent need?
And here the function code:
// INSERTION DB GÉNÉRALE
function insert_db($valeurs)
{
global $date;
global $no;
global $bdd;
// Pour le log
$log = 'Valeurs reçues BDD : ';
foreach ($valeurs as $colonne => $valeur)
{
$log .= $colonne.' = '.$valeur.' || ';
};
// On obtient la table dans $valeurs['db_table']
$resultat = $bdd->query('SELECT * FROM '.$valeurs['db_table'].' LIMIT 1');
$tous_les_champs = array_keys($resultat->fetch(PDO::FETCH_ASSOC)); // On crée un tableau avec toutes les entêtes de colonnes
$champs = array(); // Les champs qui seront mis au début de la requête
$valeurs_preparees = array(); // Les valeurs préparées (avec un : devant) pour mettre dans la deuxième portion de la requête
foreach ($tous_les_champs as $champ_unique) // On valide qu'on a des données pour chaque colonne
{
$valeur = "0";
if (strpos($champ_unique, 'DATE') !== false) { $valeur = $date; }; // Si le titre du champs contiens « DATE », on prends en considération qu'il faut y mettre quelque chose en type datetime
if (strpos($champ_unique, 'RAW_DN') !== false) { $valeur = "0000-00-00 00:00:00"; }; // Pour le champs custom de date de naissance de USAGERS
if (strpos($champ_unique, 'DATE_DEPART') !== false) { $valeur = "0000-00-00 00:00:00"; }; // Si le titre du champs contiens « DATE », on prends en considération qu'il faut y mettre quelque chose en type datetime
if (strpos($champ_unique, 'DESCRIPTION') !== false) { $valeur = "Aucune description"; };
if (strpos($champ_unique, 'COMMENTAIRE') !== false) { $valeur = "Aucun commentaire"; };
if (strpos($champ_unique, 'CREE_PAR') !== false) { $valeur = $_SESSION['DOCTUS'][$no]['ID']; };
if (strpos($champ_unique, 'MODIF_PAR') !== false) { $valeur = $_SESSION['DOCTUS'][$no]['ID']; };
if (strpos($champ_unique, 'CREATEUR') !== false) { $valeur = $_SESSION['DOCTUS'][$no]['ID']; };
if (strpos($champ_unique, 'MODIFICATEUR') !== false) { $valeur = $_SESSION['DOCTUS'][$no]['ID']; };
if (strpos($champ_unique, 'PAYE_') !== false) { $valeur = "1"; };
if (!isset($valeurs[$champ_unique]) || $valeurs[$champ_unique] == "") { $tableau[$champ_unique] = $valeur; }else{ $tableau[$champ_unique] = $valeurs[$champ_unique]; }; $champs[$champ_unique] = $champ_unique; $valeurs_preparees[$champ_unique] = ":".$champ_unique;
};
// On crée les champs pour la requête
$requete_champs = "";
foreach ($champs as $champ_unique)
{
if ($requete_champs != "") { $requete_champs .= ', '; };
$requete_champs .= $champ_unique;
};
// On crée les valeurs pour la requête
$requete_valeurs = "";
foreach ($valeurs_preparees as $valeur_unique)
{
if ($requete_valeurs != "") { $requete_valeurs .= ', '; };
$requete_valeurs .= $valeur_unique;
};
$req_insert_db = $bdd->prepare('INSERT INTO '.$valeurs['db_table'].'('.$requete_champs.') VALUES('.$requete_valeurs.')');
$req_insert_db->execute($tableau);
$id_insert = $bdd->lastInsertId();
// On log l'insertion
$log .= "\n ID inséré : ".$id_insert;
if ($id_insert == 0) { $log .= ' || ERREUR'; };
$fichier = './log/insertions_log.txt';
file_put_contents($fichier, $log, FILE_APPEND);
return $id_insert;
};
The cause is a different configuration of MySql/MariaDb server between old and new server
(see the documentation of Strict SQL Mode for more details).
The cleanest way is to do an ALTER TABLE of all your tables and give to any fields a DEFAULT value (at least to all fields that you don't want to specify a value): in this case the engine don't need all fields in INSERT statements. (see this answer to see the syntax)
Related
Good evening, I have an orders and orders_products table:
A supplier (user) can upload products to sell them.
If buyer buys a product from different suppliers. That he has for example 3 products buy from different supplier, I want to separate.
For each product purchased from different suppliers it will represent an order for the buyer made by the buyer.
I made my code for the order but I can't seem to place an order for each supplier, please I really need help.
This is my PHP code:
public function validation_commande(Request $request){
$utilisateur = Utilisateur::where('id','=',session('utilisateur'))->first();
$paniers = Panier::where('utilisateur_id','=',$utilisateur->id)->get();
$utilisateur_id = $utilisateur->id;
$mode_paiement_id = 4;
$adresse = Adresse::where('utilisateur_id','=',$utilisateur_id)
->where('adresse_par_defaut','=',1)
->first();
$total_ht = 0;
$total_ttc = 0;
$nombre_produit_panier = count($paniers);
if($nombre_produit_panier >= 1)
{
foreach ($paniers as $c) {
$total_ht += $c->produit->prix_total($c->quantite);
$total_ttc += $c->produit->prix_total_ttc($c->quantite);
$commande = Commande::firstOrCreate([
'utilisateur_id'=>$utilisateur_id,
'fournisseur_id'=>$c->produit->utilisateur_id,
'boutique_id'=>$c->produit->boutique_id,
'statut'=>'en_cours_de_traitement',
'statut_fournisseur'=>'pas_encore_vue_sa_commande',
'total_ht'=>$total_ht,
'total_ttc'=>$total_ttc,
'mode_paiement_id'=>$mode_paiement_id,
'adresse_id'=>$adresse->id,
'date_commande'=>now()
]);
break; }
if($c->achat_groupe == 1){
$achat_groupe = 1;
}else{
$achat_groupe = 0;
}
foreach ($paniers as $c) {
CommandeProduit::create([
'commande_id'=>$commande->id,
'produit_id'=>$c->produit->id,
'prix_ht'=>$c->produit->prix_sans_taxe($c->quantite),
'prix_ttc'=>$c->produit->prix($c->quantite),
'quantite'=>$c->quantite,
'utilisateur_id'=>$utilisateur->id,
'fournisseur_id'=>$c->produit->utilisateur_id,
'boutique_id'=>$c->produit->boutique_id,
'achat_groupe'=>$achat_groupe,
'date_creation'=>now()
]);
}
$message_a_envoye = "**** Market Makers **** \n \n";
$message_a_envoye .= "Une nouvelle commande vient d'arriver";
// $date_du_jour = date("d-m-Y H:i:s");
// $message_a_envoye .= "Date d'inscription : ".$utilisateur->date_creation."\n";
// $this->telegram_send(urlencode($message_a_envoye));
// sleep(3);
$this->telegram_send_2(urlencode($message_a_envoye));
$lien_button = env('APP_URL').'/mes-commandes-b/';
$data = [
'subject' => "Nouvelle commande",
'titre_page' => 'Vous avez reçu une nouvelle commande',
'message' => 'Vous avez reçu une nouvelle commande sur votre espace Market Makers',
'lien_button' => $lien_button,
'message_button' => 'Voir'
];
// Mail::to($c->produit->utilisateur->email)->send(new NotificationMail($data,$c->produit->utilisateur));
Session::flash('success','Votre commande a bien été effectué avec succès');
Panier::where('utilisateur_id', $utilisateur->id)->delete();
$request->session()->put('venue_du_panier',null);
return redirect(route('mes-commandes'));
}
else
{
return redirect(route('mes-commandes'));
}
}
http://pastebin.fr/96873
I have a little problem, I'm getting around 800 000 datas from a json and I'm trying to insert them into a MongoDB Database. But I reach memory limit (I've set it up to 8GB for testing) while doing this. I think my script isn't optimized but I can't find where. Can you guys help me ? Here is the script :
$jsonResponse = json_decode($content->response);
$datas = $jsonResponse->hits->hits;
// On crée la collection si elle n'éxiste pas
$collection = $connection->createCollection($table->getTableName(), false );
// On enregistre les données dans la collection
foreach ($datas as $data)
{
if(!empty($data) || $data)
{
$document['_id'] = $data->_id; // ID netwoof unique
$document['_updated'] = substr($data->_source->_updated, 0, -3); // Date de dernière MàJ des données
$document['_url'] = $data->_source->_url; // Start URL
// On enregistre ensuite chaque champs définis dans le dashboard
foreach ($fields as $field)
{
// On récupère le nom du champs netwoof
$containerFieldName = $field->getContainerFieldName();
// On fait correspondre notre champ db avec celui netwoof
if( isset( $data->_source->$containerFieldName ) && (!empty($data->_source->$containerFieldName) || $data->_source->$containerFieldName == 0 ) )
$document[$field->getFieldName()] = $data->_source->$containerFieldName;
/*else
$document[$field->getFieldName()] = null;*/
}
foreach ($customFields as $customField)
{
if(!empty($customField->getFieldValue()))
$document[$customField->getFieldName()] = $customField->getFieldValue();
}
// Enregistrement des données
$collection->save($document);
}
// On réinitialise la variable
unset($document);
}
Thanks all for your answer and sorry for my english.
I'm stuck; I want to not have the "-" separator on my last item! How can I do that? I know I'm supposed to use count, but I don't know how to go further.
$report = array();
$job = null; //on met la variable a zero
$i = null;
//On extrait les valeurs dans un nouveau tableau à l'aide d'une boucle :
foreach ($values_collaborateurs as $key_collab => $row_collab)//id collab prendra chaque valeur du tableau
{
//ici ne pas mettre de report[key_collab]
//exit(var_dump($values_collaborateurs));
$report[] = $row_collab; // la valeur de id collab = indice collab
//On re extrait les valeurs: boucle du table mission:
//pour chaque élément de $values_missions => id-mission
foreach($values_missions as $key_mission => $row_mission)
{
//ici ne pas mettre de report[key_missions]
// ici la condition de recherche
if ($row_collab[0] == $row_mission[1])
{
$job .= $row_mission[2]." - ";// .= concatenation pr dire s'ajoute a row mission la valeur de job
// rempli le job par des valeurs
}
}
$report[$key_collab][] = $job; //$report = table qui contient chq valeur des key collab, et tout ça tu le stock ds $job
$i = null;
$job = null; //stop - remet le cycle job a zero pour recommencer a null
}
print_r("<pre>\n");
print_r($report);
print_r("<pre>\n");
printf("<br>\n");//passage a la ligne
?>
U can delete last two chars after foreach is completed using strlen...
foreach($values_missions as $key_mission => $row_mission)
{
//ici ne pas mettre de report[key_missions]
// ici la condition de recherche
if ($row_collab[0] == $row_mission[1])
{
$job .= $row_mission[2]." - ";// .= concatenation pr dire s'ajoute a row mission la valeur de job
// rempli le job par des valeurs
}
}
$job = substr($job,0,strlen($job)-2);
Other solution is:
$jobs[] = $row_mission[2]; // instead of: $job .= $row_mission[2] . " - ";
and after foreach will ended:
$job = implode(" - ", $jobs);
Use count() to determine the total number of items and compare it with a counter ($current_mission) that you increment each iteration step.
Then you can append the separator only if the current item is not the last one:
$current_mission = 1;
$total_missions = count($values_missions);
foreach($values_missions as $key_mission => $row_mission)
{
//ici ne pas mettre de report[key_missions]
// ici la condition de recherche
if ($row_collab[0] == $row_mission[1])
{
$job .= $row_mission[2];// .= concatenation pr dire s'ajoute a row mission la valeur de job
if ($current_mission < $total_missions) {
$job .= ' - ';
}
// rempli le job par des valeurs
}
++$current_mission;
}
An alternative is to build an array of strings and use implode().
I highly suggest to not build an array and then use implode, as it's too much overhead for both CPU and memory. If you go for substr($job,0,strlen($job)-2); you are better off with substr($job, 0, -3);, which does exactly the same.
If it's easier to read for you, you can do $job .= ' - ' . $row_mission[2]; and then substr($job, 3);.
On a side note, your code looks buggy:
You use $report[] = $row_collab;, and later $report[$key_collab][], which means you are using $reportboth as un-indexed array and associative array. That your data looks right might just be a coincidence, because if $key_collaband $row_collab have the same value, they overwrite each other.
I'm trying to do:
(i'm working with codeignitor)
$conditions = $tri." LIKE'%".$prenomNom."%' OR LIKE'%".$nomPrenom."%'";
I also tried:
$conditions = ($tri." LIKE '%".$prenomNom."%' OR ".$tri." LIKE '%".$nomPrenom."%'");
But the OR doesn't work... my request return only $tri like $nameLastname.
When i do echo of $nameLastname and $LastnameName everything is ok.
My code
public function rechercheParAuteur($selection = "*", $recherche = "", $tri = "", $champs_order = "id", $direction_ordre = "ASC", $nombre_limite = NULL, $debut_limite = NULL){
//$conditions = "titre LIKE '%".$recherche."%'"; //création de la condition personnalisée
$testrecherche = str_replace("'","\'", $recherche);
$rechercheArray = explode(" ", $testrecherche);
if (isset($rechercheArray[1]))
{
$nomPrenom = $rechercheArray[0]." ".$rechercheArray[1];
$prenomNom = $rechercheArray[1]." ".$rechercheArray[0];
//$conditions = $tri." LIKE'%".$prenomNom."%' OR LIKE'%".$nomPrenom."%'";
$conditions = ($tri." LIKE '%".$prenomNom."%' OR ".$tri." LIKE '%".$nomPrenom."%'");
//echo $nomPrenom; OK
//echo $prenomNom; OK
}
else
{
$resultat = $rechercheArray[0];
$conditions = $tri." LIKE '%".$resultat."%'";
}
$retour= $this->db->select($selection)
/*à partir de quelle table*/
->from($this->table)
/*déterminer des conditions spécifiques*/
->where($conditions)
/*déterminer un ordre précis*/
->order_by($champs_order, $direction_ordre)
/*déterminer une limite*/
->limit($nombre_limite, $debut_limite)
/*obtenir les résultats (va de pair avec result()*/
->get()
/*retourner les résultats sous forme de tableau*/
->result_array();
return $retour;
You probably want to put the condition in perens.
$conditions = "($tri LIKE '%$prenomNom%' OR $tri LIKE '%$nomPrenom%')";
I want to insert 2 times but I have routes that redirects each other, I make the first Insertion and then redirijo to another path to insert again. Would have to put begin-> transanction ()
This well done ?. regards
I first made the first Insertion, in the route
$app->post("/orders/insert", function() use($app)
{
$empleado = ORM::for_table('empleado')->select('id')->where('usuario_idusuario',$_SESSION['user_id'])->find_one();
$cliente = 'proveedor';
if(!$empleado)
{
$app->flash('error','La cuenta de usuario tiene que estar asociado a un empleado registrado en la base de datos');
$app->redirect($app->urlFor('cartList'));
}
try
{
$insertOrder = ORM::for_table('pedido')->create();
$insertOrder->fechapedido = date('Y/m/d');
$insertOrder->estado = 1;
$insertOrder->empleado_id = $empleado->id;
$insertOrder->proveedor_id = $_SESSION['idproveedor'];
$insertOrder->save();
$app->redirect("/lineorder/insert/$cliente");
}
catch(PDOException $e)
{
$app->flash('error','Ha ocurrido un error en la base de datos, no se ha insertado ningún pedido'.$e->getMessage());
$app->redirect($app->urlFor('cartList'));
}
});
After I go to the route that redirect and realized:
$app->map('/lineorder/insert/:cliente', function($cliente) use($app)
{
if(!isset($_SESSION['cart-items']))
{
$app->redirect($app->urlFor('create-order'));
$app->flash('error','No tienes carritos');
}
//Si existe la variable de sesion
else
{
if(count($_SESSION['cart-items'])>0)
{
$idpedido = ORM::for_table('pedido')->count();
foreach($_SESSION['cart-items'] as $id => $cantidad)
{
$producto = ORM::for_table('producto')->select_many('id','precioVenta','precioProveedor')->where('id',$id)->find_one();
$preciounidad = ($cliente==='proveedor') ? $producto->precioProveedor : $producto->precioVenta;
$lineorder_insert = ORM::for_table('lineapedido')->create();
$lineorder_insert->pedido_idpedido = $idpedido;
$lineorder_insert->producto_idproducto =$producto->id;
$lineorder_insert->cantidad = $cantidad;
$lineorder_insert->preciounidad = $preciounidad;
$lineorder_insert->save();
//Actualizo cantidad en la table productos
$cantidad_stock =$producto->cantidad_stock;
$cantidad_stock+=$cantidad;
$update_amount = ORM::for_table('producto')->find_one($id);
$update_amount->set('cantidad_stock',$cantidad_stock);
$update_amount->save();
$app->flash('success',"pedido {$idpedido} creado correctamente");
$app->redirect($app->urlFor('orderList'));
}
}
}
})->via('GET','POST');
I need begin->transaction()
Would you be well done?