233 lines
7.1 KiB
PHP
233 lines
7.1 KiB
PHP
<?php
|
|
|
|
namespace App\Traits;
|
|
|
|
use App\Gender;
|
|
use App\Address;
|
|
use App\Contact;
|
|
use App\Country;
|
|
use App\ContactField;
|
|
use App\ContactFieldType;
|
|
use Sabre\VObject\Reader;
|
|
use Sabre\VObject\Component\VCard;
|
|
|
|
trait VCardImporter
|
|
{
|
|
protected $skippedContacts = 0;
|
|
protected $importedContacts = 0;
|
|
private $contactFieldEmailId;
|
|
private $contactFieldPhoneId;
|
|
|
|
public function work($account_id, $subject)
|
|
{
|
|
$matchCount = preg_match_all('/(BEGIN:VCARD.*?END:VCARD)/s', $subject, $matches);
|
|
|
|
if (! $this->workInit($matchCount)) {
|
|
return;
|
|
}
|
|
|
|
// create special gender for this import
|
|
// we don't know which gender all the contacts are, so we need to create a special status for them, as we
|
|
// can't guess whether they are men, women or else.
|
|
$gender = Gender::where('name', 'vCard')->first();
|
|
if (! $gender) {
|
|
$gender = new Gender;
|
|
$gender->account_id = $account_id;
|
|
$gender->name = 'vCard';
|
|
$gender->save();
|
|
}
|
|
|
|
collect($matches[0])->map(function ($vcard) {
|
|
return Reader::read($vcard);
|
|
})->each(function (VCard $vcard) use ($account_id, $gender) {
|
|
if ($this->contactExists($vcard, $account_id)) {
|
|
$this->workContactExists($vcard);
|
|
$this->skippedContacts++;
|
|
|
|
return;
|
|
}
|
|
|
|
// Skip contact if there isn't a first name or a nickname
|
|
if (! $this->contactHasName($vcard)) {
|
|
$this->workContactNoFirstname($vcard);
|
|
$this->skippedContacts++;
|
|
|
|
return;
|
|
}
|
|
|
|
$this->vCardToContact($vcard, $account_id, $gender->id);
|
|
|
|
$this->importedContacts++;
|
|
|
|
$this->workNext($vcard);
|
|
});
|
|
|
|
$this->workEnd($matchCount, $this->skippedContacts, $this->importedContacts);
|
|
}
|
|
|
|
private function vCardToContact($vcard, $account_id, $gender_id)
|
|
{
|
|
$contact = new Contact();
|
|
$contact->account_id = $account_id;
|
|
$contact->gender_id = $gender_id;
|
|
|
|
if ($vcard->N && ! empty($vcard->N->getParts()[1])) {
|
|
$contact->first_name = $this->formatValue($vcard->N->getParts()[1]);
|
|
$contact->middle_name = $this->formatValue($vcard->N->getParts()[2]);
|
|
$contact->last_name = $this->formatValue($vcard->N->getParts()[0]);
|
|
} else {
|
|
$contact->first_name = $this->formatValue($vcard->NICKNAME);
|
|
}
|
|
|
|
$contact->job = $this->formatValue($vcard->ORG);
|
|
|
|
$contact->setAvatarColor();
|
|
|
|
$contact->save();
|
|
|
|
if ($vcard->BDAY && ! empty((string) $vcard->BDAY)) {
|
|
$birthdate = new \DateTime((string) $vcard->BDAY);
|
|
|
|
$specialDate = $contact->setSpecialDate('birthdate', $birthdate->format('Y'), $birthdate->format('m'), $birthdate->format('d'));
|
|
$specialDate->setReminder('year', 1, trans('people.people_add_birthday_reminder', ['name' => $contact->first_name]));
|
|
}
|
|
|
|
if ($vcard->ADR) {
|
|
$address = new Address();
|
|
$address->street = $this->formatValue($vcard->ADR->getParts()[2]);
|
|
$address->city = $this->formatValue($vcard->ADR->getParts()[3]);
|
|
$address->province = $this->formatValue($vcard->ADR->getParts()[4]);
|
|
$address->postal_code = $this->formatValue($vcard->ADR->getParts()[5]);
|
|
|
|
$country = Country::where('country', $vcard->ADR->getParts()[6])
|
|
->orWhere('iso', mb_strtolower($vcard->ADR->getParts()[6]))
|
|
->first();
|
|
|
|
if ($country) {
|
|
$address->country_id = $country->id;
|
|
}
|
|
|
|
$address->contact_id = $contact->id;
|
|
$address->account_id = $contact->account_id;
|
|
$address->save();
|
|
}
|
|
|
|
if (! is_null($this->formatValue($vcard->EMAIL))) {
|
|
// Saves the email
|
|
$contactField = new ContactField;
|
|
$contactField->contact_id = $contact->id;
|
|
$contactField->account_id = $contact->account_id;
|
|
$contactField->data = $this->formatValue($vcard->EMAIL);
|
|
$contactField->contact_field_type_id = $this->contactFieldEmailId();
|
|
$contactField->save();
|
|
}
|
|
|
|
if (! is_null($this->formatValue($vcard->TEL))) {
|
|
// Saves the phone number
|
|
$contactField = new ContactField;
|
|
$contactField->contact_id = $contact->id;
|
|
$contactField->account_id = $contact->account_id;
|
|
$contactField->data = $this->formatValue($vcard->TEL);
|
|
$contactField->contact_field_type_id = $this->contactFieldPhoneId();
|
|
$contactField->save();
|
|
}
|
|
|
|
$contact->updateGravatar();
|
|
|
|
$contact->logEvent('contact', $contact->id, 'create');
|
|
}
|
|
|
|
private function contactFieldEmailId()
|
|
{
|
|
if (! $this->contactFieldEmailId) {
|
|
$contactFieldType = ContactFieldType::where('type', 'email')->first();
|
|
$this->contactFieldEmailId = $contactFieldType->id;
|
|
}
|
|
|
|
return $this->contactFieldEmailId;
|
|
}
|
|
|
|
private function contactFieldPhoneId()
|
|
{
|
|
if (! $this->contactFieldPhoneId) {
|
|
$contactFieldType = ContactFieldType::where('type', 'phone')->first();
|
|
$this->contactFieldPhoneId = $contactFieldType->id;
|
|
}
|
|
|
|
return $this->contactFieldPhoneId;
|
|
}
|
|
|
|
protected function workInit($matchCount)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
protected function workContactExists($vcard)
|
|
{
|
|
}
|
|
|
|
protected function workContactNoFirstname($vcard)
|
|
{
|
|
}
|
|
|
|
protected function workNext($vcard)
|
|
{
|
|
}
|
|
|
|
protected function workEnd($matchCount, $skippedContacts, $importedContacts)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Formats and returns a string for the contact.
|
|
*
|
|
* @param null|string $value
|
|
* @return null|string
|
|
*/
|
|
private function formatValue($value)
|
|
{
|
|
return ! empty((string) $value) ? (string) $value : null;
|
|
}
|
|
|
|
/**
|
|
* Checks whether a contact already exists for a given account.
|
|
*
|
|
* @param VCard $vcard
|
|
* @param int $account_id
|
|
* @return bool
|
|
*/
|
|
private function contactExists(VCard $vcard, int $account_id)
|
|
{
|
|
$email = (string) $vcard->EMAIL;
|
|
|
|
$contactFieldType = ContactFieldType::where([
|
|
['account_id', $account_id],
|
|
['type', 'email'],
|
|
])->first();
|
|
|
|
$contactField = null;
|
|
|
|
if ($contactFieldType) {
|
|
$contactField = ContactField::where([
|
|
['account_id', $account_id],
|
|
['data', $email],
|
|
['contact_field_type_id', $contactFieldType->id],
|
|
])->first();
|
|
}
|
|
|
|
return $email && $contactField;
|
|
}
|
|
|
|
/**
|
|
* Checks whether a contact has a first name or a nickname.
|
|
* Nickname is used as a fallback if no first name is provided.
|
|
*
|
|
* @param VCard $vcard
|
|
* @return bool
|
|
*/
|
|
public function contactHasName(VCard $vcard): bool
|
|
{
|
|
return ! empty($vcard->N->getParts()[1]) || ! empty((string) $vcard->NICKNAME);
|
|
}
|
|
}
|