1 | <?php |
||
23 | class Folder extends File { |
||
24 | |||
25 | private static $singular_name = "Folder"; |
||
26 | |||
27 | private static $plural_name = "Folders"; |
||
28 | |||
29 | public function exists() { |
||
32 | |||
33 | /** |
||
34 | * |
||
35 | */ |
||
36 | public function populateDefaults() { |
||
37 | parent::populateDefaults(); |
||
38 | |||
39 | if(!$this->Name) { |
||
40 | $this->Name = _t('AssetAdmin.NEWFOLDER', "NewFolder"); |
||
41 | } |
||
42 | } |
||
43 | |||
44 | /** |
||
45 | * Find the given folder or create it as a database record |
||
46 | * |
||
47 | * @param string $folderPath Directory path relative to assets root |
||
48 | * @return Folder|null |
||
49 | */ |
||
50 | public static function find_or_make($folderPath) { |
||
51 | // replace leading and trailing slashes |
||
52 | $folderPath = preg_replace('/^\/?(.*)\/?$/', '$1', trim($folderPath)); |
||
53 | $parts = explode("/",$folderPath); |
||
54 | |||
55 | $parentID = 0; |
||
56 | $item = null; |
||
57 | $filter = FileNameFilter::create(); |
||
58 | foreach($parts as $part) { |
||
59 | if(!$part) { |
||
60 | continue; // happens for paths with a trailing slash |
||
61 | } |
||
62 | |||
63 | // Ensure search includes folders with illegal characters removed, but |
||
64 | // err in favour of matching existing folders if $folderPath |
||
65 | // includes illegal characters itself. |
||
66 | $partSafe = $filter->filter($part); |
||
67 | $item = Folder::get()->filter(array( |
||
|
|||
68 | 'ParentID' => $parentID, |
||
69 | 'Name' => array($partSafe, $part) |
||
70 | ))->first(); |
||
71 | |||
72 | if(!$item) { |
||
73 | $item = new Folder(); |
||
74 | $item->ParentID = $parentID; |
||
75 | $item->Name = $partSafe; |
||
76 | $item->Title = $part; |
||
77 | $item->write(); |
||
78 | } |
||
79 | $parentID = $item->ID; |
||
80 | } |
||
81 | |||
82 | return $item; |
||
83 | } |
||
84 | |||
85 | public function onBeforeDelete() { |
||
86 | foreach($this->AllChildren() as $child) { |
||
87 | $child->delete(); |
||
88 | } |
||
89 | |||
90 | parent::onBeforeDelete(); |
||
91 | } |
||
92 | |||
93 | /** |
||
94 | * Override setting the Title of Folders to that Name and Title are always in sync. |
||
95 | * Note that this is not appropriate for files, because someone might want to create a human-readable name |
||
96 | * of a file that is different from its name on disk. But folders should always match their name on disk. |
||
97 | * |
||
98 | * @param string $title |
||
99 | * @return $this |
||
100 | */ |
||
101 | public function setTitle($title) { |
||
105 | |||
106 | /** |
||
107 | * Get the folder title |
||
108 | * |
||
109 | * @return string |
||
110 | */ |
||
111 | public function getTitle() { |
||
114 | |||
115 | /** |
||
116 | * Override setting the Title of Folders to that Name and Title are always in sync. |
||
117 | * Note that this is not appropriate for files, because someone might want to create a human-readable name |
||
118 | * of a file that is different from its name on disk. But folders should always match their name on disk. |
||
119 | * |
||
120 | * @param string $name |
||
121 | * @return $this |
||
122 | */ |
||
123 | public function setName($name) { |
||
124 | parent::setName($name); |
||
125 | $this->setField('Title', $this->Name); |
||
126 | return $this; |
||
127 | } |
||
128 | |||
129 | /** |
||
130 | * A folder doesn't have a (meaningful) file size. |
||
131 | * |
||
132 | * @return null |
||
133 | */ |
||
134 | public function getSize() { |
||
137 | |||
138 | /** |
||
139 | * Returns all children of this folder |
||
140 | * |
||
141 | * @return DataList |
||
142 | */ |
||
143 | public function myChildren() { |
||
146 | |||
147 | /** |
||
148 | * Returns true if this folder has children |
||
149 | * |
||
150 | * @return bool |
||
151 | */ |
||
152 | public function hasChildren() { |
||
155 | |||
156 | /** |
||
157 | * Returns true if this folder has children |
||
158 | * |
||
159 | * @return bool |
||
160 | */ |
||
161 | public function hasChildFolders() { |
||
164 | |||
165 | /** |
||
166 | * Return the FieldList used to edit this folder in the CMS. |
||
167 | * You can modify this FieldList by subclassing folder, or by creating a {@link DataExtension} |
||
168 | * and implemeting updateCMSFields(FieldList $fields) on that extension. |
||
169 | * |
||
170 | * @return FieldList |
||
171 | */ |
||
172 | public function getCMSFields() { |
||
173 | // Hide field on root level, which can't be renamed |
||
174 | if(!$this->ID || $this->ID === "root") { |
||
175 | $titleField = new HiddenField("Name"); |
||
176 | } else { |
||
177 | $titleField = new TextField("Name", $this->fieldLabel('Name')); |
||
178 | } |
||
179 | |||
180 | $fields = new FieldList( |
||
181 | $titleField, |
||
182 | new HiddenField('ParentID') |
||
183 | ); |
||
184 | $this->extend('updateCMSFields', $fields); |
||
185 | |||
186 | return $fields; |
||
187 | } |
||
188 | |||
189 | /** |
||
190 | * Get the children of this folder that are also folders. |
||
191 | * |
||
192 | * @return DataList |
||
193 | */ |
||
194 | public function ChildFolders() { |
||
197 | |||
198 | /** |
||
199 | * Get the number of children of this folder that are also folders. |
||
200 | * |
||
201 | * @return int |
||
202 | */ |
||
203 | public function numChildFolders() { |
||
206 | /** |
||
207 | * @return string |
||
208 | */ |
||
209 | public function CMSTreeClasses() { |
||
210 | $classes = sprintf('class-%s', $this->class); |
||
211 | |||
212 | if(!$this->canDelete()) { |
||
213 | $classes .= " nodelete"; |
||
214 | } |
||
215 | |||
216 | if(!$this->canEdit()) { |
||
217 | $classes .= " disabled"; |
||
218 | } |
||
219 | |||
220 | $classes .= $this->markingClasses('numChildFolders'); |
||
221 | |||
222 | return $classes; |
||
223 | } |
||
224 | |||
225 | /** |
||
226 | * @return string |
||
227 | */ |
||
228 | public function getTreeTitle() { |
||
229 | return sprintf( |
||
230 | "<span class=\"jstree-foldericon\"></span><span class=\"item\">%s</span>", |
||
231 | Convert::raw2att(preg_replace('~\R~u', ' ', $this->Title)) |
||
232 | ); |
||
233 | } |
||
234 | |||
235 | public function getFilename() { |
||
238 | |||
239 | /** |
||
240 | * Folders do not have public URLs |
||
241 | * |
||
242 | * @param bool $grant |
||
243 | * @return null|string |
||
244 | */ |
||
245 | public function getURL($grant = true) { |
||
248 | |||
249 | /** |
||
250 | * Folders do not have public URLs |
||
251 | * |
||
252 | * @return string |
||
253 | */ |
||
254 | public function getAbsoluteURL() { |
||
257 | |||
258 | public function onAfterWrite() { |
||
259 | parent::onAfterWrite(); |
||
260 | |||
261 | // No publishing UX for folders, so just cascade changes live |
||
262 | if(Versioned::get_stage() === Versioned::DRAFT) { |
||
263 | $this->publish(Versioned::DRAFT, Versioned::LIVE); |
||
264 | } |
||
265 | |||
266 | // Update draft version of all child records |
||
267 | $this->updateChildFilesystem(); |
||
268 | } |
||
269 | |||
270 | public function onAfterDelete() { |
||
271 | parent::onAfterDelete(); |
||
272 | |||
273 | // Cascade deletions to live |
||
274 | if(Versioned::get_stage() === Versioned::DRAFT) { |
||
275 | $this->deleteFromStage(Versioned::LIVE); |
||
276 | } |
||
277 | } |
||
278 | |||
279 | public function updateFilesystem() { |
||
282 | |||
283 | /** |
||
284 | * If a write is skipped due to no changes, ensure that nested records still get asked to update |
||
285 | */ |
||
286 | public function onAfterSkippedWrite() { |
||
289 | |||
290 | /** |
||
291 | * Update filesystem of all children |
||
292 | */ |
||
293 | public function updateChildFilesystem() { |
||
294 | // Don't synchronise on live (rely on publishing instead) |
||
295 | if(Versioned::get_stage() === Versioned::LIVE) { |
||
296 | return; |
||
297 | } |
||
298 | |||
299 | $this->flushCache(); |
||
300 | // Writing this record should trigger a write (and potential updateFilesystem) on each child |
||
301 | foreach ($this->AllChildren() as $child) { |
||
302 | $child->write(); |
||
303 | } |
||
304 | } |
||
305 | |||
306 | public function StripThumbnail() { |
||
309 | } |
||
310 |
This check looks for accesses to local static members using the fully qualified name instead of
self::
.While this is perfectly valid, the fully qualified name of
Certificate::TRIPLEDES_CBC
could just as well be replaced byself::TRIPLEDES_CBC
. Referencing local members withself::
assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.