/
Pagefiles.php
945 lines (857 loc) · 25.3 KB
/
Pagefiles.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
<?php namespace ProcessWire;
/**
* ProcessWire Pagefiles
*
* #pw-summary Pagefiles is a type of WireArray that contains Pagefile objects. It also acts as the value for multi-file fields in ProcessWire.
* #pw-body =
* The items in a Pagefiles array are `Pagefile` objects, indexed by file basename, i.e. `myfile.pdf`.
* Information on most traversal, filtering and manipulation methods can be found in the `WireArray` class that Pagefiles extends.
* In the examples below, `$page->files` is an instance of Pagefiles:
* ~~~~~
* // Determining if any files are present
* if($page->files->count()) {
* // There are files here
* }
*
* // Traversing and outputting links to all files
* foreach($page->files as $name => $pagefile) {
* echo "<li><a href='$pagefile->url'>$name: $pagefile->description</a></li>";
* }
*
* // Adding new file(s)
* $page->files->add('/path/to/file.pdf');
* $page->files->add('http://domain.com/photo.png');
* $page->save('files');
*
* // Getting file by name
* $pagefile = $page->files->getFile('file.pdf');
* $pagefile = $page->files['file.pdf']; // alternate
*
* // Getting first and last file
* $pagefile = $page->files->first();
* $pagefile = $page->files->last();
* ~~~~~
*
* #pw-body
*
* Typically a Pagefiles object will be associated with a specific field attached to a Page.
* There may be multiple instances of Pagefiles attached to a given Page (depending on what fields are in it's fieldgroup).
*
* ProcessWire 3.x, Copyright 2018 by Ryan Cramer
* https://processwire.com
*
*
* @property string $path Returns the full server disk path where files are stored.
* @property string $url Returns the URL where files are stored.
* @property Page $page Returns the Page that contains this set of files, same as the getPage() method. #pw-group-other
* @property Field $field Returns the Field that contains this set of files, same as the getField() method. #pw-group-other
* @method Pagefiles delete() delete(Pagefile $file) Removes the file and deletes from disk when page is saved. #pw-group-manipulation
* @method Pagefile|bool clone(Pagefile $item, array $options = array()) Duplicate a file and return it. #pw-group-manipulation
*
*/
class Pagefiles extends WireArray implements PageFieldValueInterface {
/**
* The Page object associated with these Pagefiles
*
* @var Page
*
*/
protected $page;
/**
* The Field object associated with these Pagefiles
*
* @var Field
*
*/
protected $field;
/**
* Items to be deleted when Page is saved
*
* @var array
*
*/
protected $unlinkQueue = array();
/**
* Items to be renamed when Page is saved (oldName => newName)
*
* @var array
*
*/
protected $renameQueue = array();
/**
* Items to be made non-temp upon page save (like duplicated files)
*
* @var array
*
*/
protected $unTempQueue = array();
/**
* IDs of any hooks added in this instance, used by the destructor
*
* @var array
*
*/
protected $hookIDs = array();
/**
* Whether or not this is a formatted value
*
* @var bool
*
*/
protected $formatted = false;
/**
* Construct a Pagefiles object
*
* @param Page $page The page associated with this Pagefiles instance
*
*/
public function __construct(Page $page) {
$this->setPage($page);
}
/**
* Destruct and ensure that hooks are removed
*
*/
public function __destruct() {
$this->removeHooks();
}
/**
* Remove hooks to the PagefilesManager instance
*
*/
protected function removeHooks() {
if(count($this->hookIDs) && $this->page && $this->page->filesManager) {
foreach($this->hookIDs as $id) $this->page->filesManager->removeHook($id);
}
}
/**
* Set the Page these files are assigned to
*
* @param Page $page
*
*/
public function setPage(Page $page) {
$this->page = $page;
// call the filesmanager, just to ensure paths are where they should be
$page->filesManager();
}
/**
* Set the field these files are assigned to
*
* @param Field $field
*
*/
public function setField(Field $field) {
$this->field = $field;
}
/**
* Get the page these files are assigned to
*
* @return Page
*
*/
public function getPage() {
return $this->page;
}
/**
* Get the field these files are assigned to
*
* @return Field|null Returns Field, or null if Field has not yet been assigned.
*
*/
public function getField() {
return $this->field;
}
/**
* Creates a new blank instance of itself. For internal use, part of the WireArray interface.
*
* Adapted here so that $this->page can be passed to the constructor of a newly created Pagefiles.
*
* #pw-internal
*
* @return Pagefiles|WireArray
*
*/
public function makeNew() {
$class = get_class($this);
$newArray = $this->wire(new $class($this->page));
$newArray->setField($this->field);
return $newArray;
}
/**
* Make a copy, overriding the default clone method used by WireArray::makeCopy
*
* This is necessary because our __clone() makes new copies of each Pagefile (deep clone)
* and we don't want that to occur for the regular find() and filter() operations that
* make use of makeCopy().
*
* #pw-internal
*
* @return Pagefiles
*
*/
public function makeCopy() {
$newArray = $this->makeNew();
foreach($this->data as $key => $value) $newArray[$key] = $value;
foreach($this->extraData as $key => $value) $newArray->data($key, $value);
$newArray->resetTrackChanges($this->trackChanges());
foreach($newArray as $item) $item->setPagefilesParent($newArray);
return $newArray;
}
/**
* When Pagefiles is cloned, ensure that the individual Pagefile items are also cloned
*
* #pw-internal
*
*/
public function __clone() {
foreach($this as $key => $pagefile) {
$pagefile = clone $pagefile;
$pagefile->setPagefilesParent($this);
$this->set($key, $pagefile);
}
parent::__clone();
}
/**
* Per the WireArray interface, items must be of type Pagefile
*
* #pw-internal
*
* @param mixed $item
* @return bool
*
*/
public function isValidItem($item) {
return $item instanceof Pagefile;
}
/**
* Per the WireArray interface, items are indexed by Pagefile::basename
*
* #pw-internal
*
* @param mixed $item
* @return string
*
*/
public function getItemKey($item) {
return $item->basename;
}
/**
* Per the WireArray interface, return a blank Pagefile
*
* #pw-internal
*
* @return Pagefile
*
*/
public function makeBlankItem() {
return $this->wire(new Pagefile($this, ''));
}
/**
* Get a value from this Pagefiles instance
*
* You may also specify a file's 'tag' and it will return the first Pagefile matching the tag.
*
* #pw-internal
*
* @param string $key
* @return mixed
*
*/
public function get($key) {
if($key == 'page') return $this->getPage();
if($key == 'field') return $this->getField();
if($key == 'url') return $this->url();
if($key == 'path') return $this->path();
return parent::get($key);
}
/**
* Get for direct access to properties
*
* @param int|string $key
* @return bool|mixed|Page|Wire|WireData
*
*/
public function __get($key) {
if(in_array($key, array('page', 'field', 'url', 'path'))) return $this->get($key);
return parent::__get($key);
}
/**
* Find all Pagefiles matching the given selector string or tag
*
* @param string $selector
* @return Pagefiles New instance of Pagefiles
*
public function find($selector) {
if(!Selectors::stringHasOperator($selector)) {
// if there is no selector operator in the strong, consider it a tag first
$value = $this->findTag($selector);
// if it didn't match any tag, then see if it matches in some other way
if(!count($value)) $value = parent::find($selector);
} else {
// there is an operator so we send it straight to WireArray
$value = parent::find($selector);
}
return $value;
}
*/
/**
* Add a new Pagefile item or filename
*
* If give a filename (string) it will create the new `Pagefile` item from it and add it.
*
* #pw-group-manipulation
*
* @param Pagefile|string $item If item is a string (filename) it will create the new `Pagefile` item from it and add it.
* @return $this
*
*/
public function add($item) {
if(is_string($item)) {
/** @var Pagefile $item */
$item = $this->wire(new Pagefile($this, $item));
} else if($item instanceof Pagefile) {
$page = $this->get('page');
if($page && "$page" !== "$item->page") {
$newItem = clone $item;
$newItem->setPagefilesParent($this);
$newItem->install($item->filename);
$newItem->isTemp(true);
$this->unTempQueue($newItem);
$this->message("Copied $item->url to $newItem->url", Notice::debug);
$item = $newItem;
}
}
/** @var Pagefiles $result */
$result = parent::add($item);
return $result;
}
/**
* Make any removals take effect on disk
*
* #pw-internal
*
*/
public function hookPageSave() {
if($this->page && $this->field && !$this->page->isChanged($this->field->name)) return $this;
foreach($this->unTempQueue as $item) {
$item->isTemp(false);
}
foreach($this->unlinkQueue as $item) {
$item->unlink();
}
foreach($this->renameQueue as $item) {
$name = $item->get('_rename');
if(!$name) continue;
$item->rename($name);
}
$this->unTempQueue = array();
$this->unlinkQueue = array();
$this->renameQueue = array();
$this->removeHooks();
return $this;
}
protected function addSaveHook() {
if(!count($this->unlinkQueue) && !count($this->renameQueue) && !count($this->unTempQueue)) {
$this->hookIDs[] = $this->page->filesManager->addHookBefore('save', $this, 'hookPageSave');
}
}
/**
* Delete a pagefile item
*
* Deletes the filename associated with the Pagefile and removes it from this Pagefiles array.
* The actual deletion of the file does not take effect until `$page->save()`.
*
* #pw-group-manipulation
*
* @param Pagefile|string $item Pagefile or basename
* @return $this
*
*/
public function ___delete($item) {
return $this->remove($item);
}
/**
* Delete/remove a Pagefile item
*
* Deletes the filename associated with the Pagefile and removes it from this Pagefiles array.
* The actual deletion of the file does not take effect until `$page->save()`.
*
* #pw-internal Please use the hookable delete() method for public API
*
* @param Pagefile $item Item to delete/remove.
* @return $this
* @throws WireException
*
*/
public function remove($item) {
if(is_string($item)) $item = $this->get($item);
if(!$this->isValidItem($item)) throw new WireException("Invalid type to {$this->className}::remove(item)");
$this->addSaveHook();
$this->unlinkQueue[] = $item;
parent::remove($item);
return $this;
}
/**
* Delete all files associated with this Pagefiles instance, leaving a blank Pagefiles instance.
*
* The actual deletion of the files does not take effect until `$page->save()`.
*
* #pw-group-manipulation
*
* @return $this
*
*/
public function deleteAll() {
foreach($this as $item) {
$this->delete($item);
}
return $this;
}
/**
* Queue a rename of a Pagefile
*
* This only queues a rename. Rename actually occurs when page is saved.
* Note this differs from the behavior of `Pagefile::rename()`.
*
* #pw-group-manipulation
*
* @param Pagefile $item
* @param string $name
* @return Pagefiles
* @see Pagefile::rename()
*
*/
public function rename(Pagefile $item, $name) {
$item->set('_rename', $name);
$this->renameQueue[] = $item;
$this->trackChange('renameQueue', $item->name, $name);
$this->addSaveHook();
return $this;
}
/**
* Duplicate the Pagefile and add to this Pagefiles instance
*
* After duplicating a file, you must follow up with a save of the page containing it.
* Otherwise the file is marked for deletion.
*
* @param Pagefile $item Pagefile item to duplicate
* @param array $options Options to modify default behavior:
* - `action` (string): Specify "append", "prepend", "after", "before" or blank to only return Pagefile. (default="after")
* - `pagefiles` (Pagefiles): Pagefiles instance file should be duplicated to. (default=$this)
* @return Pagefile|bool Returns new Pagefile or boolean false on fail
*
*/
public function ___clone(Pagefile $item, array $options = array()) {
$defaults = array(
'action' => 'after',
'pagefiles' => $this,
);
$options = array_merge($defaults, $options);
/** @var Pagefiles $pagefiles */
$pagefiles = $options['pagefiles'];
$itemCopy = false;
$path = $pagefiles->path();
$parts = explode('.', $item->basename(), 2);
$n = $path === $this->path() ? 1 : 0;
if($n && preg_match('/^(.+?)-(\d+)$/', $parts[0], $matches)) {
$parts[0] = $matches[1];
$n = (int) $matches[2];
if(!$n) $n = 1;
}
do {
$pathname = $n ? ($path . $parts[0] . "-$n." . $parts[1]) : ($path . $item->basename);
} while(file_exists($pathname) && $n++);
if(copy($item->filename(), $pathname)) {
$this->wire('files')->chmod($pathname);
$itemCopy = clone $item;
$itemCopy->setPagefilesParent($pagefiles);
$itemCopy->setFilename($pathname);
$itemCopy->isTemp(true);
switch($options['action']) {
case 'append': $pagefiles->append($itemCopy); break;
case 'prepend': $pagefiles->prepend($itemCopy); break;
case 'before': $pagefiles->insertBefore($itemCopy, $item); break;
case 'after': $pagefiles->insertAfter($itemCopy, $item); break;
}
$pagefiles->unTempQueue($itemCopy);
}
return $itemCopy;
}
/**
* Return the full disk path where files are stored
*
* @return string
*
*/
public function path() {
return $this->page->filesManager->path();
}
/**
* Returns the web accessible index URL where files are stored
*
* @return string
*
*/
public function url() {
return $this->page->filesManager->url();
}
/**
* Given a basename, this method returns a clean version containing valid characters
*
* #pw-internal
*
* @param string $basename May also be a full path/filename, but it will still return a basename
* @param bool $originalize If true, it will generate an original filename if $basename already exists
* @param bool $allowDots If true, dots "." are allowed in the basename portion of the filename.
* @param bool $translate True if we should translate accented characters to ascii equivalents (rather than substituting underscores)
* @return string
*
*/
public function cleanBasename($basename, $originalize = false, $allowDots = true, $translate = false) {
$basename = strtolower($basename);
$dot = strrpos($basename, '.');
$ext = $dot ? substr($basename, $dot) : '';
$basename = basename($basename, $ext);
$test = str_replace(array('-', '_', '.'), '', $basename);
if(!ctype_alnum($test)) {
if($translate) {
$basename = $this->wire('sanitizer')->filename($basename, Sanitizer::translate);
} else {
$basename = preg_replace('/[^-_.a-z0-9]/', '_', $basename);
$basename = $this->wire('sanitizer')->filename($basename);
}
}
if(!ctype_alnum(ltrim($ext, '.'))) $ext = preg_replace('/[^a-z0-9.]/', '_', $ext);
if(!$allowDots && strpos($basename, '.') !== false) $basename = str_replace('.', '_', $basename);
$basename .= $ext;
if($originalize) {
$path = $this->path();
$n = 0;
$p = pathinfo($basename);
while(is_file($path . $basename)) {
$n++;
$basename = "$p[filename]-$n.$p[extension]"; // @hani
// $basename = (++$n) . "_" . preg_replace('/^\d+_/', '', $basename);
}
}
return $basename;
}
/**
* Return all Pagefile objects that have the given tag(s).
*
* Given tag may be any of the following:
*
* - `foo` (single tag): Will return all Pagefile objects having the specified tag.
* - `foo|bar|baz` (multiple OR tags): Will return Pagefile objects having at least one of the tags listed.
* - `foo,bar,baz` (multiple AND tags): Will return Pagefile objects having ALL of the tags listed (since 3.0.17).
* - `['foo','bar','baz']` (multiple AND tags array): Same as above but can be specified as an array (since 3.0.17).
*
* #pw-group-tags
* #pw-changelog 3.0.17 Added support for multiple AND tags and allow tag specified as an array.
*
* @param string|array $tag
* @return Pagefiles New Pagefiles array with items that matched the given tag(s).
* @see Pagefiles::getTag(), Pagefile::hasTag(), Pagefile::tags()
*
*/
public function findTag($tag) {
$items = $this->makeNew();
foreach($this as $pagefile) {
if($pagefile->hasTag($tag)) $items->add($pagefile);
}
return $items;
}
/**
* Return the first Pagefile that matches the given tag or NULL if no match
*
* Given tag may be any of the following:
*
* - `foo` (single tag): Will return the first Pagefile object having the specified tag.
* - `foo|bar|baz` (multiple OR tags): Will return first Pagefile object having at least one of the tags listed.
* - `foo,bar,baz` (multiple AND tags): Will return first Pagefile object having ALL of the tags listed (since 3.0.17).
* - `['foo','bar','baz']` (multiple AND tags array): Same as above but can be specified as an array (since 3.0.17).
*
* #pw-group-tags
* #pw-changelog 3.0.17 Added support for multiple AND tags and allow tag specified as an array.
*
* @param string $tag
* @return Pagefile|null
* @see Pagefiles::findTag(), Pagefile::hasTag(), Pagefile::tags()
*
*/
public function getTag($tag) {
$item = null;
foreach($this as $pagefile) {
if(!$pagefile->hasTag($tag)) continue;
$item = $pagefile;
break;
}
return $item;
}
/**
* Get list of tags for all files in this Pagefiles array, or return files matching given tag(s)
*
* This method can either return a list of all tags available, or return all files
* matching the given tag or tags (an alias of findTag method).
*
* ~~~~~
* // Get string of all tags
* $tagsString = $page->files->tags();
*
* // Get array of all tags
* $tagsArray = $page->files->tags(true);
*
* // Find all files matching given tag
* $pagefiles = $page->files->tags('foobar');
* ~~~~~
*
* #pw-group-tags
*
* @param bool|string|array $value Specify one of the following:
* - Omit to return all tags as a string.
* - Boolean true if you want to return tags as an array (rather than string).
* - Boolean false to return tags as an array, with lowercase enforced.
* - String if you want to return files matching tags (See `Pagefiles::findTag()` method for usage)
* - Array if you want to return files matching tags (See `Pagefiles::findTag()` method for usage)
* @return string|array|Pagefiles Returns all tags as a string or an array, or Pagefiles matching given tag(s).
* When a tags array is returned, it is an associative array where the key and value are both the tag (keys are always lowercase).
* @see Pagefiles::findTag(), Pagefile::tags()
*
*/
public function tags($value = null) {
if($value === null) {
$returnString = true;
$value = true;
} else {
$returnString = false;
}
if(is_bool($value)) {
// return array of tags
$tags = array();
foreach($this as $pagefile) {
$tags = array_merge($tags, $pagefile->tags($value));
}
if($returnString) $tags = implode(' ', $tags);
return $tags;
}
// fallback to behavior of findTag
return $this->findTag($value);
}
/**
* Track a change
*
* #pw-internal
*
* @param string $what
* @param null $old
* @param null $new
* @return $this
*
*/
public function trackChange($what, $old = null, $new = null) {
if($this->field && $this->page) $this->page->trackChange($this->field->name);
/** @var Pagefiles $result */
$result = parent::trackChange($what, $old, $new);
return $result;
}
/**
* Get the Pagefile having the given basename, or null if not found.
*
* @param string $name
* @return null|Pagefile
*
*/
public function getFile($name) {
$hasFile = null;
$name = basename($name);
foreach($this as $pagefile) {
if($pagefile->basename == $name) {
$hasFile = $pagefile;
break;
}
}
return $hasFile;
}
/**
* Returns true if the given Pagefile is temporary, not yet published.
*
* You may also provide a 2nd argument boolean to set the temp status or check if temporary AND deletable.
*
* #pw-internal
*
* @param Pagefile $pagefile
* @param bool|string $set Optionally set the temp status to true or false, or specify string "deletable" to check if file is temporary AND deletable.
* @return bool
*
*/
public function isTemp(Pagefile $pagefile, $set = null) {
$isTemp = Pagefile::createdTemp == $pagefile->created;
$checkDeletable = ($set === 'deletable' || $set === 'deleteable');
if(!is_bool($set)) {
// temp status is not being set
if(!$isTemp) return false; // if not a temp file, we can exit now
if(!$checkDeletable) return $isTemp; // if not checking deletable, we can exit now
}
$now = time();
$session = $this->wire('session');
$pageID = $this->page ? $this->page->id : 0;
$fieldID = $this->field ? $this->field->id : 0;
$sessionKey = "tempFiles_{$pageID}_{$fieldID}";
$tempFiles = $pageID && $fieldID ? $session->get($this, $sessionKey) : array();
if(!is_array($tempFiles)) $tempFiles = array();
if($isTemp && $checkDeletable) {
$isTemp = false;
if(isset($tempFiles[$pagefile->basename])) {
// if file was uploaded in this session and still temp, it is deletable
$isTemp = true;
} else if($pagefile->modified < ($now - 14400)) {
// if file was added more than 4 hours ago, it is deletable, regardless who added it
$isTemp = true;
}
// isTemp means isDeletable at this point
if($isTemp) {
unset($tempFiles[$pagefile->basename]);
// remove file from session - note that this means a 'deletable' check can only be used once, for newly uploaded files
// as it is assumed you will be removing the file as a result of this method call
if(count($tempFiles)) $session->set($this, $sessionKey, $tempFiles);
else $session->remove($this, $sessionKey);
}
}
if($set === true) {
// set temporary status to true
$pagefile->created = Pagefile::createdTemp;
$pagefile->modified = $now;
// mtime atime
@touch($pagefile->filename, Pagefile::createdTemp, $now);
$isTemp = true;
if($pageID && $fieldID) {
$tempFiles[$pagefile->basename] = 1;
$session->set($this, $sessionKey, $tempFiles);
}
} else if($set === false && $isTemp) {
// set temporary status to false
$pagefile->created = $now;
$pagefile->modified = $now;
@touch($pagefile->filename, $now);
$isTemp = false;
if(isset($tempFiles[$pagefile->basename])) {
unset($tempFiles[$pagefile->basename]);
if(count($tempFiles)) {
// set temp files back to session, minus current file
$session->set($this, $sessionKey, $tempFiles);
} else {
// if temp files is empty, we can remove it from the session
$session->remove($this, $sessionKey);
}
}
}
return $isTemp;
}
/**
* Remove all deletable temporary pagefiles immediately
*
* #pw-internal
*
* @return int Number of files removed
*
*/
public function deleteAllTemp() {
$removed = array();
foreach($this as $pagefile) {
if(!$this->isTemp($pagefile, 'deletable')) continue;
$removed[] = $pagefile->basename();
$this->remove($pagefile);
}
if(count($removed) && $this->page && $this->field) {
$this->page->save($this->field->name, array('quiet' => true));
$this->message("Removed '{$this->field->name}' temp file(s) for page {$this->page->path} - " . implode(', ', $removed), Notice::debug | Notice::log);
}
return count($removed);
}
/**
* Add Pagefile as item to have temporary status removed when Page is saved
*
* #pw-internal
*
* @param Pagefile $pagefile
*
*/
public function unTempQueue(Pagefile $pagefile) {
$this->addSaveHook();
$this->unTempQueue[] = $pagefile;
}
/**
* Is the given Pagefiles identical to this one?
*
* #pw-internal
*
* @param WireArray $items
* @param bool|int $strict
* @return bool
*
*/
public function isIdentical(WireArray $items, $strict = true) {
if($strict) return $this === $items;
return parent::isIdentical($items, $strict);
}
/**
* Reset track changes
*
* #pw-internal
*
* @param bool $trackChanges
* @return $this
*
*/
public function resetTrackChanges($trackChanges = true) {
$this->unlinkQueue = array();
if($this->page && $this->page->id && $this->field) {
$this->page->untrackChange($this->field->name);
}
/** @var Pagefiles $result */
$result = parent::resetTrackChanges($trackChanges);
return $result;
}
/**
* Uncache
*
* #pw-internal
*
*/
public function uncache() {
//$this->page = null;
}
/**
* Get or set formatted state
*
* @param bool|null $set
* @return bool
*
*/
public function formatted($set = null) {
if(is_bool($set)) $this->formatted = $set;
return $this->formatted;
}
/**
* Debug info
*
* @return array
*
*/
public function __debugInfo() {
$info = array(
'count' => $this->count(),
'page' => $this->page ? $this->page->path() : '?',
'field' => $this->field ? $this->field->name : '?',
'url' => $this->url(),
'path' => $this->path(),
'items' => array(),
);
foreach($this as $key => $pagefile) {
/** @var Pagefile $pagefile */
$info['items'][$key] = $pagefile->__debugInfo();
}
return $info;
}
}