123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- <?php
- /**
- * @package Grav\Common\User
- *
- * @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
- * @license MIT License; see LICENSE file for details.
- */
- namespace Grav\Common\User\DataUser;
- use Grav\Common\Data\Blueprint;
- use Grav\Common\Data\Blueprints;
- use Grav\Common\Data\Data;
- use Grav\Common\File\CompiledYamlFile;
- use Grav\Common\Grav;
- use Grav\Common\Media\Interfaces\MediaCollectionInterface;
- use Grav\Common\Page\Media;
- use Grav\Common\Page\Medium\Medium;
- use Grav\Common\Page\Medium\MediumFactory;
- use Grav\Common\User\Authentication;
- use Grav\Common\User\Interfaces\UserInterface;
- use Grav\Common\User\Traits\UserTrait;
- use Grav\Common\Utils;
- use Grav\Framework\Flex\Flex;
- use function is_array;
- /**
- * Class User
- * @package Grav\Common\User\DataUser
- */
- class User extends Data implements UserInterface
- {
- use UserTrait;
- /** @var MediaCollectionInterface */
- protected $_media;
- /**
- * User constructor.
- * @param array $items
- * @param Blueprint|null $blueprints
- */
- public function __construct(array $items = [], $blueprints = null)
- {
- // User can only be authenticated via login.
- unset($items['authenticated'], $items['authorized']);
- // Always set blueprints.
- if (null === $blueprints) {
- $blueprints = (new Blueprints)->get('user/account');
- }
- parent::__construct($items, $blueprints);
- }
- /**
- * @param string $offset
- * @return bool
- */
- #[\ReturnTypeWillChange]
- public function offsetExists($offset)
- {
- $value = parent::offsetExists($offset);
- // Handle special case where user was logged in before 'authorized' was added to the user object.
- if (false === $value && $offset === 'authorized') {
- $value = $this->offsetExists('authenticated');
- }
- return $value;
- }
- /**
- * @param string $offset
- * @return mixed
- */
- #[\ReturnTypeWillChange]
- public function offsetGet($offset)
- {
- $value = parent::offsetGet($offset);
- // Handle special case where user was logged in before 'authorized' was added to the user object.
- if (null === $value && $offset === 'authorized') {
- $value = $this->offsetGet('authenticated');
- $this->offsetSet($offset, $value);
- }
- return $value;
- }
- /**
- * @return bool
- */
- public function isValid(): bool
- {
- return $this->items !== null;
- }
- /**
- * Update object with data
- *
- * @param array $data
- * @param array $files
- * @return $this
- */
- public function update(array $data, array $files = [])
- {
- // Note: $this->merge() would cause infinite loop as it calls this method.
- parent::merge($data);
- return $this;
- }
- /**
- * Save user
- *
- * @return void
- */
- public function save()
- {
- /** @var CompiledYamlFile|null $file */
- $file = $this->file();
- if (!$file || !$file->filename()) {
- user_error(__CLASS__ . ': calling \$user = new ' . __CLASS__ . "() is deprecated since Grav 1.6, use \$grav['accounts']->load(\$username) or \$grav['accounts']->load('') instead", E_USER_DEPRECATED);
- }
- if ($file) {
- $username = $this->filterUsername((string)$this->get('username'));
- if (!$file->filename()) {
- $locator = Grav::instance()['locator'];
- $file->filename($locator->findResource('account://' . $username . YAML_EXT, true, true));
- }
- // if plain text password, hash it and remove plain text
- $password = $this->get('password') ?? $this->get('password1');
- if (null !== $password && '' !== $password) {
- $password2 = $this->get('password2');
- if (!\is_string($password) || ($password2 && $password !== $password2)) {
- throw new \RuntimeException('Passwords did not match.');
- }
- $this->set('hashed_password', Authentication::create($password));
- }
- $this->undef('password');
- $this->undef('password1');
- $this->undef('password2');
- $data = $this->items;
- if ($username === $data['username']) {
- unset($data['username']);
- }
- unset($data['authenticated'], $data['authorized']);
- $file->save($data);
- // We need to signal Flex Users about the change.
- /** @var Flex|null $flex */
- $flex = Grav::instance()['flex'] ?? null;
- $users = $flex ? $flex->getDirectory('user-accounts') : null;
- if (null !== $users) {
- $users->clearCache();
- }
- }
- }
- /**
- * @return MediaCollectionInterface|Media
- */
- public function getMedia()
- {
- if (null === $this->_media) {
- // Media object should only contain avatar, nothing else.
- $media = new Media($this->getMediaFolder() ?? '', $this->getMediaOrder(), false);
- $path = $this->getAvatarFile();
- if ($path && is_file($path)) {
- $medium = MediumFactory::fromFile($path);
- if ($medium) {
- $media->add(Utils::basename($path), $medium);
- }
- }
- $this->_media = $media;
- }
- return $this->_media;
- }
- /**
- * @return string
- */
- public function getMediaFolder()
- {
- return $this->blueprints()->fields()['avatar']['destination'] ?? 'account://avatars';
- }
- /**
- * @return array
- */
- public function getMediaOrder()
- {
- return [];
- }
- /**
- * Serialize user.
- *
- * @return string[]
- */
- public function __sleep()
- {
- return [
- 'items',
- 'storage'
- ];
- }
- /**
- * Unserialize user.
- */
- public function __wakeup()
- {
- $this->gettersVariable = 'items';
- $this->nestedSeparator = '.';
- if (null === $this->items) {
- $this->items = [];
- }
- // Always set blueprints.
- if (null === $this->blueprints) {
- $this->blueprints = (new Blueprints)->get('user/account');
- }
- }
- /**
- * Merge two configurations together.
- *
- * @param array $data
- * @return $this
- * @deprecated 1.6 Use `->update($data)` instead (same but with data validation & filtering, file upload support).
- */
- public function merge(array $data)
- {
- user_error(__CLASS__ . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6, use ->update($data) method instead', E_USER_DEPRECATED);
- return $this->update($data);
- }
- /**
- * Return media object for the User's avatar.
- *
- * @return Medium|null
- * @deprecated 1.6 Use ->getAvatarImage() method instead.
- */
- public function getAvatarMedia()
- {
- user_error(__CLASS__ . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6, use getAvatarImage() method instead', E_USER_DEPRECATED);
- return $this->getAvatarImage();
- }
- /**
- * Return the User's avatar URL
- *
- * @return string
- * @deprecated 1.6 Use ->getAvatarUrl() method instead.
- */
- public function avatarUrl()
- {
- user_error(__CLASS__ . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6, use getAvatarUrl() method instead', E_USER_DEPRECATED);
- return $this->getAvatarUrl();
- }
- /**
- * Checks user authorization to the action.
- * Ensures backwards compatibility
- *
- * @param string $action
- * @return bool
- * @deprecated 1.5 Use ->authorize() method instead.
- */
- public function authorise($action)
- {
- user_error(__CLASS__ . '::' . __FUNCTION__ . '() is deprecated since Grav 1.5, use authorize() method instead', E_USER_DEPRECATED);
- return $this->authorize($action) ?? false;
- }
- /**
- * Implements Countable interface.
- *
- * @return int
- * @deprecated 1.6 Method makes no sense for user account.
- */
- #[\ReturnTypeWillChange]
- public function count()
- {
- user_error(__CLASS__ . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6', E_USER_DEPRECATED);
- return parent::count();
- }
- /**
- * @param string $username
- * @return string
- */
- protected function filterUsername(string $username): string
- {
- return mb_strtolower($username);
- }
- /**
- * @return string|null
- */
- protected function getAvatarFile(): ?string
- {
- $avatars = $this->get('avatar');
- if (is_array($avatars) && $avatars) {
- $avatar = array_shift($avatars);
- return $avatar['path'] ?? null;
- }
- return null;
- }
- }
|