Solved SQL Query and tree algorithm! #230

This commit is contained in:
leogermani 2019-04-18 18:01:54 -03:00
parent 49bee40ced
commit befb9044bb
2 changed files with 458 additions and 18 deletions

View File

@ -1014,19 +1014,78 @@ class Metadata extends Repository {
if ( $metadatum_type === 'Tainacan\Metadata_Types\Taxonomy' ) {
if ($items_query) {
$base_query = $wpdb->prepare("FROM $wpdb->term_relationships tr
INNER JOIN $wpdb->term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
INNER JOIN $wpdb->terms t ON tt.term_id = t.term_id
WHERE
tt.parent = %d AND
tr.object_id IN ($items_query) AND
tt.taxonomy = %s
$search_q
// $base_query = $wpdb->prepare("FROM $wpdb->term_relationships tr
// INNER JOIN $wpdb->term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
// INNER JOIN $wpdb->terms t ON tt.term_id = t.term_id
// WHERE
// tt.parent = %d AND
// tr.object_id IN ($items_query) AND
// tt.taxonomy = %s
// $search_q
// ORDER BY t.name ASC
// ",
// $args['parent_id'],
// $taxonomy_slug
// );
//$search_query = "AND (tt.parent <> %d OR t.name LIKE '%master%')";
$base_query = $wpdb->prepare("
SELECT DISTINCT t.term_id, t.name, tt.parent, coalesce(tr.term_taxonomy_id, 0) as have_items
FROM
$wpdb->terms t INNER JOIN $wpdb->term_taxonomy tt ON t.term_id = tt.term_id
LEFT JOIN $wpdb->term_relationships tr ON tt.term_taxonomy_id = tr.term_taxonomy_id AND tr.object_id IN ($items_query)
WHERE tt.taxonomy = %s
ORDER BY t.name ASC
",
$args['parent_id'],
$taxonomy_slug
",
$taxonomy_slug
);
$all_hierarchy = $wpdb->get_results($base_query);
$results = $this->_process_terms_tree($all_hierarchy, $args['parent_id']);
$total = count($results);
// $results = [];
//
// function children_has_items($term_id, $hierarchy) {
//
// $has_items = false;
//
// foreach ( $hierarchy as $h ) {
//
// if ( $term_in_hierarchy->parent != $term_id ) {
// continue;
// }
//
// if ( $h->have_items > 0 ) {
// return true;
// } else {
// return children_has_items($h->term_id, $hierarchy);
// }
//
// }
//
// return false;
//
// }
// var_dump($all_hierarchy);
// foreach ($all_hierarchy as $term_in_hierarchy) {
// if ( $term_in_hierarchy->parent != $args['parent_id'] ) {
// continue;
// }
//
// if ( $term_in_hierarchy->have_items > 0 || children_has_items($term_in_hierarchy->term_id, $all_hierarchy) ) {
// $results[] = $term_in_hierarchy;
// }
//
// }
} else {
$base_query = $wpdb->prepare("FROM $wpdb->term_taxonomy tt
INNER JOIN $wpdb->terms t ON tt.term_id = t.term_id
@ -1039,14 +1098,18 @@ class Metadata extends Repository {
$args['parent_id'],
$taxonomy_slug
);
$query = "SELECT DISTINCT t.name, t.term_id, tt.term_taxonomy_id, tt.parent $base_query $pagination";
$total_query = "SELECT COUNT(DISTINCT tt.term_taxonomy_id) $base_query";
$total = $wpdb->get_var($total_query);
$results = $wpdb->get_results($query);
}
$query = "SELECT DISTINCT t.name, t.term_id, tt.term_taxonomy_id, tt.parent $base_query $pagination";
$total_query = "SELECT COUNT(DISTINCT tt.term_taxonomy_id) $base_query";
$results = $wpdb->get_results($query);
// add selected to the result
if ( !empty($args['include']) ) {
@ -1071,7 +1134,7 @@ class Metadata extends Repository {
}
}
$total = $wpdb->get_var($total_query);
$number = is_integer($args['number']) && $args['number'] >=1 ? $args['number'] : $total;
if( $number < 1){
$pages = 1;
@ -1197,6 +1260,75 @@ class Metadata extends Repository {
];
}
public function _process_terms_tree($tree, $search_parent) {
$h_map = [];
$results = [];
foreach ( $tree as $h ) {
//echo "Processing $h->term_id\n";
//var_dump($h);
//echo "Já ta mapeado?\n";
//var_dump(( isset($h_map[$h->term_id]) && $h_map[$h->term_id]->have_items > 0 ));
if ( $h->have_items > 0 || ( isset($h_map[$h->term_id]) && $h_map[$h->term_id]->have_items > 0 ) ) {
//echo "have_items\n";
$h->have_items = 1;
$h_map[$h->term_id] = $h;
if ($h->parent == $search_parent) {
//echo "Add to results\n";
$results[] = $h;
}
$_parent = $h->parent;
if ( $h->parent > 0 && !isset($h_map[$_parent]) ) {
//echo "Setting parent with have items 1\n";
//echo "Parent ID = $_parent\n";
$h_map[$_parent] = (object)['have_items' => 1];
}
while( isset($h_map[$_parent]) && $h_map[$_parent]->have_items != 1 ) {
//echo "Looping\n";
$h_map[$_parent]->have_items = 1;
if ( isset($h_map[$_parent]->parent) ) {
//echo "Parent exists: $_parent\n";
if ($h_map[$_parent]->parent == $search_parent) {
//echo "Add to results: {$h_map[$_parent]->term_id}\n";
$results[] = $h_map[$_parent];
}
$_parent = $h_map[$_parent]->parent;
} else {
//echo "Parent not exists\n";
$_parent = 0;
}
}
} else {
//echo "Not have items\n";
$h_map[$h->term_id] = $h;
if ( $h->parent > 0 && !isset($h_map[$h->parent]) ) {
//echo "Parent added: $h->parent\n";
$h_map[$h->parent] = (object)['have_items' => $h->have_items];
}
}
}
return $results;
}
/**
* Stores the value of the taxonomy_id option to use on update_taxonomy_metadatum method.

View File

@ -52,6 +52,19 @@ class Facets extends TAINACAN_UnitApiTestCase {
$this->taxonomy = $taxonomy;
$taxonomy2 = $this->tainacan_entity_factory->create_entity(
'taxonomy',
array(
'name' => 'genero2',
'description' => 'tipos de musica2',
'allow_insert' => 'yes',
'status' => 'publish'
),
true
);
$this->taxonomy = $taxonomy;
$term_1 = $this->tainacan_entity_factory->create_entity(
'term',
array(
@ -113,6 +126,104 @@ class Facets extends TAINACAN_UnitApiTestCase {
true
);
$term2_root = $this->tainacan_entity_factory->create_entity(
'term',
array(
'taxonomy' => $taxonomy2->get_db_identifier(),
'name' => 'Root'
),
true
);
$term2_root2 = $this->tainacan_entity_factory->create_entity(
'term',
array(
'taxonomy' => $taxonomy2->get_db_identifier(),
'name' => 'Root2'
),
true
);
$term2_root_c1 = $this->tainacan_entity_factory->create_entity(
'term',
array(
'taxonomy' => $taxonomy2->get_db_identifier(),
'name' => 'Children',
'parent' => $term2_root->get_id()
),
true
);
$term2_root_c2 = $this->tainacan_entity_factory->create_entity(
'term',
array(
'taxonomy' => $taxonomy2->get_db_identifier(),
'name' => 'Children2',
'parent' => $term2_root->get_id()
),
true
);
$term2_root_gc1 = $this->tainacan_entity_factory->create_entity(
'term',
array(
'taxonomy' => $taxonomy2->get_db_identifier(),
'name' => 'GChildren',
'parent' => $term2_root_c2->get_id()
),
true
);
$term2_root_gc2 = $this->tainacan_entity_factory->create_entity(
'term',
array(
'taxonomy' => $taxonomy2->get_db_identifier(),
'name' => 'GChildren2',
'parent' => $term2_root_c2->get_id()
),
true
);
$term2_root2_c1 = $this->tainacan_entity_factory->create_entity(
'term',
array(
'taxonomy' => $taxonomy2->get_db_identifier(),
'name' => 'Children',
'parent' => $term2_root2->get_id()
),
true
);
$term2_root2_c2 = $this->tainacan_entity_factory->create_entity(
'term',
array(
'taxonomy' => $taxonomy2->get_db_identifier(),
'name' => 'Children2',
'parent' => $term2_root2->get_id()
),
true
);
$term2_root2_gc1 = $this->tainacan_entity_factory->create_entity(
'term',
array(
'taxonomy' => $taxonomy2->get_db_identifier(),
'name' => 'GChildren',
'parent' => $term2_root2_c2->get_id()
),
true
);
$term2_root2_gc2 = $this->tainacan_entity_factory->create_entity(
'term',
array(
'taxonomy' => $taxonomy2->get_db_identifier(),
'name' => 'GChildren2',
'parent' => $term2_root2_c2->get_id()
),
true
);
$term2_root2_ggc1 = $this->tainacan_entity_factory->create_entity(
'term',
array(
'taxonomy' => $taxonomy2->get_db_identifier(),
'name' => 'GGChildren1',
'parent' => $term2_root2_gc2->get_id()
),
true
);
$meta_1_tax = $this->tainacan_entity_factory->create_entity(
'metadatum',
array(
@ -150,6 +261,24 @@ class Facets extends TAINACAN_UnitApiTestCase {
$this->meta_2_tax = $meta_2_tax;
$meta_3_tax = $this->tainacan_entity_factory->create_entity(
'metadatum',
array(
'name' => 'test taxonomy',
'status' => 'publish',
'collection' => $collection2,
'metadata_type' => 'Tainacan\Metadata_Types\Taxonomy',
'metadata_type_options' => [
'allow_new_terms' => true,
'taxonomy_id' => $taxonomy2->get_id()
],
'multiple' => 'yes'
),
true
);
$this->meta_3_tax = $meta_3_tax;
$metadatum_text = $this->tainacan_entity_factory->create_entity(
'metadatum',
array(
@ -239,8 +368,16 @@ class Facets extends TAINACAN_UnitApiTestCase {
$this->tainacan_item_metadata_factory->create_item_metadata($item, $meta_2_tax, [$term_2_c->get_id()]);
}
// hierarchical taxonomy
if ($i <= 10) {
$this->tainacan_item_metadata_factory->create_item_metadata($item, $meta_3_tax, [$term2_root_c1->get_id()]);
} elseif($i <= 20) {
$this->tainacan_item_metadata_factory->create_item_metadata($item, $meta_3_tax, [$term2_root2_c1->get_id()]);
} elseif($i <= 30) {
$this->tainacan_item_metadata_factory->create_item_metadata($item, $meta_3_tax, [$term2_root2_gc2->get_id()]);
} elseif($i <= 40) {
$this->tainacan_item_metadata_factory->create_item_metadata($item, $meta_3_tax, [$term2_root2_ggc1->get_id()]);
}
}
$this->repository = \Tainacan\Repositories\Metadata::get_instance();
@ -647,7 +784,16 @@ class Facets extends TAINACAN_UnitApiTestCase {
// test count items normal
// test default taxonomy
$values = $this->repository->fetch_all_metadatum_values( $this->meta_3_tax->get_id());
$values = $this->get_values($values);
$this->assertEquals(2, sizeof($values));
// test default taxonomy without filter
$values = $this->repository->fetch_all_metadatum_values( $this->meta_3_tax->get_id(), [
'items_filter' => false
]);
$values = $this->get_values($values);
$this->assertEquals(2, sizeof($values));
// test search taxonomy
// test search taxonomy with filter
// test search taxonomy without filter
@ -660,6 +806,168 @@ class Facets extends TAINACAN_UnitApiTestCase {
}
/**
* @group term_tree
*/
public function test_process_term_tree() {
$data = [
(object) [
'term_id' => 1,
'name' => 'Root',
'parent' => 0,
'have_items' => 0
],
(object) [
'term_id' => 2,
'name' => 'Child 1',
'parent' => 1,
'have_items' => 0
],
(object) [
'term_id' => 3,
'name' => 'G Child 1',
'parent' => 2,
'have_items' => 0
],
(object) [
'term_id' => 4,
'name' => 'G G Child',
'parent' => 3,
'have_items' => 0
],
(object) [
'term_id' => 5,
'name' => 'G G Child 2',
'parent' => 3,
'have_items' => 0
],
(object) [
'term_id' => 6,
'name' => 'G G G Child',
'parent' => 4,
'have_items' => 0
],
(object) [
'term_id' => 7,
'name' => 'G G G Child 2',
'parent' => 5,
'have_items' => 0
],
(object) [
'term_id' => 8,
'name' => '2 Root',
'parent' => 0,
'have_items' => 0
],
(object) [
'term_id' => 9,
'name' => '2 Child',
'parent' => 8,
'have_items' => 0
],
(object) [
'term_id' => 10,
'name' => '2 Child 2',
'parent' => 8,
'have_items' => 0
],
(object) [
'term_id' => 11,
'name' => '2 G Child',
'parent' => 10,
'have_items' => 0
],
(object) [
'term_id' => 12,
'name' => '2 G Child 2',
'parent' => 10,
'have_items' => 0
]
];
$data_b = $data;
$MetaRepo = \Tainacan\Repositories\Metadata::get_instance();
// items on 5 and 12
$data[4]->have_items = 1;
$data[11]->have_items = 1;
$i = 0;
while ($i<100) {
$i++;
shuffle($data);
$results = $MetaRepo->_process_terms_tree($data, 0);
$this->assertEquals(2, count($results));
$ids = array_map(function($el) {return $el->term_id; }, $results);
$this->assertContains(1, $ids);
$this->assertContains(8, $ids);
$results = $MetaRepo->_process_terms_tree($data, 3);
$this->assertEquals(1, count($results));
$ids = array_map(function($el) {return $el->term_id; }, $results);
$this->assertContains(5, $ids);
$results = $MetaRepo->_process_terms_tree($data, 5);
$this->assertEquals(0, count($results));
$results = $MetaRepo->_process_terms_tree($data, 10);
$this->assertEquals(1, count($results));
$this->assertEquals(12, $results[0]->term_id);
}
// items on 6, 7 and 8
$data = $data_b;
$data[4]->have_items = 0;
$data[11]->have_items = 0;
$data[7]->have_items = 1;
$data[6]->have_items = 1;
$data[5]->have_items = 1;
$i = 0;
while ($i<100) {
$i++;
shuffle($data);
$results = $MetaRepo->_process_terms_tree($data, 0);
$this->assertEquals(2, count($results));
$ids = array_map(function($el) {return $el->term_id; }, $results);
$this->assertContains(1, $ids);
$this->assertContains(8, $ids);
$results = $MetaRepo->_process_terms_tree($data, 3);
$this->assertEquals(2, count($results));
$ids = array_map(function($el) {return $el->term_id; }, $results);
$this->assertContains(5, $ids);
$this->assertContains(4, $ids);
$results = $MetaRepo->_process_terms_tree($data, 5);
$this->assertEquals(1, count($results));
$ids = array_map(function($el) {return $el->term_id; }, $results);
$this->assertContains(7, $ids);
$results = $MetaRepo->_process_terms_tree($data, 10);
$this->assertEquals(0, count($results));
$results = $MetaRepo->_process_terms_tree($data, 6);
$this->assertEquals(0, count($results));
}
}