PHP: do an ORDER BY using external data? - php

Ahoy all! Long story short with this one if you don't mind lending a hand to this novice PHPer. :)
I have a database field called "Categories" that has this stored:
Fruit, People, Place, Animals, Landscape
I also have a separate table in the DB that has items with these category names in the fields for each item. Right now, the script (i am trying to fork it a bit) uses:
SELECT DISTINCT(type), type FROM the_categories ORDER BY type ASC
in order to display a list of all categories available. Simple enough right?
Welllllll..... I don't want to sort by ASC, I want to sort by the list of items in the first Categories field I mentioned. Whatever order those are in is the order I want to display the "types" above.
Obviously I will have to do an explode on the commas, and maybe give them a 1 to whatever order....but even then.... how do I do an "orderby" using data stored in another folder?
Is this even possible? lol Thanks again!

... ORDER BY FIELD(type,"Fruit","People","Place","Animals","Landscape")
http://www.cfdan.com/posts/Handy_MySQL_-_ORDER_BY_FIELD.cfm

And just so future onlookers have it .... here is the explode code
$query2 = mysql_query("SELECT * FROM categorytable");
while($row = mysql_fetch_array($query2)){
$categories = html_entity_decode($row['categories']);
$thelist = explode(',', $categories);
foreach($thelist as $order){
if(trim($order) != ''){
$order = trim($order);
$order = ", '".$order."'";
$theorder .= $order;
}
}
and then for the query, just put in the the order variable
SELECT DISTINCT(type), type FROM the_categories ORDER BY FIELD(type" . $theorder .")")

Related

Load product information by comparing custom attribute in Magento

I am working on some scripts to automate some things inside our webshop.
I have looked through many forums and questions.
Now I almost have finished my script but there is a small thing that doesn't work but I can not think of what I am doing wrong.
What the goal of this script is, is to get products that has the same attribute value as the values in an array (pulled from DB).
So here is my code:
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once('../app/Mage.php');
require_once('db.php');
Mage::app();
$db = db_connection();
$collection = Mage::getModel('catalog/product')->getCollection();
$collection->addAttributeToSelect('ean');
$getean = $db->prepare('SELECT ean_l FROM mytable');
$getean->execute();
$allean = $getean->fetchAll();
foreach($allean as $ean) {
$collection->addFieldToFilter(array(
array('attribute'=>'ean','eq'=>'' . $ean['ean_l'] . ''),
));
echo 'ean_l: ' . $ean['ean_l'] . '<br>';
foreach ($collection as $product) {
echo $product['entity_id'];
}
}
So here's how it works:
We select an attribute (ean).
We get a list of all ean numbers from the database.
We loop through the list and compare any product with the ean number.
Then we loop through the collection and get the id of the corresponding product.
Yet, all $product['entity_id']'s are 273. It is correct that the entity_id is 273, but there is also product 274 with a corresponding ean number.
Here is the result from the script (it's alot more):
So why is this? Because in my reasoning, it changes the ean_l every loop and it equalizes it with the attribute values.
And then it should change the collection, right?
So shouldn't it at least show 274 at some point?
This question is not especially for Magento programmers, but other programmers can help too, so I figured to post it on SO.
Magento comes with powerfull filtering and queries into collections. If that doesn't satisfy, you can always extend with custom queries into getSelect function. Some info here.
Using addFieldToFilter into that foreach will filter the remaining values after another iterated filtering. So it's not good.
$allean = array("of", "ean", "values", "needed", "for", "filtering");
$collection = Mage::getModel('catalog/product')->getCollection();
$collection->addAttributeToSelect('ean');
//addAttributeToFilter for EAV collections
$collection->addAttributeToFilter('ean', array('in' => $allean)); //not addFieldToFilter
$collection->getColumnValues('entity_id');
var_dump($collection); //will output an array of product_ids
Alternative, if you want to group by ean values you should remove getColumnValues and run group command.
You can find additional info here.
Or you can just remove getColumnValues, start a foreach($collection as $product) and group manually or do what you want with those filtered products.

Sort by two parameters in Opencart

I want to have my products sorted by two parameters: first by "sort order" that every product has; and then by quantity.
Here is what I have in file /catalog/controller/product/category.php (Opencart 1.5.6.4) and I believe here is what should be somehow changed:
if (isset($this->request->get['sort'])) {
$sort = $this->request->get['sort'];
} else {
$sort = 'p.sort_order';
}
Anyone has any ideas? Thanks in advance
By default Opencart only uses a single field at a time for sorting. To accomplish what you described you'll need to modify the query for the getProducts() method which is built in /catalog/model/catalog/product.php. Find line 196 where it reads:
$sql .= " ORDER BY p.sort_order";
This is the default sort order when none is specified. To add a secondary sort criteria you can change it to:
$sql .= " ORDER BY p.sort_order, p.quantity";
If you always want to use quantity as a secondary sort field, you can add after the entire block like this:
} else {
$sql .= " ORDER BY p.sort_order";
}
$sql .= ", p.quantity";
This would sort by quantity as a secondary field regardless of what primary sort field was specified.

Doctrine createQueryBuilder multiple conditional where statements a bit clunky

I have an itemid and a category id that are both conditional. If none is given then all items are shown newest fist. If itemid is given then only items with an id lower than given id are shown (for paging). If category id is given than only items in a certain category are shown and if both are given than only items from a certain category where item id smaller than itemid are shown (items by category next page).
Because the parameters are conditional you get a lot of if statements depending on the params when building a SQL string (pseudo code I'm wearing out my dollar sign with php stuff):
if itemid ' where i.iid < :itemid '
if catid
if itemid
' and c.id = :catid'
else
' where c.id = :catid'
end if
end if
If more optional parameters are given this will turn very messy so I thought I'd give the createQueryBuilder a try. Was hoping for something like this:
if($itemId!==false){
$qb->where("i.id < :id");
}
if($categoryId!==false){
$qb->where("c.id = :catID");
}
This is sadly not so and the last where will overwrite the first one
What I came up with is this (in Symfony2):
private function getItems($itemId,$categoryId){
$qb=$this->getDoctrine()->getRepository('mrBundle:Item')
->createQueryBuilder('i');
$arr=array();
$qb->innerJoin('i.categories', 'c', null, null);
$itemIdWhere=null;
$categoryIdWhere=null;
if($itemId!==false){
$itemIdWhere=("i.id < :id");
}
if($categoryId!==false){
$categoryIdWhere=("c.id = :catID");
}
if($itemId!==false||$categoryId!==false){
$qb->where($itemIdWhere,$categoryIdWhere);
}
if($itemId!==false){
$qb->setParameter(':id', $itemId);
}
if($categoryId!==false){
$arr[]=("c.id = :catID");
$qb->setParameter(':catID', $categoryId);
}
$qb->add("orderBy", "i.id DESC")
->setFirstResult( 0 )
->setMaxResults( 31 );
I'm not fully trusting the $qb->where(null,null) although it is currently not creating errors or unexpected results. It looks like these parameters are ignored. Could not find anything in the documentation but an empty string would generate an error $qb->where('','').
It also looks a bit clunky to me still, if I could use multiple $qb->where(condition) then only one if statement per optional would be needed $qb->where(condition)->setParameter(':name', $val);
So the question is: Is there a better way?
I guess if doctrine had a function to escape strings I can get rid of the second if statement round (not sure if malicious user could POST something in a different character set that would allow sql injection):
private function getItems($itemId,$categoryId){
$qb=$this->getDoctrine()->getRepository('mrBundle:Item')
->createQueryBuilder('i');
$arr=array();
$qb->innerJoin('i.categories', 'c', null, null);
$itemIdWhere=null;
$categoryIdWhere=null;
if($itemId!==false){
$itemIdWhere=("i.id < ".
someDoctrineEscapeFunction($id));
}
Thank you for reading this far and hope you can enlighten me.
[UPDATE]
I am currently using a dummy where statement so any additional conditional statements can be added with andWhere:
$qb->where('1=1');// adding a dummy where
if($itemId!==false){
$qb->andWhere("i.id < :id")
->setParameter(':id',$itemId);
}
if($categoryId!==false){
$qb->andWhere("c.id = :catID")
->setParameter(':catID',$categoryId);
}
You can create filters if you want to use more generic approach of handling this.
Doctrine 2.2 features a filter system that allows the developer to add SQL to the conditional clauses of queries
Read more about filters however, I'm handling this in similar manner as you showed

Sphinx/PHP: Can Sphinx return matching order of a given array?

Using Sphinx 2.0.6, is there a way to have sphinx return a specific order based on the document ID?
For example, say there are 1000 documents all having id 1-1000. But I want to return, in order, ID 999,1000,4,5,2,and so on.
This use case: The positioning is dynamic and needs to be done through Sphinx. The positioning value needs to be as an attribute that can change on-the-fly. This is also paged -- so I can't simply gather the ID Set and request a SQL. Sphinx itself needs to return the specific order I give it.
$cl->setSelect("*,FIND_IN_SET(id,".implode($id_array).") AS id_position");
$cl->SetSortMode(SPH_SORT_EXTENDED, 'id_position DESC');
$cl->setSelect("*,FIELD(id,".implode($id_array).") AS id_position");
$cl->SetSortMode(SPH_SORT_EXTENDED, 'id_position DESC');
Unfortunately, doesn't look like Sphinx supports FIELD() and FIELD_IN_SET().
Any ideas how to complete this task? I'm at a loss right now and could use the help!
Do you need to use that array structure?
With Sphinx you can use an "ORDER BY id" statement and then when getting results use:
$cl->SetSortMode( SPH_SORT_ATTR_DESC, "id" );
Figured it out thankfully! This is an excellent solution to being able to order by a dynamic id array. (real world use... user's favorites, recommended products, user's most visited)
Sphinx PHP Code:
$cl->SetOverride("id_position", SPH_ATTR_INTEGER, user_id_position());
$cl->SetSortMode(SPH_SORT_EXTENDED, "id_position ASC");
PHP Function to create the associative array:
function user_id_position() {
$id = $_original_id_list // This variable is the original id list that is in the correct order
$max = count($id);
$set = array();
for ($i=0;$i < $max;$i++)
$set[$id[$i]] = $i; // turns the array into array(document_id1 => position, document_id2 => position, ...)
return $set;
}
sphinx.conf
source index_name
{
sql_query = \
SELECT \
*, 0 as id_position \
FROM \
database_table;
sql_attr_uint = id_position
}
After adding the information to sphinx.conf you'll need to --rotate and it'll work

Magento suppliers list.

Been trying to get this to work and can't work out if it is me, the code or the installation. Basically I am trying to get a list of all the suppliers in the system. Magento 1.4.0.1 is in use. I have tried to use the code at Magento Wiki but it just returns an empty array. As is or modified to use the "suplier" attribute. I don't seem to be able to get it to return anything. Can anyone point me in the right direction as to how to get the list?
try this code,it may be helpful to you
$attribute = Mage::getModel('eav/config')->getAttribute('catalog_product','supplier');
foreach ( $attribute->getSource()->getAllOptions(true, true) as $option )
{
echo $option['value'];
echo $option['label'];
}
Looks like only one way to do this. Dump the magento bits and just hit the database.
$magentoDb = Mage::getSingleton( 'core/resource' )->getConnection( 'core_write' );
$results = $magentoDb->fetchAll('SELECT DISTINCT(`value`) AS supplierName FROM `catalog_product_entity_varchar` WHERE `attribute_id` = 525 ORDER BY supplierName');
Gets the list as a straight array. Which can then be output as I want. The attribute id of 525 is from the eav_attribute table, no idea if it is going to be the same for all systems.

Categories