Complex classes like AbstractStreamWrapper often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use AbstractStreamWrapper, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
47 | abstract class AbstractStreamWrapper |
||
48 | { |
||
49 | /** |
||
50 | * The registered protocol |
||
51 | * |
||
52 | * @var string |
||
53 | */ |
||
54 | protected static $protocol; |
||
55 | |||
56 | /** |
||
57 | * The path factory |
||
58 | * |
||
59 | * @var PathFactoryInterface |
||
60 | */ |
||
61 | protected static $pathFactory; |
||
62 | |||
63 | /** |
||
64 | * The buffer factory |
||
65 | * |
||
66 | * @var FactoryInterface |
||
67 | */ |
||
68 | protected static $bufferFactory; |
||
69 | |||
70 | /** |
||
71 | * The directory buffer if used on a directory |
||
72 | * |
||
73 | * @var ArrayBuffer |
||
74 | */ |
||
75 | protected $dirBuffer; |
||
76 | |||
77 | /** |
||
78 | * The file buffer if used on a file |
||
79 | * |
||
80 | * @var FileBufferInterface |
||
81 | */ |
||
82 | protected $fileBuffer; |
||
83 | |||
84 | /** |
||
85 | * The opened path |
||
86 | * |
||
87 | * @var PathInformationInterface |
||
88 | */ |
||
89 | protected $path; |
||
90 | |||
91 | /** |
||
92 | * The stream context if set |
||
93 | * |
||
94 | * @var resource |
||
95 | */ |
||
96 | public $context; |
||
97 | |||
98 | /** |
||
99 | * The parsed stream context options |
||
100 | * |
||
101 | * @var array |
||
102 | */ |
||
103 | protected $contextOptions; |
||
104 | |||
105 | /** |
||
106 | * The parsed stream context parameters |
||
107 | * |
||
108 | * @var array |
||
109 | */ |
||
110 | protected $contextParameters; |
||
111 | |||
112 | /** |
||
113 | * Registers the stream wrapper with the given protocol |
||
114 | * |
||
115 | * @param string $protocol The protocol (such as "vcs") |
||
116 | * @param PathFactoryInterface $pathFactory The path factory |
||
117 | * @param FactoryInterface $bufferFactory The buffer factory |
||
118 | * @throws \RuntimeException If $protocol is already registered |
||
119 | */ |
||
120 | 116 | protected static function doRegister($protocol, PathFactoryInterface $pathFactory, FactoryInterface $bufferFactory) |
|
121 | { |
||
122 | 116 | static::$protocol = $protocol; |
|
123 | 116 | static::$pathFactory = $pathFactory; |
|
124 | 116 | static::$bufferFactory = $bufferFactory; |
|
125 | |||
126 | 116 | if (!stream_wrapper_register($protocol, get_called_class())) { |
|
127 | throw new \RuntimeException(sprintf('The protocol "%s" is already registered with the |
||
128 | runtime or it cannot be registered', $protocol)); |
||
129 | } |
||
130 | 116 | } |
|
131 | |||
132 | /** |
||
133 | * Unregisters the stream wrapper |
||
134 | */ |
||
135 | 116 | public static function unregister() |
|
148 | |||
149 | /** |
||
150 | * Returns the repository registry |
||
151 | * |
||
152 | * @return RepositoryRegistry |
||
153 | */ |
||
154 | 12 | public static function getRepositoryRegistry() |
|
158 | |||
159 | /** |
||
160 | * Returns the path information for a given stream URL |
||
161 | * |
||
162 | * @param string $streamUrl The URL given to the stream function |
||
163 | * @return PathInformationInterface The path information representing the stream URL |
||
164 | */ |
||
165 | 114 | protected function getPath($streamUrl) |
|
169 | |||
170 | /** |
||
171 | * Creates the buffer factory |
||
172 | * |
||
173 | * @return FactoryInterface |
||
174 | */ |
||
175 | 52 | protected function getBufferFactory() |
|
179 | |||
180 | /** |
||
181 | * Parses the passed stream context and returns the context options |
||
182 | * relevant for this stream wrapper |
||
183 | * |
||
184 | * @param boolean $all Return all options instead of just the relevant options |
||
185 | * @return array The context options |
||
186 | */ |
||
187 | 42 | protected function getContextOptions($all = false) |
|
188 | { |
||
189 | 42 | if ($this->contextOptions === null) { |
|
190 | 42 | $this->contextOptions = stream_context_get_options($this->context); |
|
191 | } |
||
192 | |||
193 | 42 | if (!$all && array_key_exists(self::$protocol, $this->contextOptions)) { |
|
194 | 10 | return $this->contextOptions[self::$protocol]; |
|
195 | 32 | } else if ($all) { |
|
196 | return $this->contextOptions; |
||
197 | } else { |
||
198 | 32 | return array(); |
|
199 | } |
||
200 | } |
||
201 | |||
202 | /** |
||
203 | * Returns a context option - $default if option is not found |
||
204 | * |
||
205 | * @param string $option The option to retrieve |
||
206 | * @param mixed $default The default value if $option is not found |
||
207 | * @return mixed |
||
208 | */ |
||
209 | 42 | protected function getContextOption($option, $default = null) |
|
218 | |||
219 | /** |
||
220 | * Parses the passed stream context and returns the context parameters |
||
221 | * |
||
222 | * @return array The context parameters |
||
223 | */ |
||
224 | protected function getContextParameters() |
||
225 | { |
||
226 | if ($this->contextParameters === null) { |
||
227 | $this->contextParameters = stream_context_get_params($this->context); |
||
228 | } |
||
229 | return $this->contextParameters; |
||
230 | } |
||
231 | |||
232 | /** |
||
233 | * Returns a context parameter - $default if parameter is not found |
||
234 | * |
||
235 | * @param string $parameter The parameter to retrieve |
||
236 | * @param mixed $default The default value if $parameter is not found |
||
237 | * @return mixed |
||
238 | */ |
||
239 | protected function getContextParameter($parameter, $default = null) |
||
248 | |||
249 | /** |
||
250 | * streamWrapper::dir_closedir — Close directory handle |
||
251 | * |
||
252 | * @return boolean Returns TRUE on success or FALSE on failure. |
||
253 | */ |
||
254 | 18 | public function dir_closedir() |
|
260 | |||
261 | /** |
||
262 | * streamWrapper::dir_opendir — Open directory handle |
||
263 | * |
||
264 | * @param string $path Specifies the URL that was passed to {@see opendir()}. |
||
265 | * @param integer $options Whether or not to enforce safe_mode (0x04). |
||
266 | * @return boolean Returns TRUE on success or FALSE on failure. |
||
267 | */ |
||
268 | 18 | public function dir_opendir($path, $options) |
|
282 | |||
283 | /** |
||
284 | * streamWrapper::dir_readdir — Read entry from directory handle |
||
285 | * |
||
286 | * @return string|false Should return string representing the next filename, or FALSE if there is no next file. |
||
287 | */ |
||
288 | 18 | public function dir_readdir() |
|
294 | |||
295 | /** |
||
296 | * streamWrapper::dir_rewinddir — Rewind directory handle |
||
297 | * |
||
298 | * @return boolean Returns TRUE on success or FALSE on failure. |
||
299 | */ |
||
300 | 6 | public function dir_rewinddir() |
|
305 | |||
306 | /** |
||
307 | * streamWrapper::mkdir — Create a directory |
||
308 | * |
||
309 | * @param string $path Directory which should be created. |
||
310 | * @param integer $mode The value passed to {@see mkdir()}. |
||
311 | * @param integer $options A bitwise mask of values, such as STREAM_MKDIR_RECURSIVE. |
||
312 | * @return boolean Returns TRUE on success or FALSE on failure. |
||
313 | */ |
||
314 | 12 | public function mkdir($path, $mode, $options) |
|
315 | { |
||
316 | try { |
||
317 | 12 | $path = $this->getPath($path); |
|
318 | 12 | if ($path->getRef() != 'HEAD') { |
|
319 | 2 | throw new \Exception(sprintf( |
|
320 | 2 | 'Cannot create a non-HEAD directory [%s#%s]', $path->getFullPath(), $path->getRef() |
|
321 | )); |
||
322 | } |
||
323 | 10 | if (file_exists($path->getFullPath())) { |
|
324 | 2 | throw new \Exception(sprintf('Path %s already exists', $path->getFullPath())); |
|
325 | } |
||
326 | |||
327 | 8 | $recursive = self::maskHasFlag($options, STREAM_MKDIR_RECURSIVE); |
|
328 | |||
329 | 8 | $repo = $path->getRepository(); |
|
330 | |||
331 | 8 | $commitMsg = $this->getContextOption('commitMsg', null); |
|
332 | 8 | $author = $this->getContextOption('author', null); |
|
333 | |||
334 | 8 | $repo->createDirectory($path->getLocalPath(), $commitMsg, $mode, $recursive, $author); |
|
335 | 6 | return true; |
|
336 | 6 | } catch (\Exception $e) { |
|
337 | 6 | trigger_error($e->getMessage(), E_USER_WARNING); |
|
338 | return false; |
||
339 | } |
||
340 | } |
||
341 | |||
342 | /** |
||
343 | * streamWrapper::rename — Renames a file or directory |
||
344 | * |
||
345 | * @param string $path_from The URL to the current file. |
||
346 | * @param string $path_to The URL which the $path_from should be renamed to. |
||
347 | * @return boolean Returns TRUE on success or FALSE on failure. |
||
348 | */ |
||
349 | 10 | public function rename($path_from, $path_to) |
|
350 | { |
||
351 | try { |
||
352 | 10 | $pathFrom = $this->getPath($path_from); |
|
353 | 10 | if ($pathFrom->getRef() != 'HEAD') { |
|
354 | 2 | throw new \Exception(sprintf( |
|
355 | 2 | 'Cannot rename a non-HEAD file [%s#%s]', $pathFrom->getFullPath(), $pathFrom->getRef() |
|
356 | )); |
||
357 | } |
||
358 | 8 | if (!file_exists($pathFrom->getFullPath())) { |
|
359 | 2 | throw new \Exception(sprintf('Path %s not found', $pathFrom->getFullPath())); |
|
360 | } |
||
361 | |||
362 | 6 | if (!is_file($pathFrom->getFullPath())) { |
|
363 | 2 | throw new \Exception(sprintf('Path %s is not a file', $pathFrom->getFullPath())); |
|
364 | } |
||
365 | |||
366 | 4 | $pathTo = self::$pathFactory->parsePath($path_to); |
|
367 | 4 | $pathTo = $pathTo['path']; |
|
368 | |||
369 | 4 | if (strpos($pathTo, $pathFrom->getRepositoryPath()) !== 0) { |
|
370 | throw new \Exception(sprintf('Cannot rename across repositories [%s -> %s]', |
||
371 | $pathFrom->getFullPath(), $pathTo)); |
||
372 | } |
||
373 | |||
374 | 4 | $repo = $pathFrom->getRepository(); |
|
375 | |||
376 | 4 | $commitMsg = $this->getContextOption('commitMsg', null); |
|
377 | 4 | $author = $this->getContextOption('author', null); |
|
378 | |||
379 | 4 | $repo->renameFile($pathFrom->getLocalPath(), $pathTo, $commitMsg, false, $author); |
|
380 | 4 | return true; |
|
381 | 6 | } catch (\Exception $e) { |
|
382 | 6 | trigger_error($e->getMessage(), E_USER_WARNING); |
|
383 | return false; |
||
384 | } |
||
385 | } |
||
386 | |||
387 | /** |
||
388 | * streamWrapper::rmdir — Removes a directory |
||
389 | * |
||
390 | * @param string $path The directory URL which should be removed. |
||
391 | * @param integer $options A bitwise mask of values, such as STREAM_MKDIR_RECURSIVE. |
||
392 | * @return boolean Returns TRUE on success or FALSE on failure. |
||
393 | */ |
||
394 | 10 | public function rmdir($path, $options) |
|
395 | { |
||
396 | try { |
||
397 | 10 | $path = $this->getPath($path); |
|
398 | 10 | if ($path->getRef() != 'HEAD') { |
|
399 | 2 | throw new \Exception(sprintf( |
|
400 | 2 | 'Cannot remove a non-HEAD directory [%s#%s]', $path->getFullPath(), $path->getRef() |
|
401 | )); |
||
402 | } |
||
403 | 8 | if (!file_exists($path->getFullPath())) { |
|
404 | 2 | throw new \Exception(sprintf('Path %s not found', $path->getFullPath())); |
|
405 | } |
||
406 | 6 | if (!is_dir($path->getFullPath())) { |
|
407 | 2 | throw new \Exception(sprintf('Path %s is not a directory', $path->getFullPath())); |
|
408 | } |
||
409 | |||
410 | 4 | $options |= STREAM_MKDIR_RECURSIVE; |
|
411 | 4 | $recursive = self::maskHasFlag($options, STREAM_MKDIR_RECURSIVE); |
|
412 | |||
413 | 4 | $repo = $path->getRepository(); |
|
414 | |||
415 | 4 | $commitMsg = $this->getContextOption('commitMsg', null); |
|
416 | 4 | $author = $this->getContextOption('author', null); |
|
417 | |||
418 | 4 | $repo->removeFile($path->getLocalPath(), $commitMsg, $recursive, false, $author); |
|
419 | 4 | return true; |
|
420 | 6 | } catch (\Exception $e) { |
|
421 | 6 | trigger_error($e->getMessage(), E_USER_WARNING); |
|
422 | return false; |
||
423 | } |
||
424 | } |
||
425 | |||
426 | /** |
||
427 | * streamWrapper::stream_cast — Retrieve the underlaying resource |
||
428 | * |
||
429 | * @param integer $cast_as Can be STREAM_CAST_FOR_SELECT when stream_select() is calling stream_cast() |
||
430 | * or STREAM_CAST_AS_STREAM when stream_cast() is called for other uses. |
||
431 | * @return resource Should return the underlying stream resource used by the wrapper, or FALSE. |
||
432 | */ |
||
433 | /* |
||
434 | abstract public function stream_cast($cast_as); |
||
435 | */ |
||
436 | |||
437 | /** |
||
438 | * streamWrapper::stream_close — Close an resource |
||
439 | */ |
||
440 | 50 | public function stream_close() |
|
441 | { |
||
442 | 50 | $this->fileBuffer->close(); |
|
443 | 50 | $this->fileBuffer = null; |
|
444 | |||
445 | 50 | $repo = $this->path->getRepository(); |
|
446 | 50 | if ($repo->isDirty()) { |
|
447 | 22 | $repo->add(array($this->path->getFullPath())); |
|
448 | 22 | $commitMsg = $this->getContextOption('commitMsg', null); |
|
449 | 22 | $author = $this->getContextOption('author', null); |
|
450 | 22 | $repo->commit($commitMsg, array($this->path->getFullPath()), $author); |
|
451 | } |
||
452 | |||
453 | 50 | $this->path = null; |
|
454 | 50 | } |
|
455 | |||
456 | /** |
||
457 | * streamWrapper::stream_eof — Tests for end-of-file on a file pointer |
||
458 | * |
||
459 | * @return boolean Should return TRUE if the read/write position is at the end of the stream |
||
460 | * and if no more data is available to be read, or FALSE otherwise. |
||
461 | */ |
||
462 | 30 | public function stream_eof() |
|
466 | |||
467 | /** |
||
468 | * streamWrapper::stream_flush — Flushes the output |
||
469 | * |
||
470 | * @return boolean Should return TRUE if the cached data was successfully stored |
||
471 | * (or if there was no data to store), or FALSE if the data could not be stored. |
||
472 | */ |
||
473 | 22 | public function stream_flush() |
|
477 | |||
478 | /** |
||
479 | * streamWrapper::stream_lock — Advisory file locking |
||
480 | * |
||
481 | * @param integer $operation operation is one of the following: |
||
482 | * LOCK_SH to acquire a shared lock (reader). |
||
483 | * LOCK_EX to acquire an exclusive lock (writer). |
||
484 | * LOCK_UN to release a lock (shared or exclusive). |
||
485 | * LOCK_NB if you don't want flock() to block while locking. (not supported on Windows) |
||
486 | * @return boolean Returns TRUE on success or FALSE on failure. |
||
487 | */ |
||
488 | /* |
||
489 | abstract public function stream_lock($operation); |
||
490 | */ |
||
491 | |||
492 | /** |
||
493 | * streamWrapper::stream_metadata — Change stream options |
||
494 | * |
||
495 | * @param string $path The file path or URL to set metadata. Note that in the case of a URL, |
||
496 | * it must be a :// delimited URL. Other URL forms are not supported. |
||
497 | * @param integer $option One of: |
||
498 | * PHP_STREAM_META_TOUCH (The method was called in response to touch()) |
||
499 | * PHP_STREAM_META_OWNER_NAME (The method was called in response to chown() with string parameter) |
||
500 | * PHP_STREAM_META_OWNER (The method was called in response to chown()) |
||
501 | * PHP_STREAM_META_GROUP_NAME (The method was called in response to chgrp()) |
||
502 | * PHP_STREAM_META_GROUP (The method was called in response to chgrp()) |
||
503 | * PHP_STREAM_META_ACCESS (The method was called in response to chmod()) |
||
504 | * @param integer $var If option is |
||
505 | * PHP_STREAM_META_TOUCH: Array consisting of two arguments of the touch() function. |
||
506 | * PHP_STREAM_META_OWNER_NAME or PHP_STREAM_META_GROUP_NAME: The name of the owner |
||
507 | * user/group as string. |
||
508 | * PHP_STREAM_META_OWNER or PHP_STREAM_META_GROUP: The value owner user/group argument as integer. |
||
509 | * PHP_STREAM_META_ACCESS: The argument of the chmod() as integer. |
||
510 | * @return boolean Returns TRUE on success or FALSE on failure. If option is not implemented, FALSE should be returned. |
||
511 | */ |
||
512 | /* |
||
513 | abstract public function stream_metadata($path, $option, $var); |
||
514 | */ |
||
515 | |||
516 | /** |
||
517 | * streamWrapper::stream_open — Opens file or URL |
||
518 | * |
||
519 | * @param string $path Specifies the URL that was passed to the original function. |
||
520 | * @param string $mode The mode used to open the file, as detailed for fopen(). |
||
521 | * @param integer $options Holds additional flags set by the streams API. It can hold one or more of |
||
522 | * the following values OR'd together. |
||
523 | * STREAM_USE_PATH If path is relative, search for the resource using |
||
524 | * the include_path. |
||
525 | * STREAM_REPORT_ERRORS If this flag is set, you are responsible for raising |
||
526 | * errors using trigger_error() during opening of the |
||
527 | * stream. If this flag is not set, you should not raise |
||
528 | * any errors. |
||
529 | * @param string $opened_path If the path is opened successfully, and STREAM_USE_PATH is set in options, opened_path |
||
530 | * should be set to the full path of the file/resource that was actually opened. |
||
531 | * @return boolean Returns TRUE on success or FALSE on failure. |
||
532 | */ |
||
533 | 52 | public function stream_open($path, $mode, $options, &$opened_path) |
|
534 | { |
||
535 | try { |
||
536 | 52 | $path = $this->getPath($path); |
|
537 | |||
538 | 52 | $factory = $this->getBufferFactory(); |
|
539 | 52 | $this->fileBuffer = $factory->createFileBuffer($path, $mode); |
|
540 | 50 | $this->path = $path; |
|
541 | |||
542 | 50 | if (self::maskHasFlag($options, STREAM_USE_PATH)) { |
|
543 | $opened_path = $this->path->getUrl(); |
||
544 | } |
||
545 | |||
546 | 50 | return true; |
|
547 | 3 | } catch (\Exception $e) { |
|
548 | 3 | if (self::maskHasFlag($options, STREAM_REPORT_ERRORS)) { |
|
549 | trigger_error($e->getMessage(), E_USER_WARNING); |
||
550 | } |
||
551 | 3 | return false; |
|
552 | } |
||
553 | } |
||
554 | |||
555 | /** |
||
556 | * streamWrapper::stream_read — Read from stream |
||
557 | * |
||
558 | * @param integer $count How many bytes of data from the current position should be returned. |
||
559 | * @return string If there are less than count bytes available, return as many as are available. |
||
560 | * If no more data is available, return either FALSE or an empty string. |
||
561 | */ |
||
562 | 30 | public function stream_read($count) |
|
570 | |||
571 | /** |
||
572 | * streamWrapper::stream_seek — Seeks to specific location in a stream |
||
573 | * |
||
574 | * @param integer $offset The stream offset to seek to. |
||
575 | * @param integer $whence Possible values: |
||
576 | * SEEK_SET - Set position equal to offset bytes. |
||
577 | * SEEK_CUR - Set position to current location plus offset. |
||
578 | * SEEK_END - Set position to end-of-file plus offset. |
||
579 | * @return boolean Return TRUE if the position was updated, FALSE otherwise. |
||
580 | */ |
||
581 | 12 | public function stream_seek($offset, $whence = SEEK_SET) |
|
585 | |||
586 | /** |
||
587 | * streamWrapper::stream_set_option |
||
588 | * |
||
589 | * @param integer $option One of: |
||
590 | * STREAM_OPTION_BLOCKING (The method was called in response to stream_set_blocking()) |
||
591 | * STREAM_OPTION_READ_TIMEOUT (The method was called in response to stream_set_timeout()) |
||
592 | * STREAM_OPTION_WRITE_BUFFER (The method was called in response to stream_set_write_buffer()) |
||
593 | * @param integer $arg1 If option is |
||
594 | * STREAM_OPTION_BLOCKING: requested blocking mode (1 meaning block 0 not blocking). |
||
595 | * STREAM_OPTION_READ_TIMEOUT: the timeout in seconds. |
||
596 | * STREAM_OPTION_WRITE_BUFFER: buffer mode (STREAM_BUFFER_NONE or STREAM_BUFFER_FULL). |
||
597 | * @param integer $arg2 If option is |
||
598 | * STREAM_OPTION_BLOCKING: This option is not set. |
||
599 | * STREAM_OPTION_READ_TIMEOUT: the timeout in microseconds. |
||
600 | * STREAM_OPTION_WRITE_BUFFER: the requested buffer size. |
||
601 | * @return boolean Returns TRUE on success or FALSE on failure. If option is not implemented, |
||
602 | * FALSE should be returned. |
||
603 | */ |
||
604 | /* |
||
605 | abstract public function stream_set_option($option, $arg1, $arg2); |
||
606 | */ |
||
607 | |||
608 | /** |
||
609 | * streamWrapper::stream_stat — Retrieve information about a file resource |
||
610 | * |
||
611 | * @return array stat() and fstat() result format |
||
612 | * Numeric Associative (since PHP 4.0.6) Description |
||
613 | * 0 dev device number |
||
614 | * 1 ino inode number * |
||
615 | * 2 mode inode protection mode |
||
616 | * 3 nlink number of links |
||
617 | * 4 uid userid of owner * |
||
618 | * 5 gid groupid of owner * |
||
619 | * 6 rdev device type, if inode device |
||
620 | * 7 size size in bytes |
||
621 | * 8 atime time of last access (Unix timestamp) |
||
622 | * 9 mtime time of last modification (Unix timestamp) |
||
623 | * 10 ctime time of last inode change (Unix timestamp) |
||
624 | * 11 blksize blocksize of filesystem IO ** |
||
625 | * 12 blocks number of 512-byte blocks allocated ** |
||
626 | * * On Windows this will always be 0. |
||
627 | * ** Only valid on systems supporting the st_blksize type - other systems (e.g. Windows) return -1. |
||
628 | */ |
||
629 | 22 | public function stream_stat() |
|
633 | |||
634 | /** |
||
635 | * streamWrapper::stream_tell — Retrieve the current position of a stream |
||
636 | * |
||
637 | * @return integer Should return the current position of the stream. |
||
638 | */ |
||
639 | 12 | public function stream_tell() |
|
643 | |||
644 | /** |
||
645 | * streamWrapper::stream_write — Write to stream |
||
646 | * |
||
647 | * @param string $data Should be stored into the underlying stream. |
||
648 | * @return integer Should return the number of bytes that were successfully stored, or 0 if none could be stored. |
||
649 | */ |
||
650 | 22 | public function stream_write($data) |
|
654 | |||
655 | /** |
||
656 | * streamWrapper::unlink — Delete a file |
||
657 | * |
||
658 | * @param string $path The file URL which should be deleted. |
||
659 | * @return boolean Returns TRUE on success or FALSE on failure. |
||
660 | */ |
||
661 | 10 | public function unlink($path) |
|
662 | { |
||
663 | try { |
||
664 | 10 | $path = $this->getPath($path); |
|
665 | 10 | if ($path->getRef() != 'HEAD') { |
|
666 | 2 | throw new \Exception(sprintf( |
|
667 | 2 | 'Cannot unlink a non-HEAD file [%s#%s]', $path->getFullPath(), $path->getRef() |
|
668 | )); |
||
669 | } |
||
670 | 8 | if (!file_exists($path->getFullPath())) { |
|
671 | 2 | throw new \Exception(sprintf('Path %s not found', $path->getFullPath())); |
|
672 | } |
||
673 | 6 | if (!is_file($path->getFullPath())) { |
|
674 | 2 | throw new \Exception(sprintf('Path %s is not a file', $path->getFullPath())); |
|
675 | } |
||
676 | |||
677 | 4 | $repo = $path->getRepository(); |
|
678 | |||
679 | 4 | $commitMsg = $this->getContextOption('commitMsg', null); |
|
680 | 4 | $author = $this->getContextOption('author', null); |
|
681 | |||
682 | 4 | $repo->removeFile($path->getLocalPath(), $commitMsg, false, false, $author); |
|
683 | 4 | return true; |
|
684 | 6 | } catch (\Exception $e) { |
|
685 | 6 | trigger_error($e->getMessage(), E_USER_WARNING); |
|
686 | return false; |
||
687 | } |
||
688 | } |
||
689 | |||
690 | /** |
||
691 | * streamWrapper::url_stat — Retrieve information about a file |
||
692 | * |
||
693 | * mode bit mask: |
||
694 | * S_IFMT 0170000 bit mask for the file type bit fields |
||
695 | * S_IFSOCK 0140000 socket |
||
696 | * S_IFLNK 0120000 symbolic link |
||
697 | * S_IFREG 0100000 regular file |
||
698 | * S_IFBLK 0060000 block device |
||
699 | * S_IFDIR 0040000 directory |
||
700 | * S_IFCHR 0020000 character device |
||
701 | * S_IFIFO 0010000 FIFO |
||
702 | * S_ISUID 0004000 set UID bit |
||
703 | * S_ISGID 0002000 set-group-ID bit (see below) |
||
704 | * S_ISVTX 0001000 sticky bit (see below) |
||
705 | * S_IRWXU 00700 mask for file owner permissions |
||
706 | * S_IRUSR 00400 owner has read permission |
||
707 | * S_IWUSR 00200 owner has write permission |
||
708 | * S_IXUSR 00100 owner has execute permission |
||
709 | * S_IRWXG 00070 mask for group permissions |
||
710 | * S_IRGRP 00040 group has read permission |
||
711 | * S_IWGRP 00020 group has write permission |
||
712 | * S_IXGRP 00010 group has execute permission |
||
713 | * S_IRWXO 00007 mask for permissions for others (not in group) |
||
714 | * S_IROTH 00004 others have read permission |
||
715 | * S_IWOTH 00002 others have write permission |
||
716 | * S_IXOTH 00001 others have execute permission |
||
717 | * |
||
718 | * @param string $path The file path or URL to stat. Note that in the case of a URL, it must be a :// delimited URL. |
||
719 | * Other URL forms are not supported. |
||
720 | * @param integer $flags Holds additional flags set by the streams API. It can hold one or more of the following |
||
721 | * values OR'd together. |
||
722 | * STREAM_URL_STAT_LINK For resources with the ability to link to other resource (such |
||
723 | * as an HTTP Location: forward, or a filesystem symlink). This flag |
||
724 | * specified that only information about the link itself should be returned, |
||
725 | * not the resource pointed to by the link. This flag is set in response |
||
726 | * to calls to lstat(), is_link(), or filetype(). |
||
727 | * STREAM_URL_STAT_QUIET If this flag is set, your wrapper should not raise any errors. If this |
||
728 | * flag is not set, you are responsible for reporting errors using the |
||
729 | * trigger_error() function during stating of the path. |
||
730 | * @return array Should return as many elements as stat() does. Unknown or unavailable values should be set to a |
||
731 | * rational value (usually 0). |
||
732 | */ |
||
733 | 12 | public function url_stat($path, $flags) |
|
734 | { |
||
735 | try { |
||
736 | 12 | $path = $this->getPath($path); |
|
737 | 12 | if ($path->getRef() == 'HEAD' && file_exists($path->getFullPath())) { |
|
738 | 8 | return stat($path->getFullPath()); |
|
739 | } else { |
||
740 | 6 | $repo = $path->getRepository(); |
|
741 | 6 | $info = $repo->getObjectInfo($path->getLocalPath(), $path->getRef()); |
|
742 | |||
743 | $stat = array( |
||
744 | 6 | 'ino' => 0, |
|
745 | 6 | 'mode' => $info['mode'], |
|
746 | 6 | 'nlink' => 0, |
|
747 | 6 | 'uid' => 0, |
|
748 | 6 | 'gid' => 0, |
|
749 | 6 | 'rdev' => 0, |
|
750 | 6 | 'size' => $info['size'], |
|
751 | 6 | 'atime' => 0, |
|
752 | 6 | 'mtime' => 0, |
|
753 | 6 | 'ctime' => 0, |
|
754 | 'blksize' => -1, |
||
755 | 'blocks' => -1, |
||
756 | ); |
||
757 | 6 | return array_merge($stat, array_values($stat)); |
|
758 | } |
||
759 | } catch (\Exception $e) { |
||
760 | if (!self::maskHasFlag($flags, STREAM_URL_STAT_QUIET)) { |
||
761 | trigger_error($e->getMessage(), E_USER_WARNING); |
||
762 | } |
||
763 | return false; |
||
764 | } |
||
765 | } |
||
766 | |||
767 | /** |
||
768 | * Checks if a bitmask has a specific flag set |
||
769 | * |
||
770 | * @param integer $mask The bitmask |
||
771 | * @param integer $flag The flag to check |
||
772 | * @return boolean |
||
773 | */ |
||
774 | 64 | protected static function maskHasFlag($mask, $flag) |
|
779 | } |
||
780 |