Elgg /
Elgg
| 1 | <?php |
||
| 2 | |||
| 3 | namespace Elgg\Likes; |
||
| 4 | |||
| 5 | /** |
||
| 6 | * Likes preloader |
||
| 7 | */ |
||
| 8 | class Preloader { |
||
| 9 | |||
| 10 | /** |
||
| 11 | * @var \Elgg\Likes\DataService |
||
| 12 | */ |
||
| 13 | protected $data; |
||
| 14 | |||
| 15 | /** |
||
| 16 | * Create a preloader |
||
| 17 | * |
||
| 18 | * @param \Elgg\Likes\DataService $data a dataservice |
||
| 19 | */ |
||
| 20 | public function __construct(DataService $data) { |
||
| 21 | $this->data = $data; |
||
| 22 | } |
||
| 23 | |||
| 24 | /** |
||
| 25 | * Preload likes for a set of items |
||
| 26 | * |
||
| 27 | * @param \ElggRiverItem[]|\ElggEntity[] $items the items to preload for |
||
| 28 | * |
||
| 29 | * @return void |
||
| 30 | */ |
||
| 31 | public function preloadForList(array $items) { |
||
| 32 | $guids = $this->getGuidsToPreload($items); |
||
| 33 | if (count($guids) < 2) { |
||
| 34 | return; |
||
| 35 | } |
||
| 36 | |||
| 37 | $this->preloadCurrentUserLikes($guids); |
||
| 38 | |||
| 39 | $guids_remaining = $this->preloadCountsFromHook($this->getEntities($guids)); |
||
| 40 | if ($guids_remaining) { |
||
|
0 ignored issues
–
show
|
|||
| 41 | $this->preloadCountsFromQuery($guids_remaining); |
||
| 42 | } |
||
| 43 | } |
||
| 44 | |||
| 45 | /** |
||
| 46 | * Preload likes count based on guids |
||
| 47 | * |
||
| 48 | * @param int[] $guids the guids to preload |
||
| 49 | * |
||
| 50 | * @return void |
||
| 51 | */ |
||
| 52 | protected function preloadCountsFromQuery(array $guids) { |
||
| 53 | $count_rows = elgg_get_annotations([ |
||
| 54 | 'annotation_names' => 'likes', |
||
| 55 | 'guids' => $guids, |
||
| 56 | 'selects' => ['e.guid', 'COUNT(*) AS cnt'], |
||
| 57 | 'group_by' => 'e.guid', |
||
| 58 | 'limit' => false, |
||
| 59 | 'callback' => false, |
||
| 60 | ]); |
||
| 61 | foreach ($guids as $guid) { |
||
| 62 | $this->data->setNumLikes($guid, 0); |
||
| 63 | } |
||
| 64 | foreach ($count_rows as $row) { |
||
| 65 | $this->data->setNumLikes($row->guid, $row->cnt); |
||
| 66 | } |
||
| 67 | } |
||
| 68 | |||
| 69 | /** |
||
| 70 | * Preload based of entities |
||
| 71 | * |
||
| 72 | * @param \ElggEntity[] $entities given entities |
||
| 73 | * |
||
| 74 | * @return int[] |
||
| 75 | */ |
||
| 76 | protected function preloadCountsFromHook(array $entities) { |
||
| 77 | $guids_not_loaded = []; |
||
| 78 | |||
| 79 | foreach ($entities as $entity) { |
||
| 80 | // BC with likes_count(). If this hook is used this preloader may not be of much help. |
||
| 81 | $type = $entity->getType(); |
||
| 82 | $params = ['entity' => $entity]; |
||
| 83 | |||
| 84 | $num_likes = elgg_trigger_plugin_hook('likes:count', $type, $params, false); |
||
| 85 | if ($num_likes) { |
||
| 86 | $this->data->setNumLikes($entity->guid, $num_likes); |
||
| 87 | } else { |
||
| 88 | $guids_not_loaded[] = $entity->guid; |
||
| 89 | } |
||
| 90 | } |
||
| 91 | |||
| 92 | return $guids_not_loaded; |
||
| 93 | } |
||
| 94 | |||
| 95 | /** |
||
| 96 | * Preload likes for given guids for current user |
||
| 97 | * |
||
| 98 | * @param int[] $guids preload guids |
||
| 99 | * |
||
| 100 | * @return void |
||
| 101 | */ |
||
| 102 | protected function preloadCurrentUserLikes(array $guids) { |
||
| 103 | $owner_guid = elgg_get_logged_in_user_guid(); |
||
| 104 | if (!$owner_guid) { |
||
| 105 | return; |
||
| 106 | } |
||
| 107 | |||
| 108 | $annotation_rows = elgg_get_annotations([ |
||
| 109 | 'annotation_names' => 'likes', |
||
| 110 | 'annotation_owner_guids' => $owner_guid, |
||
| 111 | 'guids' => $guids, |
||
| 112 | 'limit' => false, |
||
| 113 | 'callback' => false, |
||
| 114 | ]); |
||
| 115 | |||
| 116 | foreach ($guids as $guid) { |
||
| 117 | $this->data->setLikedByCurrentUser($guid, false); |
||
| 118 | } |
||
| 119 | foreach ($annotation_rows as $row) { |
||
| 120 | $this->data->setLikedByCurrentUser($row->entity_guid, true); |
||
| 121 | } |
||
| 122 | } |
||
| 123 | |||
| 124 | /** |
||
| 125 | * Convert river items and/or entities to guids |
||
| 126 | * |
||
| 127 | * @param \ElggRiverItem[]|\ElggEntity[] $items the items to process |
||
| 128 | * |
||
| 129 | * @return int[] |
||
| 130 | */ |
||
| 131 | protected function getGuidsToPreload(array $items) { |
||
| 132 | $guids = []; |
||
| 133 | |||
| 134 | foreach ($items as $item) { |
||
| 135 | if ($item instanceof \ElggRiverItem) { |
||
| 136 | // only like group creation #3958 |
||
| 137 | if ($item->type == "group" && $item->view != "river/group/create") { |
||
| 138 | continue; |
||
| 139 | } |
||
| 140 | |||
| 141 | $type = $item->type; |
||
| 142 | $subtype = $item->subtype; |
||
| 143 | $likable = (bool) elgg_trigger_plugin_hook('likes:is_likable', "$type:$subtype", [], false); |
||
| 144 | if (!$likable) { |
||
| 145 | continue; |
||
| 146 | } |
||
| 147 | |||
| 148 | if ($item->annotation_id != 0) { |
||
| 149 | continue; |
||
| 150 | } |
||
| 151 | |||
| 152 | if ($item->object_guid) { |
||
| 153 | $guids[$item->object_guid] = true; |
||
| 154 | } |
||
| 155 | } elseif ($item instanceof \ElggEntity) { |
||
| 156 | $type = $item->type; |
||
| 157 | $subtype = $item->getSubtype(); |
||
| 158 | $likable = (bool) elgg_trigger_plugin_hook('likes:is_likable', "$type:$subtype", [], false); |
||
| 159 | if ($likable) { |
||
| 160 | $guids[$item->guid] = true; |
||
| 161 | } |
||
| 162 | } |
||
| 163 | } |
||
| 164 | return array_keys($guids); |
||
| 165 | } |
||
| 166 | |||
| 167 | /** |
||
| 168 | * Get entities in any order checking cache first |
||
| 169 | * |
||
| 170 | * @param int[] $guids guids of entities to return |
||
| 171 | * |
||
| 172 | * @return \ElggEntity[] |
||
| 173 | */ |
||
| 174 | protected function getEntities(array $guids) { |
||
| 175 | // most objects are already preloaded |
||
| 176 | $entities = []; |
||
| 177 | $fetch_guids = []; |
||
| 178 | |||
| 179 | foreach ($guids as $guid) { |
||
| 180 | $entity = _elgg_services()->entityTable->getFromCache($guid); |
||
| 181 | if ($entity) { |
||
| 182 | $entities[] = $entity; |
||
| 183 | } else { |
||
| 184 | $fetch_guids[] = $guid; |
||
| 185 | } |
||
| 186 | } |
||
| 187 | if ($fetch_guids) { |
||
| 188 | $fetched = elgg_get_entities([ |
||
| 189 | 'guids' => $fetch_guids, |
||
| 190 | 'limit' => false, |
||
| 191 | ]); |
||
| 192 | array_splice($entities, count($entities), 0, $fetched); |
||
| 193 | } |
||
| 194 | return $entities; |
||
| 195 | } |
||
| 196 | } |
||
| 197 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)or! empty(...)instead.