In symfony and Doctrine i am using the session to save a query result then later on i am filtering this result with some parameters.
The problem is that once the parameters are changed i can't get the original results set. Here is the code
fetching results and saving to session
$query = $this->getDoctrine()->getManager()->createQueryBuilder();
$query->select("sp")
->from("CoreBundle:ServiceProvider","sp")
->innerJoin("sp.offers","offer")
->innerJoin("offer.service","service","with","offer.service = service")
->innerJoin("sp.firstImage","fi")
->andWhere("sp.city = :city_name")->setParameter("city_name",$cityName)
->orderBy("sp.points" ,"DESC")
->addOrderBy("sp.name" ,"ASC");
$queryAndFilters = $this->getFilters($query,$postData);
$query = $queryAndFilters['query'];
$filters=$queryAndFilters['filters'];
$paginator = $this->get('knp_paginator');
$pagination = $paginator->paginate(
$query, /* query NOT result */
$pageNumber,
20/*limit per page*/
);
$query = $query->getQuery();
$query->setHint(\Doctrine\ORM\Query::HINT_INCLUDE_META_COLUMNS, true);
$this->get('session')->set("results",$query->getResult());
and then in another function
filtering the results
$results = $this->get('session')->get("results");
$filteredResults = array();
// print_r(array_keys($results[0]));
foreach($results as $result){
$sp = $result;
foreach($sp->getOffers() as $offer){
// echo "found offer ".$offer->getName()." with price ".$offer->getPrice()."<br />";
$sp->removeOffer($offer);
if($offer->getPrice() < $minPrice || $offer->getPrice() > $maxPrice){
}else{
$sp->addOffer($offer);
// echo 'added $offer '.$offer->getName()." with price : ".$offer->getPrice()."<br />";
}
if(sizeof($sp->getOffers()) > 0 ){
array_push($filteredResults,$sp);
}
}
}
the first time i change the $minPrice and $maxPrice variables the results are filtered right and exactly what i need
but after raising the $maxPrice again the high prices are not being added to the $filteredResults
i tried also to assign $offer and $result to new variables but still not working
any idea how to fix this ?
ps. i can't change the query or to fetch them already with the query.
When you save entities in the session this entities are serialized with the values that actual at the serialization moment. Next changes of entities are not affect the stored values if you don't rewrite them in the session.
Also entitiy serializing has some limitations on private properties.
Related
I am working with laravel's LengthAwarePaginator Class. My problem is that I cannot use
$users = DB::table('users')->paginate(15);
or in other words,larvel's querybuilder or eloquent results. The reason is I have provided user with a frontend where they can create queries dynamically that can as simple as a select query and can be as complicated as queries with multiple joins etc. So I am left with only option of using LengthAwarePaginator. Here is what I have done do far
private function queryWithPagination($queryString,$path,$fieldName = '',$sortOrder = '',$perPage = 100){
$queryString = str_replace(''',"'",$queryString);
$queryString = str_replace('**',"",$queryString);
if(!empty($fieldName) && !empty($sortOrder)){
$queryString .= " ORDER BY '{$fieldName}' {$sortOrder}";
}
$currentPage = LengthAwarePaginator::resolveCurrentPage();
$limit = $perPage +1; // to have pagination links clickable i.e next,previous buttons
$queryString.= " LIMIT {$limit}";
if($currentPage == 1){
$queryString.= " OFFSET 0";
}
else{
$offset = ($currentPage-1)*$perPage;
$queryString.= " OFFSET {$offset}";
}
$path = preg_replace('/&page(=[^&]*)?|^page(=[^&]*)?&?/','', $path);
$result = DB::connection('database')->select($queryString);
$collection = new Collection($result);
//$currentPageSearchResults = $collection->slice(($currentPage - 1) * $perPage, $perPage)->all();
$entries = new LengthAwarePaginator($collection, count($collection), $perPage);
$entries->setPath($path);
//dd($queryString,$result);
dd($entries);
return $entries;
}
As you can see I append LIMIT and OFFSET in the query otherwise, for complex queries the load time was getting greater resulting in bad user experience. The problem with current set up is that the last page is always set to 2 and when I get to second page I cannot browse more results i.e cases where records returned were more than 500 I can still only browse upto page 2. How do I fix this issue where by using limit offset I can still keep browsing all the results until I get to the last page and then disable the pagination links?
made the second parameter to LengthAwarePaginator dynamic as follows in the given code,it solved my problem
$entries = new LengthAwarePaginator($collection, (count($collection)>=101)?$currentPage*$limit:count($collection), $perPage);
I'm new to php and I'm trying to add items to my DB table (cart) but when I click on 'add to cart' nothing happens. The button is displayed through the function getPro, which is below.
function cart(){
if(isset($_GET['add_cart'])){
global $con;
$ip = getIp();
$pro_id = $_GET['add_cart'];
$check_pro = "SELECT * FROM cart where ip_add='$ip' and p_id='$pro_id'";
$run_check = mysqli_query($con, $check_pro);
if(mysqli_num_rows($run_check)>0){
echo "";
}
else {
$insert_pro = "insert into cart(p_id,ip_add) values ('$pro_id','$ip')";
$run_pro = mysqli_query($con, $insert_pro);
echo "<script>window.open('index.php','_self')</script>";
}
}}
Add to cart button is echoed by this function.
function getPro(){
global $con;
$get_pro = "select * from products order by RAND() LIMIT 0,6";
$run_pro = mysqli_query($con, $get_pro);
while ($row_brand_pro=mysqli_fetch_array($run_pro)) {
$pro_id = $row_brand_pro['product_id'];
$pro_cat = $row_brand_pro['product_cat'];
$pro_brand = $row_brand_pro['product_brand'];
$pro_title = $row_brand_pro['product_title'];
$pro_price = $row_brand_pro['product_price'];
$pro_image = $row_brand_pro['product_image'];
echo "
<a href='index.php?add_cart=$pro_id'><button style='float:right;'>Add to Cart</button></a>
</div>
";
}
}
}
I can't really solve this for you because the problem could be anywhere, but you have some issues that should be resolved, hopefully some of what I am demonstrating will be useful:
1) If at all possible, use a framework instead, a lot of what you are doing is already solved (securely) by free frameworks. If you are dead-set on this:
2) Try to avoid using global, you can inject the database instead:
cart($con);
3) Split out your functions a bit more, each function is doing too much:
# Try to make this more flexible by adding the limits as variables
# Also, you might decide that random is not a great idea, so this allows you
# to change that at each instance
# Also, if you leave the columns flexible, you will make your function that
# much more useful
function getProducts($con, $cols = '*', $page = 0, $limit = 6, $rand = true)
{
# Perhaps you don't want to limit one day
$limitSql = (!empty($page) || !empty($limit))? "LIMIT {$page}, {$limit}" : "";
# This allows you to insert an array and only select certain columns
$cols = (is_array($cols))? implode(", ", $cols) : $cols;
# Only add the randomness if you want to (default is to randomize)
$sql = ($rand)? "ORDER BY RAND()" : '';
# Create your dynamic statement
$stmnt = "SELECT {$cols} FROM products {$sql} {$limitSql}";
$query = mysqli_query($con, $stmnt);
# Have this just assemble the values, don't echo anything
while ($result = mysqli_fetch_array($query)) {
$row[] = $result;
}
# Send back the results
return (!empty($row))? $row : [];
}
Using this function:
# This would give you results with just the two columns with 10 results, no random
$products = getProducts($con, array("product_id", "product_title"), 0, 10, false);
# This should just return the count
$products = getProducts($con, "COUNT(*) as count", false, false, false);
So, now that you have this function, you write the loop in the view:
<?php foreach(getProducts($con, 'product_id') as $row): ?>
<!-- Now you have only pulled the one column required for this use -->
Add to Cart
<?php endforeach ?>
4) This cart function is more problematic, it has a few issues. a) You need to bind parameters if your values from the user are not numeric, what you have is an sql injection and is a security issue b) You should split this function into two, c) You should leave the echoing outside in the view. d) If you are storing carts by ip, I would maybe not do that, more than one computer can have the same ip if they are using a VPN or on the same network. A cookie may be a better solution:
function itemExists($con, $pid, $ip)
{
$stmnt = "SELECT * FROM cart WHERE ip_add = '{$ip}' and p_id = '{$pid}'";
$query = mysqli_query($con, $stmnt);
return (mysqli_num_rows($query) > 0);
}
function addToCart($con, $pid, $qty = 1)
{
# Since you aren't binding, you need some sort of safeguard here, I am assuming
# your product id values are numeric. If not, you definitely need to bind parameters
if(!is_numeric($pid))
return false;
# Same here, you need to make sure nothing but numbers get through (or bind)
if(!is_numeric($qty))
$qty = 1;
# Pass on your connection and pid, inject the getIp() function if you choose
# to keep using it
$itemExists = itemExists($con, $pid, getIp());
# Confirm the item has no row in database
if($itemExists)
# Stop if it does
return false;
# You may want to echo here to see if this is what you expect
$stmnt = "insert into cart(p_id, ip_add) values ('{$pid}', '{$ip}')";
# I use PDO, but I am sure you can get an error back on this if the sql
# fails for whatever reason, that is a good place to start for your issue
$query = mysqli_query($con, $stmnt);
# Run this again to make sure it inserted
return itemExists($con, $pid, getIp());
}
Now in your view:
if(!empty($_GET['add_cart'])) {
# When you add to cart, there should be some feed back to whether it was successful
$success = addToCart($con, $_GET['add_cart']);
# If not you can echo it
if(!$success)
echo '<div class="msg error">An error occurred adding item to cart.</div>';
}
Anyway, hopefully this is useful, but you should think about 1) using a framework and if not, then use the OOP version of mysqli (or PDO) because the binding of parameters is much easier (I find) than the functional mysqli library.
I have this script executing as a cron job everyday to update days remaining to pay invoices. I first query every row of my table and attempt to store the data in a multidimensional array but this seems to be storing everything I query in the first element of my array.
Here's my script:
<?php
include '../inc/dbinfo.inc';
ini_set("log_errors", 1);
ini_set("error_log", "/tmp/php-error.log");
error_log( "################################################# UpdateVendorInvoiceDays.php #################################################" );
$three = 3;
$fetchAllInvoices = "SELECT VENDORINVOICEID, VdrInvoiceReceived, PaymentDue, COUNT(*), DATEDIFF(PaymentDue, NOW()) FROM tblVendorInvoices WHERE VdrInvoiceStatusID != ?";
$getInvoices = $conn->prepare($fetchAllInvoices);
$getInvoices->bind_param("i", $three);
$getInvoices->execute();
$result = $getInvoices->get_result();
$rows = array();
$j = 0;
while($row = $result->fetch_assoc())
{
$rows[$j][] = $row;
$j++;
}
echo json_encode($rows[0][0]); //Only outputs one row
//UPDATE DAYS REMAINING IN EACH ENTRY THAT ISNT PAID
$updateDaysRemaining = "UPDATE tblVendorInvoices SET DaysRemaining = ? WHERE VENDORINVOICEID = ? AND VdrInvoiceStatusID ! = ?";
$setDays = $conn->prepare($updateDaysRemaining);
$k = 0; //incrementor
$numberOfEntries = $rows['COUNT(*)'];
for($k;$k<$numberOfEntries;$k++){
$setDays->bind_param("iii", $rows[$k]["DATEDIFF(PaymentDue, NOW())"],
$rows[$k]['VENDORINVOICEID'], $three);
if($setDays->execute()){
error_log('Cron success');
}else{
error_log('Cron fail');
}
}
?>
Currently the output from my first query is:
[[{"VENDORINVOICEID":88,"VdrInvoiceReceived":"2018-08-21","PaymentDue":"2018-07-27","COUNT(*)":2,"DATEDIFF(PaymentDue, NOW())":-25}]]
and my error log only gives me a notice for $rows['COUNT(*)'] being undefined (which makes sense)
I've looked at other answers here but they don't seem to have the same structure as I do.
EDIT: I also have 2 rows in my database but this only puts out one. I forgot to mention this.
There are a couple of simplifications to get all of the rows. Instead of...
while($row = $result->fetch_assoc())
{
$rows[$j][] = $row;
$j++;
}
echo json_encode($rows[0][0]);
You can just return all rows using fetch_all()...
$rows = $result->fetch_all (MYSQLI_ASSOC);
echo json_encode($rows);
Then encode the whole array and not just the one element - which is what $rows[0][0] was showing you.
As for you other problem - change in your select statement to
COUNT(*) as rowCount
and then you can use this alias for the field reference...
$rows['COUNT(*)']
becomes
$rows['rowCount']
I am trying to get a list of coupons through ajax when the checkboxes are selected. So everything else is working fine but the query is returning only the first match.
So my query is:
$this->db->from('tbl_coupons');
if($storeids !=''){
$ids = array($storeids);
$this->db->where_in('coupon_store', $ids );
}
$this->db->where('coupon_cat', $catid);
$this->db->where('coupon_status', 'active');
$query = $this->db->get();
if ($query->num_rows() > 0) {
$ds = $query->result_array();}
According to this my SQLquery becomes
SELECT * FROM `tbl_coupons`
WHERE `coupon_store` IN('1,97')
AND `coupon_cat` = '16'
AND `coupon_status` = 'active'
But this query is returning values with coupon_store=1 and no results are coming for coupon_store=97
I checked values for coupon store 97 which exists in that category.
use below way if data exist it will be part of query.
storeids = explode(',',storeids);
$ids = array();
foreach($storeids as $val){
$ids[] = $val;
}
if(!empty($ids)){
$this->db->where_in('coupon_store', $ids );
}
hope it will create proper sql query
The query is mostly correct, except at line 2, where you need to make the change as:
WHERE coupon_store IN('1','97')
everything else remains the same.
Code is below if I run one value in the array the results are correct if I run more than one value the results are of the price is incorrect its like it has messed around with the values somewhere ?? help appreciated
$dido=array('42204131','22204131');
foreach($dido as $did):
$query = "select * from dispatch,link where lid=dlid and did=$did";
$result = mysql_query($query) or die(mysql_error());
while($row = mysql_fetch_array($result)){
$vanc1=$row['vanc1'];
$vanc2=$row['vanc2'];
$vanc3=$row['vanc3'];
$vanc4=$row['vanc4'];
$vanc5=$row['vanc5'];
$anc1=$row['anc1'];
$anc2=$row['anc2'];
$anc3=$row['anc3'];
$anc4=$row['anc4'];
$anc5=$row['anc5'];
// price anc1
$querypanc1 = "select pprice from products where pid=$anc1";
$resultpanc1 = mysql_query($querypanc1);
while($row = mysql_fetch_array($resultpanc1))
{
$priceanc1=$row[pprice];
$tpriceanc1=$vanc1*$priceanc1;
}
// price anc2
$querypanc2 = "select pprice from products where pid=$anc2";
$resultpanc2 = mysql_query($querypanc2);
while($row = mysql_fetch_array($resultpanc2))
{
$priceanc2=$row[pprice];
$tpriceanc2=$vanc2*$priceanc2;
}
// price anc3
$querypanc3 = "select pprice from products where pid=$anc3";
$resultpanc3 = mysql_query($querypanc3);
while($row = mysql_fetch_array($resultpanc3))
{
$priceanc3=$row[pprice];
$tpriceanc3=$vanc3*$priceanc3;
}
// price anc4
$querypanc4 = "select pprice from products where pid=$anc4";
$resultpanc4 = mysql_query($querypanc4);
while($row = mysql_fetch_array($resultpanc4))
{
$priceanc4=$row[pprice];
$tpriceanc4=$vanc4*$priceanc4;
}
// price anc5
$querypanc5 = "select pprice from products where pid=$anc5";
$resultpanc5 = mysql_query($querypanc5);
while($row = mysql_fetch_array($resultpanc5))
{
$priceanc5=$row[pprice];
$tpriceanc5=$vanc5*$priceanc5;
}
$gtprice=$tpriceanc1+$tpriceanc2+$tpriceanc3+$tpriceanc4+$tpriceanc5;
$qrygt="UPDATE dispatch SET gtprice=$gtprice WHERE did=$did";
$resultgt=#mysql_query($qrygt);
}
endforeach;
1) The only possible issue I could spot in your code, is that when some of your select pprice from products where pid ... queries do not return any data, you retain value of $tpriceancX from previous iteration.
2) Also (out of topic) you can replace your 5 blocks of repeated code with for loop.
$gtprice = 0;
for ($i = 1; $i <= 5; $i++)
{
$querypanc = "select pprice from products where pid=".$row["anc$i"];
$resultpanc = mysql_query($querypanc);
while($pancrow = mysql_fetch_array($resultpanc))
{
$priceanc=$pancrow[pprice];
$tpriceanc=$row["vanc$i"]*$priceanc;
$gtprice += $tpriceanc;
}
}
Your first and biggest problem is the copy-pasta nature of your code. Let's try and break down what you're doing:
Setting up a list of ids
Running a query on those ids
Putting the results into an array
Running a separate query on each of those results
You are also using some very janky syntax. (ie foreach($foo as $bar):).
Break these things down into methods. What is a method? It takes an input and transforms it into an output.
//returns an array of price information
public function getPrices($idArray) { //note the good method and parameter names!
//do stuff
}
Now that we know what we are doing, we can start to fill in the implementation details:
public function getPrices($idArray) {
foreach($idArray as $id) {
//somehow get the gross-scale information
//then put it in a data object
//then call a function to get specific information
}
}
What should that sub-method do? Lets look at your current code snippet:
// price anc1
$querypanc1 = "select pprice from products where pid=$anc1";//sets up sql query
$resultpanc1 = mysql_query($querypanc1); //runs the query
while($row = mysql_fetch_array($resultpanc1)) { //for each result
$priceanc1=$row[pprice]; //gets the price
$tpriceanc1=$vanc1*$priceanc1; //calculates some other price
}
Those last two lines really suggest an object but maybe that's too heavyweight for your purpose. The first two lines are boiler plate you repeat endlessly. Lets write a function!
public function getPrices($name, $pid, $multiplier) {
$sqlQuery = "SELECT pprice FROM products WHERE pid=$pid";
$result = mysql_query($sqlQuery);
$prices = array();
while ($row = mysql_fetch_array($result) {
$key = "price".$name;//$key will be something like 'priceanc1'
$prices[$key] = $row[pprice];
$tkey = "tprice".$name;
$prices[$tkey] = $prices[$key] * $multiplier;
}
}
Now, this function is a bit unclean because it tries to do two things at once (queries the database and then massages the data into a usable array) but I wanted it to resemble what you were doing. With this function written we can go back to our higher level function an call it:
public function getPrices($idArray) {
foreach($idArray as $id) {
$sqlQuery = "SELECT * from dispatch, link WHERE lid=dlid and did=$id";
$prices = array();
while ($row = mysql_fetch_array($result) {
for ($idx = 1; $idx <= 5; $idx++) {
$name = "anc".$idx;
$pid = $row[$name];
$multiplier = $row["vanc".$idx];
$priceArray = getPrices($name, $pid, $multiplier);
$prices = array_merge($prices, $priceArray);
}
}
}
//put a var_dump here to check to see if you're getting good results!
return $prices;//Should be the aggregated prices you've gotten from the db
}
Now, that is what you're attempting to do, but I admit I don't understand how your database is set up or what your variables actually mean. Pressing on! We also note that unnecessary massaging of data falls away.
You can call this like so:
$ids = array();
$ids[] = 42204131;
$ids[] = 22204131;
$prices = getPrices($ids);
var_dump($prices);//shows the result of your work
Now that you have the prices, you can pass them to another function to run the update:
updatePrices($prices);
I'll let you write that part on your own. But remember; break down what you're doing and have repeated elements be handled by the same function. The real lesson to learn here is that programming is really communicating: your code doesn't communicate anything because there is so much repeated noise. Use good variable names. Tighten what you're doing down to functions with single tasks. This way anyone reading your code (including you!) will know what you're trying to do and where you've gone wrong.