PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 4.14.5
GiveWP – Donation Plugin and Fundraising Platform v4.14.5
4.16.4 4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / src / API / REST / V3 / Routes / Donors / ViewModels / DonorViewModel.php
give / src / API / REST / V3 / Routes / Donors / ViewModels Last commit date
DonorViewModel.php 5 months ago
DonorViewModel.php
258 lines
1 <?php
2
3 namespace Give\API\REST\V3\Routes\Donors\ViewModels;
4
5 use Give\API\REST\V3\Routes\Donors\ValueObjects\DonorAnonymousMode;
6 use Give\DonationForms\Models\DonationForm;
7 use Give\DonationForms\Repositories\DonationFormRepository;
8 use Give\Donors\Models\Donor;
9 use Give\Framework\FieldsAPI\Field;
10 use Give\Framework\FieldsAPI\Types;
11 use Give\Framework\Support\Facades\Str;
12
13 /**
14 * @since 4.14.0 Move from Give\Donors\ViewModels to API REST V3 namespace
15 * @since 4.4.0
16 */
17 class DonorViewModel
18 {
19 private Donor $donor;
20 private DonorAnonymousMode $anonymousMode;
21 private bool $includeSensitiveData = false;
22
23 /**
24 * @since 4.4.0
25 */
26 public function __construct(Donor $donor)
27 {
28 $this->donor = $donor;
29 }
30
31 /**
32 * @since 4.4.0
33 */
34 public function includeSensitiveData(bool $includeSensitiveData = true): DonorViewModel
35 {
36 $this->includeSensitiveData = $includeSensitiveData;
37
38 return $this;
39 }
40
41 /**
42 * @since 4.4.0
43 */
44 public function anonymousMode(DonorAnonymousMode $mode): DonorViewModel
45 {
46 $this->anonymousMode = $mode;
47
48 return $this;
49 }
50
51 /**
52 * @since 4.14.0 name and lastName should return only the first letter of the last name when sensitive data is not included
53 * @since 4.4.0
54 */
55 public function exports(): array
56 {
57 $data = array_merge(
58 $this->donor->toArray(),
59 [
60 'addresses' => array_map(function ($address) { return $address->toArray(); }, $this->donor->addresses),
61 'avatarUrl' => $this->getAvatarUrl(),
62 'wpUserPermalink' => $this->donor->userId ? get_edit_user_link($this->donor->userId) : null,
63 'customFields' => $this->getCustomFields(),
64 ],
65 );
66
67 if (!$this->includeSensitiveData) {
68 $sensitiveDataExcluded = [
69 'userId',
70 'email',
71 'phone',
72 'additionalEmails',
73 'name',
74 'lastName',
75 'avatarUrl',
76 'company',
77 'addresses',
78 'wpUserPermalink',
79 'customFields',
80 ];
81
82 foreach ($sensitiveDataExcluded as $propertyName) {
83 switch ($propertyName) {
84 case 'name':
85 $data[$propertyName] = $data['firstName'] . ' ' . Str::substr($data['lastName'], 0, 1);
86 break;
87 case 'lastName':
88 $data[$propertyName] = Str::substr($data[$propertyName], 0, 1);
89 break;
90 case 'additionalEmails':
91 case 'customFields':
92 $data[$propertyName] = [];
93 break;
94 default:
95 $data[$propertyName] = '';
96 break;
97 }
98 }
99 }
100
101 if (isset($this->anonymousMode) && $this->anonymousMode->isRedacted() && $this->donor->isAnonymous()) {
102 $anonymousDataRedacted = [
103 'id',
104 'name',
105 'firstName',
106 'lastName',
107 'prefix',
108 'avatarUrl',
109 'company',
110 'email',
111 'phone',
112 'additionalEmails',
113 'wpUserPermalink',
114 'customFields'
115 ];
116
117 foreach ($anonymousDataRedacted as $propertyName) {
118 switch ($propertyName) {
119 case 'id':
120 $data[$propertyName] = 0;
121 break;
122 case 'wpUserPermalink':
123 case 'avatarUrl':
124 $data[$propertyName] = '';
125 break;
126 case 'additionalEmails':
127 case 'customFields':
128 $data[$propertyName] = [];
129 break;
130 default:
131 $data[$propertyName] = __('anonymous', 'give');
132 break;
133 }
134 }
135 }
136
137 return $data;
138 }
139
140 /**
141 * Get avatar URL from avatar ID with fallback to Gravatar
142 *
143 * @since 4.4.0
144 */
145 private function getAvatarUrl(): ?string
146 {
147 $avatarId = $this->donor->avatarId;
148
149 if ($avatarId) {
150 return wp_get_attachment_image_url($avatarId, ['width' => '80', 'height' => '80']);
151 } else {
152 return give_validate_gravatar($this->donor->email) ? get_avatar_url($this->donor->email, ['size' => 80]) : null;
153 }
154 }
155
156 /**
157 * Get custom fields for the donor
158 *
159 * @since 4.4.0
160 */
161 private function getCustomFields(): array
162 {
163 $forms = $this->getUniqueDonationFormsForDonor();
164
165 if (empty($forms)) {
166 return [];
167 }
168
169 $allFields = [];
170 foreach ($forms as $form) {
171 $allFields = array_merge($allFields, $this->getDisplayedDonorMetaFieldsForForm($form));
172 }
173
174 $customFields = [];
175 foreach ($allFields as $field) {
176 $value = $this->getFieldValue($field);
177
178 if (empty($value)) {
179 continue;
180 }
181
182 $customFields[] = [
183 'label' => method_exists($field, 'getLabel') ? $field->getLabel() : $field->getName(),
184 'value' => $value,
185 ];
186 }
187
188 return $customFields;
189 }
190
191 /**
192 * Get unique donation forms for the donor
193 *
194 * @since 4.4.0
195 */
196 private function getUniqueDonationFormsForDonor(): array
197 {
198 $donations = $this->donor->donations()->getAll();
199
200 if (empty($donations)) {
201 return [];
202 }
203
204 $uniqueFormIds = [];
205 foreach ($donations as $donation) {
206 $formId = $donation->formId;
207
208 // Skip legacy forms and avoid duplicates
209 if (!give(DonationFormRepository::class)->isLegacyForm($formId) && !in_array($formId, $uniqueFormIds, true)) {
210 $uniqueFormIds[] = $formId;
211 }
212 }
213
214 $forms = [];
215 foreach ($uniqueFormIds as $formId) {
216 $form = DonationForm::find($formId);
217 if ($form !== null) {
218 $forms[] = $form;
219 }
220 }
221
222 return $forms;
223 }
224
225 /**
226 * Get displayed donor meta fields for a form
227 *
228 * @since 4.4.0
229 */
230 private function getDisplayedDonorMetaFieldsForForm(DonationForm $form): array
231 {
232 return array_filter($form->schema()->getFields(), static function (Field $field): bool {
233 return $field->shouldShowInAdmin() && $field->shouldStoreAsDonorMeta();
234 });
235 }
236
237 /**
238 * Get field value for a custom field
239 *
240 * @since 4.4.0
241 */
242 private function getFieldValue(Field $field): string
243 {
244 $metaValue = give()->donor_meta->get_meta($this->donor->id, $field->getName(), true);
245
246 if (empty($metaValue)) {
247 return '';
248 }
249
250 if ($field->getType() === Types::FILE) {
251 $attachmentLink = wp_get_attachment_link($metaValue);
252 return $attachmentLink ?: '';
253 }
254
255 return (string) $metaValue;
256 }
257 }
258