diff options
-rw-r--r-- | engine/lib/metadata.php | 49 | ||||
-rw-r--r-- | engine/tests/api/entity_getter_functions.php | 683 |
2 files changed, 720 insertions, 12 deletions
diff --git a/engine/lib/metadata.php b/engine/lib/metadata.php index 71b6c2634..67a135d75 100644 --- a/engine/lib/metadata.php +++ b/engine/lib/metadata.php @@ -539,6 +539,13 @@ function find_metadata($meta_name = "", $meta_value = "", $entity_type = "", $en * options available to elgg_get_entities(). Supports * the singular option shortcut. * + * NB: Using metadata_names and metadata_values results in a + * "names IN (...) AND values IN (...)" clause. This is subtly + * differently than default multiple metadata_name_value_pairs, which use + * "(name = value) AND (name = value)" clauses. + * + * When in doubt, use name_value_pairs. + * * @see elgg_get_entities * @param array $options Array in format: * @@ -546,7 +553,8 @@ function find_metadata($meta_name = "", $meta_value = "", $entity_type = "", $en * * metadata_values => NULL|ARR metadata values * - * metadata_name_value_pairs => NULL|ARR (name = 'name', value => 'value', 'operand' => '=', 'case_sensitive' => TRUE) entries + * metadata_name_value_pairs => NULL|ARR (name = 'name', value => 'value', 'operand' => '=', 'case_sensitive' => TRUE) entries. + * Currently if multiple values are sent via an array (value => array('value1', 'value2') the pair's operand will be forced to "IN". * * metadata_name_value_pairs_operator => NULL|STR The operator to use for combining (name = value) OPERATOR (name = value); default AND * @@ -739,9 +747,28 @@ function elgg_get_entity_metadata_where_sql($table, $names = NULL, $values = NUL // if the value is an int, don't quote it because str '15' < str '5' // if the operand is IN don't quote it because quoting should be done already. - //$value = trim(strtolower($operand)) == 'in' ? $pair['value'] : "'{$pair['value']}'"; - if (trim(strtolower($operand)) == 'in' || is_numeric($pair['value'])) { + if (is_numeric($pair['value'])) { $value = sanitise_string($pair['value']); + } else if (is_array($pair['value'])) { + $values_array = array(); + + foreach ($pair['value'] as $pair_value) { + if (is_numeric($v)) { + $values_array[] = sanitise_string($pair_value); + } else { + $values_array[] = '\'' . sanitise_string($pair_value) . '\''; + } + } + + if ($values_array) { + $value = '(' . implode(', ', $values_array) . ')'; + } + + // @todo allow support for non IN operands with array of values. + // will have to do more silly joins. + $operand = 'IN'; + } else if (trim(strtolower($operand)) == 'in') { + $value = "({$pair['value']})"; } else { $value = '\'' . sanitise_string($pair['value']) . '\''; } @@ -854,14 +881,14 @@ function list_entities_from_metadata($meta_name, $meta_value = "", $entity_type $offset = (int) get_input('offset'); $limit = (int) $limit; $options = array( - 'metadata_name' => $meta_name, - 'metadata_value' => $meta_value, - 'types' => $entity_type, - 'subtypes' => $entity_subtype, - 'owner_guid' => $owner_guid, - 'limit' => $limit, - 'offset' => $offset, - 'count' => TRUE, + 'metadata_name' => $meta_name, + 'metadata_value' => $meta_value, + 'types' => $entity_type, + 'subtypes' => $entity_subtype, + 'owner_guid' => $owner_guid, + 'limit' => $limit, + 'offset' => $offset, + 'count' => TRUE, 'case_sensitive' => $case_sensitive ); $count = elgg_get_entities_from_metadata($options); diff --git a/engine/tests/api/entity_getter_functions.php b/engine/tests/api/entity_getter_functions.php index aa7442d4b..04fa3e4e5 100644 --- a/engine/tests/api/entity_getter_functions.php +++ b/engine/tests/api/entity_getter_functions.php @@ -27,10 +27,11 @@ class ElggCoreEntityGetterFunctionsTest extends ElggCoreUnitTest { // create some fun objects to play with. // 5 with random subtypes for ($i=0; $i<5; $i++) { - $subtype = "test_object_subtype_" . rand(); + $subtype = 'test_object_subtype_' . rand(); $e = new ElggObject(); $e->subtype = $subtype; $e->save(); + $this->entities[] = $e; $this->subtypes['object'][] = $subtype; } @@ -42,6 +43,7 @@ class ElggCoreEntityGetterFunctionsTest extends ElggCoreUnitTest { $e->username = "test_user_" . rand(); $e->subtype = $subtype; $e->save(); + $this->entities[] = $e; $this->subtypes['user'][] = $subtype; } @@ -52,6 +54,7 @@ class ElggCoreEntityGetterFunctionsTest extends ElggCoreUnitTest { $e = new ElggGroup(); $e->subtype = $subtype; $e->save(); + $this->entities[] = $e; $this->subtypes['group'][] = $subtype; } @@ -929,4 +932,682 @@ class ElggCoreEntityGetterFunctionsTest extends ElggCoreUnitTest { $q = "DELETE FROM {$CONFIG->dbprefix}entity_subtypes WHERE subtype = '$subtype'"; delete_data($q); } + + + + /************ + * METADATA + ************/ + + //names + + function testElggApiGettersEntityMetadataNameValidSingle() { + // create a new entity with a subtype we know + // use an existing type so it will clean up automatically + $subtypes = $this->getRandomValidSubtypes(array('object'), 1); + $subtype = $subtypes[0]; + $md_name = 'test_metadata_name_' . rand(); + $md_value = 'test_metadata_value_' . rand(); + + $e = new ElggObject(); + $e->subtype = $subtype; + $e->$md_name = $md_value; + $e->save(); + + $options = array( + 'type' => 'object', + 'subtype' => $subtype, + 'metadata_name' => $md_name + ); + + $entities = elgg_get_entities_from_metadata($options); + + $this->assertIsa($entities, 'array'); + $this->assertEqual(count($entities), 1); + + foreach ($entities as $entity) { + $this->assertEqual($entity->getGUID(), $e->getGUID()); + $this->assertEqual($entity->$md_name, $md_value); + } + + $e->delete(); + } + + function testElggApiGettersEntityMetadataNameValidMultiple() { + $subtypes = $this->getRandomValidSubtypes(array('object'), 1); + $subtype = $subtypes[0]; + $md_names = array(); + + $md_name = 'test_metadata_name_' . rand(); + $md_value = 'test_metadata_value_' . rand(); + $md_names[] = $md_name; + $e_guids = array(); + + $e = new ElggObject(); + $e->subtype = $subtype; + $e->$md_name = $md_value; + $e->save(); + $e_guids[] = $e->getGUID(); + + $md_name = 'test_metadata_name_' . rand(); + $md_value = 'test_metadata_value_' . rand(); + $md_names[] = $md_name; + + $e = new ElggObject(); + $e->subtype = $subtype; + $e->$md_name = $md_value; + $e->save(); + $e_guids[] = $e->getGUID(); + + $options = array( + 'type' => 'object', + 'subtype' => $subtype, + 'metadata_names' => $md_names + ); + + $entities = elgg_get_entities_from_metadata($options); + + $this->assertIsa($entities, 'array'); + $this->assertEqual(count($entities), 2); + + foreach ($entities as $entity) { + $this->assertTrue(in_array($entity->getGUID(), $e_guids)); + $entity->delete(); + } + } + + function testElggApiGettersEntityMetadataNameInvalidSingle() { + $subtypes = $this->getRandomValidSubtypes(array('object'), 1); + $subtype = $subtypes[0]; + $md_name = 'test_metadata_name_' . rand(); + $md_value = 'test_metadata_value_' . rand(); + + $e = new ElggObject(); + $e->subtype = $subtype; + $e->$md_name = $md_value; + $e->save(); + + $md_invalid_name = 'test_metadata_name_' . rand(); + + $options = array( + 'type' => 'object', + 'subtype' => $subtype, + 'metadata_name' => $md_invalid_name + ); + + $entities = elgg_get_entities_from_metadata($options); + + $this->assertFalse($entities); + + $e->delete(); + } + + function testElggApiGettersEntityMetadataNameInvalidMultiple() { + $subtypes = $this->getRandomValidSubtypes(array('object'), 1); + $subtype = $subtypes[0]; + $md_name = 'test_metadata_name_' . rand(); + $md_value = 'test_metadata_value_' . rand(); + + $e = new ElggObject(); + $e->subtype = $subtype; + $e->$md_name = $md_value; + $e->save(); + + $md_invalid_names = array(); + $md_invalid_names[] = 'test_metadata_name_' . rand(); + $md_invalid_names[] = 'test_metadata_name_' . rand(); + + $options = array( + 'type' => 'object', + 'subtype' => $subtype, + 'metadata_names' => $md_invalid_names + ); + + $entities = elgg_get_entities_from_metadata($options); + + $this->assertFalse($entities); + + $e->delete(); + } + + + function testElggApiGettersEntityMetadataNameMixedMultiple() { + $subtypes = $this->getRandomValidSubtypes(array('object'), 1); + $subtype = $subtypes[0]; + $md_names = array(); + + $md_name = 'test_metadata_name_' . rand(); + $md_value = 'test_metadata_value_' . rand(); + $md_names[] = $md_name; + $e_guids = array(); + + $valid = new ElggObject(); + $valid->subtype = $subtype; + $valid->$md_name = $md_value; + $valid->save(); + $e_guids[] = $valid->getGUID(); + + $md_name = 'test_metadata_name_' . rand(); + $md_value = 'test_metadata_value_' . rand(); + + // add a random invalid name. + $md_names[] = 'test_metadata_name_' . rand(); + + $e = new ElggObject(); + $e->subtype = $subtype; + $e->$md_name = $md_value; + $e->save(); + $e_guids[] = $e->getGUID(); + + $options = array( + 'type' => 'object', + 'subtype' => $subtype, + 'metadata_names' => $md_names + ); + + $entities = elgg_get_entities_from_metadata($options); + + $this->assertIsa($entities, 'array'); + $this->assertEqual(count($entities), 1); + + foreach ($entities as $entity) { + $this->assertEqual($entity->getGUID(), $valid->getGUID()); + } + + foreach ($e_guids as $guid) { + if ($e = get_entity($guid)) { + $e->delete(); + } + } + } + + + // values + function testElggApiGettersEntityMetadataValueValidSingle() { + // create a new entity with a subtype we know + // use an existing type so it will clean up automatically + $subtypes = $this->getRandomValidSubtypes(array('object'), 1); + $subtype = $subtypes[0]; + $md_name = 'test_metadata_name_' . rand(); + $md_value = 'test_metadata_value_' . rand(); + + $e = new ElggObject(); + $e->subtype = $subtype; + $e->$md_name = $md_value; + $e->save(); + + $options = array( + 'type' => 'object', + 'subtype' => $subtype, + 'metadata_value' => $md_value + ); + + $entities = elgg_get_entities_from_metadata($options); + + $this->assertIsa($entities, 'array'); + $this->assertEqual(count($entities), 1); + + foreach ($entities as $entity) { + $this->assertEqual($entity->getGUID(), $e->getGUID()); + $this->assertEqual($entity->$md_name, $md_value); + } + + $e->delete(); + } + + function testElggApiGettersEntityMetadataValueValidMultiple() { + $subtypes = $this->getRandomValidSubtypes(array('object'), 1); + $subtype = $subtypes[0]; + $md_values = array(); + + $md_name = 'test_metadata_name_' . rand(); + $md_value = 'test_metadata_value_' . rand(); + $md_values[] = $md_value; + $e_guids = array(); + + $e = new ElggObject(); + $e->subtype = $subtype; + $e->$md_name = $md_value; + $e->save(); + $e_guids[] = $e->getGUID(); + + $md_name = 'test_metadata_name_' . rand(); + $md_value = 'test_metadata_value_' . rand(); + $md_values[] = $md_value; + + $e = new ElggObject(); + $e->subtype = $subtype; + $e->$md_name = $md_value; + $e->save(); + $e_guids[] = $e->getGUID(); + + $options = array( + 'type' => 'object', + 'subtype' => $subtype, + 'metadata_values' => $md_values + ); + + $entities = elgg_get_entities_from_metadata($options); + + $this->assertIsa($entities, 'array'); + $this->assertEqual(count($entities), 2); + + foreach ($entities as $entity) { + $this->assertTrue(in_array($entity->getGUID(), $e_guids)); + $entity->delete(); + } + } + + function testElggApiGettersEntityMetadatavalueInvalidSingle() { + $subtypes = $this->getRandomValidSubtypes(array('object'), 1); + $subtype = $subtypes[0]; + $md_name = 'test_metadata_name_' . rand(); + $md_value = 'test_metadata_value_' . rand(); + + $e = new ElggObject(); + $e->subtype = $subtype; + $e->$md_name = $md_value; + $e->save(); + + $md_invalid_value = 'test_metadata_value_' . rand(); + + $options = array( + 'type' => 'object', + 'subtype' => $subtype, + 'metadata_value' => $md_invalid_value + ); + + $entities = elgg_get_entities_from_metadata($options); + + $this->assertFalse($entities); + + $e->delete(); + } + + function testElggApiGettersEntityMetadataValueInvalidMultiple() { + $subtypes = $this->getRandomValidSubtypes(array('object'), 1); + $subtype = $subtypes[0]; + $md_name = 'test_metadata_name_' . rand(); + $md_value = 'test_metadata_value_' . rand(); + + $e = new ElggObject(); + $e->subtype = $subtype; + $e->$md_name = $md_value; + $e->save(); + + $md_invalid_values = array(); + $md_invalid_values[] = 'test_metadata_value_' . rand(); + $md_invalid_values[] = 'test_metadata_value_' . rand(); + + $options = array( + 'type' => 'object', + 'subtype' => $subtype, + 'metadata_values' => $md_invalid_values + ); + + $entities = elgg_get_entities_from_metadata($options); + + $this->assertFalse($entities); + + $e->delete(); + } + + + function testElggApiGettersEntityMetadataValueMixedMultiple() { + $subtypes = $this->getRandomValidSubtypes(array('object'), 1); + $subtype = $subtypes[0]; + $md_values = array(); + + $md_name = 'test_metadata_name_' . rand(); + $md_value = 'test_metadata_value_' . rand(); + $md_values[] = $md_value; + $e_guids = array(); + + $valid = new ElggObject(); + $valid->subtype = $subtype; + $valid->$md_name = $md_value; + $valid->save(); + $e_guids[] = $valid->getGUID(); + + $md_name = 'test_metadata_name_' . rand(); + $md_value = 'test_metadata_value_' . rand(); + + // add a random invalid value. + $md_values[] = 'test_metadata_value_' . rand(); + + $e = new ElggObject(); + $e->subtype = $subtype; + $e->$md_name = $md_value; + $e->save(); + $e_guids[] = $e->getGUID(); + + $options = array( + 'type' => 'object', + 'subtype' => $subtype, + 'metadata_values' => $md_values + ); + + $entities = elgg_get_entities_from_metadata($options); + + $this->assertIsa($entities, 'array'); + $this->assertEqual(count($entities), 1); + + foreach ($entities as $entity) { + $this->assertEqual($entity->getGUID(), $valid->getGUID()); + } + + foreach ($e_guids as $guid) { + if ($e = get_entity($guid)) { + $e->delete(); + } + } + } + + + // name_value_pairs + + + function testElggApiGettersEntityMetadataNVPValidNValidVEquals() { + $subtypes = $this->getRandomValidSubtypes(array('object'), 1); + $subtype = $subtypes[0]; + $md_name = 'test_metadata_name_' . rand(); + $md_value = 'test_metadata_value_' . rand(); + $guids = array(); + + // our target + $valid = new ElggObject(); + $valid->subtype = $subtype; + $valid->$md_name = $md_value; + $valid->save(); + $guids[] = $valid->getGUID(); + + // make some bad ones + $invalid_md_name = 'test_metadata_name_' . rand(); + $e = new ElggObject(); + $e->subtype = $subtype; + $e->$md_name = $invalid_md_value; + $e->save(); + $guids[] = $e->getGUID(); + + $invalid_md_value = 'test_metadata_value_' . rand(); + $e = new ElggObject(); + $e->subtype = $subtype; + $e->$md_name = $invalid_md_value; + $e->save(); + $guids[] = $e->getGUID(); + + $md_invalid_names = array(); + + $options = array( + 'type' => 'object', + 'subtype' => $subtype, + 'metadata_name_value_pairs' => array(array( + 'name' => $md_name, + 'value' => $md_value + )) + ); + + $entities = elgg_get_entities_from_metadata($options); + + $this->assertIsa($entities, 'array'); + $this->assertEqual(count($entities), 1); + + foreach ($entities as $entity) { + $this->assertEqual($entity->getGUID(), $valid->getGUID()); + $this->assertEqual($entity->$md_name, $md_value); + $entity->delete(); + } + + foreach ($guids as $guid) { + if ($e = get_entity($guid)) { + $e->delete(); + } + } + } + + function testElggApiGettersEntityMetadataNVPValidNInvalidV() { + $subtypes = $this->getRandomValidSubtypes(array('object'), 1); + $subtype = $subtypes[0]; + $md_name = 'test_metadata_name_' . rand(); + $md_value = 'test_metadata_value_' . rand(); + $guids = array(); + + // make some bad ones + $invalid_md_name = 'test_metadata_name_' . rand(); + $e = new ElggObject(); + $e->subtype = $subtype; + $e->$md_name = $invalid_md_value; + $e->save(); + $guids[] = $e->getGUID(); + + $invalid_md_value = 'test_metadata_value_' . rand(); + $e = new ElggObject(); + $e->subtype = $subtype; + $e->$md_name = $invalid_md_value; + $e->save(); + $guids[] = $e->getGUID(); + + $md_invalid_names = array(); + + $options = array( + 'type' => 'object', + 'subtype' => $subtype, + 'metadata_name_value_pairs' => array(array( + 'name' => $md_name, + 'value' => 'test_metadata_value_' . rand() + )) + ); + + $entities = elgg_get_entities_from_metadata($options); + + $this->assertFalse($entities); + + foreach ($guids as $guid) { + if ($e = get_entity($guid)) { + $e->delete(); + } + } + } + + + function testElggApiGettersEntityMetadataNVPInvalidNValidV() { + $subtypes = $this->getRandomValidSubtypes(array('object'), 1); + $subtype = $subtypes[0]; + $md_name = 'test_metadata_name_' . rand(); + $md_value = 'test_metadata_value_' . rand(); + $guids = array(); + + // make some bad ones + $invalid_md_name = 'test_metadata_name_' . rand(); + $e = new ElggObject(); + $e->subtype = $subtype; + $e->$md_name = $invalid_md_value; + $e->save(); + $guids[] = $e->getGUID(); + + $invalid_md_value = 'test_metadata_value_' . rand(); + $e = new ElggObject(); + $e->subtype = $subtype; + $e->$md_name = $invalid_md_value; + $e->save(); + $guids[] = $e->getGUID(); + + $md_invalid_names = array(); + + $options = array( + 'type' => 'object', + 'subtype' => $subtype, + 'metadata_name_value_pairs' => array(array( + 'name' => 'test_metadata_name_' . rand(), + 'value' => $md_value + )) + ); + + $entities = elgg_get_entities_from_metadata($options); + + $this->assertFalse($entities); + + foreach ($guids as $guid) { + if ($e = get_entity($guid)) { + $e->delete(); + } + } + } + + + function testElggApiGettersEntityMetadataNVPValidNValidVOperandIn() { + $subtypes = $this->getRandomValidSubtypes(array('object'), 1); + $subtype = $subtypes[0]; + $md_name = 'test_metadata_name_' . rand(); + $md_value = 'test_metadata_value_' . rand(); + $guids = array(); + $valid_guids = array(); + + // our targets + $valid = new ElggObject(); + $valid->subtype = $subtype; + $valid->$md_name = $md_value; + $valid->save(); + $guids[] = $valid->getGUID(); + $valid_guids[] = $valid->getGUID(); + + $md_name2 = 'test_metadata_name_' . rand(); + $md_value2 = 'test_metadata_value_' . rand(); + + $valid2 = new ElggObject(); + $valid2->subtype = $subtype; + $valid2->$md_name2 = $md_value2; + $valid2->save(); + $guids[] = $valid->getGUID(); + $valid_guids[] = $valid2->getGUID(); + + // make some bad ones + $invalid_md_name = 'test_metadata_name_' . rand(); + $e = new ElggObject(); + $e->subtype = $subtype; + $e->$md_name = $invalid_md_value; + $e->save(); + $guids[] = $e->getGUID(); + + $invalid_md_value = 'test_metadata_value_' . rand(); + $e = new ElggObject(); + $e->subtype = $subtype; + $e->$md_name = $invalid_md_value; + $e->save(); + $guids[] = $e->getGUID(); + + $md_valid_values = "'$md_value', '$md_value2'"; + + $options = array( + 'type' => 'object', + 'subtype' => $subtype, + 'metadata_name_value_pairs' => array( + array( + 'name' => $md_name, + 'value' => $md_valid_values, + 'operand' => 'IN' + ), + array( + 'name' => $md_name2, + 'value' => $md_valid_values, + 'operand' => 'IN' + ), + ), + 'metadata_name_value_pairs_operator' => 'OR' + ); + + $entities = elgg_get_entities_from_metadata($options); + + $this->assertIsa($entities, 'array'); + $this->assertEqual(count($entities), 2); + + foreach ($entities as $entity) { + $this->assertTrue(in_array($entity->getGUID(), $valid_guids)); + $entity->delete(); + } + + foreach ($guids as $guid) { + if ($e = get_entity($guid)) { + $e->delete(); + } + } + } + + function testElggApiGettersEntityMetadataNVPValidNValidVPlural() { + $subtypes = $this->getRandomValidSubtypes(array('object'), 1); + $subtype = $subtypes[0]; + $md_name = 'test_metadata_name_' . rand(); + $md_value = 'test_metadata_value_' . rand(); + $guids = array(); + $valid_guids = array(); + + // our targets + $valid = new ElggObject(); + $valid->subtype = $subtype; + $valid->$md_name = $md_value; + $valid->save(); + $guids[] = $valid->getGUID(); + $valid_guids[] = $valid->getGUID(); + + $md_name2 = 'test_metadata_name_' . rand(); + $md_value2 = 'test_metadata_value_' . rand(); + + $valid2 = new ElggObject(); + $valid2->subtype = $subtype; + $valid2->$md_name2 = $md_value2; + $valid2->save(); + $guids[] = $valid->getGUID(); + $valid_guids[] = $valid2->getGUID(); + + // make some bad ones + $invalid_md_name = 'test_metadata_name_' . rand(); + $e = new ElggObject(); + $e->subtype = $subtype; + $e->$md_name = $invalid_md_value; + $e->save(); + $guids[] = $e->getGUID(); + + $invalid_md_value = 'test_metadata_value_' . rand(); + $e = new ElggObject(); + $e->subtype = $subtype; + $e->$md_name = $invalid_md_value; + $e->save(); + $guids[] = $e->getGUID(); + + $md_valid_values = array($md_value, $md_value2); + + $options = array( + 'type' => 'object', + 'subtype' => $subtype, + 'metadata_name_value_pairs' => array( + array( + 'name' => $md_name, + 'value' => $md_valid_values, + 'operand' => 'IN' + ), + array( + 'name' => $md_name2, + 'value' => $md_valid_values, + 'operand' => 'IN' + ), + ), + 'metadata_name_value_pairs_operator' => 'OR' + ); + + $entities = elgg_get_entities_from_metadata($options); + + $this->assertIsa($entities, 'array'); + $this->assertEqual(count($entities), 2); + + foreach ($entities as $entity) { + $this->assertTrue(in_array($entity->getGUID(), $valid_guids)); + $entity->delete(); + } + + foreach ($guids as $guid) { + if ($e = get_entity($guid)) { + $e->delete(); + } + } + } } |