I am a .NET programmer and rarely work with PHP. How can I tell if this query fails or if this query updates 0 rows? I am using OpenCart:
public function updateInventory($product_id, $quantity)
{
$query = $this->db->query("Update " . DB_PREFIX . "product SET quantity ='" . $this->db->escape($quantity) . "' WHERE sku='" . $this->db->escape($product_id) . "'");
return "OK";
}
replacing
return "OK";
with (depends on libraries you use to connect with database. mysql , mysqli or pdo)
return mysql_affected_rows();
will get you the affected rows. That is from PHP code side. Opencart has a default function that you can use: $this->db->countAffected()
but i am not sure if they have kept it the same through different versions.
source : http://us3.php.net//manual/en/function.mysql-affected-rows.php
Hope everything is clear enough.
You probably have no updated quantity for the product because you are comparing SKU and product_id in your query.
If you want to update product quantity by product_id, you need to change your expression to this one:
'UPDATE `' . DB_PREFIX . 'product` SET `quantity` =' . (int)$quantity . ' WHERE `product_id`= " . (int)$product_id
"WHERE product_id = some_product_id" instead of "WHERE sku = some_product_id"
Comparing SKU with product_id in WHERE statement is the reason why your query updates 0 rows.
Related
I'm working with Opencart 3.0 to set up a product cross-sell to display similar items to the user when they add something to the cart. I thought I had seen a pattern with the array of products in the cart that put the last item of cart at the end. So my php looked something like this:
$this->load->model('catalog/product');
$related_product_id = $products;
$related_product_id = end($related_product_id);
$related_product_id = $related_product_id['product_id'];
$related = $this->model_catalog_product->getProductRelated($related_product_id);
foreach ($related as $related) {
//..do something
}
Using the end() method in the above code would take the very last Key=>Value (Product_id) in the array so I could use it to display the product on the page.
This worked for a while until I noticed that it was not always accurate. If someone added something already in the cart, it wouldn't place it at the end of the array, and also other certain products for some reason didn't show up at the end of the array.
Is there another way to get the Product_Id of the last item a user added to the cart than the way I'm going about it? My way doesn't seem very consistent. Thanks!
I was able to figured it out adding my own function to /system/libray/cart/cart.php
I added this function
public function getProductsInCart() {
$product_data = array();
$cart_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "cart WHERE api_id = '" . (isset($this->session->data['api_id']) ? (int)$this->session->data['api_id'] : 0) . "' AND customer_id = '" . (int)$this->customer->getId() . "' AND session_id = '" . $this->db->escape($this->session->getId()) . "' ORDER BY date_added ASC");
foreach ($cart_query->rows as $cart) {
$product_data[] = array(
'cart_id' => $cart['cart_id'],
'product_id' => $cart['product_id'],
'date_added' => $cart['date_added'],
);
}
return $product_data;
}
And instead of using the $this->cart->getProducts() line to get products from the cart, I'm using my new function $this->cart->getProductsInCart().
This works way more consistent. The only thing it doesn't take into consideration is when someone goes back to a product already added. It doesn't count it as a new product added, but instead just updates it quantity.
Let me know if someone finds a better solution.
I "inherited" an existing and working install of OpenCart 1.5.2.1.
For test purpuses I wanted to set up a dev site on my local server. So I installed it locally and copied the DB over.
I can log into the backend without any issues - stores are set up, all the products and categories are there as well.
On the frontend, I can visit the home page of the store, and the list of categories gets displayed correctly, including the product count per category.
However, when I try to view the category listings, or an individual product for that matter, I get a blank page.
I am not getting a PHP error - I appended
display_errors = 1;
error_reporting = E_ALL;
log_errors = 1;
to the php.ini in the cart root folder.
From within the OpenCart Error Log, I am getting the following error message:
2013-03-13 18:51:15 - PHP Notice: Error: Column 'product_id' cannot be null<br />Error No: 1048<br />SELECT DISTINCT *, p [...] AND p2s.store_id = '5' in /path/to/root/system/database/mysql.php on line 49
Any idea how to resolve this issue?
** UPDATE: **
The full query is:
SELECT DISTINCT *, pd.name, pd.creator, pd.keyword, pd.circa, pd.year, pd.century, pd.decade, pd.scenelocation, pd.fm_quicksearch AS fm_quicksearch, p.image, m.name AS manufacturer, (SELECT price FROM product_discount pd2 WHERE pd2.product_id = p.product_id AND pd2.customer_group_id = '8' AND pd2.quantity = '1' AND ((pd2.date_start = '0000-00-00' OR pd2.date_start < NOW()) AND (pd2.date_end = '0000-00-00' OR pd2.date_end > NOW())) ORDER BY pd2.priority ASC, pd2.price ASC LIMIT 1) AS discount, (SELECT price FROM product_special ps WHERE ps.product_id = p.product_id AND ps.customer_group_id = '8' AND ((ps.date_start = '0000-00-00' OR ps.date_start < NOW()) AND (ps.date_end = '0000-00-00' OR ps.date_end > NOW())) ORDER BY ps.priority ASC, ps.price ASC LIMIT 1) AS special, (SELECT points FROM product_reward pr WHERE pr.product_id = p.product_id AND customer_group_id = '8') AS reward, (SELECT ss.name FROM stock_status ss WHERE ss.stock_status_id = p.stock_status_id AND ss.language_id = '1') AS stock_status, (SELECT wcd.unit FROM weight_class_description wcd WHERE p.weight_class_id = wcd.weight_class_id AND wcd.language_id = '1') AS weight_class, (SELECT lcd.unit FROM length_class_description lcd WHERE p.length_class_id = lcd.length_class_id AND lcd.language_id = '1') AS length_class, (select (r.sum + p.rat)/(r.tot + p.tot) from (select COALESCE(j.sum,0) as sum , COALESCE(j.tot,0) as tot from (select SUM(rating) as sum , COUNT(rating) as tot, product_id from rating where product_id = '9206' group by product_id) j right join product on product.product_id = j.product_id where product.product_id = '9206') r, (select product_id, COALESCE(rating,0) as rat, count(rating) as tot from product where product_id = '9206' and rating > 0) p ) AS rating, p.sort_order FROM product p LEFT JOIN product_description pd ON (p.product_id = pd.product_id) LEFT JOIN product_to_store p2s ON (p.product_id = p2s.product_id) LEFT JOIN manufacturer m ON (p.manufacturer_id = m.manufacturer_id) WHERE p.product_id = '9206' AND pd.language_id = '1' AND p.status = '1' AND p.date_available <= NOW() AND p2s.store_id = '5'
UPDATE
I suspect it has something to do with the MySQL or PHP configuration. Because when I run the same query on the live site, it works without fail.
UPDATE
The issue is related to my local MySQL install. When using the online DB all is fine. Someone in the OpenCart Forum - Link to Post indicated the following:
This error originates from an insert query on a specific contribution which the author has >untestedly tried to add a null statement which an auto-incremented field will reject >especially starting on mySQL 5.1+ . This methodology from mySQL developers has been blocked >ages ago.
Contact the author to address this issue by stating that the auto-incremented field does NOT >require to be addressed in the query as it is already creating an incremented value >automatically along with the executed query.
It might be along these lines. The query itself is not an insert, but it has most likely to do with that. I'll look further into the matter.
Set “Output Compression Level” to 0 in the System > Settings > Server tab.
Then in php.ini file display_errors = 1; error_reporting = E_ALL; log_errors = 1;
So the problem is with the 'product_id' . In the page controller page check the product id (just echo it). then check the model query. the problem is product id only.
Yes, the answer indeed had to do with my local MySQL install. I moved it to a different server, and it worked just fine. Thank you for the input! Sorry to not have a more specific answer than that. I just wanted to tie up a loose end with this post.
I wish I knew where to find the position that makes the backend OpenCart Remove Option Value-for product / option - table
If you mean which file options get deleted and re-generated when you edit a product, the file is admin/model/catalog/product.php and the method is the editProduct() method. You'll notice that there's these two lines in there
$this->db->query("DELETE FROM " . DB_PREFIX . "product_option WHERE product_id = '" . (int)$product_id . "'");
$this->db->query("DELETE FROM " . DB_PREFIX . "product_option_value WHERE product_id = '" . (int)$product_id . "'");
You might try setting max_input_vars value in php.ini to 2000 and restart apache. This seem to fixed my issue where option values were deleted even when only product name was updated from product update page.
I have several database tables with 2 primary keys, id and date. I do not update the records but instead insert a new record with the updated information. This new record has the same id and the date field is NOW(). I will use a product table to explain my question.
I want to be able to request the product details at a specific date. I therefore use the following subquery in DQL, which works fine:
WHERE p.date = (
SELECT MAX(pp.date)
FROM Entity\Product pp
WHERE pp.id = p.id
AND pp.date < :date
)
This product table has some referenced tables, like category. This category table has the same id and date primary key combination. I want to be able to request the product details and the category details at a specific date. I therefore expanded the DQL as shown above to the following, which also works fine:
JOIN p.category c
WHERE p.date = (
SELECT MAX(pp.date)
FROM Entity\Product pp
WHERE pp.id = p.id
AND pp.date < :date
)
AND c.date = (
SELECT MAX(cc.date)
FROM Entity\ProductCategory cc
WHERE cc.id = c.id
AND cc.date < :date
)
However, as you can see, if I have multiple referenced tables I will have to copy the same piece of DQL. I want to somehow add these subqueries to the entities so that every time an entity is called it adds this subquery.
I have thought of adding this in a __construct($date) or some kind of setUp($date) method, but I'm kind of stuck here. Also, would it help to add #Id to Entity\Product::date?
I hope someone can help me. I do not expect a complete solution, one step in a good direction would be very much appreciated.
I think I've found my solution. The trick was (first, to update to Doctrine 2.2 and) using a filter:
namespace Filter;
use Doctrine\ORM\Mapping\ClassMetaData,
Doctrine\ORM\Query\Filter\SQLFilter;
class VersionFilter extends SQLFilter {
public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias) {
$return = $targetTableAlias . '.date = (
SELECT MAX(sub.date)
FROM ' . $targetEntity->table['name'] . ' sub
WHERE sub.id = ' . $targetTableAlias . '.id
AND sub.date < ' . $this->getParameter('date') . '
)';
return $return;
}
}
Add the filter to the configuration:
$configuration->addFilter("version", Filter\VersionFilter");
And enable it in my repository:
$this->_em->getFilters()->enable("version")->setParameter('date', $date);
Using Zend Lucene Search, I am returning a list of relevance-ordered IDs that map to blog records that I will fetch from the database.
Is this the proper way of handling an array with Doctrine2's WHERE IN expression:
$dql = "SELECT b FROM BlogPost WHERE b.id IN (" . implode(', ', $ids) . ")";
$query = $em->createQuery($dql);
...
Or is there a better way of maybe passing in the actual $ids array as a parameter to the query?
Also, the Zend Search returns the array of IDs based on relevance. Will using the above technique preserve the order of relevance in retrieving the blog posts?
If it makes you feel better, you can use the ExpressionBuilder.
$ex = $em->getExpressionBuilder();
$dql = 'SELECT b FROM BlogPost b WHERE ' . $ex->in('b.id', $ids));
$query = $em->createQuery($dql);
function cmp($a, $b) {
global $ids;
return (array_search($a->getId(), $ids) < array_search($b->getId(), $ids)) ? -1 : 1;
}
usort($res, 'cmp');
It's a bit cleaner, but does the same as you behind the screens.
You should pas the $ids array through setParameter() function as this is a best practice in doctrine:
$query = $this->_em->createQuery('SELECT b FROM BlogPost WHERE b.id IN (?1)');
$query->setParameter(1, implode(',', $ids));
I think the IN statement will not preserve the order of the passed ID's as IN will match the first found $id not depending on the order.