|
1 <?php |
|
2 |
|
3 /* |
|
4 * This file is part of the FOSUserBundle package. |
|
5 * |
|
6 * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/> |
|
7 * |
|
8 * For the full copyright and license information, please view the LICENSE |
|
9 * file that was distributed with this source code. |
|
10 */ |
|
11 |
|
12 namespace FOS\UserBundle\Document; |
|
13 |
|
14 use Doctrine\ODM\MongoDB\DocumentManager; |
|
15 use Doctrine\ODM\MongoDB\Proxy\Proxy; |
|
16 use FOS\UserBundle\Model\UserInterface; |
|
17 use FOS\UserBundle\Model\UserManager as BaseUserManager; |
|
18 use FOS\UserBundle\Util\CanonicalizerInterface; |
|
19 use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; |
|
20 use Symfony\Component\Validator\Constraint; |
|
21 |
|
22 class UserManager extends BaseUserManager |
|
23 { |
|
24 protected $dm; |
|
25 protected $repository; |
|
26 protected $class; |
|
27 |
|
28 /** |
|
29 * Constructor. |
|
30 * |
|
31 * @param EncoderFactoryInterface $encoderFactory |
|
32 * @param string $algorithm |
|
33 * @param CanonicalizerInterface $usernameCanonicalizer |
|
34 * @param CanonicalizerInterface $emailCanonicalizer |
|
35 * @param DocumentManager $dm |
|
36 * @param string $class |
|
37 */ |
|
38 public function __construct(EncoderFactoryInterface $encoderFactory, $algorithm, CanonicalizerInterface $usernameCanonicalizer, CanonicalizerInterface $emailCanonicalizer, DocumentManager $dm, $class) |
|
39 { |
|
40 parent::__construct($encoderFactory, $algorithm, $usernameCanonicalizer, $emailCanonicalizer); |
|
41 |
|
42 $this->dm = $dm; |
|
43 $this->repository = $dm->getRepository($class); |
|
44 |
|
45 $metadata = $dm->getClassMetadata($class); |
|
46 $this->class = $metadata->name; |
|
47 } |
|
48 |
|
49 /** |
|
50 * {@inheritDoc} |
|
51 */ |
|
52 public function deleteUser(UserInterface $user) |
|
53 { |
|
54 $this->dm->remove($user); |
|
55 $this->dm->flush(); |
|
56 } |
|
57 |
|
58 /** |
|
59 * {@inheritDoc} |
|
60 */ |
|
61 public function getClass() |
|
62 { |
|
63 return $this->class; |
|
64 } |
|
65 |
|
66 /** |
|
67 * {@inheritDoc} |
|
68 */ |
|
69 public function findUserBy(array $criteria) |
|
70 { |
|
71 return $this->repository->findOneBy($criteria); |
|
72 } |
|
73 |
|
74 /** |
|
75 * {@inheritDoc} |
|
76 */ |
|
77 public function findUsers() |
|
78 { |
|
79 return $this->repository->findAll(); |
|
80 } |
|
81 |
|
82 /** |
|
83 * {@inheritDoc} |
|
84 */ |
|
85 public function reloadUser(UserInterface $user) |
|
86 { |
|
87 $this->dm->refresh($user); |
|
88 } |
|
89 |
|
90 /** |
|
91 * Updates a user. |
|
92 * |
|
93 * @param UserInterface $user |
|
94 * @param Boolean $andFlush Whether to flush the changes (default true) |
|
95 */ |
|
96 public function updateUser(UserInterface $user, $andFlush = true) |
|
97 { |
|
98 $this->updateCanonicalFields($user); |
|
99 $this->updatePassword($user); |
|
100 |
|
101 $this->dm->persist($user); |
|
102 if ($andFlush) { |
|
103 $this->dm->flush(); |
|
104 } |
|
105 } |
|
106 |
|
107 /** |
|
108 * {@inheritDoc} |
|
109 */ |
|
110 public function validateUnique(UserInterface $value, Constraint $constraint) |
|
111 { |
|
112 // Since we probably want to validate the canonical fields, |
|
113 // we'd better make sure we have them. |
|
114 $this->updateCanonicalFields($value); |
|
115 |
|
116 $classMetadata = $this->dm->getClassMetadata($this->class); |
|
117 // TODO: ODM seems to be missing handling for multiple properties |
|
118 // $fields = array_map('trim', explode(',', $constraint->property)); |
|
119 $query = $this->getQueryArray($classMetadata, $value, $constraint->property); |
|
120 |
|
121 $document = $this->findUserBy($query); |
|
122 if (null === $document) { |
|
123 return true; |
|
124 } |
|
125 |
|
126 // check if document in mongodb is the same document as the checked one |
|
127 if ($document->isUser($value)) { |
|
128 return true; |
|
129 } |
|
130 // check if returned document is proxy and initialize the minimum identifier if needed |
|
131 if ($document instanceof Proxy) { |
|
132 $classMetadata->setIdentifierValue($document, $document->__identifier); |
|
133 } |
|
134 // check if document has the same identifier as the current one |
|
135 if ($classMetadata->getIdentifierValue($document) === $classMetadata->getIdentifierValue($value)) { |
|
136 return true; |
|
137 } |
|
138 |
|
139 return false; |
|
140 } |
|
141 |
|
142 protected function getQueryArray($classMetadata, $value, $fieldName) |
|
143 { |
|
144 $field = $this->getFieldNameFromPropertyPath($fieldName); |
|
145 if (!isset($classMetadata->fieldMappings[$field])) { |
|
146 throw new \LogicException("Mapping for '$fieldName' doesn't exist for " . $this->class); |
|
147 } |
|
148 |
|
149 $mapping = $classMetadata->fieldMappings[$field]; |
|
150 if (isset($mapping['reference']) && $mapping['reference']) { |
|
151 throw new \LogicException('Cannot determine uniqueness of referenced document values'); |
|
152 } |
|
153 |
|
154 $criteria[$field] = $value instanceOf UserInterface ? $classMetadata->getFieldValue($value, $field) : $value; |
|
155 |
|
156 return $criteria; |
|
157 } |
|
158 |
|
159 /** |
|
160 * Returns the actual document field value. |
|
161 * |
|
162 * E.g. document.someVal -> document |
|
163 * user.emails -> user |
|
164 * username -> username |
|
165 * |
|
166 * @param string $field |
|
167 * @return string |
|
168 */ |
|
169 protected function getFieldNameFromPropertyPath($field) |
|
170 { |
|
171 $pieces = explode('.', $field); |
|
172 return $pieces[0]; |
|
173 } |
|
174 } |