UserCollection.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. <?php
  2. /**
  3. * @package Grav\Common\User
  4. *
  5. * @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
  6. * @license MIT License; see LICENSE file for details.
  7. */
  8. namespace Grav\Common\User\DataUser;
  9. use Grav\Common\Data\Blueprints;
  10. use Grav\Common\File\CompiledYamlFile;
  11. use Grav\Common\Grav;
  12. use Grav\Common\User\Interfaces\UserCollectionInterface;
  13. use Grav\Common\User\Interfaces\UserInterface;
  14. use Grav\Common\Utils;
  15. use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
  16. use RuntimeException;
  17. use function count;
  18. use function in_array;
  19. use function is_string;
  20. /**
  21. * Class UserCollection
  22. * @package Grav\Common\User\DataUser
  23. */
  24. class UserCollection implements UserCollectionInterface
  25. {
  26. /** @var string */
  27. private $className;
  28. /**
  29. * UserCollection constructor.
  30. * @param string $className
  31. */
  32. public function __construct(string $className)
  33. {
  34. $this->className = $className;
  35. }
  36. /**
  37. * Load user account.
  38. *
  39. * Always creates user object. To check if user exists, use $this->exists().
  40. *
  41. * @param string $username
  42. * @return UserInterface
  43. */
  44. public function load($username): UserInterface
  45. {
  46. $username = (string)$username;
  47. $grav = Grav::instance();
  48. /** @var UniformResourceLocator $locator */
  49. $locator = $grav['locator'];
  50. // Filter username.
  51. $username = $this->filterUsername($username);
  52. $filename = 'account://' . $username . YAML_EXT;
  53. $path = $locator->findResource($filename) ?: $locator->findResource($filename, true, true);
  54. if (!is_string($path)) {
  55. throw new RuntimeException('Internal Error');
  56. }
  57. $file = CompiledYamlFile::instance($path);
  58. $content = (array)$file->content() + ['username' => $username, 'state' => 'enabled'];
  59. $userClass = $this->className;
  60. $callable = static function () {
  61. $blueprints = new Blueprints;
  62. return $blueprints->get('user/account');
  63. };
  64. /** @var UserInterface $user */
  65. $user = new $userClass($content, $callable);
  66. $user->file($file);
  67. return $user;
  68. }
  69. /**
  70. * Find a user by username, email, etc
  71. *
  72. * @param string $query the query to search for
  73. * @param array $fields the fields to search
  74. * @return UserInterface
  75. */
  76. public function find($query, $fields = ['username', 'email']): UserInterface
  77. {
  78. $fields = (array)$fields;
  79. $grav = Grav::instance();
  80. /** @var UniformResourceLocator $locator */
  81. $locator = $grav['locator'];
  82. $account_dir = $locator->findResource('account://');
  83. if (!is_string($account_dir)) {
  84. return $this->load('');
  85. }
  86. $files = array_diff(scandir($account_dir) ?: [], ['.', '..']);
  87. // Try with username first, you never know!
  88. if (in_array('username', $fields, true)) {
  89. $user = $this->load($query);
  90. unset($fields[array_search('username', $fields, true)]);
  91. } else {
  92. $user = $this->load('');
  93. }
  94. // If not found, try the fields
  95. if (!$user->exists()) {
  96. $query = mb_strtolower($query);
  97. foreach ($files as $file) {
  98. if (Utils::endsWith($file, YAML_EXT)) {
  99. $find_user = $this->load(trim(Utils::pathinfo($file, PATHINFO_FILENAME)));
  100. foreach ($fields as $field) {
  101. if (isset($find_user[$field]) && mb_strtolower($find_user[$field]) === $query) {
  102. return $find_user;
  103. }
  104. }
  105. }
  106. }
  107. }
  108. return $user;
  109. }
  110. /**
  111. * Remove user account.
  112. *
  113. * @param string $username
  114. * @return bool True if the action was performed
  115. */
  116. public function delete($username): bool
  117. {
  118. $file_path = Grav::instance()['locator']->findResource('account://' . $username . YAML_EXT);
  119. return $file_path && unlink($file_path);
  120. }
  121. /**
  122. * @return int
  123. */
  124. public function count(): int
  125. {
  126. // check for existence of a user account
  127. $account_dir = $file_path = Grav::instance()['locator']->findResource('account://');
  128. $accounts = glob($account_dir . '/*.yaml') ?: [];
  129. return count($accounts);
  130. }
  131. /**
  132. * @param string $username
  133. * @return string
  134. */
  135. protected function filterUsername(string $username): string
  136. {
  137. return mb_strtolower($username);
  138. }
  139. }