| 1 | <?php |
| 2 | |
| 3 | /* |
| 4 | +--------------------------------------------------------------------+ |
| 5 | | Copyright CiviCRM LLC. All rights reserved. | |
| 6 | | | |
| 7 | | This work is published under the GNU AGPLv3 license with some | |
| 8 | | permitted exceptions and without any warranty. For full license | |
| 9 | | and copyright information, see https://civicrm.org/licensing | |
| 10 | +--------------------------------------------------------------------+ |
| 11 | */ |
| 12 | |
| 13 | /** |
| 14 | * |
| 15 | * @package CRM |
| 16 | * @copyright CiviCRM LLC https://civicrm.org/licensing |
| 17 | * $Id$ |
| 18 | * |
| 19 | */ |
| 20 | |
| 21 | |
| 22 | namespace api\v4\Action; |
| 23 | |
| 24 | use api\v4\UnitTestCase; |
| 25 | use Civi\Api4\MockBasicEntity; |
| 26 | |
| 27 | /** |
| 28 | * @group headless |
| 29 | */ |
| 30 | class BasicActionsTest extends UnitTestCase { |
| 31 | |
| 32 | public function testCrud() { |
| 33 | MockBasicEntity::delete()->addWhere('id', '>', 0)->execute(); |
| 34 | |
| 35 | $id1 = MockBasicEntity::create()->addValue('foo', 'one')->execute()->first()['id']; |
| 36 | |
| 37 | $result = MockBasicEntity::get()->execute(); |
| 38 | $this->assertCount(1, $result); |
| 39 | |
| 40 | $id2 = MockBasicEntity::create()->addValue('foo', 'two')->execute()->first()['id']; |
| 41 | |
| 42 | $result = MockBasicEntity::get()->selectRowCount()->execute(); |
| 43 | $this->assertEquals(2, $result->count()); |
| 44 | |
| 45 | MockBasicEntity::update()->addWhere('id', '=', $id2)->addValue('foo', 'new')->execute(); |
| 46 | |
| 47 | $result = MockBasicEntity::get()->addOrderBy('id', 'DESC')->setLimit(1)->execute(); |
| 48 | $this->assertCount(1, $result); |
| 49 | $this->assertEquals('new', $result->first()['foo']); |
| 50 | |
| 51 | $result = MockBasicEntity::save() |
| 52 | ->addRecord(['id' => $id1, 'foo' => 'one updated', 'weight' => '5']) |
| 53 | ->addRecord(['id' => $id2, 'group:label' => 'Second']) |
| 54 | ->addRecord(['foo' => 'three']) |
| 55 | ->addDefault('color', 'pink') |
| 56 | ->setReload(TRUE) |
| 57 | ->execute() |
| 58 | ->indexBy('id'); |
| 59 | |
| 60 | $this->assertTrue(5 === $result[$id1]['weight']); |
| 61 | $this->assertEquals('new', $result[$id2]['foo']); |
| 62 | $this->assertEquals('two', $result[$id2]['group']); |
| 63 | $this->assertEquals('three', $result->last()['foo']); |
| 64 | $this->assertCount(3, $result); |
| 65 | foreach ($result as $item) { |
| 66 | $this->assertEquals('pink', $item['color']); |
| 67 | } |
| 68 | |
| 69 | $ent1 = MockBasicEntity::get()->addWhere('id', '=', $id1)->execute()->first(); |
| 70 | $this->assertEquals('one updated', $ent1['foo']); |
| 71 | $this->assertFalse(isset($ent1['group:label'])); |
| 72 | |
| 73 | $ent2 = MockBasicEntity::get()->addWhere('group:label', '=', 'Second')->addSelect('group:label', 'group')->execute()->first(); |
| 74 | $this->assertEquals('two', $ent2['group']); |
| 75 | $this->assertEquals('Second', $ent2['group:label']); |
| 76 | // We didn't select this |
| 77 | $this->assertFalse(isset($ent2['group:name'])); |
| 78 | |
| 79 | // With no SELECT, all fields should be returned but not suffixy stuff like group:name |
| 80 | $ent2 = MockBasicEntity::get()->addWhere('group:label', '=', 'Second')->execute()->first(); |
| 81 | $this->assertEquals('two', $ent2['group']); |
| 82 | $this->assertFalse(isset($ent2['group:name'])); |
| 83 | // This one wasn't selected but did get used by the WHERE clause; ensure it isn't returned |
| 84 | $this->assertFalse(isset($ent2['group:label'])); |
| 85 | |
| 86 | MockBasicEntity::delete()->addWhere('id', '=', $id2); |
| 87 | $result = MockBasicEntity::get()->execute(); |
| 88 | $this->assertEquals('one updated', $result->first()['foo']); |
| 89 | } |
| 90 | |
| 91 | public function testReplace() { |
| 92 | MockBasicEntity::delete()->addWhere('id', '>', 0)->execute(); |
| 93 | |
| 94 | $objects = [ |
| 95 | ['group' => 'one', 'color' => 'red'], |
| 96 | ['group' => 'one', 'color' => 'blue'], |
| 97 | ['group' => 'one', 'color' => 'green'], |
| 98 | ['group' => 'two', 'color' => 'orange'], |
| 99 | ]; |
| 100 | |
| 101 | foreach ($objects as &$object) { |
| 102 | $object['id'] = MockBasicEntity::create()->setValues($object)->execute()->first()['id']; |
| 103 | } |
| 104 | |
| 105 | // Keep red, change blue, delete green, and add yellow |
| 106 | $replacements = [ |
| 107 | ['color' => 'red', 'id' => $objects[0]['id']], |
| 108 | ['color' => 'not blue', 'id' => $objects[1]['id']], |
| 109 | ['color' => 'yellow'], |
| 110 | ]; |
| 111 | |
| 112 | MockBasicEntity::replace()->addWhere('group', '=', 'one')->setRecords($replacements)->execute(); |
| 113 | |
| 114 | $newObjects = MockBasicEntity::get()->addOrderBy('id', 'DESC')->execute()->indexBy('id'); |
| 115 | |
| 116 | $this->assertCount(4, $newObjects); |
| 117 | |
| 118 | $this->assertEquals('yellow', $newObjects->first()['color']); |
| 119 | |
| 120 | $this->assertEquals('not blue', $newObjects[$objects[1]['id']]['color']); |
| 121 | |
| 122 | // Ensure group two hasn't been altered |
| 123 | $this->assertEquals('orange', $newObjects[$objects[3]['id']]['color']); |
| 124 | $this->assertEquals('two', $newObjects[$objects[3]['id']]['group']); |
| 125 | } |
| 126 | |
| 127 | public function testBatchFrobnicate() { |
| 128 | MockBasicEntity::delete()->addWhere('id', '>', 0)->execute(); |
| 129 | |
| 130 | $objects = [ |
| 131 | ['group' => 'one', 'color' => 'red', 'number' => 10], |
| 132 | ['group' => 'one', 'color' => 'blue', 'number' => 20], |
| 133 | ['group' => 'one', 'color' => 'green', 'number' => 30], |
| 134 | ['group' => 'two', 'color' => 'blue', 'number' => 40], |
| 135 | ]; |
| 136 | foreach ($objects as &$object) { |
| 137 | $object['id'] = MockBasicEntity::create()->setValues($object)->execute()->first()['id']; |
| 138 | } |
| 139 | |
| 140 | $result = MockBasicEntity::batchFrobnicate()->addWhere('color', '=', 'blue')->execute(); |
| 141 | $this->assertEquals(2, count($result)); |
| 142 | $this->assertEquals([400, 1600], \CRM_Utils_Array::collect('frobnication', (array) $result)); |
| 143 | } |
| 144 | |
| 145 | public function testGetFields() { |
| 146 | $getFields = MockBasicEntity::getFields()->execute()->indexBy('name'); |
| 147 | |
| 148 | $this->assertCount(6, $getFields); |
| 149 | $this->assertEquals('Id', $getFields['id']['title']); |
| 150 | // Ensure default data type is "String" when not specified |
| 151 | $this->assertEquals('String', $getFields['color']['data_type']); |
| 152 | |
| 153 | // Getfields should default to loadOptions = false and reduce them to bool |
| 154 | $this->assertTrue($getFields['group']['options']); |
| 155 | $this->assertFalse($getFields['id']['options']); |
| 156 | |
| 157 | // Now load options |
| 158 | $getFields = MockBasicEntity::getFields() |
| 159 | ->addWhere('name', '=', 'group') |
| 160 | ->setLoadOptions(TRUE) |
| 161 | ->execute()->indexBy('name'); |
| 162 | |
| 163 | $this->assertCount(1, $getFields); |
| 164 | $this->assertArrayHasKey('one', $getFields['group']['options']); |
| 165 | } |
| 166 | |
| 167 | public function testItemsToGet() { |
| 168 | $get = MockBasicEntity::get() |
| 169 | ->addWhere('color', 'NOT IN', ['yellow']) |
| 170 | ->addWhere('color', 'IN', ['red', 'blue']) |
| 171 | ->addWhere('color', '!=', 'green') |
| 172 | ->addWhere('group', '=', 'one') |
| 173 | ->addWhere('size', 'LIKE', 'big') |
| 174 | ->addWhere('shape', 'LIKE', '%a'); |
| 175 | |
| 176 | $itemsToGet = new \ReflectionMethod($get, '_itemsToGet'); |
| 177 | $itemsToGet->setAccessible(TRUE); |
| 178 | |
| 179 | $this->assertEquals(['red', 'blue'], $itemsToGet->invoke($get, 'color')); |
| 180 | $this->assertEquals(['one'], $itemsToGet->invoke($get, 'group')); |
| 181 | $this->assertEquals(['big'], $itemsToGet->invoke($get, 'size')); |
| 182 | $this->assertEmpty($itemsToGet->invoke($get, 'shape')); |
| 183 | $this->assertEmpty($itemsToGet->invoke($get, 'weight')); |
| 184 | } |
| 185 | |
| 186 | public function testFieldsToGet() { |
| 187 | $get = MockBasicEntity::get() |
| 188 | ->addWhere('color', '!=', 'green'); |
| 189 | |
| 190 | $isFieldSelected = new \ReflectionMethod($get, '_isFieldSelected'); |
| 191 | $isFieldSelected->setAccessible(TRUE); |
| 192 | |
| 193 | // If no "select" is set, should always return true |
| 194 | $this->assertTrue($isFieldSelected->invoke($get, 'color')); |
| 195 | $this->assertTrue($isFieldSelected->invoke($get, 'shape')); |
| 196 | $this->assertTrue($isFieldSelected->invoke($get, 'size', 'color', 'shape')); |
| 197 | |
| 198 | // With a non-empty "select" fieldsToSelect() will return fields needed to evaluate each clause. |
| 199 | $get->addSelect('id'); |
| 200 | $this->assertTrue($isFieldSelected->invoke($get, 'color', 'shape', 'size')); |
| 201 | $this->assertTrue($isFieldSelected->invoke($get, 'id')); |
| 202 | $this->assertFalse($isFieldSelected->invoke($get, 'shape', 'size', 'weight')); |
| 203 | $this->assertFalse($isFieldSelected->invoke($get, 'group')); |
| 204 | |
| 205 | $get->addClause('OR', ['shape', '=', 'round'], ['AND', [['size', '=', 'big'], ['weight', '!=', 'small']]]); |
| 206 | $this->assertTrue($isFieldSelected->invoke($get, 'color')); |
| 207 | $this->assertTrue($isFieldSelected->invoke($get, 'id')); |
| 208 | $this->assertTrue($isFieldSelected->invoke($get, 'shape')); |
| 209 | $this->assertTrue($isFieldSelected->invoke($get, 'size')); |
| 210 | $this->assertTrue($isFieldSelected->invoke($get, 'group', 'weight')); |
| 211 | $this->assertFalse($isFieldSelected->invoke($get, 'group')); |
| 212 | |
| 213 | $get->addOrderBy('group'); |
| 214 | $this->assertTrue($isFieldSelected->invoke($get, 'group')); |
| 215 | } |
| 216 | |
| 217 | public function testWildcardSelect() { |
| 218 | MockBasicEntity::delete()->addWhere('id', '>', 0)->execute(); |
| 219 | |
| 220 | $records = [ |
| 221 | ['group' => 'one', 'color' => 'red', 'shape' => 'round', 'size' => 'med', 'weight' => 10], |
| 222 | ['group' => 'two', 'color' => 'blue', 'shape' => 'round', 'size' => 'med', 'weight' => 20], |
| 223 | ]; |
| 224 | MockBasicEntity::save()->setRecords($records)->execute(); |
| 225 | |
| 226 | foreach (MockBasicEntity::get()->addSelect('*')->execute() as $result) { |
| 227 | ksort($result); |
| 228 | $this->assertEquals(['color', 'group', 'id', 'shape', 'size', 'weight'], array_keys($result)); |
| 229 | } |
| 230 | |
| 231 | $result = MockBasicEntity::get() |
| 232 | ->addSelect('*e', 'weig*ht') |
| 233 | ->execute() |
| 234 | ->first(); |
| 235 | $this->assertEquals(['shape', 'size', 'weight'], array_keys($result)); |
| 236 | } |
| 237 | |
| 238 | } |