<?php
namespace XF\Entity;
use XF\CustomField\Set;
use XF\Mvc\Entity\Entity;
use XF\Mvc\Entity\Structure;
use function in_array, intval;
/**
* COLUMNS
* @property int $user_id
* @property int $dob_day
* @property int $dob_month
* @property int $dob_year
* @property string $signature
* @property string $website
* @property string $location
* @property array $following
* @property array $ignored
* @property int $avatar_crop_x
* @property int $avatar_crop_y
* @property int $banner_date
* @property int|null $banner_position_y
* @property string $about
* @property array $custom_fields_
* @property array $connected_accounts
* @property int $password_date
*
* GETTERS
* @property bool|int $age
* @property array $birthday
* @property Set $custom_fields
*
* RELATIONS
* @property \XF\Entity\User $User
* @property \XF\Mvc\Entity\AbstractCollection|\XF\Entity\UserFieldValue[] $CustomFields
*/
class UserProfile extends Entity
{
public function isFollowing($user)
{
if ($user instanceof User)
{
$userId = $user->user_id;
}
else
{
$userId = $user;
}
return in_array($userId, $this->following);
}
protected function verifyLocation($location)
{
if ($this->getOption('admin_edit'))
{
return true;
}
if ($this->isUpdate() && $location == $this->getExistingValue('location'))
{
return true;
}
if ($this->getOption('location_required') && $location === '')
{
$this->error(\XF::phrase('please_enter_valid_location'), 'location');
return false;
}
return true;
}
protected function verifyLongStringField($value, $key)
{
$maxLength = $this->getOption('max_long_string_length');
if ($maxLength && utf8_strlen($value) > $maxLength)
{
$this->error(\XF::phrase('please_enter_message_with_no_more_than_x_characters', ['count' => $maxLength]), $key);
return false;
}
return true;
}
public function setDob($day, $month, $year = 0)
{
$day = intval($day);
$month = intval($month);
$year = intval($year);
if (!$day || !$month)
{
$this->dob_day = 0;
$this->dob_month = 0;
$this->dob_year = 0;
return true;
}
if ($year && $year < 100)
{
$year += $year < 30 ? 2000 : 1900;
}
$testYear = $year ? $year : 2008; // leap year
if ($testYear < 1900
|| !checkdate($month, $day, $testYear)
|| gmmktime(0, 0, 0, $month, $day, $testYear) > \XF::$time + 86400 // +1 day to be careful with TZs ahead of GMT
)
{
$this->dob_day = 0;
$this->dob_month = 0;
$this->dob_year = 0;
$this->error(\XF::phrase('please_enter_valid_date_of_birth'), 'dob');
return false;
}
$this->dob_day = $day;
$this->dob_month = $month;
$this->dob_year = $year;
return true;
}
public function calculateAge($year, $month, $day)
{
list($cYear, $cMonth, $cDay) = explode('-', $this->app()->language()->date(\XF::$time, 'Y-m-d'));
$age = $cYear - $year;
if ($cMonth < $month || ($cMonth == $month && $cDay < $day))
{
$age--;
}
return max(0, $age);
}
/**
* @param bool $bypassPrivacy
* @return bool|int
*/
public function getAge($bypassPrivacy = false)
{
if (empty($this->dob_year) || empty($this->dob_month) || empty($this->dob_day))
{
return false;
}
if ($this->dob_year && ($bypassPrivacy || ($this->User->Option->show_dob_date && $this->User->Option->show_dob_year)))
{
return $this->calculateAge($this->dob_year, $this->dob_month, $this->dob_day);
}
else
{
return false;
}
}
/**
* @param bool $bypassPrivacy
*
* @return array
*/
public function getBirthday($bypassPrivacy = false)
{
if ($this->dob_day && ($bypassPrivacy || $this->User->Option->show_dob_date))
{
if ($this->dob_year && ($bypassPrivacy || $this->User->Option->show_dob_year))
{
return [
'age' => $this->getAge($bypassPrivacy),
'timeStamp' => new \DateTime("$this->dob_year-$this->dob_month-$this->dob_day"),
'format' => 'absolute'
];
}
else
{
return [
'age' => false,
'timeStamp' => new \DateTime("2000-$this->dob_month-$this->dob_day"),
'format' => 'monthDay'
];
}
}
else
{
return [];
}
}
public function getAbstractedBannerPath($size)
{
$userId = $this->user_id;
return sprintf('data://profile_banners/%s/%d/%d.jpg',
$size,
floor($userId / 1000),
$userId
);
}
public function getBannerUrl($sizeCode, $canonical = false)
{
$app = $this->app();
$sizeMap = $app->container('profileBannerSizeMap');
if (!isset($sizeMap[$sizeCode]))
{
// Always fallback to 'l' by default in the event of an unknown size (most common)
$sizeCode = 'l';
}
if ($this->banner_date)
{
$group = floor($this->user_id / 1000);
return $app->applyExternalDataUrl(
"profile_banners/{$sizeCode}/{$group}/{$this->user_id}.jpg?{$this->banner_date}",
$canonical
);
}
else
{
return null;
}
}
/**
* @return Set
*/
public function getCustomFields()
{
$class = 'XF\CustomField\Set';
$class = $this->app()->extendClass($class);
$fieldDefinitions = $this->app()->container('customFields.users');
return new $class($fieldDefinitions, $this);
}
public function getNewProfilePost()
{
$profilePost = $this->_em->create('XF:ProfilePost');
$profilePost->profile_user_id = $this->user_id;
return $profilePost;
}
public function rebuildUserFieldValuesCache()
{
$this->repository('XF:UserField')->rebuildUserFieldValuesCache($this->user_id);
}
protected function _postSave()
{
$user = $this->User;
if ($this->isUpdate() && $this->isChanged('password_date') && $user->security_lock)
{
$user->whenSaveable(function (User $user)
{
$user->security_lock = '';
$user->save();
});
}
}
public static function getStructure(Structure $structure)
{
$structure->table = 'xf_user_profile';
$structure->shortName = 'XF:UserProfile';
$structure->primaryKey = 'user_id';
$structure->columns = [
'user_id' => ['type' => self::UINT, 'required' => true, 'changeLog' => false],
'dob_day' => ['type' => self::UINT, 'max' => 31, 'default' => 0],
'dob_month' => ['type' => self::UINT, 'max' => 12, 'default' => 0],
'dob_year' => ['type' => self::UINT, 'max' => 2100, 'default' => 0],
'signature' => ['type' => self::STR, 'maxLength' => 20000, 'default' => '',
'verify' => 'verifyLongStringField'
],
'website' => ['type' => self::STR, 'default' => '',
'censor' => true,
'match' => 'url_empty'
],
'location' => ['type' => self::STR, 'maxLength' => 50, 'default' => '',
'censor' => true
],
'following' => ['type' => self::LIST_COMMA, 'default' => [],
'list' => ['type' => 'posint', 'unique' => true, 'sort' => SORT_NUMERIC],
'changeLog' => false
],
'ignored' => ['type' => self::JSON_ARRAY, 'default' => [], 'changeLog' => false],
'avatar_crop_x' => ['type' => self::UINT, 'default' => 0, 'changeLog' => false],
'avatar_crop_y' => ['type' => self::UINT, 'default' => 0, 'changeLog' => false],
'banner_date' => ['type' => self::UINT, 'default' => 0],
'banner_position_y' => ['type' => self::UINT, 'max' => 100, 'default' => null, 'nullable' => true, 'changeLog' => false],
'about' => ['type' => self::STR, 'maxLength' => 20000, 'default' => '',
'verify' => 'verifyLongStringField',
],
'custom_fields' => ['type' => self::JSON_ARRAY, 'default' => [], 'changeLog' => 'customFields'],
'connected_accounts' => ['type' => self::JSON_ARRAY, 'default' => [], 'changeLog' => false],
'password_date' => ['type' => self::UINT, 'default' => 1, 'changeLog' => false]
];
$structure->behaviors = [
'XF:ChangeLoggable' => ['contentType' => 'user'],
'XF:CustomFieldsHolder' => ['valueTable' => 'xf_user_field_value']
];
$structure->getters = [
'age' => true,
'birthday' => true,
'custom_fields' => true
];
$structure->relations = [
'User' => [
'entity' => 'XF:User',
'type' => self::TO_ONE,
'conditions' => 'user_id',
'primary' => true
],
'CustomFields' => [
'entity' => 'XF:UserFieldValue',
'type' => self::TO_MANY,
'conditions' => 'user_id',
'key' => 'field_id'
]
];
$options = \XF::options();
$structure->options = [
'max_long_string_length' => !empty($options->messageMaxLength) ? $options->messageMaxLength : 10000,
'location_required' => !empty($options->registrationSetup['requireLocation']),
'admin_edit' => false
];
return $structure;
}
}