Skip to content

Instantly share code, notes, and snippets.

@jedateach
Created April 15, 2012 23:50
Show Gist options
  • Save jedateach/2395385 to your computer and use it in GitHub Desktop.
Save jedateach/2395385 to your computer and use it in GitHub Desktop.
Planning the ShoppingCart custom products system
<?php
/**
* Helper class to create a filter for matching a dataobject,
* using field values or relationship ids and only those ids.
*
* Combining fields defines a way to uniquely identify an object.
*
* Useful for finding if a dataobject with given field values exists.
* Protects against SQL injection, and searching on unauthroised fields.
* Ignores fields that don't exist on the object.
* Adds IS NULL, or = 0 for values that are not passed.
*
* Similar to SearchContext
*
* Conjunctive query
*
* Example input:
* $data = array(
* 'FieldName' => 'data'
* 'AnotherField' => 32,
* 'NotIncludedField' => 'blah'
* );
*
* $required = array(
* 'FieldName',
* 'AnotherField',
* 'ARequiredField'
* );
*
* Example output:
* "FieldName" = 'data' AND "AnotherField" = 32 AND "ARequiredField" IS NULL
*
*/
class MatchObjectFilter{
protected $className, $data, $required;
/**
* @param string $className
* @param array $data field values to use
* @param array $requiredfields fields required to be included in the query
*/
function __construct($className,array $data, array $requiredfields){
$this->className = $className;
$this->required = $requiredfields;
$this->data = $data;
}
/**
* Create SQL where filter
* @return array of filter statements
*/
function getFilter(){
if(!is_array($this->data)){
return null;
}
$singleton = singleton($this->className);
$hasones = $singleton->has_one();
$db = $singleton->db();
$allowed = array_merge($db,$hasones); //fields that can be used
$fields = array_flip(array_intersect(array_keys($allowed),$this->required));
//TODO: warn against required fields that are not allowed?
//add 'ID' to has one relationship fields
foreach($hasones as $key => $value){
$fields[$key."ID"] = $value;
unset($fields[$key]);
}
$new = array();
foreach($fields as $field => $value){
$field = Convert::raw2sql($field);
if(array_key_exists($field,$db)){
$dbfield = $singleton->dbObject($field);
$value = (isset($this->data[$field])) ? $this->data[$field] : null;
$value = $dbfield->prepValueForDB($value); //product correct format for db values
$new[] = "\"$field\" = $value";
}else{
if(isset($this->data[$field])){
$value = Convert::raw2sql($this->data[$field]);
$new[] = "\"{$field}\" = $value";
}else{
$new[] = "(\"{$field}\" = 0 OR \"$field\" IS NULL)";
}
}
}
return implode(" AND ",$new);
}
}
<?php
//using the MatchObjectFilter to reference a particular order item, and only that item.
//somewhere in ShoppingCart class (probably get item function)
$required = $itemclass::$required_fields; //php 5.3!
$required = array_merge(array('Order','Product'),$required);
//TODO: allow passing exact id of item
$query = new MatchObjectFilter($itemclass,array_merge($customfilter,$filter),$required);
$filter = array(
'OrderID' => $order->ID,
'ProductID' => $product->ID
);
$query = new MatchObjectFilter($itemclass,array_merge($customfilter,$filter),$required);
$item = DataObject::get_one($itemclass, $query->getFilter());
//...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment