Passed
Push — 1.0 ( e206d7...64fd78 )
by Morven
03:35
created

ContactHelper::pushFields()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 7
c 1
b 0
f 0
dl 0
loc 13
rs 10
cc 3
nc 3
nop 2
1
<?php
2
3
namespace SilverCommerce\ContactAdmin\Helpers;
4
5
use DateTime;
6
use LogicException;
7
use SilverStripe\Security\Member;
8
use SilverStripe\Core\Config\Configurable;
9
use SilverStripe\Core\Injector\Injectable;
10
use SilverCommerce\ContactAdmin\Model\Contact;
11
use SilverStripe\Security\Group;
12
13
class ContactHelper
14
{
15
    use Injectable, Configurable;
16
17
    /**
18
     * The field that is shared between Members and Contacts.
19
     * 
20
     * Defaults to "Email"
21
     *
22
     * @var string
23
     * @config
24
     */
25
    private static $common_field = "Email";
26
27
    /**
28
     * Fields that can be synced between members and contacts
29
     *
30
     * @var array
31
     */
32
    private static $sync_fields = [
33
        "FirstName",
34
        "Surname",
35
        "Company",
36
        "Phone",
37
        "Mobile",
38
        "Email"
39
    ];
40
41
    /**
42
     * Automatically sync users and contacts on save and auto create contacts for existing users
43
     *
44
     * @var boolean
45
     */
46
    private static $auto_sync = true;
47
48
    /**
49
     * Add codes for default groups linked user accounts are added to 
50
     *
51
     * @var array
52
     */
53
    private static $default_user_groups = [
54
        'contact_users' => 'Contact Users'
55
    ];
56
57
    /**
58
     * @var Contact
59
     */
60
    private $contact;
61
62
    /**
63
     * @var Member
64
     */
65
    private $member;
66
67
    /**
68
     * Create a member from the provided contact
69
     *
70
     * @return Member
71
     */
72
    public function findOrMakeMember()
73
    {
74
        $contact = $this->getContact();
75
76
        if (empty($contact)) {
77
            throw new LogicException('Must set a Contact');
78
        }
79
80
        // First off see if the member from the contact is available
81
        $member = $contact->Member();
0 ignored issues
show
Bug introduced by
The method Member() does not exist on SilverCommerce\ContactAdmin\Model\Contact. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

81
        /** @scrutinizer ignore-call */ 
82
        $member = $contact->Member();
Loading history...
82
        $link = false;
83
84
        // If no member assigned, try to find one with matching field 
85
        if (empty($member) || !$member->exists()) {
86
            $common_field = $this->config()->common_field;
87
            $member = Member::get()->find($common_field, $contact->{$common_field});
88
            $link = true;
89
        }
90
91
        // Finally, if still no member found, then create a new one, link to the contact
92
        // and pass the relevent data
93
        if (empty($member)) {
94
            $member = Member::create();
95
            self::pushFields($contact, $member);
96
            $member->write();
97
            $link = true;
98
        }
99
100
        if ($link) {
101
            $contact->MemberID = $member->ID;
0 ignored issues
show
Bug Best Practice introduced by
The property MemberID does not exist on SilverCommerce\ContactAdmin\Model\Contact. Since you implemented __set, consider adding a @property annotation.
Loading history...
102
            $contact->write();
103
        }
104
105
        return $member;
106
    }
107
108
    /**
109
     * Find or create a Contact from the provided member
110
     *
111
     * @return Contact
112
     */
113
    public function findOrMakeContact()
114
    {
115
        $member = $this->getMember();
116
117
        if (empty($member)) {
118
            throw new LogicException('Must set a Member');
119
        }
120
121
        // First off see if the contact is available as relation
122
        $contact = $member->Contact();
123
        $link = false;
124
125
        // If no member assigned, try to find one with matching field 
126
        if (empty($contact) || !$contact->exists()) {
127
            $common_field = $this->config()->common_field;
128
            $contact = Contact::get()->find($common_field, $member->{$common_field});
129
            $link = true;
130
        }
131
132
        // Finally, if still no member found, then create a new one, link to the contact
133
        // and pass the relevent data
134
        if (empty($contact)) {
135
            $contact = Contact::create();
136
            self::pushFields($member, $contact);
137
            $link = true;
138
        }
139
140
        if ($link) {
141
            $contact->MemberID = $member->ID;
142
            $contact->write();
143
        }
144
145
        return $contact;
146
    }
147
148
    /**
149
     * Update an associated member with the data from this contact
150
     * 
151
     * @todo Currently sync is pretty basic (pushes data from one object to another). This could be more intilligent.
152
     *
153
     * @param bool $write Write the syncronised record
154
     * 
155
     * @return void
156
     */
157
    public function syncContactAndMember(bool $write = true)
0 ignored issues
show
Unused Code introduced by
The parameter $write is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

157
    public function syncContactAndMember(/** @scrutinizer ignore-unused */ bool $write = true)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
158
    {
159
        $member = $this->getMember();
160
        $contact = $this->getContact();
161
        $changes = [];
162
163
        if (empty($member) || empty($contact)) {
164
            throw new LogicException('Must set a Member AND a Contact');
165
        }
166
167
        // Find out which object just changed and sync in the correct direction
168
        $member_changed = $member->getChangedFields();
169
        $contact_changed = $contact->getChangedFields();
170
171
        if (count($contact_changed) > 0) {
172
            $changes = self::pushChangedFields($contact, $member);
173
            $obj_to_write = $contact;
174
        } elseif (count($member_changed) > 0) {
175
            $changes = self::pushChangedFields($member, $contact);
176
            $obj_to_write = $member;
177
        }
178
179
        if (count($changes) > 0) {
180
            $obj_to_write->write();
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $obj_to_write does not seem to be defined for all execution paths leading up to this point.
Loading history...
181
        }
182
183
        return $this;
184
    }
185
186
    /**
187
     * Push any fields relevent fields changed on the origin obvject, to the destination,
188
     * if the destination is different. 
189
     * 
190
     * @var DataObject $origin
191
     * @var DataObject $destination
192
     *
193
     * @return array
194
     */
195
    public static function pushChangedFields($origin, $destination)
196
    {
197
        $sync = self::config()->sync_fields;
198
        $changes = [];
199
200
        foreach ($origin->getChangedFields() as $field => $change) {
201
            if (in_array($field, $sync) && !empty($origin->$field) && $origin->$field != $destination->$field) {
202
                $destination->$field = $origin->$field;
203
                $changes[$field] = $origin->$field;
204
            }
205
        }
206
207
        return $changes;
208
    }
209
210
    /**
211
     * Push the field values from the origin object and the destination object
212
     * (if values do not match)
213
     *
214
     * Return a list of fields pushed
215
     * 
216
     * @var DataObject $origin
217
     * @var DataObject $destination
218
     *
219
     * @return array
220
     */
221
    public static function pushFields($origin, $destination)
222
    {
223
        $sync = self::config()->sync_fields;
224
        $changes = [];
225
226
        foreach ($sync as $field) {
227
            if ($origin->$field != $destination->$field) {
228
                $destination->$field = $origin->$field;
229
                $changes[$field] = $origin->$field;
230
            }
231
        }
232
233
        return $changes;
234
    }
235
236
    /**
237
     * Link the set member to all the groups specified via config
238
     *
239
     * Return the number of groups added
240
     * 
241
     * @return int 
242
     */
243
    public function linkMemberToGroups()
244
    {
245
        $member = $this->getMember();
246
        $groups = $this->config()->get('default_user_groups');
247
        $count = 0;
248
249
        if (empty($member)) {
250
            throw new LogicException('Must set a Member');
251
        }
252
253
        if (empty($groups)) {
254
            return $count;
255
        }
256
257
        foreach (array_keys($groups) as $code) {
258
            $group = Group::get()->filter('Code', $code)->first();
259
260
            if (!empty($group)) {
261
                $member->Groups()->add($group);
262
                $count++;
263
            }
264
        }
265
266
        return $count;
267
    }
268
269
    /**
270
     * Get the value of contact. If not assigned directly, try to get from the member
271
     *
272
     * @return Contact
273
     */ 
274
    public function getContact()
275
    {
276
        $contact = $this->contact;
277
278
        if (empty($contact) && !empty($this->getMember())) {
279
            $contact = $this->getMember()->Contact();
280
        }
281
282
        return $contact;
283
    }
284
285
    /**
286
     * Set the value of contact
287
     *
288
     * @param Contact $contact
289
     *
290
     * @return self
291
     */ 
292
    public function setContact(Contact $contact)
293
    {
294
        $this->contact = $contact;
295
        return $this;
296
    }
297
298
    /**
299
     * Get the value of member. If not assigned directly, try to get from Contact
300
     *
301
     * @return Member
302
     */ 
303
    public function getMember()
304
    {
305
        $member = $this->member;
306
307
        if (empty($member) && !empty($this->getContact())) {
308
            $member = $this->getContact()->Member();
309
        }
310
311
        return $member;
312
    }
313
314
    /**
315
     * Set the value of member
316
     *
317
     * @param Member $member
318
     *
319
     * @return self
320
     */ 
321
    public function setMember(Member $member)
322
    {
323
        $this->member = $member;
324
        return $this;
325
    }
326
}
327