PHP - How to accomplish this if? - syntax

I am creating an order cart.
On the page that displays the cart, it checks if a value stored in the session $order corresponds with an id of a row in a mysql table. If this match exists, then the corresponding row is returned.
Within this process, I am trying to retrieve the quantity value stored in the session $quantity that corresponds to the id of the row in the table.
Each value in $order and $quantityis assigned a name, which is the id of the item they were added from.
This is the code that adds the order to the cart:
if (isset($_POST['action']) and $_POST['action'] == 'Order')
{
// Add item to the end of the $_SESSION['order'] array
$_SESSION['order'][$_POST['id']] = $_POST['id'];
$_SESSION['quantity'][$_POST['id']] = $_POST['quantity'];
header('Location: .');
exit();
}
This is the code on the cart page:
foreach ($order as $item)
foreach ($quantity as $amount)
{
mysql_data_seek( $productsSql, 0); //<- this line, to reset the pointer for every EACH.
while($row = mysql_fetch_assoc($productsSql))
{
$itId = $row['id'];
$itDesc = $row['desc'];
$itPrice1 = $row['price1'];
if ($item == $itId)
{
$pageContent .= '
<tr>
<td>'.$itDesc.'</td>
<td>'.if ($item[''.$itId.''] == $amount[''.$itId.'']) {echo $amount}.'</td>
<td>R'.number_format($itPrice1*$amount, 2).'</td>
</tr>
';
}
}
}
This row is producing a syntax error:
<td>'.if ($item[''.$itId.''] == $amount[''.$itId.'']) {echo $amount}.'</td>
What is the problem here for starters?
Secondly, how would I need to do to accomplish the task that I am facing?
Any input on this would be greatly appreciated!

Could you try this?
<td>'.($item[$itId] == $amount[$itId] ? $amount : '').'</td>
This is a ternary operator, look at http://en.wikipedia.org/wiki/Ternary_operation

You can't simply add conditional statements like that while you're building a string.
You can do this, however
<td>' . ($item[$itId] == $amount[$itId]) ? $amount : null . '</td>
but you should use a more legible method.
Another issue you may get is if $amount is an array, you won't be able to print it as a string. If, however, $amount is an object with ArrayAccess interface, you can print it with the __toString() method; but that's another story.

The code for creating the cart page has several issues.
You walk over items and over quantities, which will probably give you duplicate outputs.
$item is a plain string, so I wonder what $item[$itId] is supposed to do?
You walk over your complete result set several times which actually is not necessary. I really hope that "$productSql" isn't a "select * from product", otherwhise this might get REAL slow in production mode.
I suggest creating a good SQL for getting the data and using this as a basis for filling the page:
// note this has SQL-injection issues, so you really need to make sure that $order contains no crap
$productsSql = mysql_query("select * from product where id in (".join($order, ',').")");
// you now have a result set with all products from your order.
while($row = mysql_fetch_assoc($productsSql))
{
$itId = $row['id'];
$itDesc = $row['desc'];
$itPrice1 = $row['price1'];
// session contains the quantity array mapping ID -> Quantity, so grab it from there
$itQuantity = $quantity[$itId];
// finally calculate the price
$itPrice = number_format($itPrice1*$itQuantity, 2);
// now you have all data for your template and can just insert it.
// if you use double quotes you can put the $xyz into the string directly
$pageContent .= "
<tr>
<td>$itDesc</td>
<td>$itQuanty</td>
<td>R $itPrice</td>
</tr>
";
}

Related

Update a database field with Joomla UpdateObject method with a calculated field from same table

