Skip to content

Instantly share code, notes, and snippets.

@bobmagicii
Created January 13, 2015 18:00
Show Gist options
  • Save bobmagicii/6084ba58a0d50db51abc to your computer and use it in GitHub Desktop.
Save bobmagicii/6084ba58a0d50db51abc to your computer and use it in GitHub Desktop.
static function Search($opt=null) {
/*//
@todo cache search results for a little bit.
@argv object Options
@return object
perform a search of objects with various properties. if called from a child
class then that type will be automatically forced and relevant tables
automatically joined.
//*/
// allow the child class to extend these options.
$opt = static::Search_Extend_Options($opt);
////////
////////
// the basic listing with pagination.
$search = (new DMA\Database)
->Select('dma_objects o')
->Fields(['Fields' => 'SQL_CALC_FOUND_ROWS *'])
->Limit($opt->Limit)
->Offset(($opt->Page - 1) / $opt->Limit);
// specific type filtering. use the child class join tables to construct
// an inner join so we don't pull any broken rows.
if($opt->Type) {
$search->Where('o.obj_type=:Type');
foreach(static::$JoinTables as $table) {
list($tname,$talias) = explode(' ',$table);
$search->Join(sprintf(
'%s ON o.obj_id=%s.obj_id',
$table,
$talias
),Verse::JoinInner);
}
}
static::Search_Extend_Filters($search,$opt);
static::Search_Extend_Sorts($search,$opt);
////////
////////
// stop now if all we wanted from this was a count.
if($opt->CountOnly) return $search->Count($opt);
////////
////////
$set = $search->Query($opt);
$list = [];
while($row = $set->Result->Next()) $list[] = new static($row);
return (object)[
'Query' => $search->GetSQL(),
'Count' => $set->Found,
'Page' => $opt->Page,
'PageCount' => ceil($set->Found / $opt->Limit),
'PageLimit' => $opt->Limit,
'Payload' => $list
];
}
protected static function Search_Extend_Options($opt) {
/*//
setup the options for the search so that we can use the data in advanced
filtering later on. any classes that which to overwrite this method should
immediately call parent::Search_Extend_Options($opt) before adding their
own data to it.
//*/
$opt = new Nether\Object($opt,[
// object properties
'Type' => static::GetObjectType(),
'Subtype' => null,
'Owner' => 0,
'Parent' => 0,
'Title' => null,
'Alias' => null,
'Enabled' => true,
'Deleted' => false,
'Flags' => 0,
'Tags' => [],
// sort options.
'Sort' => [],
// search options.
'ByText' => null,
'Page:int' => 1,
'Limit:int' => 20,
'CountOnly:bool' => false
]);
return $opt;
}
protected static function Search_Extend_Filters($s,$opt) {
/*//
bind the filters to the sql that will perform the search upon the database.
any classes that which to overwrite this method should immeidately call
parent::Search_Extend_Filters($s,$opt) before adding their own filters to
the search object.
//*/
// specific properties.
if($opt->Subtype) $s->Where([ 'Subtype' => 'o.obj_subtype=:Subtype' ]);
if($opt->Flags) $s->Where([ 'Flags' => '(o.obj_flags1&:Flags)=:Flags' ]);
if($opt->Owner) $s->Where([ 'Owner' => 'o.u_id=:Owner' ]);
if($opt->Parent) $s->Where([ 'Parent' => 'o.obj_parent=:Parent' ]);
// fuzzy text searches.
if($opt->Title) $s->Where([ 'Title' => 'o.obj_title LIKE :Title' ]);
if($opt->Alias) $s->Where([ 'Alias' => 'o.obj_alias LIKE :Alias' ]);
if($opt->ByText) {
$opt->ByText = "%{$opt->ByText}%";
$s->Where([ 'ByText' => '(o.obj_alias LIKE :ByText OR o.obj_title LIKE :ByText)' ]);
}
// if enabled is true then only show enabled. if false then only show
// disabled. if null or omitted then ignore the enabled state all
// together.
if($opt->Enabled === true) $s->Where([ 'Enabled' => 'o.obj_enabled=1' ]);
if($opt->Enabled === false) $s->Where([ 'Enabled' => 'o.obj_enabled=0' ]);
// if deleted is false then only show objects which have never been
// marked as deleted. if true, only show objects which have been marked
// deleted. if you pass a numeric value treat it as a unix time and then
// only pull the items which have been deleted since that time.
if($opt->Deleted === false) $s->Where([ 'Enabled' => 'o.obj_deleted=0' ]);
if($opt->Deleted === true) $s->Where([ 'Enabled' => 'o.obj_deleted!=0' ]);
if(is_numeric($opt->Deleted)) $s->Where([ 'Enabled' => 'o.obj_deleted>=:Deleted' ]);
// if any tags are provided then only find things that have them. if
// the tag id is positive then use it to include the tag. if negitive
// use it to exclude.
if(!empty($opt->Tags)) {
$tagin = [];
$tagout = [];
foreach($opt->Tags as $tid) {
if($tid > 0) $tagin[] = $tid;
elseif($tid < 0) $tagout[] = $tid * -1;
}
if(!empty($tagin)) {
$s->Join(sprintf(
'dma_tag_assoc ta ON ((ta.obj_id=o.obj_id AND ta.tag_obj_id IN (%1$s)) OR (ta.tag_obj_id=o.obj_id AND ta.obj_id IN (%1$s)))',
implode(',',$tagin)
),Verse::JoinRight);
}
// TODO tag exclusion. my first few attempts resulted in a slow
// query returning mutliples of the same objects.
}
return;
}
protected static function Search_Extend_Sorts($s,$opt) {
/*//
create any sorting that needs to be done to the query. any classes which
overwrite this method should immediately call
parent::Search_Extend_Sorts($s,$opt) before adding their own sorts to the
search object.
//*/
foreach($opt->Sort as $sort) {
switch(strtolower($sort)) {
case 'alias-az': {
$s->Sort([ 'Alias-AZ' => 'o.obj_alias' ],Verse::SortAsc);
break;
}
case 'alias-za': {
$s->Sort([ 'Alias-ZA' => 'o.obj_alias' ],Verse::SortDesc);
break;
}
case 'title-az': {
$s->Sort([ 'Title-AZ' => 'o.obj_title' ],Verse::SortAsc);
break;
}
case 'title-za': {
$s->Sort([ 'Title-ZA' => 'o.obj_title' ],Verse::SortDesc);
break;
}
case 'newest': {
$s->Sort([ 'Newest' => 'o.obj_time_created' ],Verse::SortDesc);
break;
}
case 'oldest': {
$s->Sort([ 'Oldest' => 'o.obj_time_created' ],Verse::SortAsc);
break;
}
case 'modified': {
$s->Sort([ 'Modified' => 'o.obj_time_modified' ],Verse::SortDesc);
break;
}
case 'hitcount': {
$s->Sort([ 'Hitcount' => 'o.obj_hit_count' ],Verse::SortDesc);
}
}
}
return;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment