blob: 79a9d63d0be4d71c8e15d4dcedcc1ec600dcf26b [file] [log] [blame]
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001<?php
2
3namespace LdapRecord\Models\ActiveDirectory;
4
5use InvalidArgumentException;
6use LdapRecord\Connection;
7use LdapRecord\Models\Attributes\Sid;
8use LdapRecord\Models\Entry as BaseEntry;
9use LdapRecord\Models\Events\Updated;
10use LdapRecord\Models\Types\ActiveDirectory;
11use LdapRecord\Query\Model\ActiveDirectoryBuilder;
12
13/** @mixin ActiveDirectoryBuilder */
14class Entry extends BaseEntry implements ActiveDirectory
15{
16 /**
17 * The default attributes that should be mutated to dates.
18 *
19 * @var array
20 */
21 protected $defaultDates = [
22 'whenchanged' => 'windows',
23 'whencreated' => 'windows',
24 'dscorepropagationdata' => 'windows',
25 ];
26
27 /**
28 * The attribute key that contains the Object SID.
29 *
30 * @var string
31 */
32 protected $sidKey = 'objectsid';
33
34 /**
35 * @inheritdoc
36 */
37 public function getObjectSidKey()
38 {
39 return $this->sidKey;
40 }
41
42 /**
43 * @inheritdoc
44 */
45 public function getObjectSid()
46 {
47 return $this->getFirstAttribute($this->sidKey);
48 }
49
50 /**
51 * @inheritdoc
52 */
53 public function getConvertedSid()
54 {
55 try {
56 return (string) new Sid($this->getObjectSid());
57 } catch (InvalidArgumentException $e) {
58 return;
59 }
60 }
61
62 /**
63 * Create a new query builder.
64 *
65 * @param Connection $connection
66 *
67 * @return ActiveDirectoryBuilder
68 */
69 public function newQueryBuilder(Connection $connection)
70 {
71 return new ActiveDirectoryBuilder($connection);
72 }
73
74 /**
75 * Determine if the object is deleted.
76 *
77 * @return bool
78 */
79 public function isDeleted()
80 {
81 return strtoupper($this->getFirstAttribute('isDeleted')) === 'TRUE';
82 }
83
84 /**
85 * Restore a deleted object.
86 *
87 * @param string|null $newParentDn
88 *
89 * @throws \LdapRecord\LdapRecordException
90 *
91 * @return bool
92 */
93 public function restore($newParentDn = null)
94 {
95 if (! $this->isDeleted()) {
96 return false;
97 }
98
99 $root = $newParentDn ?? $this->getDefaultRestoreLocation();
100 $rdn = explode('\0A', $this->getDn(), 2)[0];
101 $newDn = implode(',', [$rdn, $root]);
102
103 // We will initialize a model listener for the "updated" event to set
104 // the models distinguished name so all attributes are synchronized
105 // properly after the model has been successfully restored.
106 $this->listenForModelEvent(Updated::class, function (Updated $event) use ($newDn) {
107 if ($this->is($event->getModel())) {
108 $this->setDn($newDn);
109 }
110 });
111
112 $this->save([
113 'isDeleted' => null,
114 'distinguishedName' => $newDn,
115 ]);
116 }
117
118 /**
119 * Get the RootDSE (AD schema) record from the directory.
120 *
121 * @param string|null $connection
122 *
123 * @throws \LdapRecord\Models\ModelNotFoundException
124 *
125 * @return static
126 */
127 public static function getRootDse($connection = null)
128 {
129 return static::on($connection ?? (new static())->getConnectionName())
130 ->in(null)
131 ->read()
132 ->whereHas('objectclass')
133 ->firstOrFail();
134 }
135
136 /**
137 * Get the objects restore location.
138 *
139 * @return string
140 */
141 protected function getDefaultRestoreLocation()
142 {
143 return $this->getFirstAttribute('lastKnownParent') ?? $this->getParentDn($this->getParentDn($this->getDn()));
144 }
145
146 /**
147 * Converts attributes for JSON serialization.
148 *
149 * @param array $attributes
150 *
151 * @return array
152 */
153 protected function convertAttributesForJson(array $attributes = [])
154 {
155 $attributes = parent::convertAttributesForJson($attributes);
156
157 if ($this->hasAttribute($this->sidKey)) {
158 // If the model has a SID set, we need to convert it due to it being in
159 // binary. Otherwise we will receive a JSON serialization exception.
160 return array_replace($attributes, [
161 $this->sidKey => [$this->getConvertedSid()],
162 ]);
163 }
164
165 return $attributes;
166 }
167}