Right to the point.
I need to update a field in the database using the field to calculate the new value first.
E.g of fields: https://i.stack.imgur.com/FADH6.jpg
Now I am using the Joomla updateObject function. my goal is to take the "spent" value from the DB table without using a select statement.
Then I need to calculate a new value with it like (spent + 10.00) and update the field with the new value. Check out the code below:
// Create an object for the record we are going to update.
$object = new stdClass();
// Must be a valid primary key value.
$object->catid = $item['category'];
$object->spent = ($object->spent - $item['total']);
// Update their details in the users table using id as the primary key.
$result = JFactory::getDbo()->updateObject('#__mytable', $object, 'catid');
The bit which i need to make the calculation on is
$object->spent = ($object->spent - $item['total']);
I realise I can use a seperate insert statement but I am wondering if there is a better way. Any help is much appreciated.
It needs to work like this, WITHOUT THE SELECT (working example)
$query = $db->getQuery(true);
$query->select($db->quoteName('spent'));
$query->from($db->quoteName('#__mytable'));
$query->where($db->quoteName('catid')." = ". $item['category']);
// Reset the query using our newly populated query object.
$db->setQuery($query);
$oldspent = $db->loadResult();
// Create an object for the record we are going to update.
$object = new stdClass();
// Must be a valid primary key value.
$object->catid = $item['category'];
$object->spent = ($oldspent - $item['total']);
// Update their details in the users table using id as the primary key.
$result = JFactory::getDbo()->updateObject('#__mytable', $object, 'catid');
The sticking point with trying to use updateObject('#__mytable', $object, 'catid'); is that your query logic needs to reference the column name in the calculation to assign the "difference" as the new value. The raw mysql query syntax to update a column value with the value minus another value is like:
"`spent` = `spent` - {$item['total']}"
updateObject() will convert spent - {$item['total']} to a literal string, the database will expect a numeric value, so UPDATE results in a 0 value recorded. In other words, $db->getAffectedRows() will give you a positive count and there will be no errors generated, but you don't get the desired mathematical action.
The workaround is to discard updateObject() as a tool and build an UPDATE query without objects -- don't worry it's not too convoluted. I'll build in some diagnostics and failure checking, but you can remove whatever parts that you wish.
I have tested the following code to be successful on my localhost:
$db = JFactory::getDBO();
try {
$query = $db->getQuery(true)
->update($db->quoteName('#__mytable'))
->set($db->quoteName("price") . " = " . $db->qn("price") . " - " . (int)$item['total'])
->where($db->quoteName("catid") . " = " . (int)$item['category']);
echo $query->dump(); // see the generated query (but don't show to public)
$db->setQuery($query);
$db->execute();
if ($affrows = $db->getAffectedRows()) {
JFactory::getApplication()->enqueueMessage("Updated. Affected Rows: $affrows", 'success');
} else {
JFactory::getApplication()->enqueueMessage("Logic Error", 'error');
}
} catch (Exception $e) {
JFactory::getApplication()->enqueueMessage("Query Syntax Error: " . $e->getMessage(), 'error'); // never show getMessage() to public
}
Here is a StackOverflow page discussing the mysql subtraction logic: update a column by subtracting a value

Multiple array manipulations and merging

