]> git.mxchange.org Git - friendica.git/blob - src/Repository/ProfileField.php
Merge pull request #10160 from annando/issue-10156
[friendica.git] / src / Repository / ProfileField.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2021, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Repository;
23
24 use Friendica\BaseModel;
25 use Friendica\BaseRepository;
26 use Friendica\Collection;
27 use Friendica\Core\L10n;
28 use Friendica\Database\Database;
29 use Friendica\Database\DBA;
30 use Friendica\Model;
31 use Friendica\Util\ACLFormatter;
32 use Friendica\Util\DateTimeFormat;
33 use Psr\Log\LoggerInterface;
34
35 class ProfileField extends BaseRepository
36 {
37         protected static $table_name = 'profile_field';
38
39         protected static $model_class = Model\ProfileField::class;
40
41         protected static $collection_class = Collection\ProfileFields::class;
42
43         /** @var PermissionSet */
44         private $permissionSet;
45         /** @var ACLFormatter */
46         private $aclFormatter;
47         /** @var L10n */
48         private $l10n;
49
50         public function __construct(Database $dba, LoggerInterface $logger, PermissionSet $permissionSet, ACLFormatter $aclFormatter, L10n $l10n)
51         {
52                 parent::__construct($dba, $logger);
53
54                 $this->permissionSet = $permissionSet;
55                 $this->aclFormatter = $aclFormatter;
56                 $this->l10n = $l10n;
57         }
58
59         /**
60          * @param array $data
61          * @return Model\ProfileField
62          */
63         protected function create(array $data)
64         {
65                 return new Model\ProfileField($this->dba, $this->logger, $this->permissionSet, $data);
66         }
67
68         /**
69          * @param array $condition
70          * @return Model\ProfileField
71          * @throws \Friendica\Network\HTTPException\NotFoundException
72          */
73         public function selectFirst(array $condition)
74         {
75                 return parent::selectFirst($condition);
76         }
77
78         /**
79          * @param array $condition
80          * @param array $params
81          * @return Collection\ProfileFields
82          * @throws \Exception
83          */
84         public function select(array $condition = [], array $params = [])
85         {
86                 return parent::select($condition, $params);
87         }
88
89         /**
90          * @param array    $condition
91          * @param array    $params
92          * @param int|null $min_id
93          * @param int|null $max_id
94          * @param int      $limit
95          * @return Collection\ProfileFields
96          * @throws \Exception
97          */
98         public function selectByBoundaries(array $condition = [], array $params = [], int $min_id = null, int $max_id = null, int $limit = self::LIMIT)
99         {
100                 return parent::selectByBoundaries($condition, $params, $min_id, $max_id, $limit);
101         }
102
103         /**
104          * @param int $uid Field owner user Id
105          * @return Collection\ProfileFields
106          * @throws \Exception
107          */
108         public function selectByUserId(int $uid)
109         {
110                 return $this->select(
111                         ['uid' => $uid],
112                         ['order' => ['order']]
113                 );
114         }
115
116         /**
117          * Retrieve all custom profile field a given contact is able to access to, including public profile fields.
118          *
119          * @param int $cid Private contact id, must be owned by $uid
120          * @param int $uid Field owner user id
121          * @return Collection\ProfileFields
122          * @throws \Exception
123          */
124         public function selectByContactId(int $cid, int $uid)
125         {
126                 $permissionSets = $this->permissionSet->selectByContactId($cid, $uid);
127
128                 $psids = $permissionSets->column('id');
129
130                 // Includes public custom fields
131                 $psids[] = 0;
132
133                 return $this->select(
134                         ['uid' => $uid, 'psid' => $psids],
135                         ['order' => ['order']]
136                 );
137         }
138
139         /**
140          * @param array $fields
141          * @return Model\ProfileField|bool
142          * @throws \Exception
143          */
144         public function insert(array $fields)
145         {
146                 $fields['created'] = DateTimeFormat::utcNow();
147                 $fields['edited']  = DateTimeFormat::utcNow();
148
149                 return parent::insert($fields);
150         }
151
152         /**
153          * @param Model\ProfileField $model
154          * @return bool
155          * @throws \Exception
156          */
157         public function update(BaseModel $model)
158         {
159                 $model->edited = DateTimeFormat::utcNow();
160
161                 return parent::update($model);
162         }
163         
164         /**
165          * @param int                      $uid                User Id
166          * @param Collection\ProfileFields $profileFields      Collection of existing profile fields
167          * @param array                    $profileFieldInputs Array of profile field form inputs indexed by profile field id
168          * @param array                    $profileFieldOrder  List of profile field id in order
169          * @return Collection\ProfileFields
170          * @throws \Exception
171          */
172         public function updateCollectionFromForm(int $uid, Collection\ProfileFields $profileFields, array $profileFieldInputs, array $profileFieldOrder)
173         {
174                 // Returns an associative array of id => order values
175                 $profileFieldOrder = array_flip($profileFieldOrder);
176
177                 // Creation of the new field
178                 if (!empty($profileFieldInputs['new']['label'])) {
179                         $psid = $this->permissionSet->getIdFromACL(
180                                 $uid,
181                                 $this->aclFormatter->toString($profileFieldInputs['new']['contact_allow'] ?? ''),
182                                 $this->aclFormatter->toString($profileFieldInputs['new']['group_allow'] ?? ''),
183                                 $this->aclFormatter->toString($profileFieldInputs['new']['contact_deny'] ?? ''),
184                                 $this->aclFormatter->toString($profileFieldInputs['new']['group_deny'] ?? '')
185                         );
186
187                         $newProfileField = $this->insert([
188                                 'uid' => $uid,
189                                 'label' => $profileFieldInputs['new']['label'],
190                                 'value' => $profileFieldInputs['new']['value'],
191                                 'psid' => $psid,
192                                 'order' => $profileFieldOrder['new'],
193                         ]);
194
195                         $profileFieldInputs[$newProfileField->id] = $profileFieldInputs['new'];
196                         $profileFieldOrder[$newProfileField->id] = $profileFieldOrder['new'];
197
198                         $profileFields[] = $newProfileField;
199                 }
200
201                 unset($profileFieldInputs['new']);
202                 unset($profileFieldOrder['new']);
203
204                 // Prunes profile field whose label has been emptied
205                 $profileFields = $profileFields->filter(function (Model\ProfileField $profileField) use (&$profileFieldInputs, &$profileFieldOrder) {
206                         $keepModel = !isset($profileFieldInputs[$profileField->id]) || !empty($profileFieldInputs[$profileField->id]['label']);
207
208                         if (!$keepModel) {
209                                 unset($profileFieldInputs[$profileField->id]);
210                                 unset($profileFieldOrder[$profileField->id]);
211                                 $this->delete($profileField);
212                         }
213
214                         return $keepModel;
215                 });
216
217                 // Regenerates the order values if items were deleted
218                 $profileFieldOrder = array_flip(array_keys($profileFieldOrder));
219
220                 // Update existing profile fields from form values
221                 $profileFields = $profileFields->map(function (Model\ProfileField $profileField) use ($uid, &$profileFieldInputs, &$profileFieldOrder) {
222                         if (isset($profileFieldInputs[$profileField->id]) && isset($profileFieldOrder[$profileField->id])) {
223                                 $psid = $this->permissionSet->getIdFromACL(
224                                         $uid,
225                                         $this->aclFormatter->toString($profileFieldInputs[$profileField->id]['contact_allow'] ?? ''),
226                                         $this->aclFormatter->toString($profileFieldInputs[$profileField->id]['group_allow'] ?? ''),
227                                         $this->aclFormatter->toString($profileFieldInputs[$profileField->id]['contact_deny'] ?? ''),
228                                         $this->aclFormatter->toString($profileFieldInputs[$profileField->id]['group_deny'] ?? '')
229                                 );
230
231                                 $profileField->psid  = $psid;
232                                 $profileField->label = $profileFieldInputs[$profileField->id]['label'];
233                                 $profileField->value = $profileFieldInputs[$profileField->id]['value'];
234                                 $profileField->order = $profileFieldOrder[$profileField->id];
235
236                                 unset($profileFieldInputs[$profileField->id]);
237                                 unset($profileFieldOrder[$profileField->id]);
238                         }
239
240                         return $profileField;
241                 });
242
243                 return $profileFields;
244         }
245
246         /**
247          * Migrates a legacy profile to the new slimmer profile with extra custom fields.
248          * Multi profiles are converted to ACl-protected custom fields and deleted.
249          *
250          * @param array $profile Profile table row
251          * @throws \Exception
252          */
253         public function migrateFromLegacyProfile(array $profile)
254         {
255                 // Already processed, aborting
256                 if ($profile['is-default'] === null) {
257                         return;
258                 }
259
260                 if (!$profile['is-default']) {
261                         $contacts = Model\Contact::selectToArray(['id'], ['uid' => $profile['uid'], 'profile-id' => $profile['id']]);
262                         if (!count($contacts)) {
263                                 // No contact visibility selected defaults to user-only permission
264                                 $contacts = Model\Contact::selectToArray(['id'], ['uid' => $profile['uid'], 'self' => true]);
265                         }
266
267                         $allow_cid = $this->aclFormatter->toString(array_column($contacts, 'id'));
268                 }
269
270                 $psid = $this->permissionSet->getIdFromACL($profile['uid'], $allow_cid ?? '');
271
272                 $order = 1;
273
274                 $custom_fields = [
275                         'hometown'  => $this->l10n->t('Hometown:'),
276                         'marital'   => $this->l10n->t('Marital Status:'),
277                         'with'      => $this->l10n->t('With:'),
278                         'howlong'   => $this->l10n->t('Since:'),
279                         'sexual'    => $this->l10n->t('Sexual Preference:'),
280                         'politic'   => $this->l10n->t('Political Views:'),
281                         'religion'  => $this->l10n->t('Religious Views:'),
282                         'likes'     => $this->l10n->t('Likes:'),
283                         'dislikes'  => $this->l10n->t('Dislikes:'),
284                         'pdesc'     => $this->l10n->t('Title/Description:'),
285                         'summary'   => $this->l10n->t('Summary'),
286                         'music'     => $this->l10n->t('Musical interests'),
287                         'book'      => $this->l10n->t('Books, literature'),
288                         'tv'        => $this->l10n->t('Television'),
289                         'film'      => $this->l10n->t('Film/dance/culture/entertainment'),
290                         'interest'  => $this->l10n->t('Hobbies/Interests'),
291                         'romance'   => $this->l10n->t('Love/romance'),
292                         'work'      => $this->l10n->t('Work/employment'),
293                         'education' => $this->l10n->t('School/education'),
294                         'contact'   => $this->l10n->t('Contact information and Social Networks'),
295                 ];
296
297                 foreach ($custom_fields as $field => $label) {
298                         if (!empty($profile[$field]) && $profile[$field] > DBA::NULL_DATE && $profile[$field] > DBA::NULL_DATETIME) {
299                                 $this->insert([
300                                         'uid' => $profile['uid'],
301                                         'psid' => $psid,
302                                         'order' => $order++,
303                                         'label' => trim($label, ':'),
304                                         'value' => $profile[$field],
305                                 ]);
306                         }
307
308                         $profile[$field] = null;
309                 }
310
311                 if ($profile['is-default']) {
312                         $profile['profile-name'] = null;
313                         $profile['is-default'] = null;
314                         $this->dba->update('profile', $profile, ['id' => $profile['id']]);
315                 } elseif (!empty($profile['id'])) {
316                         $this->dba->delete('profile', ['id' => $profile['id']]);
317                 }
318         }
319 }