Replace term_exists() native function. Fixes #159

This commit is contained in:
leogermani 2018-11-13 18:21:02 -02:00
parent 3aefcf9e42
commit 76a52dd8a4
8 changed files with 270 additions and 56 deletions

View File

@ -439,26 +439,32 @@ class Bulk_Edit {
private function _add_value(Entities\Metadatum $metadatum, $value) {
global $wpdb;
$type = $metadatum->get_metadata_type_object();
$taxRepo = Repositories\Taxonomies::get_instance();
if ($type->get_primitive_type() == 'term') {
$options = $metadatum->get_metadata_type_options();
$taxonomy_id = $options['taxonomy_id'];
$tax = Repositories\Taxonomies::get_instance()->fetch($taxonomy_id);
$tax = $taxRepo->fetch($taxonomy_id);
if ($tax instanceof Entities\Taxonomy) {
$term = term_exists($value, $tax->get_db_identifier());
$term = $taxRepo->term_exists($tax, $value, 0, true);
$term_id = false;
if (!is_array($term)) {
if (false === $term) {
$term = wp_insert_term($value, $tax->get_db_identifier());
if (is_WP_Error($term) || !isset($term['term_taxonomy_id'])) {
return new \WP_Error( 'error', __( 'Error adding term', 'tainacan' ) );
}
$term_id = $term['term_taxonomy_id'];
} else {
$term_id = $term->term_taxonomy_id;
}
if (is_WP_Error($term) || !isset($term['term_taxonomy_id'])) {
return new \WP_Error( 'error', __( 'Error adding term', 'tainacan' ) );
}
$insert_q = $this->_build_select( $wpdb->prepare("post_id, %d", $term['term_taxonomy_id']) );
$insert_q = $this->_build_select( $wpdb->prepare("post_id, %d", $term_id) );
$query = "INSERT IGNORE INTO $wpdb->term_relationships (object_id, term_taxonomy_id) $insert_q";
@ -506,28 +512,29 @@ class Bulk_Edit {
private function _remove_value(Entities\Metadatum $metadatum, $value) {
global $wpdb;
$type = $metadatum->get_metadata_type_object();
$taxRepo = Repositories\Taxonomies::get_instance();
if ($type->get_primitive_type() == 'term') {
$options = $metadatum->get_metadata_type_options();
$taxonomy_id = $options['taxonomy_id'];
$tax = Repositories\Taxonomies::get_instance()->fetch($taxonomy_id);
$tax = $taxRepo->fetch($taxonomy_id);
if ($tax instanceof Entities\Taxonomy) {
$term = term_exists($value, $tax->get_db_identifier());
$term = $taxRepo->term_exists($tax, $value, null, true);
if (!$term) {
return 0;
}
if (is_WP_Error($term) || !isset($term['term_taxonomy_id'])) {
if ( !isset($term->term_taxonomy_id) ) {
return new \WP_Error( 'error', __( 'Term not found', 'tainacan' ) );
}
$delete_q = $this->_build_select( "post_id" );
$query = $wpdb->prepare( "DELETE FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d AND object_id IN ($delete_q)", $term['term_taxonomy_id'] );
$query = $wpdb->prepare( "DELETE FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d AND object_id IN ($delete_q)", $term->term_taxonomy_id );
return $wpdb->query($query);
@ -566,42 +573,48 @@ class Bulk_Edit {
return new \WP_Error( 'error', __( 'New value and old value can not be the same', 'tainacan' ) );
}
$taxRepo = Repositories\Taxonomies::get_instance();
$type = $metadatum->get_metadata_type_object();
if ($type->get_primitive_type() == 'term') {
$options = $metadatum->get_metadata_type_options();
$taxonomy_id = $options['taxonomy_id'];
$tax = Repositories\Taxonomies::get_instance()->fetch($taxonomy_id);
$tax = $taxRepo->fetch($taxonomy_id);
if ($tax instanceof Entities\Taxonomy) {
// check old term
$term = term_exists($value, $tax->get_db_identifier());
$term = $taxRepo->term_exists($tax, $value, null, true);
if (!$term) {
return 0;
}
if (is_WP_Error($term) || !isset($term['term_taxonomy_id'])) {
if (is_WP_Error($term) || !isset($term->term_taxonomy_id)) {
return new \WP_Error( 'error', __( 'Term not found', 'tainacan' ) );
}
// check new term
$newterm = term_exists($newvalue, $tax->get_db_identifier());
$newterm = $taxRepo->term_exists($tax, $newvalue, 0, true);
if (!is_array($newterm)) {
if (false === $newterm) {
$newterm = wp_insert_term($newvalue, $tax->get_db_identifier());
if (is_WP_Error($newterm) || !isset($newterm['term_taxonomy_id'])) {
return new \WP_Error( 'error', __( 'Error adding term', 'tainacan' ) );
}
$newtermid = $newterm['term_taxonomy_id'];
} else {
$newtermid = $newterm->term_taxonomy_id;
}
if (is_WP_Error($newterm) || !isset($newterm['term_taxonomy_id'])) {
return new \WP_Error( 'error', __( 'Error adding term', 'tainacan' ) );
}
$insert_q = $this->_build_select( $wpdb->prepare("post_id, %d", $newterm['term_taxonomy_id']) );
$insert_q = $this->_build_select( $wpdb->prepare("post_id, %d", $newtermid) );
// only where old_value is present (this is what this method have different from the _add_value())
$insert_q .= $wpdb->prepare( " AND post_id IN(SELECT object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d)", $term['term_taxonomy_id'] );
$insert_q .= $wpdb->prepare( " AND post_id IN(SELECT object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d)", $term->term_taxonomy_id );
$query = "INSERT IGNORE INTO $wpdb->term_relationships (object_id, term_taxonomy_id) $insert_q ";

View File

@ -197,4 +197,18 @@ class Taxonomy extends Entity {
}
/**
* Check if a term already exists
*
* @param string $term_name The term name
* @param int|null $parent The ID of the parent term to look for children or null to look for terms in any hierarchical position. Default is null
* @param bool $return_term wether to return the term object if it exists. default is to false
*
* @return bool|WP_Term return boolean indicating if term exists. If $return_term is true and term exists, return WP_Term object
*/
function term_exists($term_name, $parent = null, $return_term = false) {
$repo = $this->get_repository();
return $repo->term_exists($this, $term_name, $parent, $return_term);
}
}

View File

@ -218,40 +218,17 @@ class Term extends Entity {
$name = $this->get_name();
$taxonomy = $this->get_taxonomy();
/**
* Code from WordPress Core, taxonomy.php#2070
*/
$repo = $this->get_repository();
/*
* Prevent the creation of terms with duplicate names at the same level of a taxonomy hierarchy,
* unless a unique slug has been explicitly provided.
*/
$name_matches = get_terms( $taxonomy, array(
'name' => $name,
'hide_empty' => false,
'parent' => $parent,
'exclude' => $this->get_id()
) );
$term_exists = $repo->term_exists($name, $taxonomy, $parent, true);
/*
* The `name` match in `get_terms()` doesn't differentiate accented characters,
* so we do a stricter comparison here.
*/
$name_match = null;
if ( $name_matches ) {
foreach ( $name_matches as $_match ) {
if ( is_object($_match) && isset($_match) && strtolower( $name ) === strtolower( $_match->name ) ) {
$name_match = $_match;
break;
}
if (false !== $term_exists) {
if ($this->get_id() != $term_exists->term_taxonomy_id) {
$this->add_error( 'repeated', __('You can not have two terms with the same name at the same level', 'tainacan') );
return false;
}
}
if ($name_match) {
$this->add_error( 'repeated', __('You can not have two terms with the same name at the same level', 'tainacan') );
return false;
}
$this->set_as_valid();
return true;

View File

@ -126,6 +126,7 @@ class Taxonomy extends Metadata_Type {
$term = $term->get_id();
}
// TODO term_exists is not fully reliable. Use $terms_repository->term_exists. see issue #159
if (!term_exists($term)) {
$valid = false;
break;

View File

@ -344,5 +344,20 @@ class Taxonomies extends Repository {
return $prefix . $id;
}
/**
* Check if a term already exists
*
* @param Entities\Taxonomy $taxonomy The taxonomy object where to look for terms
* @param string $term_name The term name
* @param int|null $parent The ID of the parent term to look for children or null to look for terms in any hierarchical position. Default is null
* @param bool $return_term wether to return the term object if it exists. default is to false
*
* @return bool|WP_Term return boolean indicating if term exists. If $return_term is true and term exists, return WP_Term object
*/
public function term_exists(Entities\Taxonomy $taxonomy, $term_name, $parent = null, $return_term = false) {
$TermsRepo = Terms::get_instance();
return $TermsRepo->term_exists($term_name, $taxonomy, $parent, $return_term);
}
}

View File

@ -266,6 +266,54 @@ class Terms extends Repository {
return $deleted;
}
/**
* Check if a term already exists
*
* @param string $term_name The term name
* @param mixed $taxonomy The taxonomy ID, slug or Entity.
* @param int $parent The ID of the parent term to look for children or null to look for terms in any hierarchical position. Default is null
* @param bool $return_term wether to return the term object if it exists. default is to false
*
* @return bool|WP_Term return boolean indicating if term exists. If $return_term is true and term exists, return WP_Term object
*/
public function term_exists($name, $taxonomy, $parent = null, $return_term = false) {
$Tainacan_Taxonomies = \Tainacan\Repositories\Taxonomies::get_instance();
if ( is_numeric( $taxonomy ) ) {
$taxonomy_slug = $Tainacan_Taxonomies->get_db_identifier_by_id( $taxonomy );
} elseif (is_string($taxonomy)) {
$taxonomy_slug = $taxonomy;
} elseif ( $taxonomy instanceof Entities\Taxonomy ) {
$taxonomy_slug = $taxonomy->get_db_identifier();
}
$args = [
'name' => $name,
'taxonomy' => $taxonomy_slug,
'parent' => $parent,
'hide_empty' => 0,
'suppress_filter' => true
];
if (is_null($parent)) {
unset($args['parent']);
}
$terms = get_terms($args);
if (empty($terms)) {
return false;
}
if ($return_term) {
return $terms[0];
}
return true;
}
/**
* @param $term_id
*

View File

@ -663,9 +663,9 @@ class CSV extends Importer {
$this->add_error_log('Malformed term hierarchy for Item ' . $this->get_current_collection_item() . '. Term skipped. Value: ' . $values);
return false;
}
$exists = term_exists( $value ,$taxonomy->get_db_identifier(), $parent );
if (0 !== $exists && null !== $exists && isset($exists['term_id'])) {
$parent = $exists['term_id'];
$exists = $Tainacan_Terms->term_exists( $value ,$taxonomy->get_db_identifier(), $parent, true );
if (false !== $exists && isset($exists->term_taxonomy_id)) {
$parent = $exists->term_taxonomy_id;
} else {
$this->add_log('New term created: ' . $value . ' in tax_id: ' . $taxonomy->get_db_identifier() . '; parent: ' . $parent);
$term = new Entities\Term();

View File

@ -105,5 +105,151 @@ class Taxonomies extends TAINACAN_UnitTestCase {
$this->assertEquals(1, sizeof($terms), 'you should be able to create a term even if the taxonomy is still auto-draft');
}
function test_term_exists() {
$taxonomy = $this->tainacan_entity_factory->create_entity(
'taxonomy',
array(
'name' => 'genero',
'description' => 'tipos de musica',
'allow_insert' => 'yes',
'status' => 'publish'
),
true
);
$Tainacan_Taxonomies = \Tainacan\Repositories\Taxonomies::get_instance();
$Tainacan_Terms = \Tainacan\Repositories\Terms::get_instance();
$term = $this->tainacan_entity_factory->create_entity(
'term',
array(
'taxonomy' => $taxonomy->get_db_identifier(),
'name' => 'Rock',
),
true
);
$parent = $this->tainacan_entity_factory->create_entity(
'term',
array(
'taxonomy' => $taxonomy->get_db_identifier(),
'name' => 'Parent',
),
true
);
$child = $this->tainacan_entity_factory->create_entity(
'term',
array(
'taxonomy' => $taxonomy->get_db_identifier(),
'name' => 'Child',
'parent' => $parent->get_id()
),
true
);
$this->assertFalse( $Tainacan_Terms->term_exists('Reggae', $taxonomy->get_db_identifier()) );
$this->assertTrue( $Tainacan_Terms->term_exists('Rock', $taxonomy->get_db_identifier()) );
//var_dump( $Tainacan_Terms->term_exists('Rock', $taxonomy->get_db_identifier(), 0, true) );
// test extreme case
$term_2 = $this->tainacan_entity_factory->create_entity(
'term',
array(
'taxonomy' => $taxonomy->get_db_identifier(),
'name' => 'test 123',
'parent' => $term->get_id()
),
true
);
$this->assertFalse( $Tainacan_Terms->term_exists('test 123', $taxonomy->get_db_identifier(), 0) ); // parent 0
$this->assertTrue( $Tainacan_Terms->term_exists('test 123', $taxonomy->get_db_identifier(), $term->get_id()) ); // spaces in between
// testing passing taxonomy object
$this->assertTrue( $Tainacan_Terms->term_exists('Rock', $taxonomy) );
// testing passing ID
$this->assertTrue( $Tainacan_Terms->term_exists('Rock', $taxonomy->get_id()) );
// testing via Taxonomy object
$this->assertTrue( $taxonomy->term_exists('Rock') );
// testing retrieving the term
$this->assertTrue( $taxonomy->term_exists('Rock', 0, true) instanceof \WP_Term );
$this->assertEquals( $term->get_id(), $taxonomy->term_exists('Rock', 0, true)->term_taxonomy_id );
// test parent
$this->assertTrue( $Tainacan_Terms->term_exists('Child', $taxonomy->get_db_identifier()) ); // parent null
$this->assertFalse( $Tainacan_Terms->term_exists('Child', $taxonomy->get_db_identifier(), 0) ); // parent 0
$this->assertTrue( $Tainacan_Terms->term_exists('Child', $taxonomy->get_db_identifier(), $parent->get_id()) ); // parent
}
function test_term_validation() {
$taxonomy = $this->tainacan_entity_factory->create_entity(
'taxonomy',
array(
'name' => 'genero',
'description' => 'tipos de musica',
'allow_insert' => 'yes',
'status' => 'publish'
),
true
);
$Tainacan_Taxonomies = \Tainacan\Repositories\Taxonomies::get_instance();
$Tainacan_Terms = \Tainacan\Repositories\Terms::get_instance();
$term = $this->tainacan_entity_factory->create_entity(
'term',
array(
'taxonomy' => $taxonomy->get_db_identifier(),
'name' => 'Rock',
),
true
);
$parent = $this->tainacan_entity_factory->create_entity(
'term',
array(
'taxonomy' => $taxonomy->get_db_identifier(),
'name' => 'Parent',
),
true
);
$child = $this->tainacan_entity_factory->create_entity(
'term',
array(
'taxonomy' => $taxonomy->get_db_identifier(),
'name' => 'Child',
'parent' => $parent->get_id()
),
true
);
$newTerm = new \Tainacan\Entities\Term();
$newTerm->set_name('Child');
$newTerm->set_taxonomy($taxonomy->get_db_identifier());
$this->assertTrue( $newTerm->validate() );
$newTerm->set_parent($parent->get_id());
$this->assertFalse( $newTerm->validate(), 'term should not validate because it has a duplicate in the same level' );
$child->set_description('changed');
$this->assertTrue( $child->validate(), 'child should validate');
}
}