Je construis un composant qui est sur le point d'être finalisé, mais il y a un peu de code que je veux refactoriser. Je pense que ce code peut être complété en une déclaration et j'ai utilisé plus de 3 déclarations.
$db = JFactory::getDBO();
$query = $db->getQuery(true);
foreach ($pks as $i => $pk)
{
//getting the sid from student table
$query->clear();
$query->select('sid')
->from('#__student')
->where('id = '.$pk);
$db->setQuery($query);
$sid = $db->loadResult();
$query->clear();
//fetching the data of old entry from log table using sid
$query->select('*')
->from('#__log')
->where('sid = '.$sid)
->where('pas= 0')
->where('stops=0');
$db->setQuery($query);
$obj=$db->loadObject('stdClass');
//updating the old entry in log table
$query->clear();
$query->update('#__log')
->set('pas = 1')
->where('sid = '.$sid)
->where('pas= 0')->where('stops=0');
$db->setQuery($query);
$db->execute();
//I'm doing this to know about is there at-least one row affected if not then we will not insert a new recorded
$count=$db->getAffectedRows();
//after setting pass to 1 we will ++ class by 1 and year by 1
$obj->class=$obj->class+1;
$obj->year=$obj->year+1;
if($count == 1)
{
$query->clear();
$query->insert('#__log')
->columns('class, year, sid, prmoted')
->values($obj->class.','.$obj->year.','.$sid.','. 1);
$db->setQuery($query);
$db->execute();
}
Dans ce code, je sélectionne d’abord l’enregistrement d’étudiant en cours à partir du #__log
table pour la prochaine utilisation. Ensuite, je mets à jour le même enregistrement et mets pass
sur 1
. Puis, en utilisant les données précédemment sélectionnées, j’insère un nouvel enregistrement dans la même table de journal avec class+1
et year+1
valeurs.
Je pense que ce code peut être hautement refactorisé, est-ce que n'importe quel corps peut m'aider?
Au moins, je vois un moyen de combiner vos deux premières requêtes de sélection en une seule à l’aide de SQL JOIN:
$query->select('sid')->from('#__student')->where('id = '.$pk);
$db->setQuery($query);
$sid = $db->loadResult();
$query->clear();
//fetching the data of old entry from log table using sid
$query->select('*')->from('#__log')->where('sid = '.$sid)->where('pas= 0')->where('stops=0');
$db->setQuery($query);
$obj=$db->loadObject('stdClass');
devient quelque chose comme:
$query
->select('l.*')
->from('#__log l')
->leftJoin('#__student s ON s.sid = l.sid')
->where('s.id = ' . (int) $pk)
->where('l.pas = 0')
->where('l.stops = 0')
$obj = $db->setQuery($query)->loadObject();
(pas testé)
Je ne vois pas un moyen de faire votre SELECT, UPDATE et INSERT en une seule étape.
Pour tester mon code-refactor suggéré, il me faudrait accéder à vos structures de table et à un nombre suffisant de lignes d'échantillon. Je vais tenter le coup quand même ...
Essentiellement, vous devez exécuter une requête de sélection pour isoler toutes les lignes à traiter. En incluant les valeurs class
et year
dans votre jeu de résultats éligible, vous pourrez créer un seul lot de mises à jour et un seul lot d'insertions.
Garder le nombre minimal de déplacements dans la base de données est certainement un exemple de meilleure pratique. Mon extrait fera 1 voyage s'il n'y a pas de lignes qualifiantes et 3 voyages s'il y a des lignes qualifiantes. Votre code d'origine cherchait à faire N * 3 voyages vers la base de données. Mon refactor est une amélioration majeure de la performance.
Ce code n'est pas testé (... si quelqu'un remarque une erreur, merci de le commenter):
try {
// generate result set of qualifying rows which need to be updated and inserted
$db = JFactory::getDBO();
$select_query = $db->getQuery(true)
->select($db->qn(["a.sid", "a.class", "a.year"]))
->from("#__log a")
->innerJoin("#__student b ON a.sid = b.sid")
->where([
"a.pas = 0",
"a.stops = 0",
"b.id IN (" . implode(',', array_map(function($n){return (int)$n;}, $pks)) . ")" // just in case $pks is not secure
]);
// don't show rendered queries to the public
JFactory::getApplication()->enqueueMessage("<div>Rendered Select Query<br><b>" . $select_query->dump() . "</b></div>", 'notice');
$db->setQuery($select_query);
if (!$log_rows = $db->loadAssocList()) {
"No qualifying student logs to process";
} else {
$insert_query = $db->getQuery(true)
->insert('#__log')
->columns($db->qn(["class", "year", "sid", "prmoted"]));
foreach ($log_rows as $row) { // generate batched data for just two total queries
$update_ids[] = (int)$row['sid'];
$insert_query->values((1 + $row['class']) . ", " . (1 + $row['year']) . ", " . (int)$row['sid'] . ", 1");
}
$update_query = $db->getQuery(true)
->update("#__log")
->set("pas = 1")
->where("sid IN (" . implode(",", $update_ids) . ")");
// don't show rendered queries to the public
JFactory::getApplication()->enqueueMessage("<div>Rendered Update Query<br><b>" . $update_query->dump() . "</b></div>", 'notice');
$db->setQuery($update_query);
$db->execute();
JFactory::getApplication()->enqueueMessage("<div>" . $db->getAffectedRows() . " Rows Of Data Updated", 'success');
// don't show rendered queries to the public
JFactory::getApplication()->enqueueMessage("<div>Rendered Insert Query<br><b>" . $insert_query->dump() . "</b></div>", 'notice');
$db->setQuery($insert_query);
$db->execute();
JFactory::getApplication()->enqueueMessage("<div>" . $db->getAffectedRows() . " Rows Of Data Inserted", 'success');
}
} catch (Exception $e) { // this will halt the execution within the try block as soon as something errs
// don't show actual error message to public
JFactory::getApplication()->enqueueMessage("Query Syntax Error: " . $e->getMessage(), 'error');
}