How to create a PDO query for fetch with variables - php

I am trying to build a PDO query for a large project to fetch SQL fetch queries. These SQL queries use variables to get values. I can't use the ones I get in the tutorials - I don't understand how to modify them to be able to use variables instead of :id for example. I have many many many files to update to PDO, because currently they are written using mysql()
An example of the query (one in of hundreds of files):
if(!$GLOBALS['this_brand']->id) return false;
if(!$GLOBALS['url_lang']) return false;
if(!$GLOBALS['this_region']->id) return false;
if(!$GLOBALS['this_type']->id) return false;
if(!$GLOBALS['this_user']->group) return false;
if(!$liveid = $GLOBALS['this_config']->get('config_live_id')) return false;
if(!$draftid = $GLOBALS['this_config']->get('config_draft_id')) return false;
if(!$archiveid = $GLOBALS['this_config']->get('config_archive_id')) return false;
if($GLOBALS['this_user']->is_admin()) {
$statussql = "AND (page.status = ".$liveid." OR page.status = ".$draftid." OR page.status = ".$archiveid.")";
}
else {
$statussql = "AND page.status = ".$liveid;
}
$the_statement = "SELECT * FROM page
LEFT JOIN _page_brand ON page.id = _page_brand.page_id
LEFT JOIN _page_language ON page.id = _page_language.page_id
LEFT JOIN _page_region ON page.id = _page_region.page_id
LEFT JOIN _page_type ON page.id = _page_type.page_id
LEFT JOIN _page_group ON page.id = _page_group.page_id
LEFT JOIN _page_section ON page.id = _page_section.page_id
WHERE _page_brand.brand_id = ".$GLOBALS['this_brand']->id."
AND _page_language.language_iso = '".$GLOBALS['url_lang']."'
AND _page_region.region_id = ".$GLOBALS['this_region']->id."
AND _page_type.type_id = ".$GLOBALS['this_type']->id."
AND _page_group.group_id = ".$GLOBALS['this_user']->group."
AND _page_section.section_id = ".$GLOBALS['this_section']->id."
".$statussql."
AND page.url = '".$this->url."'
ORDER BY page.status ASC, page.moddate DESC
LIMIT 1";
My PDO attempt (it looks really lame but I did try different ways, but removed the code once they didn't work):
public function fetchRaw($query){
$stmt = $this->db->query($query);
$arr = [];
foreach ($stmt as $row) {
$rarr = [];
foreach($row as $k=>$v) {
$rarr[$k] = $v;
}
$arr[] = $rarr;
}
return $arr;
}
I tried with the fetch(), the while loop etc. I cannot go and change each current query - there are thousands of them. Any help on how this should be approached will be appreciated. I am not an expert on PDO yet, and this huge project is a bit overwhelming, but I need to do this.

Related

Load optimisation of a logic where query is running inside loop

I have a rest api code block which is then being used for a report. The api returns collection of invoices, but adds few fields to individual invoices.
The fields are of order item level.
Currently this code works fetching the items information
private function pushAdditionalData($invoicedetails): array
{
foreach($invoicedetails as &$invoice) {
$connection = $this->resource->getConnection();
$sql = "SELECT SUM(TRUNCATE(soi.original_price * soi.qty_invoiced,2)) AS tot_original_price,SUM(TRUNCATE(cped.value * soi.qty_invoiced,2)) AS tot_cost,SUM(TRUNCATE(soi.price_incl_tax * soi.qty_invoiced,2)) AS tot_discount_price,sal.customer_id AS customer_id,sal.increment_id AS order_id FROM sales_order_item soi INNER JOIN catalog_product_entity_decimal cped ON soi.product_id = cped.entity_id INNER JOIN sales_order sal ON soi.order_id = sal.entity_id WHERE cped.attribute_id = 81 AND soi.order_id = ".$invoice['order_id'];
$data = $connection->fetchRow($sql);
$invoice['customer_id'] = $data['customer_id'];
$invoice['order_increment_id'] = $data['order_id'];
$invoice['product_cost'] = $data['tot_cost'];
$invoice['product_discounts'] = (string)abs($data['tot_original_price'] - $data['tot_discount_price']);
}
return $invoicedetails;
}
But as this is a query running inside a loop, I am trying to find a better way of doing this.
I tried using the same query with IN statement. But the data manipulation after that is getting too heavy and complex. This code is returning a similar result
private function testPushAdditionalData($invoicedetails)
{
foreach($invoicedetails as $invoice) {
$invoiceData[] = $invoice['order_id'];
}
$invoiceStr = implode(',', $invoiceData);
$connection = $this->resource->getConnection();
$sql = "SELECT sii.parent_id AS invoice_id,TRUNCATE(soi.original_price * soi.qty_invoiced,2) AS tot_original_price,TRUNCATE(cped.value * soi.qty_invoiced,2) AS tot_cost,TRUNCATE(soi.price_incl_tax * soi.qty_invoiced,2) AS tot_discount_price,sal.customer_id AS customer_id,sal.increment_id AS order_id FROM sales_order_item soi INNER JOIN catalog_product_entity_decimal cped ON soi.product_id = cped.entity_id INNER JOIN sales_order sal ON soi.order_id = sal.entity_id INNER JOIN sales_invoice_item sii ON soi.item_id = sii.order_item_id WHERE cped.attribute_id = 81 AND soi.order_id IN (".$invoiceStr.")";
$additionalInvoiceData = $connection->fetchAll($sql);
foreach($invoiceData as $invD) {
$totOrgPrice = $totCost = $totDisc = [];
foreach($additionalInvoiceData as $addInvD) {
if($invD == $addInvD['main_id']) {
$totOrgPrice[] = $addInvD['tot_original_price'];
$totCost[] = $addInvD['tot_cost'];
$totDisc[] = $addInvD['tot_discount_price'];
$customerId = $addInvD['customer_id'];
$orderId = $addInvD['order_id'];
}
}
$data[$invD] = [
'product_cost'=>number_format(array_sum($totCost),2),
'product_discounts'=>number_format(abs(array_sum($totOrgPrice) - array_sum($totDisc)),2),
'customer_id'=>$customerId,
'order_id'=>$orderId
];
}
foreach($invoicedetails as &$invoice) {
$invoice['customer_id'] = $data[$invoice['order_id']]['customer_id'];
$invoice['order_increment_id'] = $data[$invoice['order_id']]['order_id'];
$invoice['product_cost'] = (string)$data[$invoice['order_id']]['product_cost'];
$invoice['product_discounts'] = (string)$data[$invoice['order_id']]['product_discounts'];;
}
return $invoicedetails;
}
But the execution time of this is twice of the original one.
What is the best way I can optimise this code?

php if else statement: display data if there are results from either 2 functions

I'd really appreciate some help with this code as I can't get it to work properly.
I have two separate functions that both check a table in my database for data against an ID that is fetched from the page's URL. On displaying the information, I want to use an IF ELSE statement to check if there are results from either of those functions, and if there are no results, post nothing, and if there are results, post the results.
Below are my functions:
function getArtistsBySongId($id) {
$query = "SELECT * FROM `Credit_To_Artist` AS c2a
INNER JOIN `Credits` AS cr ON cr.credit_id = c2a.credit_id
INNER JOIN `Artist` AS a ON a.artist_id = c2a.artist_id
LEFT OUTER JOIN `Song` AS s ON s.song_id = c2a.song_id
LEFT OUTER JOIN `Remix` AS r ON r.remix_id = c2a.remix_id
LEFT OUTER JOIN `Project` AS p ON p.project_id = s.project_id
WHERE c2a.song_id = $id
ORDER BY a.artist_name ASC";
$res = mysql_query($query);
$artists = Array();
$artisttoid = Array();
$songtoid = Array();
while( $row = mysql_fetch_array($res) ) {
$artist = $row[artist_name];
$credit = $row[credit_name];
$songcr = $row[song_id];
if(!array_key_exists($artist, $artists) ) {
$artists[$artist] = Array();
$artisttoid[$artist] = $row[artist_id];
$songtoid[$songcr] = $row[song_id];
}
$artists[$artist][] = $credit;
}
return array($artists, $artisttoid, $songtoid);
}
function getGroupsBySongId($id) {
$query = "SELECT * FROM `Credit_To_Artist` AS c2a
INNER JOIN `Credits` AS cr ON cr.credit_id = c2a.credit_id
INNER JOIN `Artist_Group` AS ag ON ag.group_id = c2a.group_id
LEFT OUTER JOIN `Song` AS s ON s.song_id = c2a.song_id
LEFT OUTER JOIN `Remix` AS r ON r.remix_id = c2a.remix_id
LEFT OUTER JOIN `Project` AS p ON p.project_id = s.project_id
WHERE c2a.song_id = $id
ORDER BY ag.group_name ASC";
$res = mysql_query($query);
$groups = Array();
$grouptoid = Array();
$song2id = Array();
while( $row = mysql_fetch_array($res) ) {
$group = $row[group_name];
$credits = $row[credit_name];
$songcred = $row[song_id];
if(!array_key_exists($group, $groups) ) {
$groups[$group] = Array();
$grouptoid[$group] = $row[group_id];
$song2id[$songcred] = $row[song_id];
}
$groups[$group][] = $credits;
}
return array($groups, $grouptoid, $song2id);
}
At the moment I have this code:
<?php
if ((getArtistsBySongId($id) != NULL) OR (getGroupsBySongId($id) != NULL)) {
include 'songs/getsongcredits.php';
}
?>
While the code works in displaying my data, it seems to be ignoring my IF statement, and just posting what's in the include. Would someone be able to let me know the correct way to do this? Thanks in advance.
Both of your functions are returning an array regardless of the outcome of the query. Therefore you should check if the result returned from your functions are empty or not.
<?php
if (!empty(getArtistsBySongId($id)) OR !empty(getGroupsBySongId($id))) {
include 'songs/getsongcredits.php';
}
?>
Since both of your functions return arrays I would consider checking the size of the arrays returned. If you have data then the array size would be greater than 0 otherwise it would be 0.
<?php
$artistsBySongId = count(getArtistsBySongId($id));
$groupsBySongId = count(getGroupsBySongId($id));
if (($artistsBySongId != 0) || ($groupsBySongId != 0)) {
include 'songs/getsongcredits.php';
}
?>
Thanks all for taking the time to answer my question. However, neither of the codes worked in my site. A friend of mine has helped me though and it is now working. This is the code he used:
<?php
$errors = array_filter(getArtistsBySongId( $id ));
$errors1 = array_filter(getGroupsBySongId( $id ));
if (empty($errors) AND empty($errors1)) {
} else {
include 'songs/getsongcredits.php';
}
?>

SQL Optimisation, inner ? (RBAC)

Can you tell me a better choice for doing nested select statements?
Am working on rbac project and I need to get privilege on tables.
Now this code works perfectly but if I have many data in table, the query count gets bigger.
$DB_Query_AID = $DB_Cnx->query("SELECT * FROM stackover_link WHERE link_from='123456' AND link_level='0';");
while($DB_DataAID = $DB_Query_AID->fetch()) {
if(!empty($DB_DataAID['LID'])) {
$AID = $DB_DataAID['link_to'];
$DB_Query_BID = $DB_Cnx->query("SELECT * FROM stackover_link WHERE link_from='$AID' AND link_level='1';");
while($DB_DataBID = $DB_Query_BID->fetch()) {
if(!empty($DB_DataBID['LID'])) {
$BID = $DB_DataBID['link_to'];
$DB_Query_CID = $DB_Cnx->query("SELECT * FROM stackover_link WHERE link_from='$BID' AND link_level='2';");
while($DB_DataCID = $DB_Query_CID->fetch()) {
if(!empty($DB_DataCID['LID'])) {
$CID = $DB_DataCID['link_to'];
$DB_Query_DID = $DB_Cnx->query("SELECT * FROM stackover_link WHERE link_from='$CID' AND link_level='3';");
while($DB_DataDID = $DB_Query_DID->fetch()) {
if(!empty($DB_DataDID['LID'])) {
//foooooooooooooooo........
}
}
}
}
}
}
}
}
Is possible do to same with only 1 query ?
Thanks for you help.
This looks like an INNER JOIN is possible:
SELECT sl0.*, sl1.* FROM stackover_link sl0
INNER JOIN stackover_link sl1 ON sl0.link_to = sl1.link_from and sl1.link_level = 1
...
WHERE sl0.link_from='123456' AND sl0.link_level='0';

Php - mysql - Return number of rows

I am trying to get the number of friends that a user has, but I can't seem to get it to work, so i'm really hoping that you can help me.
Here is the php
$findFriendssql = "select u.firstName, u.id from friends f, user u
where (f.u_ID1 = '$loggedId' and u.id = f.u_id2)
or (f.u_id2 = '$loggedId' and u.id = f.u_id1)";
$all_friends_sql = $db->getRows($findFriendssql);
//$number_of_friends = mysql_num_rows($all_friends_sql);
if ($all_friends_sql) {
$number_of_friends = mysql_num_rows($all_friends_sql);
$friends = "";
foreach ($all_friends_sql as $one_post) {
//doing stuff here.
and here is the get rows function
public function getRows($sql) {
$result = array();
$table = mysql_query($sql, $this->db_link);
if (!$table) {
die("\"$sql\" seems to be an invalid query: " . mysql_error());
}
while ($row = mysql_fetch_assoc($table)) {
array_push($result, $row);
}
return $result;
}
whatever I try - I get the error that the num rows expects parameter 1 to be resource.
thank you in advance
$findFriendssql = "select u.firstName, u.id from friends f, user u where (f.u_ID1 = '$loggedId' and u.id = f.u_id2)
or (f.u_id2 = '$loggedId' and u.id = f.u_id1)";
$all_friends_sql = $db->getRows($findFriendssql);
//$number_of_friends = mysql_num_rows($all_friends_sql);
if (count($all_friends_sql)>0) {
$number_of_friends = mysqli_num_rows($all_friends_sql);
$friends = "";
foreach ($all_friends_sql as $one_post) {
The num row is supposed to happen immediatelly after this:
$table = mysql_query($sql, $this->db_link);
$totalFirends = mysql_num_rows($table);
Use $table as input parameter. $table is supposed to be a resource. to be able to use mysql_num_rows.
The following in your function changes $table not to be a resource anymore. Besides you do not need this code to know how many friend the user has:
while ($row = mysql_fetch_assoc($table)) {
array_push($result, $row);
}
return $result;
}
Also if you just need the number then the query should change to SELECT COUNT(some-field)
And I do not know what is the content of $loggedId hope you tested that the query returns what is supposed to return. is correct the output of the query with a sample data, let say in phpmyadmin?

PHP: Join two separate mysql queries into the same json data object

I'm trying to mesh the below mysql query results into a single json object, but not quite sure how to do it properly.
$id = $_POST['id'];
$sql = "SELECT contracts.po_number, contracts.start_date, contracts.end_date, contracts.description, contracts.taa_required, contracts.account_overdue, jobs.id AS jobs_id, jobs.job_number, companies.id AS companies_id, companies.name AS companies_name
FROM contracts
LEFT JOIN jobs ON contracts.job_id = jobs.id
LEFT JOIN companies ON contracts.company_id = companies.id
WHERE contracts.id = '$id'
ORDER BY contracts.end_date";
$sql2 = "SELECT types_id
FROM contracts_types
WHERE contracts_id = '$id'";
//return data
$sql_result = mysql_query($sql,$connection) or die ("Fail.");
$arr = array();
while($obj = mysql_fetch_object($sql_result)) { $arr[] = $obj; }
echo json_encode($arr); //return json
//plus the selected options
$sql_result2 = mysql_query($sql2,$connection) or die ("Fail.");
$arr2 = array();
while($obj2 = mysql_fetch_object($sql_result2)) { $arr2[] = $obj2; }
echo json_encode($arr2); //return json
Here's the current result:
[{"po_number":"test","start_date":"1261116000","end_date":"1262239200","description":"test","taa_required":"0","account_overdue":"1","jobs_id":null,"job_number":null,"companies_id":"4","companies_name":"Primacore Inc."}][{"types_id":"37"},{"types_id":"4"}]
Notice how the last section [{"types_id":"37"},{"types_id":"4"}] is placed into a separate chunk under root. I'm wanting it to be nested inside the first branch under a name like, "types".
I think my question has more to do with Php array manipulation, but I'm not the best with that.
Thank you for any guidance.
Combine the results into another structure before outputting as JSON. Use array_values to convert the type IDs into an array of type IDs. Also, fix that SQL injection vulnerability. Using PDO, and assuming the error mode is set to PDO::ERRMODE_EXCEPTION:
$id = $_POST['id'];
try {
$contractQuery = $db->prepare("SELECT contracts.po_number, contracts.start_date, contracts.end_date, contracts.description, contracts.taa_required, contracts.account_overdue, jobs.id AS jobs_id, jobs.job_number, companies.id AS companies_id, companies.name AS companies_name
FROM contracts
LEFT JOIN jobs ON contracts.job_id = jobs.id
LEFT JOIN companies ON contracts.company_id = companies.id
WHERE contracts.id = ?
ORDER BY contracts.end_date");
$typesQuery = $db->prepare("SELECT types_id
FROM contracts_types
WHERE contracts_id = ?");
$contractQuery->execute(array($id));
$typesQuery->execute(array($id));
$result = array();
$result['contracts'] = $contractQuery->fetchAll(PDO::FETCH_ASSOC);
$result['types'] = array_values($typesQuery->fetchAll(PDO::FETCH_NUM));
echo json_encode($result); //return json
} catch (PDOException $exc) {
...
}
If $contractQuery returns at most one row, change the fetch lines to:
$result = $contractQuery->fetch(PDO::FETCH_ASSOC);
$result['types'] = array_values($typesQuery->fetchAll(PDO::FETCH_NUM));
It would seem like you'd be better served by consolidating the two queries with a JOIN at the SQL level. However, assuming the two arrays have equal length:
for ($x = 0, $c = count($arr); $x < $c; $x++) {
if (isset($arr2[$x])) {
$arr[$x] += $arr2[$x];
}
}
echo json_encode($arr);
Edit: you would need to change from mysql_fetch_object to mysql_fetch_assoc for this to work properly.
Why are you using 2 distinct arrays ? I would simply add the rows of the 2nd query in $arr instead of $arr2. This way, you end up with a single array containing all rows from the 2 queries.

Categories