I am an amateur programmer that needs the help of a real one to resolve this beautiful problem, because I must admit that I am really stuck on this one!
In my database I have a « tslines » table that contains a value (sum_week) for a given week(startdate) and a given contract(contract_id)
The fields that are important are : sum_week, user_id , startdate and contract_id
I also have a « users » table, the important values are « first_name, last_name »
I have many workers that have worked on a contract, at different times (startdate, represents the first day of the week)
Example (table below): I can have 3 lines for worker A, and 2 lines for worker B
For some week(startdate), it can happend that no one worked on the contract
I want to show a table with those informations, for contract_id=3(ex) (this field is in tslines table) :
sum_week is a field, I don't want to recalculate with a SQL query
I don’t want to run a query for each weeks to check for each user if he worked on a contract because that would become a problem if I have ex : 30 weeks with 30 users that worked on the project..
I started by building an array of all possible « startdate »
//Selects min and max startdate of the tslines, use $dates->maxdate and ->mindate
$dates = $contract->tslines()->whereIsOfficial(true)->select(DB::raw('MAX(startdate) as maxdate, MIN(startdate) as mindate'))->first();
//Define first date declared in tslines
$loopdate = Carbon::parse($dates->mindate);
$maxdt = Carbon::parse($dates->maxdate);
//While loop to create array of date ranges from min to max
$date_count = 0;
$daterange = array();
while($loopdate->gt($maxdt) == false)
{
$daterange[] = $loopdate->format('Y-m-d');
$loopdate->addDays(7);
$date_count++;
}
I know I have to do some array manipulations but I really don’t know from where to start, even witht the queries..
I can get all the related tslines of contract by doing:
$contract->tslines()->get()
But I dont't know how to build an array that contains user information and all the startdate (even if he didn't work that week)
Can anybody give me some hints.. It would be greatly appreciated!!
Thanks in advance!
Raphaël
Let's start from what we know.
We know which users have worked on which contracts and on what date.
With your function above, we have the max date and the min date a user has started working on a contract.
Solution:
$tslines = $contract->tslines()->orderBy('user_id','ASC')->orderBy('startdate','ASC')->get();
//I didn't see any relationship calls to the user's object, so you'll have to add one of your own. I am assuming, your `tslines` has a relationship `user` here.
$userListResult = $contract->tslines()->with('user')->orderBy('user_id','ASC')->select(\Db::raw('distinct("user_id")')->get();
$dates = $contract->tslines()->whereIsOfficial(true)->select(DB::raw('MAX(startdate) as maxdate, MIN(startdate) as mindate'))->first();
$minDate = Carbon::parse($dates->mindate);
$maxDate = Carbon::parse($dates->maxdate);
//we flatten the array for future use.
$userList = array();
foreach($userListResult as $l)
{
$userList[$l->user_id] = $l->user->first_name.' '.$l->user->last_name;
}
//Assuming you are printing a table in blade
<table>
<?php
//Print the table headers
echo"<tr>
<td>User</td>";
$currDate = clone($minDate);
do
{
echo "<td>".$currDate->format('Y-m-d')."</td>";
$currDate->addDay();
}
while($currDate->diffInDays($maxDate) !== 0);
echo "</tr>";
//Print each user's row
foreach($userlist as $userid => $username)
{
echo "<tr>
<td>
$username
</td>";
$currDate = clone($minDate);
//loop through all the dates in range (min to max date)
do
{
$foundDate = false;
//We check if user has worked on that day
foreach($tslines as $row)
{
if($row->user_id === $userid && $row->startdate->format('Y-m-d') === $currDate->format('Y-m-d'))
{
//Print result if startdate & userid matches
echo "<td>{$row->sum_week}</td>";
$foundDate = true;
//Get out of the loops
break;
}
}
if(!$foundDate)
{
echo "<td>X (didn't work)</td>";
}
$currDate->addDay();
}
while($currDate->diffInDays($maxDate) !== 0);
echo "</tr>";
}
?>
</table>

Magmi overwriting position of products in category

I'm using Magmi to import products into my Magento store. Categories are created on the fly and products are imported. All is working well.
Except for one thing: each time I run a Magmi import, the position of the product in the Magento category is set to 0. This way I cannot sort my products on position.
I have searched the Magmi wiki and github for someone who has run into the same problem, but didn't find anything.
Anyone familiar with this issue and is there a way to avoid it?
I wait too long an answer and do it myself, here is a fix:
my fix works other way - category positions clear only if you add $item["category_reset"] == 1; param to product params.
:1280 sting(in current magmi version) or find the public function assignCategories($pid, $item) in magmi_productimportengine.php.
ater
$cce = $this->tablename("catalog_category_entity");
$ccpt = $this->tablename("catalog_category_product");
add next code:
$sql = "SELECT $ccpt.*
FROM $ccpt
JOIN $cce ON $cce.entity_id=$ccpt.category_id
WHERE product_id=?";
$currentPositions = $this->selectAll($sql,$pid);
then change category reset:
if (!isset($item["category_reset"]) || $item["category_reset"] == 1)
{...}
to
if (isset($item["category_reset"]) && $item["category_reset"] == 1)
{
$sql = "DELETE $ccpt.*
FROM $ccpt
JOIN $cce ON $cce.entity_id=$ccpt.category_id
WHERE product_id=?";
$this->delete($sql, $pid);
$currentPositions = array();
}
after this change block with positioning
foreach ($catids as $catdef)
{...}
to:
// find positive category assignments
if (is_array($currentPositions) && count($currentPositions)) {
foreach ($currentPositions as $currentPosition) {
$catPos[$currentPosition['category_id']] = $currentPosition['position'];
}
}
foreach ($catids as $catdef)
{
$a = explode("::", $catdef);
$catid = $a[0];
if (count($a) > 1 && $a[1] != 0) {
$catpos = $a[1];
}
else {
if (isset($catPos[$catid]) && $catPos[$catid] != 0) {
$catpos = $catPos[$catid];
}
else {
$catpos = "0";
}
}
$rel = getRelative($catid);
if ($rel == "-")
{
$ddata[] = $catid;
}
else
{
$cdata[$catid] = $catpos;
}
}
if you dont import position, your current position will save. If it 0, it stay 0.
for clear actual position - add param to product item:
$item["category_reset"] == 1;
or change string back:
if ($item["category_reset"] == 1)
{ ....}
to:
if (!isset($item["category_reset"]) || $item["category_reset"] == 1)
{...}
Only a comment but since I'm a long-time reader but never setup an account and can't leave a comment directly with no rep. I know this is an old post, but I just found it and used AlexVegas's code above (thank you!). Worked almost fine for me, but in my case I still wanted the categories to fully reset to only what was in my Magmi import but I wanted the positions to remain intact. As-is above, the categories only append to the existing unless you use the category_reset column in your import, and if you do that it also resets the position.
If you're like me and want only the position to remain intact, but allow Magmi to overwrite the categories each time, use Alex's code above but tweak it a little
Where he says to change
if (!isset($item["category_reset"]) || $item["category_reset"] == 1)
{...}
to
if (isset($item["category_reset"]) && $item["category_reset"] == 1)
{
$sql = "DELETE $ccpt.*
FROM $ccpt
JOIN $cce ON $cce.entity_id=$ccpt.category_id
WHERE product_id=?";
$this->delete($sql, $pid);
$currentPositions = array();
}
Don't change it. It's that simple. In his code it prevents the category reset unless the column is specified, which is why the if statement gets changed. If the column exists, it also wipes out the currentPositions array that stores the current positions within the categories so those get reset as well.
If you want to append to the categories unless category_reset is in your import, but don't want to overwrite the positioning, use Alex's code as it is above in his answer but leave out
$currentPositions = array();
That way it won't overwrite the array that is storing the positions within the categories
Not an actual solution-
You can try using this plugin
http://www.magentocommerce.com/magento-connect/c3-category-position-import-export-extension.html/
You can ignore UPDATE position if exist
category creator/importer v0.2.5
at line 1248 replace with
if (count($inserts) > 0) {
$sql = "INSERT IGNORE INTO $ccpt (`category_id`,`product_id`,`position`) VALUES ";
$sql .= implode(",", $inserts);
// $sql .= " ON DUPLICATE KEY IGNORE";
$this->insert($sql, $data);
unset($data);
}
The Magmi wiki specifically mentions item positioning functionality here See quoted text below. This seems to describe exactly the functionality you are looking for? I have not tested it myself.
Quote:
Item positioning
From magmi 0.7.18 , category_ids column has been enhanced with item positioning. This feature is also supported in category importer from version 0.2+ (since category importer plugin is roughly a category_ids generator)
Sample
store,sku,....,categories
admin,00001,.....,cat name with \/ in the name and positioning::3
<= here we "escaped" the tree separator with a backslash , the category will be created as "catname with / in the name and positioning"
sku 00001 will be set with position 3 in the category
End quote

Magento - cms/page collection - apply filter to return only pages which are unique to a given store id (ie not also assigned to other stores)

I can use:
Mage::getModel('cms/page')->getCollection()->addStoreFilter($store_id);
to retrieve a collection of CMS pages filtered by Store Id.
But how do I get it to remove ones which are also assigned to other stores?
ie: I do not want it to return items which have 'All Store Views' as the Store View. (Or any other additional store id assigned to that CMS page.) It has to only return pages unique to that one store.
I am extending the Aitoc permissions module, so that Store Admins cant view or edit CMS pages and static blocks which might impact other stores. This involves filtering those items from the grid.
There's no native collection method to do this, so you'll need to
Query the cms_page_store table for pages unique to a given store
Use the results from above in your filter
I didn't fully test the following, but it should work (and if it doesn't, it'll give you a good start on your own query)
$page = Mage::getModel('cms/page');
$resource = $page->getResource();
$read = $resource->getReadConnection();
#$select = $read->query('SELECT page_id FROM ' . $resource->getTable('cms/page_store') . ' GROUP BY store_id');
//set total count to look for. 1 means the page only appears once.
$total_stores_count_to_look_for = '1';
//get the table name. Need to pass through getTable to ensure any prefix used is added
$table_name = $resource->getTable('cms/page_store');
//aggregate count select from the cmd_page_store database
//greater than 0 ensures the "all stores" pages aren't selected
$select = $read->query('SELECT page_id as total
FROM '.$table_name.'
WHERE store_id > 0
GROUP BY page_id
HAVING count(page_id) = ?',array($total_stores_count_to_look_for));
//fetch all the rows, which will be page ids
$ids = $select->fetchAll();
//query for pages using IDs from above
$pages = Mage::getModel('cms/page')->getCollection()->addFieldToFilter('page_id',array('in'=>$ids));
foreach($pages as $page)
{
var_dump($page->getData());
}
If you have thousands and thousands of CMS pages it may be worth it to alter the cms/page collection's select to join in aggregate table data. I'll leave that as an exercise for the reader, as those sorts of joins can get tricky.
$collection = Mage::getModel('cms/page')->getCollection();
$collection->getSelect()
->join(
array('cps' => $collection->getTable('cms/page_store')),
'cps.page_id = main_table.page_id AND cps.store_id != 0',
array('store_id')
)
->columns(array('stores_count' => new Zend_Db_Expr('COUNT(cps.store_id)')))
->group('main_table.page_id')
->having('stores_count = ?', 1)
->having('cps.store_id = ?', $storeId)
;
Fusing some elements of the solutions proposed by Alan and Vitaly with my own cumbersome understanding, I achieved what I needed with the following code.
To put into context, I was extending the Aitoc permissions module, so that Store Admins cant view or edit CMS pages and static blocks which might impact other stores. This involved filtering those items from the grid.
$collection = Mage::getModel('cms/page')->getCollection();
$collection->addStoreFilter(Mage::helper('aitpermissions')->getStoreIds());
$conn = Mage::getSingleton('core/resource')->getConnection('core_read');
$page_ids = array();
foreach($collection as $key=>$item) {
$page_id = $item->getId();
$results = $conn->fetchAll("SELECT * FROM cms_page_store
WHERE page_id = ".$page_id.";");
$count = 0;
$arr_stores = array();
foreach($results as $row) {
$arr_stores[] = $row['store_id'];
$count++;
}
//We dont want to show the item if any of the following are true:
//The store id = 0 (Means its assigned to All Stores)
//There is more than one store assigned to this CMS page
if( in_array('0',$arr_stores) || $count>1) {
//This removes results from the grid (but oddly not the paging)
$collection->removeItemByKey($key);
}
else {
//build an array which we will use to remove results from the paging
$page_ids[] = $page_id;
}
}
//This removes results from paging (but not the grid)
$collection->addFieldToFilter('page_id',array('in'=>$page_ids));
I'm not sure why I needed to use two different methods to filter from the paging and the grid.
The site uses magento 1.5 so perhaps there is an issue related to that.
Either way, this solution worked for me.
My solution to add field store_id to pages collection via join, and use collection method addFieldToFilter().
$pages = Mage::getModel('cms/page')->getCollection();
$pages->getSelect()->joinInner(
array('cms_page_store' => 'cms_page_store'),
'main_table.page_id = cms_page_store.page_id',
array()
);
$pages->addFieldToFilter('store_id', ['in' => [1, 2]]);

attribute select magento query

i am trying to get this query in magento.
Select merk, option_id from catalog ....... group by option_id
Sofar i have this but it aint showing the option_id value unfortunately and also i dont know how to group by them...
i hope someone is willing to help me
[code]
<?php
function getMenuWatches(){
$collection = Mage::getModel("catalog/product")->getCollection();
$collection->addAttributeToFilter("attribute_set_id", 26);
$collection->addAttributeToSelect("option_id , merk");
return $collection;
}
$collection=getMenuWatches();
//print_r($collection);
foreach ($collection as $product){
echo $product->getOptionId();
$product->getMerk();
echo $product->getId('merk');
echo $product->getAttributeText('merk')."<br/>";
}
?>
[/code]
$collection->addAttributeToSelect(array('option_id', 'merk'));
$collection->groupByAttribute('option_id');
Attributes with multiple choices are stored as comma separated values.
So you just need add "merk" attribute in select object:
$collection->addAttributeToSelect('merk');
and when you are iterating the collection, you may retrieve options id by calling your attribute value:
// List of option_id values
$values = explode(',', $product->getMerk());
After retrieving of the values you need to retrieve option label for each option id
$attribute = $product->getResource()->getAttribute('merk');
$optionLabel = $attribute->getSource()->getOptionText($optionId);
To filter by one of the multiple values you may use:
// Creates FIND_IN_SET statement for comma-separated attribute values
$collection->addAttributeToFilter('merk', array('finset' => $optionId));

Resources