This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Zurbaev\Achievements; |
||
4 | |||
5 | use Zurbaev\Achievements\Contracts\AchievementsStorageInterface; |
||
6 | use Zurbaev\Achievements\Contracts\CriteriaHandler; |
||
7 | use Zurbaev\Achievements\Contracts\CriteriaHandlersManager as CriteriaHandlersManagerContract; |
||
8 | |||
9 | class AchievementsManager |
||
10 | { |
||
11 | /** |
||
12 | * @var AchievementsStorageInterface |
||
13 | */ |
||
14 | protected $storage; |
||
15 | |||
16 | /** |
||
17 | * Contains list of achievement IDs that |
||
18 | * should be checked for completeness |
||
19 | * in current criterias update. |
||
20 | * |
||
21 | * @var array |
||
22 | */ |
||
23 | protected $achievementsToCheck = []; |
||
24 | |||
25 | /** |
||
26 | * Criteria handlers manager. |
||
27 | * |
||
28 | * @var CriteriaHandlersManagerContract |
||
29 | */ |
||
30 | protected $handlers; |
||
31 | |||
32 | /** |
||
33 | * AchievementsManager constructor. |
||
34 | * |
||
35 | * @param AchievementsStorageInterface $storage |
||
36 | * @param CriteriaHandlersManagerContract $handlers |
||
37 | */ |
||
38 | public function __construct(AchievementsStorageInterface $storage, CriteriaHandlersManagerContract $handlers) |
||
39 | { |
||
40 | $this->storage = $storage; |
||
41 | $this->handlers = $handlers; |
||
42 | } |
||
43 | |||
44 | /** |
||
45 | * Updates criterias progress by given type & checks |
||
46 | * referred achievements for completeness state. |
||
47 | * |
||
48 | * Returns number of updated criterias. |
||
49 | * |
||
50 | * @param mixed $owner |
||
51 | * @param string $type |
||
52 | * @param mixed $data = null |
||
53 | * |
||
54 | * @return int |
||
55 | */ |
||
56 | public function updateAchievementCriterias($owner, string $type, $data = null): int |
||
57 | { |
||
58 | $criterias = $this->storage->getOwnerCriteriasByType($owner, $type, $data); |
||
59 | |||
60 | if (!count($criterias)) { |
||
61 | return 0; |
||
62 | } |
||
63 | |||
64 | $this->achievementsToCheck = []; |
||
65 | |||
66 | $achievements = $this->storage->getAchievementsByCriterias($criterias); |
||
67 | $updatedCriteriasCount = 0; |
||
68 | |||
69 | foreach ($criterias as $criteria) { |
||
70 | /** @var AchievementCriteria $criteria*/ |
||
71 | |||
72 | if ($criteria->completed()) { |
||
73 | continue; |
||
74 | } |
||
75 | |||
76 | $achievement = $this->storage->getAchievementForCriteria($criteria, $achievements); |
||
77 | |||
78 | if (is_null($achievement)) { |
||
79 | continue; |
||
80 | } |
||
81 | |||
82 | $change = $this->getCriteriaChange($owner, $criteria, $achievement, $data); |
||
83 | |||
84 | if (is_null($change)) { |
||
85 | continue; |
||
86 | } |
||
87 | |||
88 | $this->setCriteriaProgress($owner, $criteria, $achievement, $change); |
||
89 | $updatedCriteriasCount++; |
||
90 | } |
||
91 | |||
92 | if (count($this->achievementsToCheck) > 0) { |
||
93 | $this->checkCompletedAchievements($owner); |
||
94 | } |
||
95 | |||
96 | return $updatedCriteriasCount; |
||
97 | } |
||
98 | |||
99 | /** |
||
100 | * Requests new progress value for given owner & criteria. |
||
101 | * |
||
102 | * @param mixed $owner |
||
103 | * @param AchievementCriteria $criteria |
||
104 | * @param Achievement $achievement |
||
105 | * @param mixed $data = null |
||
106 | * |
||
107 | * @return AchievementCriteriaChange|null |
||
108 | */ |
||
109 | public function getCriteriaChange($owner, AchievementCriteria $criteria, Achievement $achievement, $data = null) |
||
110 | { |
||
111 | $handler = $this->handlers->getHandlerFor($criteria->type()); |
||
112 | |||
113 | if (!$handler instanceof CriteriaHandler) { |
||
114 | return null; |
||
115 | } |
||
116 | |||
117 | return $handler->handle($owner, $criteria, $achievement, $data); |
||
118 | } |
||
119 | |||
120 | /** |
||
121 | * Updates criteria progress & saves achievement for completeness check (if eligible for). |
||
122 | * |
||
123 | * @param mixed $owner |
||
124 | * @param AchievementCriteria $criteria |
||
125 | * @param Achievement $achievement |
||
126 | * @param AchievementCriteriaChange $change |
||
127 | * |
||
128 | * @return bool |
||
129 | */ |
||
130 | protected function setCriteriaProgress($owner, AchievementCriteria $criteria, Achievement $achievement, AchievementCriteriaChange $change) |
||
131 | { |
||
132 | $maxValue = $criteria->maxValue(); |
||
133 | $changeValue = $change->value; |
||
134 | $oldValue = null; |
||
135 | $newValue = $changeValue; |
||
136 | $progress = new AchievementCriteriaProgress(0, false); |
||
137 | |||
138 | if ($maxValue > 0 && $changeValue > $maxValue) { |
||
139 | $changeValue = $maxValue; |
||
140 | } |
||
141 | |||
142 | if ($criteria->hasProgress()) { |
||
143 | $progress = $criteria->progress(); |
||
144 | $oldValue = $progress->value; |
||
145 | $newValue = $progress->getNewValue($maxValue, $changeValue, $change->progressType); |
||
146 | } |
||
147 | |||
148 | if ($oldValue === $newValue) { |
||
149 | return false; |
||
150 | } |
||
151 | |||
152 | $progress->value = $newValue; |
||
153 | $progress->changed = true; |
||
154 | $progress->data = $change->progressData; |
||
155 | |||
156 | $this->storage->setCriteriaProgressUpdated($owner, $criteria, $achievement, $progress); |
||
157 | |||
158 | if ($this->isCompletedCriteria($criteria, $progress)) { |
||
159 | $this->completedCriteriaFor($achievement); |
||
160 | } |
||
161 | |||
162 | return true; |
||
163 | } |
||
164 | |||
165 | /** |
||
166 | * Saves achievement to completeness check list. |
||
167 | * |
||
168 | * @param Achievement $achievement |
||
169 | */ |
||
170 | protected function completedCriteriaFor(Achievement $achievement) |
||
171 | { |
||
172 | if (!in_array($achievement->id(), $this->achievementsToCheck)) { |
||
173 | $this->achievementsToCheck[] = $achievement->id(); |
||
174 | } |
||
175 | } |
||
176 | |||
177 | /** |
||
178 | * Checks all saved achievements for completeness state. |
||
179 | * |
||
180 | * Returns number of completed achievements. |
||
181 | * |
||
182 | * @param mixed $owner |
||
183 | * |
||
184 | * @return int |
||
185 | */ |
||
186 | protected function checkCompletedAchievements($owner): int |
||
187 | { |
||
188 | $achievements = $this->storage->getAchievementsWithProgressFor($owner, $this->achievementsToCheck); |
||
189 | $this->achievementsToCheck = []; |
||
190 | |||
191 | if (!$achievements || !count($achievements)) { |
||
0 ignored issues
–
show
|
|||
192 | return 0; |
||
193 | } |
||
194 | |||
195 | $completedAchievements = array_filter($achievements, function (Achievement $achievement) { |
||
196 | return !$achievement->completed() && $this->isCompletedAchievement($achievement); |
||
197 | }); |
||
198 | |||
199 | if (count($completedAchievements) > 0) { |
||
200 | $this->storage->setAchievementsCompleted($owner, $completedAchievements); |
||
201 | } |
||
202 | |||
203 | return count($completedAchievements); |
||
204 | } |
||
205 | |||
206 | /** |
||
207 | * Determines if given criteria was completed. |
||
208 | * |
||
209 | * @param AchievementCriteria $criteria |
||
210 | * @param AchievementCriteriaProgress $progress |
||
211 | * |
||
212 | * @return bool |
||
213 | */ |
||
214 | protected function isCompletedCriteria(AchievementCriteria $criteria, AchievementCriteriaProgress $progress): bool |
||
215 | { |
||
216 | $progress->completed = $progress->value >= $criteria->maxValue(); |
||
217 | |||
218 | return $progress->completed; |
||
219 | } |
||
220 | |||
221 | /** |
||
222 | * Determines if given achievement was completed. |
||
223 | * |
||
224 | * @param Achievement $achievement |
||
225 | * |
||
226 | * @return bool |
||
227 | */ |
||
228 | protected function isCompletedAchievement(Achievement $achievement): bool |
||
229 | { |
||
230 | $completedCriterias = array_filter($achievement->criterias(), function (AchievementCriteria $criteria) { |
||
231 | return $this->isCompletedCriteria($criteria, $criteria->progress()); |
||
232 | }); |
||
233 | |||
234 | return count($achievement->criterias()) === count($completedCriterias); |
||
235 | } |
||
236 | } |
||
237 |
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.