ElggCoreGetEntitiesFromAnnotationsTest.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. <?php
  2. /**
  3. * Test elgg_get_entities_from_annotations() and
  4. * elgg_get_entities_from_annotation_calculation()
  5. */
  6. class ElggCoreGetEntitiesFromAnnotationsTest extends \ElggCoreGetEntitiesBaseTest {
  7. /**
  8. * Creates random annotations on $entity
  9. *
  10. * @param \ElggEntity $entity
  11. * @param int $max
  12. */
  13. protected function createRandomAnnotations($entity, $max = 1) {
  14. $annotations = array();
  15. for ($i=0; $i<$max; $i++) {
  16. $name = 'test_annotation_name_' . rand();
  17. $value = rand();
  18. $id = create_annotation($entity->getGUID(), $name, $value, 'integer', $entity->getGUID());
  19. $annotations[] = elgg_get_annotation_from_id($id);
  20. }
  21. return $annotations;
  22. }
  23. public function testElggApiGettersEntitiesFromAnnotation() {
  24. // grab a few different users to annotation
  25. // there will always be at least 2 here because of the construct.
  26. $users = elgg_get_entities(array('type' => 'user', 'limit' => 2));
  27. // create some test annotations
  28. $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
  29. $subtype = $subtypes[0];
  30. $annotation_name = 'test_annotation_name_' . rand();
  31. $annotation_value = rand(1000, 9999);
  32. $annotation_name2 = 'test_annotation_name_' . rand();
  33. $annotation_value2 = rand(1000, 9999);
  34. $guids = array();
  35. // our targets
  36. $valid = new \ElggObject();
  37. $valid->subtype = $subtype;
  38. $valid->save();
  39. $guids[] = $valid->getGUID();
  40. create_annotation($valid->getGUID(), $annotation_name, $annotation_value, 'integer', $users[0]->getGUID());
  41. $valid2 = new \ElggObject();
  42. $valid2->subtype = $subtype;
  43. $valid2->save();
  44. $guids[] = $valid2->getGUID();
  45. create_annotation($valid2->getGUID(), $annotation_name2, $annotation_value2, 'integer', $users[1]->getGUID());
  46. $options = array(
  47. 'annotation_owner_guid' => $users[0]->getGUID(),
  48. 'annotation_name' => $annotation_name
  49. );
  50. $entities = elgg_get_entities_from_annotations($options);
  51. foreach ($entities as $entity) {
  52. $this->assertTrue(in_array($entity->getGUID(), $guids));
  53. $annotations = $entity->getAnnotations(array('annotation_name' => $annotation_name));
  54. $this->assertEqual(count($annotations), 1);
  55. $this->assertEqual($annotations[0]->name, $annotation_name);
  56. $this->assertEqual($annotations[0]->value, $annotation_value);
  57. $this->assertEqual($annotations[0]->owner_guid, $users[0]->getGUID());
  58. }
  59. foreach ($guids as $guid) {
  60. if ($e = get_entity($guid)) {
  61. $e->delete();
  62. }
  63. }
  64. }
  65. /**
  66. * This function tests the deprecated behaviour of egef_annotations
  67. * discussed in https://github.com/Elgg/Elgg/issues/6638
  68. */
  69. public function testElggApiGettersEntitiesFromAnnotationOrderByMaxtime() {
  70. // grab a few different users to annotation
  71. // there will always be at least 2 here because of the construct.
  72. $users = elgg_get_entities(array('type' => 'user', 'limit' => 2));
  73. // create some test annotations
  74. $subtypes = $this->getRandomValidSubtypes(array('object'), 1);
  75. $subtype = $subtypes[0];
  76. $annotation_name = 'test_annotation_name_' . rand();
  77. $annotation_value = rand(1000, 9999);
  78. $annotation_name2 = 'test_annotation_name_' . rand();
  79. $annotation_value2 = rand(1000, 9999);
  80. $guids = array();
  81. // our targets
  82. $valid = new \ElggObject();
  83. $valid->subtype = $subtype;
  84. $valid->save();
  85. $guids[] = $valid->getGUID();
  86. create_annotation($valid->getGUID(), $annotation_name, $annotation_value, 'integer', $users[0]->getGUID());
  87. $valid2 = new \ElggObject();
  88. $valid2->subtype = $subtype;
  89. $valid2->save();
  90. $guids[] = $valid2->getGUID();
  91. create_annotation($valid2->getGUID(), $annotation_name2, $annotation_value2, 'integer', $users[1]->getGUID());
  92. $options = array(
  93. 'annotation_owner_guid' => $users[0]->getGUID(),
  94. 'annotation_name' => $annotation_name,
  95. 'selects' => array('MAX(n_table.time_created) AS maxtime'),
  96. 'group_by' => 'n_table.entity_guid',
  97. 'order_by' => 'maxtime'
  98. );
  99. $entities = elgg_get_entities_from_annotations($options);
  100. foreach ($entities as $entity) {
  101. $this->assertTrue(in_array($entity->getGUID(), $guids));
  102. $annotations = $entity->getAnnotations(array('annotation_name' => $annotation_name));
  103. $this->assertEqual(count($annotations), 1);
  104. $this->assertEqual($annotations[0]->name, $annotation_name);
  105. $this->assertEqual($annotations[0]->value, $annotation_value);
  106. $this->assertEqual($annotations[0]->owner_guid, $users[0]->getGUID());
  107. }
  108. foreach ($guids as $guid) {
  109. if ($e = get_entity($guid)) {
  110. $e->delete();
  111. }
  112. }
  113. }
  114. /**
  115. * Get entities ordered by various MySQL calculations on their annotations
  116. *
  117. * @covers elgg_get_entities_from_annotation_calculation()
  118. */
  119. public function testElggGetEntitiesFromAnnotationsCalculateX() {
  120. $types = array('sum', 'avg', 'min', 'max');
  121. $num_entities = 5;
  122. // these are chosen to avoid the sums, means, mins, maxs being the same
  123. // note that the calculation is cast to an int in SQL
  124. $numbers = array(
  125. array(0, 5),
  126. array(2, 13),
  127. array(-3, 11),
  128. array(7, 9),
  129. array(1.2, 22),
  130. );
  131. foreach ($types as $type) {
  132. $subtypes = $this->getRandomValidSubtypes(array('object'), $num_entities);
  133. $name = "test_annotation_tegefacx_$type";
  134. $values = array();
  135. $options = array(
  136. 'type' => 'object',
  137. 'subtypes' => $subtypes,
  138. 'limit' => $num_entities,
  139. );
  140. $es = elgg_get_entities($options);
  141. foreach ($es as $index => $e) {
  142. $value = $numbers[$index][0];
  143. $e->annotate($name, $value);
  144. $value2 = $numbers[$index][1];
  145. $e->annotate($name, $value2);
  146. switch ($type) {
  147. case 'sum':
  148. $calc_value = $value + $value2;
  149. break;
  150. case 'avg':
  151. $calc_value = ($value + $value2) / 2;
  152. break;
  153. case 'min':
  154. $calc_value = min(array($value, $value2));
  155. break;
  156. case 'max':
  157. $calc_value = max(array($value, $value2));
  158. break;
  159. }
  160. $values[$e->guid] = $calc_value;
  161. }
  162. arsort($values);
  163. $order = array_keys($values);
  164. $options = array(
  165. 'type' => 'object',
  166. 'subtypes' => $subtypes,
  167. 'limit' => $num_entities,
  168. 'annotation_name' => $name,
  169. 'calculation' => $type
  170. );
  171. $es = elgg_get_entities_from_annotation_calculation($options);
  172. foreach ($es as $i => $e) {
  173. $value = 0;
  174. $as = $e->getAnnotations(array('annotation_name' => $name));
  175. // should only ever be 2
  176. $this->assertEqual(2, count($as));
  177. $value = $as[0]->value;
  178. $value2 = $as[1]->value;
  179. switch ($type) {
  180. case 'sum':
  181. $calc_value = $value + $value2;
  182. break;
  183. case 'avg':
  184. $calc_value = ($value + $value2) / 2;
  185. break;
  186. case 'min':
  187. $calc_value = min(array($value, $value2));
  188. break;
  189. case 'max':
  190. $calc_value = max(array($value, $value2));
  191. break;
  192. }
  193. $this->assertEqual($e->guid, $order[$i]);
  194. $this->assertEqual($values[$e->guid], $calc_value);
  195. }
  196. $options['count'] = true;
  197. $es_count = elgg_get_entities_from_annotation_calculation($options);
  198. $this->assertEqual($es_count, $num_entities);
  199. }
  200. }
  201. /**
  202. * Get entities ordered by various MySQL calculations on their annotations constrained by a where clause
  203. *
  204. * @covers elgg_get_entities_from_annotation_calculation()
  205. */
  206. public function testElggGetEntitiesFromAnnotationsCalculateConstrainedByWhere() {
  207. $num_entities = 3;
  208. $subtypes = $this->getRandomValidSubtypes(array('object'), $num_entities);
  209. $name = "test_annotation_tegefacxwhere_" . rand(0, 9999);
  210. $values = array(
  211. array(-3, 0, 5, 8, 'foo'),
  212. array(-8, -5, -2, 0, 1),
  213. array(-4, -2, -1, 'bar')
  214. );
  215. $assert_count = 2;
  216. $options = array(
  217. 'type' => 'object',
  218. 'subtypes' => $subtypes,
  219. 'limit' => $num_entities,
  220. );
  221. $entities = elgg_get_entities($options);
  222. foreach ($entities as $index => $entity) {
  223. foreach ($values[$index] as $value) {
  224. $entity->annotate($name, $value);
  225. }
  226. }
  227. $options = array(
  228. 'type' => 'object',
  229. 'subtypes' => $subtypes,
  230. 'limit' => $num_entities,
  231. 'annotation_name' => $name,
  232. 'annotation_values' => array_unique(call_user_func_array('array_merge', $values)),
  233. 'calculation' => 'sum',
  234. 'wheres' => array(
  235. "CAST(msv.string as SIGNED) > 0"
  236. )
  237. );
  238. $es = elgg_get_entities_from_annotation_calculation($options);
  239. foreach ($es as $i => $e) {
  240. $assertion_values = array();
  241. foreach ($values[$i] as $value) {
  242. if (is_numeric($value) && $value > 0) {
  243. $assertion_values[] = $value;
  244. }
  245. }
  246. $annotations = $e->getAnnotations(array(
  247. 'annotation_name' => $name,
  248. 'where' => array("CAST(v.string AS SIGNED) > 0")
  249. ));
  250. if (count($assertion_values)) {
  251. $this->assertIsA($annotations, 'array');
  252. $this->assertEqual(count($assertion_values), count($annotations));
  253. } else {
  254. $this->assertFalse($annotations);
  255. }
  256. $annotation_values = array();
  257. foreach ($annotations as $ann) {
  258. $annotation_values[] = $ann->value;
  259. }
  260. $this->assertEqual(array_sum($assertion_values), array_sum($annotation_values));
  261. }
  262. $options['count'] = true;
  263. $es_count = elgg_get_entities_from_annotation_calculation($options);
  264. $this->assertEqual($es_count, $assert_count);
  265. }
  266. /**
  267. * Get a count of entities using egefac()
  268. * Testing to make sure that the count includes each entity with multiple annotations of the same name only once
  269. * Irrespective of the calculation type passed
  270. *
  271. * @covers elgg_get_entities_from_annotation_calculation()
  272. */
  273. public function testElggGetEntitiesFromAnnotationCalculationCount() {
  274. // add two annotations with a unique name to a set of entities
  275. // then count the number of entities using egefac()
  276. $subtypes = $this->getRandomValidSubtypes(array('object'), 3);
  277. $name = 'test_annotation_' . rand(0, 9999);
  278. $options = array(
  279. 'type' => 'object',
  280. 'subtypes' => $subtypes,
  281. 'limit' => 3
  282. );
  283. $entities = elgg_get_entities($options);
  284. foreach ($entities as $entity) {
  285. $value = rand(0, 9999);
  286. $entity->annotate($name, $value);
  287. $value = rand(0, 9999);
  288. $entity->annotate($name, $value);
  289. }
  290. $options = array(
  291. 'type' => 'object',
  292. 'subtypes' => $subtypes,
  293. 'annotation_name' => $name,
  294. 'count' => true,
  295. );
  296. $calculations = array('sum', 'avg', 'min', 'max');
  297. foreach ($calculations as $calculation) {
  298. $options['calculation'] = $calculation;
  299. $count = elgg_get_entities_from_annotation_calculation($options);
  300. $this->assertIdentical(3, $count);
  301. }
  302. }
  303. /**
  304. * Get a count of entities annotated with the same value but different annotation names
  305. * Irrespective of the calculation
  306. *
  307. * @covers elgg_get_entities_from_annotation_calculation()
  308. */
  309. public function testElggGetEntitiesFromAnnotationCalculationCountFromAnnotationValues() {
  310. $subtypes = $this->getRandomValidSubtypes(array('object'), 3);
  311. $value = rand(0, 9999);
  312. $options = array(
  313. 'type' => 'object',
  314. 'subtypes' => $subtypes,
  315. 'limit' => 3
  316. );
  317. $es = elgg_get_entities($options);
  318. foreach ($es as $e) {
  319. $name = 'test_annotation_egefacval_' . rand(0, 9999);
  320. $e->annotate($name, $value);
  321. }
  322. $options = array(
  323. 'type' => 'object',
  324. 'subtypes' => $subtypes,
  325. 'annotation_value' => $value,
  326. 'count' => true,
  327. );
  328. $calculations = array('sum', 'avg', 'min', 'max');
  329. foreach ($calculations as $calculation) {
  330. $options['calculation'] = $calculation;
  331. $count = elgg_get_entities_from_annotation_calculation($options);
  332. $this->assertIdentical(3, $count);
  333. }
  334. }
  335. /**
  336. * Get a count of entities annotated with the same name => value annotation pairs
  337. * Irrespective of the calculation
  338. *
  339. * @covers elgg_get_entities_from_annotation_calculation()
  340. */
  341. public function testElggGetEntitiesFromAnnotationCalculationCountFromAnnotationNameValuesPairs() {
  342. $subtypes = $this->getRandomValidSubtypes(array('object'), 3);
  343. $value = rand(0, 9999);
  344. $name = 'test_annotation_egefacnv';
  345. $options = array(
  346. 'type' => 'object',
  347. 'subtypes' => $subtypes,
  348. 'limit' => 3
  349. );
  350. $es = elgg_get_entities($options);
  351. foreach ($es as $e) {
  352. $e->annotate($name, $value);
  353. }
  354. $options = array(
  355. 'type' => 'object',
  356. 'subtypes' => $subtypes,
  357. 'annotation_name' => $name,
  358. 'annotation_value' => $value,
  359. 'count' => true,
  360. );
  361. $calculations = array('sum', 'avg', 'min', 'max');
  362. foreach ($calculations as $calculation) {
  363. $options['calculation'] = $calculation;
  364. $count = elgg_get_entities_from_annotation_calculation($options);
  365. $this->assertIdentical(3, $count);
  366. }
  367. }
  368. public function testElggGetAnnotationsAnnotationNames() {
  369. $options = array('annotation_names' => array());
  370. $a_e_map = array();
  371. // create test annotations on a few entities.
  372. for ($i=0; $i<3; $i++) {
  373. do {
  374. $e = $this->entities[array_rand($this->entities)];
  375. } while(in_array($e->guid, $a_e_map));
  376. $annotations = $this->createRandomAnnotations($e);
  377. foreach($annotations as $a) {
  378. $options['annotation_names'][] = $a->name;
  379. $a_e_map[$a->id] = $e->guid;
  380. }
  381. }
  382. $as = elgg_get_annotations($options);
  383. $this->assertEqual(count($a_e_map), count($as));
  384. foreach ($as as $a) {
  385. $this->assertEqual($a_e_map[$a->id], $a->entity_guid);
  386. }
  387. }
  388. public function testElggGetAnnotationsAnnotationValues() {
  389. $options = array('annotation_values' => array());
  390. $a_e_map = array();
  391. // create test annotations on a few entities.
  392. for ($i=0; $i<3; $i++) {
  393. do {
  394. $e = $this->entities[array_rand($this->entities)];
  395. } while(in_array($e->guid, $a_e_map));
  396. $annotations = $this->createRandomAnnotations($e);
  397. foreach($annotations as $a) {
  398. $options['annotation_values'][] = $a->value;
  399. $a_e_map[$a->id] = $e->guid;
  400. }
  401. }
  402. $as = elgg_get_annotations($options);
  403. $this->assertEqual(count($a_e_map), count($as));
  404. foreach ($as as $a) {
  405. $this->assertEqual($a_e_map[$a->id], $a->entity_guid);
  406. }
  407. }
  408. public function testElggGetAnnotationsAnnotationOwnerGuids() {
  409. $options = array('annotation_owner_guids' => array());
  410. $a_e_map = array();
  411. // create test annotations on a single entity
  412. for ($i=0; $i<3; $i++) {
  413. do {
  414. $e = $this->entities[array_rand($this->entities)];
  415. } while(in_array($e->guid, $a_e_map));
  416. // remove annotations left over from previous tests.
  417. elgg_delete_annotations(array('annotation_owner_guid' => $e->guid));
  418. $annotations = $this->createRandomAnnotations($e);
  419. foreach($annotations as $a) {
  420. $options['annotation_owner_guids'][] = $e->guid;
  421. $a_e_map[$a->id] = $e->guid;
  422. }
  423. }
  424. $as = elgg_get_annotations($options);
  425. $this->assertEqual(count($a_e_map), count($as));
  426. foreach ($as as $a) {
  427. $this->assertEqual($a_e_map[$a->id], $a->owner_guid);
  428. }
  429. }
  430. }